blob: 9b525aeee9df0e579212b34078df0a7bee4c3be2 [file] [log] [blame] [edit]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <asm/types.h>
#include <asm/io.h>
#include <stdio.h>
#include <common.h>
#include <malloc.h>
#include <amlogic/amfc.h>
#include <command.h>
#include <time.h>
#include <amlogic/cpu_id.h>
#include <asm/amlogic/arch/register.h>
#define CONFIG_AMFC_TEST 1
#ifdef CONFIG_AMFC_TEST
#include <linux/zstd.h>
#include <abuf.h>
#define TABLE_SRC 0
#define TABLE_DST 1
static unsigned long total_sw_compressed_size;
static unsigned long total_hw_compressed_size;
static unsigned long total_hw_compress_time;
static unsigned long total_hw_decompress_time;
static unsigned long total_hw_self_decompress_time;
bool self;
int table_test_mask;
#endif
int amfc_init(void)
{
unsigned int value;
cpu_id_t cpu_id = get_cpu_id();
if (cpu_id.family_id == MESON_CPU_MAJOR_ID_S7D && cpu_id.chip_rev == 0x0A) {
writel(0 | (1 << 6) | (5 << 7), CLKCTRL_AMFC_CLK_CTRL); // 500MHz
} else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_T6D) {
writel(1 | (1 << 8) | (6 << 9), CLKCTRL_AMFC_CLK_CTRL); // 576MHz
} else { // s7d/s6
writel(0 | (1 << 6) | (4 << 7), CLKCTRL_AMFC_CLK_CTRL); // 666MHz
}
printf("AMFC VLSI version:%x, feature:%x\n",
readl(AMFC_GL_VERSION), readl(AMFC_GL_CMD1_FEATURE));
writel(0, AMFC_GL_CMD0_CONTROL);
writel(0, AMFC_GL_CMD1_CONTROL);
writel(3, AMFC_GL_CMD0_IRQCLR);
writel(3, AMFC_GL_CMD1_IRQCLR);
writel(0, AMFC_GL_MISC); // cmd0/1 mixed mode
writel((2 << 6) | (2 << 4) | (1 << 1) | (1), AMFC_CODEC_CTRL);
writel(1, AMFC_ZSTD_MODE_MISC);
value = readl(AMFC_WR_MIF_CTRL);
value &= ~(0x7 << 8);
value |= (2 << 8);
writel(value, AMFC_WR_MIF_CTRL);
value = readl(AMFC_RD_MIF_CTRL);
value &= ~(0x7 << 8);
value |= (2 << 8);
writel(value, AMFC_RD_MIF_CTRL);
return 0;
}
static struct amfc_cmd_list acl __attribute__((aligned(64)));
static int page_table_mode = 0;
static int log_en = 0;
static void dump_addr(void *buf, unsigned int size)
{
int i;
unsigned int *p = (unsigned int *)buf;
printf("%s addr:%px, size:%d\n", __func__, buf, size);
for (i = 0; i < size / 4; i += 4) {
printf("%px: %08x %08x %08x %08x\n",
p + i, p[i], p[i + 1], p[i + 2], p[i + 3]);
}
}
static int build_tables(unsigned int *table, unsigned long base, ssize_t size, int type)
{
int i, count, need_reverse = 0;
unsigned long tmp;
if (!table || size <= PAGE_SIZE)
return -1;
if (base & ~PAGE_MASK) {
printf("%s, base:%lx not align to %d\n",
__func__, base, PAGE_SIZE);
return -1;
}
/* physical contiguous in uboot */
count = ALIGN(size, PAGE_SIZE) / PAGE_SIZE;
/*
* type and page_table_mode for test
* page_table_mode = 1 --> src/dst all sequence table
* page_table_mode = 2 --> src sequence/dst reverse
* page_table_mode = 3 --> src reverse/dst sequence
* page_table_mode = 4 --> src/dst all reverse table
* page_table_mode = 5 --> dst sequence table/src not use page_table,
* for EROFS test
*/
if ((page_table_mode == 2 && type == TABLE_DST) ||
(page_table_mode == 3 && type == TABLE_SRC) ||
(page_table_mode == 4))
need_reverse = 1;
if (need_reverse)
base += (count - 1) * PAGE_SIZE;
for (i = 0; i < count; i++) {
tmp = ((base >> PAGE_SHIFT) << 6) | 1;
table[i] = tmp;
if (need_reverse)
base -= PAGE_SIZE;
else
base += PAGE_SIZE;
}
flush_dcache_range((unsigned long)table,
(unsigned long)table + count * 4);
return 0;
}
#define ADDR_SRC 0
#define ADDR_DST 1
static void set_up_addr(struct amfc_cmd_list *acl, unsigned long addr, int type)
{
unsigned int low, high = 0;
low = addr & 0xffffffff;
high = (addr >> 32) & 0xf;
switch (type) {
case ADDR_SRC:
acl->src_addr = low;
acl->control |= (high << 20);
break;
case ADDR_DST:
acl->dst_addr = low;
acl->control |= (high << 16);
break;
default:
break;
}
}
/*
* src: source buffer that need decompress
* dst: destination buffer that need store
* src_size: size of source buffer
* dst_size: size for destination buffer, caller should make sure
* dst size is enough
* return value: decompressed size if success, negative value if failed
*/
int amfc_decompress(void *src, void *dst, ssize_t src_size, ssize_t dst_size)
{
unsigned int *src_table = NULL, *dst_table = NULL, *tmp;
int table_size;
unsigned int status;
int cmd_time;
int timeout = ((src_size + PAGE_SIZE) / PAGE_SIZE) * 100 + 5000;
unsigned long inv_end = (unsigned long)dst + dst_size;
unsigned long secmon_start = readl(SYSCTRL_SEC_STATUS_REG17) + (1 << 20);
if (log_en)
printf("%s, acl:%p, src:%p, dst:%p, src size:%ld, dst size:%ld\n",
__func__, &acl, src, dst, src_size, dst_size);
/* setup command list */
memset(&acl, 0, sizeof(acl));
acl.src_size = src_size;
acl.dst_size = dst_size;
if (page_table_mode && src_size > PAGE_SIZE) {
table_size = sizeof(int) * (src_size / PAGE_SIZE) +
PAGE_SIZE * 2;
src_table = malloc(table_size);
if (!src_table)
return -ENOMEM;
tmp = (unsigned int *)(((unsigned long)src_table + PAGE_SIZE) & PAGE_MASK);
build_tables(tmp, (unsigned long)src, src_size, TABLE_SRC);
set_up_addr(&acl, virt_to_phys(tmp), ADDR_SRC);
acl.src_scatter = 1;
if (log_en)
printf("%s, table_size:%d, src_table:%p, tmp:%p\n",
__func__, table_size, src_table, tmp);
} else {
set_up_addr(&acl, virt_to_phys(src), ADDR_SRC);
}
if (page_table_mode && dst_size > PAGE_SIZE) {
table_size = sizeof(int) * (dst_size / PAGE_SIZE) +
PAGE_SIZE * 2;
dst_table = malloc(table_size);
if (!dst_table)
return -ENOMEM;
tmp = (unsigned int *)(((unsigned long)dst_table + PAGE_SIZE) & PAGE_MASK);
build_tables(tmp, (unsigned long)dst, dst_size, TABLE_DST);
set_up_addr(&acl, virt_to_phys(tmp), ADDR_DST);
acl.dst_scatter = 1;
if (log_en)
printf("%s, table_size:%d, dst_table:%p, tmp:%p\n",
__func__, table_size, dst_table, tmp);
} else {
set_up_addr(&acl, virt_to_phys(dst), ADDR_DST);
}
acl.algorithm = ALGORITHM_ZSTD;
acl.end = 1;
acl.compress = CMD_DECOMPRESS;
acl.owner = 1;
acl.status = 0xffffffff;
flush_dcache_range((unsigned long)src, (unsigned long)src + src_size);
flush_dcache_range((unsigned long)&acl, (unsigned long)&acl + sizeof(acl));
if (inv_end > secmon_start && (unsigned long)dst < secmon_start)
inv_end = secmon_start;
invalidate_dcache_range((unsigned long)dst, inv_end);
/* sw reset */
writel(0x80000000, AMFC_GL_CMD1_CONTROL);
writel(0x03, AMFC_GL_CMD1_IRQCLR);
writel((unsigned long)&acl >> ADDR_SHIFT, AMFC_GL_CMD1_DESC_BASE0_ADDR);
/* trigger */
writel(1, AMFC_GL_CMD1_CONTROL);
cmd_time = get_time();
/* wait for done or error */
while (1) {
status = readl(AMFC_GL_CMD1_STATUS);
if ((status & IRQ_MASK))
break;
if (get_time() - cmd_time > timeout) {
printf("time out\n");
break;
}
}
cmd_time = get_time() - cmd_time;
if (src_table)
free(src_table);
if (dst_table)
free(dst_table);
status = readl(AMFC_GL_CMD1_STATUS);
if (!(status & AMFC_ERROR_MASK)) {
#ifdef CONFIG_AMFC_TEST
if (self)
total_hw_self_decompress_time += readl(AMFC_CMD1_TIME_MEASURE);
else
total_hw_decompress_time += readl(AMFC_CMD1_TIME_MEASURE);
#endif
writel(0x01, AMFC_GL_CMD1_IRQCLR);
if (log_en)
printf("decompress done:%x %x, size:%d, cycles:%d, time:%d us\n",
acl.status, status, acl.result_size,
readl(AMFC_CMD1_TIME_MEASURE), cmd_time);
return acl.result_size;
} else {
printf("decompress failed:%x %x, time:%d us, acl:%p, src:%p, dst:%p, src_size:%ld, dst_size:%ld, timeout:%d\n",
acl.status, readl(AMFC_GL_CMD1_STATUS),
readl(AMFC_CMD1_TIME_MEASURE),
&acl, src, dst, src_size, dst_size, timeout);
dump_addr((void *)0xfe024000, 300);
dump_addr((void *)&acl, 32);
dump_addr((void *)src, 32);
dump_addr((void *)dst, 32);
writel(0x03, AMFC_GL_CMD1_IRQCLR);
return -EINVAL;
}
}
int amfc_compress(void *src, void *dst, ssize_t src_size, ssize_t dst_size)
{
unsigned int *src_table = NULL, *dst_table = NULL, *tmp;
int table_size;
unsigned int status;
int cmd_time;
int timeout = ((src_size + PAGE_SIZE) / PAGE_SIZE) * 20 + 5000;
if (log_en)
printf("%s, acl:%p, src:%p, dst:%p, src sizs:%ld, dst size:%ld\n",
__func__, &acl, src, dst, src_size, dst_size);
/* setup command list */
memset(&acl, 0, sizeof(acl));
acl.src_size = src_size;
acl.dst_size = dst_size;
if (page_table_mode && src_size > PAGE_SIZE) {
table_size = sizeof(int) * (src_size / PAGE_SIZE) +
PAGE_SIZE * 2;
src_table = malloc(table_size);
if (!src_table)
return -ENOMEM;
tmp = (unsigned int *)(((unsigned long)src_table + PAGE_SIZE) & PAGE_MASK);
build_tables(tmp, (unsigned long)src, src_size, TABLE_SRC);
set_up_addr(&acl, virt_to_phys(tmp), ADDR_SRC);
acl.src_scatter = 1;
if (log_en)
printf("%s, table_size:%d, src_table:%p, tmp:%p\n",
__func__, table_size, src_table, tmp);
} else {
set_up_addr(&acl, virt_to_phys(src), ADDR_SRC);
}
if (page_table_mode && dst_size > PAGE_SIZE) {
table_size = sizeof(int) * (dst_size / PAGE_SIZE) +
PAGE_SIZE * 2;
dst_table = malloc(table_size);
if (!dst_table)
return -ENOMEM;
tmp = (unsigned int *)(((unsigned long)dst_table + PAGE_SIZE) & PAGE_MASK);
build_tables(tmp, (unsigned long)dst, dst_size, TABLE_DST);
set_up_addr(&acl, virt_to_phys(tmp), ADDR_DST);
acl.dst_scatter = 1;
#ifdef CONFIG_AMFC_TEST
if (table_test_mask)
tmp[2] = 0;
#endif
if (log_en)
printf("%s, table_size:%d, dst_table:%p, tmp:%p\n",
__func__, table_size, dst_table, tmp);
} else {
set_up_addr(&acl, virt_to_phys(dst), ADDR_DST);
}
acl.algorithm = ALGORITHM_ZSTD;
acl.end = 1;
acl.compress = CMD_COMPRESS;
acl.owner = 1;
acl.status = 0xffffffff;
flush_dcache_range((unsigned long)src, (unsigned long)src + src_size);
flush_dcache_range((unsigned long)&acl, (unsigned long)&acl + sizeof(acl));
invalidate_dcache_range((unsigned long)dst, (unsigned long)dst + dst_size);
/* SW reset */
writel(0x80000000, AMFC_GL_CMD0_CONTROL);
writel(0x03, AMFC_GL_CMD0_IRQCLR);
writel((unsigned long)&acl >> ADDR_SHIFT, AMFC_GL_CMD0_DESC_BASE0_ADDR);
/* trigger */
writel(1, AMFC_GL_CMD0_CONTROL);
cmd_time = get_time();
// wait for done or error
while (1) {
status = readl(AMFC_GL_CMD0_STATUS);
if ((status & IRQ_MASK))
break;
if (get_time() - cmd_time > timeout) {
printf("time out\n");
break;
}
}
cmd_time = get_time() - cmd_time;
if (src_table)
free(src_table);
if (dst_table)
free(dst_table);
status = readl(AMFC_GL_CMD0_STATUS);
if (!(status & AMFC_ERROR_MASK)) {
#ifdef CONFIG_AMFC_TEST
total_hw_compress_time += readl(AMFC_CMD0_TIME_MEASURE);
#endif
writel(0x01, AMFC_GL_CMD0_IRQCLR);
if (log_en)
printf("compress done:%x %x, size:%d, cycles:%d, time:%d us\n",
acl.status, status, acl.result_size,
readl(AMFC_CMD0_TIME_MEASURE), cmd_time);
return acl.result_size;
} else {
printf("compress failed:%x %x, time:%d us, acl:%p, src:%p, dst:%p, src_size:%ld, dst_size:%ld, timeout:%d\n",
acl.status, readl(AMFC_GL_CMD0_STATUS),
readl(AMFC_CMD0_TIME_MEASURE),
&acl, src, dst, src_size, dst_size, timeout);
writel(0x03, AMFC_GL_CMD0_IRQCLR);
return -EINVAL;
}
}
#ifdef CONFIG_AMFC_TEST
#define EROFS_MAX_SIZE (PAGE_SIZE * 64)
struct pack_file {
char *name;
int type;
unsigned int size;
unsigned int offset;
};
/*
* one raw file and different compressed args files
*/
struct pack_file test_files[] = {
{"compress/521-new-log-2023-08-18_10_53_51.log", 0, 10858121, 0},
{"amfc_4m4k_level1/compress/521-new-log-2023-08-18_10_53_51.log.zsd", 1, 1076412, 10858496},
{"amfc_4m4k_level3/compress/521-new-log-2023-08-18_10_53_51.log.zsd", 1, 1212912, 11935744},
{"amfc_4m4k_level22/compress/521-new-log-2023-08-18_10_53_51.log.zsd", 1, 704301, 13152256},
{"amfc_4m128k_level1/compress/521-new-log-2023-08-18_10_53_51.log.zsd", 1, 926383, 13856768},
{"amfc_4m128k_level3/compress/521-new-log-2023-08-18_10_53_51.log.zsd", 1, 1057632, 14786560},
{"amfc_4m128k_level22/compress/521-new-log-2023-08-18_10_53_51.log.zsd", 1, 610781, 15847424},
{"compress/android_r_anon.bin", 0, 16777216, 16461824},
{"amfc_4m4k_level1/compress/android_r_anon.bin.zsd", 1, 4557912, 33243136},
{"amfc_4m4k_level3/compress/android_r_anon.bin.zsd", 1, 4353752, 37801984},
{"amfc_4m4k_level22/compress/android_r_anon.bin.zsd", 1, 3796876, 42156032},
{"amfc_4m128k_level1/compress/android_r_anon.bin.zsd", 1, 4800941, 45953024},
{"amfc_4m128k_level3/compress/android_r_anon.bin.zsd", 1, 4510906, 50757632},
{"amfc_4m128k_level22/compress/android_r_anon.bin.zsd", 1, 3784060, 55271424},
{"compress/DroidLogicTvInput.apk", 0, 10823186, 59056128},
{"amfc_4m4k_level1/compress/DroidLogicTvInput.apk.zsd", 1, 5880370, 69881856},
{"amfc_4m4k_level3/compress/DroidLogicTvInput.apk.zsd", 1, 5659473, 75763712},
{"amfc_4m4k_level22/compress/DroidLogicTvInput.apk.zsd", 1, 5260621, 81424384},
{"amfc_4m128k_level1/compress/DroidLogicTvInput.apk.zsd", 1, 5932553, 86687744},
{"amfc_4m128k_level3/compress/DroidLogicTvInput.apk.zsd", 1, 5698327, 92622848},
{"amfc_4m128k_level22/compress/DroidLogicTvInput.apk.zsd", 1, 5145713, 98324480},
{"compress/droidlogic-tv.jar", 0, 477934, 103473152},
{"amfc_4m4k_level1/compress/droidlogic-tv.jar.zsd", 1, 194111, 103952384},
{"amfc_4m4k_level3/compress/droidlogic-tv.jar.zsd", 1, 184103, 104148992},
{"amfc_4m4k_level22/compress/droidlogic-tv.jar.zsd", 1, 158674, 104333312},
{"amfc_4m128k_level1/compress/droidlogic-tv.jar.zsd", 1, 202254, 104493056},
{"amfc_4m128k_level3/compress/droidlogic-tv.jar.zsd", 1, 189089, 104697856},
{"amfc_4m128k_level22/compress/droidlogic-tv.jar.zsd", 1, 155530, 104890368},
{"compress/framework-res.apk", 0, 49495950, 105046016},
{"amfc_4m4k_level1/compress/framework-res.apk.zsd", 1, 16369915, 154542080},
{"amfc_4m4k_level3/compress/framework-res.apk.zsd", 1, 16087772, 170913792},
{"amfc_4m4k_level22/compress/framework-res.apk.zsd", 1, 15306909, 187002880},
{"amfc_4m128k_level1/compress/framework-res.apk.zsd", 1, 16283236, 202313728},
{"amfc_4m128k_level3/compress/framework-res.apk.zsd", 1, 15961873, 218599424},
{"amfc_4m128k_level22/compress/framework-res.apk.zsd", 1, 15155446, 234561536},
{"compress/Image_1", 0, 22347776, 249720832},
{"amfc_4m4k_level1/compress/Image_1.zsd", 1, 10684238, 272072704},
{"amfc_4m4k_level3/compress/Image_1.zsd", 1, 9889053, 282759168},
{"amfc_4m4k_level22/compress/Image_1.zsd", 1, 8067883, 292651008},
{"amfc_4m128k_level1/compress/Image_1.zsd", 1, 10509407, 300720128},
{"amfc_4m128k_level3/compress/Image_1.zsd", 1, 9685857, 311230464},
{"amfc_4m128k_level22/compress/Image_1.zsd", 1, 7817946, 320917504},
{"compress/NotoColorEmoji.ttf", 0, 2961984, 328736768},
{"amfc_4m4k_level1/compress/NotoColorEmoji.ttf.zsd", 1, 1794329, 331702272},
{"amfc_4m4k_level3/compress/NotoColorEmoji.ttf.zsd", 1, 1721225, 333500416},
{"amfc_4m4k_level22/compress/NotoColorEmoji.ttf.zsd", 1, 1542996, 335224832},
{"amfc_4m128k_level1/compress/NotoColorEmoji.ttf.zsd", 1, 1811509, 336769024},
{"amfc_4m128k_level3/compress/NotoColorEmoji.ttf.zsd", 1, 1723016, 338583552},
{"amfc_4m128k_level22/compress/NotoColorEmoji.ttf.zsd", 1, 1498439, 340307968},
{"compress/uImage", 0, 11194624, 341807104},
{"amfc_4m4k_level1/compress/uImage.zsd", 1, 11166211, 353005568},
{"amfc_4m4k_level3/compress/uImage.zsd", 1, 11163633, 364175360},
{"amfc_4m4k_level22/compress/uImage.zsd", 1, 11156644, 375341056},
{"amfc_4m128k_level1/compress/uImage.zsd", 1, 11170371, 386498560},
{"amfc_4m128k_level3/compress/uImage.zsd", 1, 11167452, 397672448},
{"amfc_4m128k_level22/compress/uImage.zsd", 1, 11149718, 408842240},
{"compress/zero.bin", 0, 2097152, 419995648},
{"amfc_4m4k_level1/compress/zero.bin.zsd", 1, 2070, 422096896},
{"amfc_4m4k_level3/compress/zero.bin.zsd", 1, 2069, 422100992},
{"amfc_4m4k_level22/compress/zero.bin.zsd", 1, 2068, 422105088},
{"amfc_4m128k_level1/compress/zero.bin.zsd", 1, 87, 422109184},
{"amfc_4m128k_level3/compress/zero.bin.zsd", 1, 86, 422113280},
{"amfc_4m128k_level22/compress/zero.bin.zsd", 1, 85, 422117376},
{}
};
/*
* pack file test for performance and data consistant.
* test file and above array are generated by scripts
* You need preload packed test file to a ddr address and then
* use command like:
*
* s7_pxp# amfc pack_test 12000000 30000000 34000000
*
* dst address must not overlap with base + file_size
* dst2 address must not overlap with dst 1
*/
static void amfc_pack_test(unsigned long base, void *dst, void *dst2)
{
int i, ret;
struct pack_file *pack;
void *src, *cur_src_addr = NULL;
int cur_src_size = 0;
for (i = 0; i < ARRAY_SIZE(test_files); i++) {
pack = &test_files[i];
if (!pack->name)
break;
src = (void *)(base + pack->offset);
if (!pack->type) {
/*
* check hw compress and hw decompress
*/
printf("-----------------------------\n");
printf("compress %s\n", pack->name);
ret = amfc_compress(src, dst, pack->size, pack->size);
cur_src_size = pack->size;
cur_src_addr = src;
if (ret > 0) {
printf("decompress %s\n", pack->name);
ret = amfc_decompress(dst, dst2, ret, pack->size);
ret = memcmp(dst2, src, pack->size);
printf("compare %p -> %p with %d %s\n\n",
dst2, cur_src_addr, cur_src_size,
ret ? "FAIL!!" : "OK!!");
} else {
printf("compress failed\n");
}
} else {
/*
* check sw compressed and hw decompress
*/
printf("decompress %s\n", pack->name);
ret = amfc_decompress(src, dst, pack->size, cur_src_size);
ret = memcmp(dst, cur_src_addr, cur_src_size);
printf("compare %p -> %p with %d %s\n\n",
dst, cur_src_addr, cur_src_size,
ret ? "FAIL!!" : "OK!!");
}
if (tstc()) {
printf("key abort\n");
(void)getchar();
break;
}
}
}
static unsigned char test_page[EROFS_MAX_SIZE * 2] __attribute__((aligned(4096)));
static int get_sw_compressed_size(void *src)
{
int i = 0;
unsigned char *p;
p = (unsigned char *)src + PAGE_SIZE - 1;
while (*p == 0) {
i++;
p--;
}
return i > PAGE_SIZE ? 0 : PAGE_SIZE - i;
}
static void *contain_zstd_page(void *src, int cluster)
{
unsigned char *p = (unsigned char *)src;
int i = 0;
/* skip leading zero */
while (p[i] == 0 && i < cluster) {
i++;
}
if (i >= cluster)
return NULL;
p += i;
if (p[0] == 0x28 && p[1] == 0xb5 && p[2] == 0x2f && p[3] == 0xfd) {
return p;
} else
return NULL;
}
static int memcmp1(void *p1, void *p2, int size)
{
unsigned int *i1, *i2;
int i;
int ret = 0;
i1 = (unsigned int *)p1;
i2 = (unsigned int *)p2;
for (i = 0; i < size / 4; i++) {
if (i1[i] != i2[i]) {
printf("i:%d, addr:%p->%p, value:%x->%x\n",
i, i1, i2, i1[i], i2[i]);
ret = 1;
}
}
return ret;
}
/*
* data is captured from Android system by
* https://scgit.amlogic.com/#/c/329847/
* pattern: a raw page + a zstd compressed page interleave
*
* before test, you should change a captured data to hex and pre-load it
* to DDR via load_mem.tcl in PXP
*/
static void amfc_zram_test(void *src, unsigned long size, int cmp)
{
unsigned long i;
unsigned char *p, *z;
int sw_csize, hw_csize;
int no_compress = 0;
int sw_decompress = 0;
int hw_compress = 0;
int hw_decompress = 0;
int sd_error = 0;
total_sw_compressed_size = 0;
total_hw_compressed_size = 0;
total_hw_compress_time = 0;
total_hw_decompress_time = 0;
total_hw_self_decompress_time = 0;
for (i = 0; i < size; i += PAGE_SIZE) {
p = (unsigned char *)(src + i);
if (self) { // sw compressed page
self = 0;
z = contain_zstd_page(p, PAGE_SIZE);
if (z) {
sw_csize = PAGE_SIZE - (z - p);
total_sw_compressed_size += sw_csize;
amfc_decompress(z, test_page, sw_csize, PAGE_SIZE);
sw_decompress++;
if (cmp && memcmp(test_page, (void *)((unsigned long)p - PAGE_SIZE), PAGE_SIZE)) {
printf("hw decompress address :%p not match\n", p);
}
}
} else { // src page
self = 1;
memset(test_page, 0, sizeof(test_page));
hw_csize = amfc_compress(p, test_page, PAGE_SIZE, PAGE_SIZE);
hw_compress++;
if (hw_csize > 0) {
total_hw_compressed_size += hw_csize;
amfc_decompress(test_page, test_page + PAGE_SIZE, hw_csize, PAGE_SIZE);
hw_decompress++;
if (cmp && memcmp1(test_page + PAGE_SIZE, (void *)p, PAGE_SIZE)) {
char cmd[128] = {0};
printf("hw self-decompress address :%p, size:%d not match\n", p, hw_csize);
sprintf(cmd, "md %lx %x\n", (unsigned long)test_page, hw_csize / 4 + 10);
run_command(cmd, 0);
sd_error++;
}
} else {
no_compress++;
printf("hw compress address :%p failed\n", p);
}
}
if (!(i & 0x3f000)) {
printf("ADDR:%lx, sw_csize:%8ld, hw_csize:%8ld, hw_ctime:%8ld us, hw_dtime:%8ld, hw_sdtime:%8ld, no_comp:%4d, sw_dec_page:%5d, hw_dec_page:%5d, hw_com_page:%5d, sd_error:%d\n",
(unsigned long)p, total_sw_compressed_size,
total_hw_compressed_size,
total_hw_compress_time, total_hw_decompress_time,
total_hw_self_decompress_time, no_compress,
sw_decompress, hw_decompress, hw_compress, sd_error);
}
if (tstc()) {
printf("key abort\n");
(void)getchar();
break;
}
}
printf("ADDR:%lx, sw_csize:%8ld, hw_csize:%8ld, hw_ctime:%8ld us, hw_dtime:%8ld, hw_sdtime:%8ld, no_comp:%4d, sw_dec_page:%5d, hw_dec_page:%5d, hw_com_page:%5d, sd_error:%d\n",
(unsigned long)p, total_sw_compressed_size, total_hw_compressed_size,
total_hw_compress_time, total_hw_decompress_time,
total_hw_self_decompress_time,
no_compress, sw_decompress, hw_decompress, hw_compress, sd_error);
}
static void *get_zstd_addr(void *src, int cluster, int *c_size)
{
unsigned char *p = (unsigned char *)src;
int i = 0;
unsigned long addr, remain;
/* skip leading zero */
while (p[i] == 0 && i < cluster) {
i++;
}
if (i >= cluster)
return NULL;
p += i;
if (p[0] == 0x28 && p[1] == 0xb5 && p[2] == 0x2f && p[3] == 0xfd) {
if (cluster > PAGE_SIZE) {
/* search next zstd page in this cluster to detect real size */
remain = cluster - i;
remain &= PAGE_MASK;
addr = ((unsigned long)p + PAGE_SIZE) & PAGE_MASK;
while (remain) {
if (contain_zstd_page((void *)addr, PAGE_SIZE)) {
//printf("have zstd page addr:%lx, p:%p, i:%d, remain:%ld, cluster:%d\n",
// addr, p, i, remain, cluster);
break;
}
addr += PAGE_SIZE;
remain -= PAGE_SIZE;
}
*c_size = addr - (unsigned long)p;
//printf("addr:%lx, p:%p, i:%d, remain:%ld, cluster:%d, real size:%d\n",
// addr, p, i, remain, cluster, *c_size);
} else
*c_size = cluster - i;
return p;
} else
return NULL;
}
/*
* Refer https://confluence.amlogic.com/display/SW/EROFS+with+ZSTD+and+performance+compare to
* build a ZSTD supported erofs image
*
* before test, you should change a erofs image to hex and pre-load it
* to DDR via load_mem.tcl in PXP
*/
static void amfc_erofs_test(void *src, unsigned long size, int pcluster, int verify)
{
unsigned long i, total_decompress, total_sw_csize;
unsigned char *p;
int hw_decompress = 0, ret, c_size;
struct abuf in, out;
int decompress_fail = 0;
int match_fail = 0;
total_decompress = 0;
total_sw_csize = 0;
total_hw_decompress_time = 0;
self = 0;
for (i = 0; i < size; i += PAGE_SIZE) {
p = get_zstd_addr(src + i, pcluster, &c_size);
//if (c_size < 64) {
// // HW BUG:
// //1, source address must align to 64 bytes, if src size is tool small, decode will hung
// //2, if size set to 4k but too many leading zero, decode will hung
// //3, for erofs test, page table mode must closed.
// printf("skip size too small:%lx, c_size:%d\n", (unsigned long)src + i, c_size);
// continue;
//}
if (p) { // zstd compressed page
hw_decompress = amfc_decompress(p, test_page, c_size, EROFS_MAX_SIZE);
if (hw_decompress) {
/* sw_decompress and double check */
total_decompress += hw_decompress;
total_sw_csize += c_size;
if (verify) {
abuf_init_set(&in, p, c_size);
abuf_init_set(&out, test_page + EROFS_MAX_SIZE,
EROFS_MAX_SIZE);
ret = zstd_decompress(&in, &out);
if (ret >= 0 && ret == hw_decompress) {
if (memcmp(test_page, test_page + EROFS_MAX_SIZE, ret)) {
match_fail++;
printf("hw decompress %p %d->%d not match\n", p, c_size, ret);
}
} else {
printf("sw decompress %p %d %d <-> %d failed\n",
p, c_size, hw_decompress, ret);
}
}
} else {
decompress_fail++;
}
}
if (!(i & 0x3f000)) {
printf("ADDR:%lx, hw_decompressed:%8ld, time:%8ld, dec failed:%4d, match failed:%4d, sw_csize:%ld\n",
(unsigned long)src + i, total_decompress,
total_hw_decompress_time,
decompress_fail, match_fail, total_sw_csize);
}
if (tstc()) {
printf("key abort\n");
(void)getchar();
break;
}
}
printf("ADDR:%lx, hw_decompressed:%8ld, time:%8ld, dec failed:%4d, match failed:%4d, sw_csize:%ld\n",
(unsigned long)src + i, total_decompress,
total_hw_decompress_time,
decompress_fail, match_fail, total_sw_csize);
}
static void show_acl(struct amfc_cmd_list *p_acl, int count)
{
int i;
for (i = 0; i < count; i++) {
printf("%p: %08x %08x %08x %08x %08x %08x %08x %08x\n",
p_acl + i, p_acl[i].src_addr, p_acl[i].dst_addr,
p_acl[i].link_addr, p_acl[i].src_size,
p_acl[i].dst_size, p_acl[i].control,
p_acl[i].status, p_acl[i].result_size);
}
}
static void run_table_test(struct amfc_cmd_list *p_acl, void *src,
void *dst, void *dst2, long size)
{
unsigned int status;
int count;
count = ALIGN(size, PAGE_SIZE) / PAGE_SIZE;
flush_dcache_range((unsigned long)src, (unsigned long)src + size);
flush_dcache_range((unsigned long)dst, (unsigned long)dst + size);
flush_dcache_range((unsigned long)dst2, (unsigned long)dst2 + size);
flush_dcache_range((unsigned long)p_acl, (unsigned long)p_acl + (count + 3) * sizeof(acl));
/* SW reset */
writel(0x80000000, AMFC_GL_CMD0_CONTROL);
writel(0x03, AMFC_GL_CMD0_IRQCLR);
writel((unsigned long)p_acl >> ADDR_SHIFT, AMFC_GL_CMD0_DESC_BASE0_ADDR);
/* trigger */
writel(1, AMFC_GL_CMD0_CONTROL);
// wait for done or error
while (1) {
status = readl(AMFC_GL_CMD0_STATUS);
if ((status & IRQ_MASK))
break;
if (tstc()) {
printf("key abort\n");
(void)getchar();
break;
}
}
status = readl(AMFC_GL_CMD0_STATUS);
if (!(status & AMFC_ERROR_MASK)) {
writel(0x01, AMFC_GL_CMD0_IRQCLR);
} else {
writel(0x03, AMFC_GL_CMD0_IRQCLR);
printf("test failed:%x %x\n",
p_acl[0].status, readl(AMFC_GL_CMD0_STATUS));
}
}
/*
* before test, you should change a simple text file(size > 16KB) to hex and pre-load it
* to DDR via load_mem.tcl in PXP
*/
static void amfc_table_test(void *src, void *dst, void *dst2, unsigned long size)
{
struct amfc_cmd_list *p_acl, *p_raw;
int count, i;
count = ALIGN(size, PAGE_SIZE) / PAGE_SIZE;
p_acl = malloc((count + 3) * sizeof(acl));
if (!p_acl)
return;
memset(dst, 0, size);
p_raw = p_acl;
memset(p_acl, 0, (count + 3) * sizeof(acl));
if ((unsigned long)p_acl & 0x3f) // not aligned to 64 bytes
p_acl = (struct amfc_cmd_list *)(((unsigned long)p_acl + 0x40) & ~0x3f);
printf("acl:%p, src:%p, dst:%p, dst2:%p, size:%ld\n", p_acl, src, dst, dst2, size);
// case 1: compress src to dst by table mode
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)src + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = PAGE_SIZE;
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_COMPRESS;
p_acl[i].owner = 1;
}
printf("table test case 1: compress with no end bit\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 2: decompress dst to dst2 by table mode
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 2: decompress with end bit\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 3: decompress and compress interleave mode
for (i = 0; i < count; i++) {
if (i & 0x01) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
} else {
p_acl[i].src_addr = ((unsigned long)src + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = PAGE_SIZE;
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_COMPRESS;
p_acl[i].owner = 1;
}
}
p_acl[i - 1].end = 1;
printf("table test case 3: enc/dec interleave table mode\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 4: bad table with no owner bit set
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
if (i != 1)
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 4: descriptor error with no owner\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 5: bad table with no wrong algorithm
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
if (i == 1)
p_acl[i].algorithm = ALGORITHM_LZ4HC;
else
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 5: descriptor error with wrong algorithm\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 6: bad table with zero src size
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
if (i != 1)
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
else
p_acl[i].src_size = 0;
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 6: descriptor error with zero source size\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 7: bad table with zero dst size
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
if (i != 1)
p_acl[i].dst_size = PAGE_SIZE;
else
p_acl[i].dst_size = 0;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 7: descriptor error with zero dst size\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 8: bad table with zero link address
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
if (i == 1)
p_acl[i].link_mode = 1;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 8: descriptor error with zero link address\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 9: bad table with dst size over flow
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
if (i != 1)
p_acl[i].dst_size = PAGE_SIZE;
else
p_acl[i].dst_size = 10;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 9: descriptor error with dst size overflow\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 10: bad table with decompress src size too small
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
if (i == 1)
p_acl[i].src_size = 10;
else
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 10: descriptor error with decompress size too small\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
// case 11: bad table with compress size too small
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)src + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
if (i == 1)
p_acl[i].src_size = 2;
else
p_acl[i].src_size = PAGE_SIZE;
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].control = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_COMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("table test case 11: bad table with compress size too small\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count);
free(p_raw);
}
/*
* before test, you should change a simple text file(size > 64KB) to hex and pre-load it
* to DDR via load_mem.tcl in PXP
*/
static void amfc_link_test(void *src, void *dst, void *dst2, unsigned long size)
{
struct amfc_cmd_list *p_acl, *p_raw;
int count, i;
count = ALIGN(size, PAGE_SIZE) / PAGE_SIZE;
p_acl = malloc((count + 3) * sizeof(acl));
if (!p_acl)
return;
memset(dst, 0, size);
p_raw = p_acl;
memset(p_acl, 0, (count + 3) * sizeof(acl));
if ((unsigned long)p_acl & 0x3f) // not aligned to 64 bytes
p_acl = (struct amfc_cmd_list *)(((unsigned long)p_acl + 0x40) & ~0x3f);
printf("acl:%p, src:%p, dst:%p, dst2:%p, size:%ld\n", p_acl, src, dst, dst2, size);
// case 1: compress src to dst by link mode
for (i = 0; i < count; i += 2) {
p_acl[i].src_addr = ((unsigned long)src + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].link_addr = ((unsigned long)&p_acl[i + 2]) >> ADDR_SHIFT;
p_acl[i].src_size = PAGE_SIZE;
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].link_mode = 1;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_COMPRESS;
p_acl[i].owner = 1;
}
printf("link test case 1: compress with NULL link end\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count + 3);
// case 2: decompress dst to dst2 by table mode
memset(p_acl, 0, (count + 2 ) * sizeof(*p_acl));
for (i = 0; i < count; i += 2) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = ((unsigned long)&p_acl[i + 2]) >> ADDR_SHIFT;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].link_mode = 1;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 2].end = 1; // end but build a valid link next descriptor
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = 0;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].link_mode = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
p_acl[i].end = 1; // end
printf("link test case 2: decompress with end bit but have a valid link descriptor\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count + 3);
// case 3: decompress and compress interleave link mode
memset(p_acl, 0, (count + 2 ) * sizeof(*p_acl));
for (i = 0; i < count; i += 2) {
if (i & 0x02) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = ((unsigned long)&p_acl[i + 2]) >> ADDR_SHIFT;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].link_mode = 1;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
} else {
p_acl[i].src_addr = ((unsigned long)src + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].link_addr = ((unsigned long)&p_acl[i + 2]) >> ADDR_SHIFT;
p_acl[i].src_size = PAGE_SIZE;
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].link_mode = 1;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_COMPRESS;
p_acl[i].owner = 1;
}
}
p_acl[i - 2].end = 1;
p_acl[i - 2].link_mode = 0;
printf("link test case 3: enc/dec interleave link mode\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count + 3);
// case 4: valid link descriptor but link mode disabled
memset(p_acl, 0, (count + 2 ) * sizeof(*p_acl));
for (i = 0; i < count; i++) {
p_acl[i].src_addr = ((unsigned long)src + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].src_size = PAGE_SIZE;
p_acl[i].dst_size = PAGE_SIZE;
if (!i) { // link to 3rd desc
p_acl[i].link_addr = ((unsigned long)&p_acl[i + 2]) >> ADDR_SHIFT;
}
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_COMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 1].end = 1;
printf("link test case 4: valid link descriptor but link mode disabled \n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count + 3);
// case 5: circular link
memset(p_acl, 0, (count + 2 ) * sizeof(*p_acl));
for (i = 0; i < count; i += 2) {
p_acl[i].src_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst2 + PAGE_SIZE * i);
p_acl[i].link_addr = ((unsigned long)&p_acl[i + 2]) >> ADDR_SHIFT;
p_acl[i].src_size = get_sw_compressed_size(dst + PAGE_SIZE * i);
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].link_mode = 1;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_DECOMPRESS;
p_acl[i].owner = 1;
}
p_acl[i - 2].link_addr = ((unsigned long)&p_acl[0]) >> ADDR_SHIFT;
printf("link test case 5: circular link\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count + 3);
// case 6: table and link
memset(p_acl, 0, (count + 2 ) * sizeof(*p_acl));
for (i = 0; i < count; i ++) {
p_acl[i].src_addr = ((unsigned long)src + PAGE_SIZE * i);
p_acl[i].dst_addr = ((unsigned long)dst + PAGE_SIZE * i);
p_acl[i].src_size = PAGE_SIZE;
p_acl[i].dst_size = PAGE_SIZE;
p_acl[i].status = 0xffffffff;
p_acl[i].result_size = 0;
p_acl[i].algorithm = ALGORITHM_ZSTD;
p_acl[i].compress = CMD_COMPRESS;
p_acl[i].owner = 1;
if (i == 2) {
p_acl[i].link_addr = ((unsigned long)&p_acl[i + 4]) >> ADDR_SHIFT;
p_acl[i].link_mode = 1;
}
}
p_acl[i - 1].end = 1;
printf("link test case 6: table and link\n");
run_table_test(p_acl, src, dst, dst2, size);
show_acl(p_acl, count + 3);
free(p_raw);
}
static int check_zero(void *start, int range)
{
unsigned char *p = (unsigned char *)start;
int i;
for (i = 0; i < range; i++)
if (p[i])
return 1;
return 0;
}
static void amfc_address_test(void *src, void *dst,
void *dst2, int src_size)
{
int i, ret;
void *p, *p1, *p2;
char cmd_buf[128] = {};
// 1, compress dst not align test
printf("==== compress dst and decompress src not aligned test\n");
for (i = 0; i < 64; i++) {
p = (void *)(dst + i);
memset(dst, 0, src_size + 128);
memset(dst2, 0, src_size + 128);
run_command("dcache flush", 0);
ret = amfc_compress(src, p, src_size, src_size);
if (ret > 0) {
amfc_decompress(p, dst2, ret, src_size);
if (memcmp(src, dst2, src_size)) {
printf("%s, src:%p, dst:%p, dst2:%p, ret:%d, src_size:%d, i:%d not match\n",
__func__, src, p, dst2, ret, src_size, i);
}
p1 = p + ret;
p2 = (void *)(((unsigned long)p1 + 64) & ~63);
if (check_zero(dst, i)) {
printf("left over write\n");
sprintf(cmd_buf, "md %lx 10\n", (long)dst);
run_command(cmd_buf, 0);
}
if (check_zero(p1, p2 - p1)) {
printf("right over write\n");
sprintf(cmd_buf, "md %lx 10\n", (long)p1);
run_command(cmd_buf, 0);
}
}
}
// 2, compress src not aligned
memset(dst, 0, src_size + 128);
amfc_compress(src, dst, src_size, src_size);
printf("==== compress src not aligned test\n");
for (i = 0; i < 64; i++) {
p = (void *)(dst + src_size + i);
memset(p, 0, src_size + 128);
memset(dst2, 0, src_size + 128);
memcpy(p, src, src_size);
run_command("dcache flush", 0);
ret = amfc_compress(p, dst2, src_size, src_size);
if (ret > 0) {
if (memcmp(dst, dst2, ret)) {
printf("%s, dst:%p, dst2:%p, ret:%d, src_size:%d i:%d, not match\n",
__func__, dst, dst2, ret, src_size, i);
}
}
}
// 3, decompress dest not aligned
memset(dst, 0, src_size + 128);
ret = amfc_compress(src, dst, src_size, src_size);
printf("==== decompress dst not aligned test\n");
for (i = 0; i < 64; i++) {
p = (void *)(dst2 + i);
memset(dst2, 0, src_size + 128);
run_command("dcache flush", 0);
ret = amfc_decompress(dst, p, ret, src_size);
if (ret > 0) {
if (memcmp(p, src, src_size)) {
printf("%s, p:%p, src:%p, ret:%d, src_size:%d, i:%d not match\n",
__func__, p, src, ret, src_size, i);
}
if (check_zero(dst2, i)) {
printf("left over write\n");
sprintf(cmd_buf, "md %lx 10\n", (long)dst2);
run_command(cmd_buf, 0);
}
p1 = p + src_size;
p2 = (void *)(((unsigned long)p1 + 64) & ~63);
if (check_zero(p1, p2 - p1)) {
printf("right over write\n");
sprintf(cmd_buf, "md %lx 10\n", (long)p1);
run_command(cmd_buf, 0);
}
}
}
}
#endif
static int do_amfc(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
unsigned long src;
unsigned long dst;
unsigned long src_size;
unsigned long dst_size;
int ret;
if (!strcmp(argv[1], "set")) {
if (argc != 4)
return -1;
if (!strcmp(argv[2], "page_table")) {
page_table_mode = simple_strtoul(argv[3], NULL, 16);
printf("set page_table_mode to:%d\n", page_table_mode);
}
if (!strcmp(argv[2], "log")) {
log_en = simple_strtoul(argv[3], NULL, 16);
printf("set log to:%d\n", log_en);
}
return 0;
}
#ifdef CONFIG_AMFC_TEST
if (!strcmp(argv[1], "pack_test")) {
if (argc != 5)
return -1;
src = simple_strtoul(argv[2], NULL, 16);
dst = simple_strtoul(argv[3], NULL, 16);
src_size = simple_strtoul(argv[4], NULL, 16);
amfc_pack_test(src, (void *)dst, (void *)src_size);
return 0;
}
if (!strcmp(argv[1], "zram_test")) {
if (argc != 5)
return -1;
src = simple_strtoul(argv[2], NULL, 16);
src_size = simple_strtoul(argv[3], NULL, 16);
dst_size = simple_strtoul(argv[4], NULL, 16);
amfc_zram_test((void *)src, src_size, dst_size);
return 0;
}
if (!strcmp(argv[1], "erofs_test")) {
if (argc != 6)
return -1;
src = simple_strtoul(argv[2], NULL, 16);
dst = simple_strtoul(argv[3], NULL, 16);
src_size = simple_strtoul(argv[4], NULL, 16);
dst_size = simple_strtoul(argv[5], NULL, 16);
amfc_erofs_test((void *)src, dst, src_size, dst_size);
return 0;
}
if (!strcmp(argv[1], "table_test")) {
if (argc != 6)
return -1;
src = simple_strtoul(argv[2], NULL, 16);
dst = simple_strtoul(argv[3], NULL, 16);
src_size = simple_strtoul(argv[4], NULL, 16);
dst_size = simple_strtoul(argv[5], NULL, 16);
amfc_table_test((void *)src, (void *)dst, (void *)src_size, dst_size);
return 0;
}
if (!strcmp(argv[1], "link_test")) {
if (argc != 6)
return -1;
src = simple_strtoul(argv[2], NULL, 16);
dst = simple_strtoul(argv[3], NULL, 16);
src_size = simple_strtoul(argv[4], NULL, 16);
dst_size = simple_strtoul(argv[5], NULL, 16);
amfc_link_test((void *)src, (void *)dst, (void *)src_size, dst_size);
return 0;
}
if (!strcmp(argv[1], "table_mask")) {
if (argc != 3)
return -1;
table_test_mask = simple_strtoul(argv[2], NULL, 16);
return 0;
}
if (!strcmp(argv[1], "addr_test")) {
if (argc != 6)
return -1;
src = simple_strtoul(argv[2], NULL, 16);
dst = simple_strtoul(argv[3], NULL, 16);
src_size = simple_strtoul(argv[4], NULL, 16);
dst_size = simple_strtoul(argv[5], NULL, 16);
amfc_address_test((void *)src, (void *)dst, (void *)src_size, dst_size);
return 0;
}
#endif
if (argc != 6)
return -1;
src = simple_strtoul(argv[2], NULL, 16);
dst = simple_strtoul(argv[3], NULL, 16);
src_size = simple_strtoul(argv[4], NULL, 16);
dst_size = simple_strtoul(argv[5], NULL, 16);
if (!strcmp(argv[1], "compress"))
ret = amfc_compress((void *)src, (void *)dst, src_size, dst_size);
else if (!strcmp(argv[1], "decompress"))
ret = amfc_decompress((void *)src, (void *)dst, src_size, dst_size);
return 0;
}
U_BOOT_CMD(
amfc, 7, 0, do_amfc,
"amfc subsystem",
"compress/decompress [src_addr] [dst_addr] [src_size] [dst_size]\n"
"set:\n"
" page_table [0/1] ---- enable/disable page table mode\n"
"memcmp [src] [dst] [size] ----compare two memory region\n"
"All parameters in hex value"
);