18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Tests for Generic Reed Solomon encoder / decoder library
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Written by Ferdinand Blomqvist
68c2ecf20Sopenharmony_ci * Based on previous work by Phil Karn, KA9Q
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/rslib.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
128c2ecf20Sopenharmony_ci#include <linux/random.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cienum verbosity {
168c2ecf20Sopenharmony_ci	V_SILENT,
178c2ecf20Sopenharmony_ci	V_PROGRESS,
188c2ecf20Sopenharmony_ci	V_CSUMMARY
198c2ecf20Sopenharmony_ci};
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cienum method {
228c2ecf20Sopenharmony_ci	CORR_BUFFER,
238c2ecf20Sopenharmony_ci	CALLER_SYNDROME,
248c2ecf20Sopenharmony_ci	IN_PLACE
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define __param(type, name, init, msg)		\
288c2ecf20Sopenharmony_ci	static type name = init;		\
298c2ecf20Sopenharmony_ci	module_param(name, type, 0444);		\
308c2ecf20Sopenharmony_ci	MODULE_PARM_DESC(name, msg)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci__param(int, v, V_PROGRESS, "Verbosity level");
338c2ecf20Sopenharmony_ci__param(int, ewsc, 1, "Erasures without symbol corruption");
348c2ecf20Sopenharmony_ci__param(int, bc, 1, "Test for correct behaviour beyond error correction capacity");
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistruct etab {
378c2ecf20Sopenharmony_ci	int	symsize;
388c2ecf20Sopenharmony_ci	int	genpoly;
398c2ecf20Sopenharmony_ci	int	fcs;
408c2ecf20Sopenharmony_ci	int	prim;
418c2ecf20Sopenharmony_ci	int	nroots;
428c2ecf20Sopenharmony_ci	int	ntrials;
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* List of codes to test */
468c2ecf20Sopenharmony_cistatic struct etab Tab[] = {
478c2ecf20Sopenharmony_ci	{2,	0x7,	1,	1,	1,	100000	},
488c2ecf20Sopenharmony_ci	{3,	0xb,	1,	1,	2,	100000	},
498c2ecf20Sopenharmony_ci	{3,	0xb,	1,	1,	3,	100000	},
508c2ecf20Sopenharmony_ci	{3,	0xb,	2,	1,	4,	100000	},
518c2ecf20Sopenharmony_ci	{4,	0x13,	1,	1,	4,	10000	},
528c2ecf20Sopenharmony_ci	{5,	0x25,	1,	1,	6,	1000	},
538c2ecf20Sopenharmony_ci	{6,	0x43,	3,	1,	8,	1000	},
548c2ecf20Sopenharmony_ci	{7,	0x89,	1,	1,	14,	500	},
558c2ecf20Sopenharmony_ci	{8,	0x11d,	1,	1,	30,	100	},
568c2ecf20Sopenharmony_ci	{8,	0x187,	112,	11,	32,	100	},
578c2ecf20Sopenharmony_ci	{9,	0x211,	1,	1,	33,	80	},
588c2ecf20Sopenharmony_ci	{0, 0, 0, 0, 0, 0},
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistruct estat {
638c2ecf20Sopenharmony_ci	int	dwrong;
648c2ecf20Sopenharmony_ci	int	irv;
658c2ecf20Sopenharmony_ci	int	wepos;
668c2ecf20Sopenharmony_ci	int	nwords;
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistruct bcstat {
708c2ecf20Sopenharmony_ci	int	rfail;
718c2ecf20Sopenharmony_ci	int	rsuccess;
728c2ecf20Sopenharmony_ci	int	noncw;
738c2ecf20Sopenharmony_ci	int	nwords;
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistruct wspace {
778c2ecf20Sopenharmony_ci	uint16_t	*c;		/* sent codeword */
788c2ecf20Sopenharmony_ci	uint16_t	*r;		/* received word */
798c2ecf20Sopenharmony_ci	uint16_t	*s;		/* syndrome */
808c2ecf20Sopenharmony_ci	uint16_t	*corr;		/* correction buffer */
818c2ecf20Sopenharmony_ci	int		*errlocs;
828c2ecf20Sopenharmony_ci	int		*derrlocs;
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistruct pad {
868c2ecf20Sopenharmony_ci	int	mult;
878c2ecf20Sopenharmony_ci	int	shift;
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic struct pad pad_coef[] = {
918c2ecf20Sopenharmony_ci	{ 0, 0 },
928c2ecf20Sopenharmony_ci	{ 1, 2 },
938c2ecf20Sopenharmony_ci	{ 1, 1 },
948c2ecf20Sopenharmony_ci	{ 3, 2 },
958c2ecf20Sopenharmony_ci	{ 1, 0 },
968c2ecf20Sopenharmony_ci};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic void free_ws(struct wspace *ws)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	if (!ws)
1018c2ecf20Sopenharmony_ci		return;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	kfree(ws->errlocs);
1048c2ecf20Sopenharmony_ci	kfree(ws->c);
1058c2ecf20Sopenharmony_ci	kfree(ws);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic struct wspace *alloc_ws(struct rs_codec *rs)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	int nroots = rs->nroots;
1118c2ecf20Sopenharmony_ci	struct wspace *ws;
1128c2ecf20Sopenharmony_ci	int nn = rs->nn;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	ws = kzalloc(sizeof(*ws), GFP_KERNEL);
1158c2ecf20Sopenharmony_ci	if (!ws)
1168c2ecf20Sopenharmony_ci		return NULL;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	ws->c = kmalloc_array(2 * (nn + nroots),
1198c2ecf20Sopenharmony_ci				sizeof(uint16_t), GFP_KERNEL);
1208c2ecf20Sopenharmony_ci	if (!ws->c)
1218c2ecf20Sopenharmony_ci		goto err;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	ws->r = ws->c + nn;
1248c2ecf20Sopenharmony_ci	ws->s = ws->r + nn;
1258c2ecf20Sopenharmony_ci	ws->corr = ws->s + nroots;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	ws->errlocs = kmalloc_array(nn + nroots, sizeof(int), GFP_KERNEL);
1288c2ecf20Sopenharmony_ci	if (!ws->errlocs)
1298c2ecf20Sopenharmony_ci		goto err;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	ws->derrlocs = ws->errlocs + nn;
1328c2ecf20Sopenharmony_ci	return ws;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cierr:
1358c2ecf20Sopenharmony_ci	free_ws(ws);
1368c2ecf20Sopenharmony_ci	return NULL;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/*
1418c2ecf20Sopenharmony_ci * Generates a random codeword and stores it in c. Generates random errors and
1428c2ecf20Sopenharmony_ci * erasures, and stores the random word with errors in r. Erasure positions are
1438c2ecf20Sopenharmony_ci * stored in derrlocs, while errlocs has one of three values in every position:
1448c2ecf20Sopenharmony_ci *
1458c2ecf20Sopenharmony_ci * 0 if there is no error in this position;
1468c2ecf20Sopenharmony_ci * 1 if there is a symbol error in this position;
1478c2ecf20Sopenharmony_ci * 2 if there is an erasure without symbol corruption.
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * Returns the number of corrupted symbols.
1508c2ecf20Sopenharmony_ci */
1518c2ecf20Sopenharmony_cistatic int get_rcw_we(struct rs_control *rs, struct wspace *ws,
1528c2ecf20Sopenharmony_ci			int len, int errs, int eras)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	int nroots = rs->codec->nroots;
1558c2ecf20Sopenharmony_ci	int *derrlocs = ws->derrlocs;
1568c2ecf20Sopenharmony_ci	int *errlocs = ws->errlocs;
1578c2ecf20Sopenharmony_ci	int dlen = len - nroots;
1588c2ecf20Sopenharmony_ci	int nn = rs->codec->nn;
1598c2ecf20Sopenharmony_ci	uint16_t *c = ws->c;
1608c2ecf20Sopenharmony_ci	uint16_t *r = ws->r;
1618c2ecf20Sopenharmony_ci	int errval;
1628c2ecf20Sopenharmony_ci	int errloc;
1638c2ecf20Sopenharmony_ci	int i;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* Load c with random data and encode */
1668c2ecf20Sopenharmony_ci	for (i = 0; i < dlen; i++)
1678c2ecf20Sopenharmony_ci		c[i] = prandom_u32() & nn;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	memset(c + dlen, 0, nroots * sizeof(*c));
1708c2ecf20Sopenharmony_ci	encode_rs16(rs, c, dlen, c + dlen, 0);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* Make copyand add errors and erasures */
1738c2ecf20Sopenharmony_ci	memcpy(r, c, len * sizeof(*r));
1748c2ecf20Sopenharmony_ci	memset(errlocs, 0, len * sizeof(*errlocs));
1758c2ecf20Sopenharmony_ci	memset(derrlocs, 0, nroots * sizeof(*derrlocs));
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Generating random errors */
1788c2ecf20Sopenharmony_ci	for (i = 0; i < errs; i++) {
1798c2ecf20Sopenharmony_ci		do {
1808c2ecf20Sopenharmony_ci			/* Error value must be nonzero */
1818c2ecf20Sopenharmony_ci			errval = prandom_u32() & nn;
1828c2ecf20Sopenharmony_ci		} while (errval == 0);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		do {
1858c2ecf20Sopenharmony_ci			/* Must not choose the same location twice */
1868c2ecf20Sopenharmony_ci			errloc = prandom_u32() % len;
1878c2ecf20Sopenharmony_ci		} while (errlocs[errloc] != 0);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci		errlocs[errloc] = 1;
1908c2ecf20Sopenharmony_ci		r[errloc] ^= errval;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	/* Generating random erasures */
1948c2ecf20Sopenharmony_ci	for (i = 0; i < eras; i++) {
1958c2ecf20Sopenharmony_ci		do {
1968c2ecf20Sopenharmony_ci			/* Must not choose the same location twice */
1978c2ecf20Sopenharmony_ci			errloc = prandom_u32() % len;
1988c2ecf20Sopenharmony_ci		} while (errlocs[errloc] != 0);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		derrlocs[i] = errloc;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		if (ewsc && (prandom_u32() & 1)) {
2038c2ecf20Sopenharmony_ci			/* Erasure with the symbol intact */
2048c2ecf20Sopenharmony_ci			errlocs[errloc] = 2;
2058c2ecf20Sopenharmony_ci		} else {
2068c2ecf20Sopenharmony_ci			/* Erasure with corrupted symbol */
2078c2ecf20Sopenharmony_ci			do {
2088c2ecf20Sopenharmony_ci				/* Error value must be nonzero */
2098c2ecf20Sopenharmony_ci				errval = prandom_u32() & nn;
2108c2ecf20Sopenharmony_ci			} while (errval == 0);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci			errlocs[errloc] = 1;
2138c2ecf20Sopenharmony_ci			r[errloc] ^= errval;
2148c2ecf20Sopenharmony_ci			errs++;
2158c2ecf20Sopenharmony_ci		}
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return errs;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic void fix_err(uint16_t *data, int nerrs, uint16_t *corr, int *errlocs)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	int i;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	for (i = 0; i < nerrs; i++)
2268c2ecf20Sopenharmony_ci		data[errlocs[i]] ^= corr[i];
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic void compute_syndrome(struct rs_control *rsc, uint16_t *data,
2308c2ecf20Sopenharmony_ci				int len, uint16_t *syn)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct rs_codec *rs = rsc->codec;
2338c2ecf20Sopenharmony_ci	uint16_t *alpha_to = rs->alpha_to;
2348c2ecf20Sopenharmony_ci	uint16_t *index_of = rs->index_of;
2358c2ecf20Sopenharmony_ci	int nroots = rs->nroots;
2368c2ecf20Sopenharmony_ci	int prim = rs->prim;
2378c2ecf20Sopenharmony_ci	int fcr = rs->fcr;
2388c2ecf20Sopenharmony_ci	int i, j;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* Calculating syndrome */
2418c2ecf20Sopenharmony_ci	for (i = 0; i < nroots; i++) {
2428c2ecf20Sopenharmony_ci		syn[i] = data[0];
2438c2ecf20Sopenharmony_ci		for (j = 1; j < len; j++) {
2448c2ecf20Sopenharmony_ci			if (syn[i] == 0) {
2458c2ecf20Sopenharmony_ci				syn[i] = data[j];
2468c2ecf20Sopenharmony_ci			} else {
2478c2ecf20Sopenharmony_ci				syn[i] = data[j] ^
2488c2ecf20Sopenharmony_ci					alpha_to[rs_modnn(rs, index_of[syn[i]]
2498c2ecf20Sopenharmony_ci						+ (fcr + i) * prim)];
2508c2ecf20Sopenharmony_ci			}
2518c2ecf20Sopenharmony_ci		}
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/* Convert to index form */
2558c2ecf20Sopenharmony_ci	for (i = 0; i < nroots; i++)
2568c2ecf20Sopenharmony_ci		syn[i] = rs->index_of[syn[i]];
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/* Test up to error correction capacity */
2608c2ecf20Sopenharmony_cistatic void test_uc(struct rs_control *rs, int len, int errs,
2618c2ecf20Sopenharmony_ci		int eras, int trials, struct estat *stat,
2628c2ecf20Sopenharmony_ci		struct wspace *ws, int method)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	int dlen = len - rs->codec->nroots;
2658c2ecf20Sopenharmony_ci	int *derrlocs = ws->derrlocs;
2668c2ecf20Sopenharmony_ci	int *errlocs = ws->errlocs;
2678c2ecf20Sopenharmony_ci	uint16_t *corr = ws->corr;
2688c2ecf20Sopenharmony_ci	uint16_t *c = ws->c;
2698c2ecf20Sopenharmony_ci	uint16_t *r = ws->r;
2708c2ecf20Sopenharmony_ci	uint16_t *s = ws->s;
2718c2ecf20Sopenharmony_ci	int derrs, nerrs;
2728c2ecf20Sopenharmony_ci	int i, j;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	for (j = 0; j < trials; j++) {
2758c2ecf20Sopenharmony_ci		nerrs = get_rcw_we(rs, ws, len, errs, eras);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci		switch (method) {
2788c2ecf20Sopenharmony_ci		case CORR_BUFFER:
2798c2ecf20Sopenharmony_ci			derrs = decode_rs16(rs, r, r + dlen, dlen,
2808c2ecf20Sopenharmony_ci					NULL, eras, derrlocs, 0, corr);
2818c2ecf20Sopenharmony_ci			fix_err(r, derrs, corr, derrlocs);
2828c2ecf20Sopenharmony_ci			break;
2838c2ecf20Sopenharmony_ci		case CALLER_SYNDROME:
2848c2ecf20Sopenharmony_ci			compute_syndrome(rs, r, len, s);
2858c2ecf20Sopenharmony_ci			derrs = decode_rs16(rs, NULL, NULL, dlen,
2868c2ecf20Sopenharmony_ci					s, eras, derrlocs, 0, corr);
2878c2ecf20Sopenharmony_ci			fix_err(r, derrs, corr, derrlocs);
2888c2ecf20Sopenharmony_ci			break;
2898c2ecf20Sopenharmony_ci		case IN_PLACE:
2908c2ecf20Sopenharmony_ci			derrs = decode_rs16(rs, r, r + dlen, dlen,
2918c2ecf20Sopenharmony_ci					NULL, eras, derrlocs, 0, NULL);
2928c2ecf20Sopenharmony_ci			break;
2938c2ecf20Sopenharmony_ci		default:
2948c2ecf20Sopenharmony_ci			continue;
2958c2ecf20Sopenharmony_ci		}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		if (derrs != nerrs)
2988c2ecf20Sopenharmony_ci			stat->irv++;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		if (method != IN_PLACE) {
3018c2ecf20Sopenharmony_ci			for (i = 0; i < derrs; i++) {
3028c2ecf20Sopenharmony_ci				if (errlocs[derrlocs[i]] != 1)
3038c2ecf20Sopenharmony_ci					stat->wepos++;
3048c2ecf20Sopenharmony_ci			}
3058c2ecf20Sopenharmony_ci		}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci		if (memcmp(r, c, len * sizeof(*r)))
3088c2ecf20Sopenharmony_ci			stat->dwrong++;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci	stat->nwords += trials;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic int ex_rs_helper(struct rs_control *rs, struct wspace *ws,
3148c2ecf20Sopenharmony_ci			int len, int trials, int method)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	static const char * const desc[] = {
3178c2ecf20Sopenharmony_ci		"Testing correction buffer interface...",
3188c2ecf20Sopenharmony_ci		"Testing with caller provided syndrome...",
3198c2ecf20Sopenharmony_ci		"Testing in-place interface..."
3208c2ecf20Sopenharmony_ci	};
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	struct estat stat = {0, 0, 0, 0};
3238c2ecf20Sopenharmony_ci	int nroots = rs->codec->nroots;
3248c2ecf20Sopenharmony_ci	int errs, eras, retval;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (v >= V_PROGRESS)
3278c2ecf20Sopenharmony_ci		pr_info("  %s\n", desc[method]);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	for (errs = 0; errs <= nroots / 2; errs++)
3308c2ecf20Sopenharmony_ci		for (eras = 0; eras <= nroots - 2 * errs; eras++)
3318c2ecf20Sopenharmony_ci			test_uc(rs, len, errs, eras, trials, &stat, ws, method);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (v >= V_CSUMMARY) {
3348c2ecf20Sopenharmony_ci		pr_info("    Decodes wrong:        %d / %d\n",
3358c2ecf20Sopenharmony_ci				stat.dwrong, stat.nwords);
3368c2ecf20Sopenharmony_ci		pr_info("    Wrong return value:   %d / %d\n",
3378c2ecf20Sopenharmony_ci				stat.irv, stat.nwords);
3388c2ecf20Sopenharmony_ci		if (method != IN_PLACE)
3398c2ecf20Sopenharmony_ci			pr_info("    Wrong error position: %d\n", stat.wepos);
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	retval = stat.dwrong + stat.wepos + stat.irv;
3438c2ecf20Sopenharmony_ci	if (retval && v >= V_PROGRESS)
3448c2ecf20Sopenharmony_ci		pr_warn("    FAIL: %d decoding failures!\n", retval);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return retval;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int exercise_rs(struct rs_control *rs, struct wspace *ws,
3508c2ecf20Sopenharmony_ci		       int len, int trials)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	int retval = 0;
3548c2ecf20Sopenharmony_ci	int i;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (v >= V_PROGRESS)
3578c2ecf20Sopenharmony_ci		pr_info("Testing up to error correction capacity...\n");
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	for (i = 0; i <= IN_PLACE; i++)
3608c2ecf20Sopenharmony_ci		retval |= ex_rs_helper(rs, ws, len, trials, i);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	return retval;
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci/* Tests for correct behaviour beyond error correction capacity */
3668c2ecf20Sopenharmony_cistatic void test_bc(struct rs_control *rs, int len, int errs,
3678c2ecf20Sopenharmony_ci		int eras, int trials, struct bcstat *stat,
3688c2ecf20Sopenharmony_ci		struct wspace *ws)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	int nroots = rs->codec->nroots;
3718c2ecf20Sopenharmony_ci	int dlen = len - nroots;
3728c2ecf20Sopenharmony_ci	int *derrlocs = ws->derrlocs;
3738c2ecf20Sopenharmony_ci	uint16_t *corr = ws->corr;
3748c2ecf20Sopenharmony_ci	uint16_t *r = ws->r;
3758c2ecf20Sopenharmony_ci	int derrs, j;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	for (j = 0; j < trials; j++) {
3788c2ecf20Sopenharmony_ci		get_rcw_we(rs, ws, len, errs, eras);
3798c2ecf20Sopenharmony_ci		derrs = decode_rs16(rs, r, r + dlen, dlen,
3808c2ecf20Sopenharmony_ci				NULL, eras, derrlocs, 0, corr);
3818c2ecf20Sopenharmony_ci		fix_err(r, derrs, corr, derrlocs);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci		if (derrs >= 0) {
3848c2ecf20Sopenharmony_ci			stat->rsuccess++;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci			/*
3878c2ecf20Sopenharmony_ci			 * We check that the returned word is actually a
3888c2ecf20Sopenharmony_ci			 * codeword. The obious way to do this would be to
3898c2ecf20Sopenharmony_ci			 * compute the syndrome, but we don't want to replicate
3908c2ecf20Sopenharmony_ci			 * that code here. However, all the codes are in
3918c2ecf20Sopenharmony_ci			 * systematic form, and therefore we can encode the
3928c2ecf20Sopenharmony_ci			 * returned word, and see whether the parity changes or
3938c2ecf20Sopenharmony_ci			 * not.
3948c2ecf20Sopenharmony_ci			 */
3958c2ecf20Sopenharmony_ci			memset(corr, 0, nroots * sizeof(*corr));
3968c2ecf20Sopenharmony_ci			encode_rs16(rs, r, dlen, corr, 0);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci			if (memcmp(r + dlen, corr, nroots * sizeof(*corr)))
3998c2ecf20Sopenharmony_ci				stat->noncw++;
4008c2ecf20Sopenharmony_ci		} else {
4018c2ecf20Sopenharmony_ci			stat->rfail++;
4028c2ecf20Sopenharmony_ci		}
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci	stat->nwords += trials;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic int exercise_rs_bc(struct rs_control *rs, struct wspace *ws,
4088c2ecf20Sopenharmony_ci			  int len, int trials)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct bcstat stat = {0, 0, 0, 0};
4118c2ecf20Sopenharmony_ci	int nroots = rs->codec->nroots;
4128c2ecf20Sopenharmony_ci	int errs, eras, cutoff;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (v >= V_PROGRESS)
4158c2ecf20Sopenharmony_ci		pr_info("Testing beyond error correction capacity...\n");
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	for (errs = 1; errs <= nroots; errs++) {
4188c2ecf20Sopenharmony_ci		eras = nroots - 2 * errs + 1;
4198c2ecf20Sopenharmony_ci		if (eras < 0)
4208c2ecf20Sopenharmony_ci			eras = 0;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		cutoff = nroots <= len - errs ? nroots : len - errs;
4238c2ecf20Sopenharmony_ci		for (; eras <= cutoff; eras++)
4248c2ecf20Sopenharmony_ci			test_bc(rs, len, errs, eras, trials, &stat, ws);
4258c2ecf20Sopenharmony_ci	}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	if (v >= V_CSUMMARY) {
4288c2ecf20Sopenharmony_ci		pr_info("  decoder gives up:        %d / %d\n",
4298c2ecf20Sopenharmony_ci				stat.rfail, stat.nwords);
4308c2ecf20Sopenharmony_ci		pr_info("  decoder returns success: %d / %d\n",
4318c2ecf20Sopenharmony_ci				stat.rsuccess, stat.nwords);
4328c2ecf20Sopenharmony_ci		pr_info("    not a codeword:        %d / %d\n",
4338c2ecf20Sopenharmony_ci				stat.noncw, stat.rsuccess);
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (stat.noncw && v >= V_PROGRESS)
4378c2ecf20Sopenharmony_ci		pr_warn("    FAIL: %d silent failures!\n", stat.noncw);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return stat.noncw;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int run_exercise(struct etab *e)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	int nn = (1 << e->symsize) - 1;
4458c2ecf20Sopenharmony_ci	int kk = nn - e->nroots;
4468c2ecf20Sopenharmony_ci	struct rs_control *rsc;
4478c2ecf20Sopenharmony_ci	int retval = -ENOMEM;
4488c2ecf20Sopenharmony_ci	int max_pad = kk - 1;
4498c2ecf20Sopenharmony_ci	int prev_pad = -1;
4508c2ecf20Sopenharmony_ci	struct wspace *ws;
4518c2ecf20Sopenharmony_ci	int i;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	rsc = init_rs(e->symsize, e->genpoly, e->fcs, e->prim, e->nroots);
4548c2ecf20Sopenharmony_ci	if (!rsc)
4558c2ecf20Sopenharmony_ci		return retval;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	ws = alloc_ws(rsc->codec);
4588c2ecf20Sopenharmony_ci	if (!ws)
4598c2ecf20Sopenharmony_ci		goto err;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	retval = 0;
4628c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pad_coef); i++) {
4638c2ecf20Sopenharmony_ci		int pad = (pad_coef[i].mult * max_pad) >> pad_coef[i].shift;
4648c2ecf20Sopenharmony_ci		int len = nn - pad;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		if (pad == prev_pad)
4678c2ecf20Sopenharmony_ci			continue;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		prev_pad = pad;
4708c2ecf20Sopenharmony_ci		if (v >= V_PROGRESS) {
4718c2ecf20Sopenharmony_ci			pr_info("Testing (%d,%d)_%d code...\n",
4728c2ecf20Sopenharmony_ci					len, kk - pad, nn + 1);
4738c2ecf20Sopenharmony_ci		}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		retval |= exercise_rs(rsc, ws, len, e->ntrials);
4768c2ecf20Sopenharmony_ci		if (bc)
4778c2ecf20Sopenharmony_ci			retval |= exercise_rs_bc(rsc, ws, len, e->ntrials);
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	free_ws(ws);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cierr:
4838c2ecf20Sopenharmony_ci	free_rs(rsc);
4848c2ecf20Sopenharmony_ci	return retval;
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic int __init test_rslib_init(void)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	int i, fail = 0;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	for (i = 0; Tab[i].symsize != 0 ; i++) {
4928c2ecf20Sopenharmony_ci		int retval;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		retval = run_exercise(Tab + i);
4958c2ecf20Sopenharmony_ci		if (retval < 0)
4968c2ecf20Sopenharmony_ci			return -ENOMEM;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci		fail |= retval;
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (fail)
5028c2ecf20Sopenharmony_ci		pr_warn("rslib: test failed\n");
5038c2ecf20Sopenharmony_ci	else
5048c2ecf20Sopenharmony_ci		pr_info("rslib: test ok\n");
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	return -EAGAIN; /* Fail will directly unload the module */
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_cistatic void __exit test_rslib_exit(void)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cimodule_init(test_rslib_init)
5148c2ecf20Sopenharmony_cimodule_exit(test_rslib_exit)
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
5178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ferdinand Blomqvist");
5188c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Reed-Solomon library test");
519