109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2b6489d97SVikram Narayanan #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 3b6489d97SVikram Narayanan 47126bd8bSAkinobu Mita #include <linux/kernel.h> 57126bd8bSAkinobu Mita #include <linux/module.h> 67126bd8bSAkinobu Mita #include <linux/list.h> 77126bd8bSAkinobu Mita #include <linux/random.h> 87126bd8bSAkinobu Mita #include <linux/string.h> 97126bd8bSAkinobu Mita #include <linux/bitops.h> 101749c00fSAkinobu Mita #include <linux/slab.h> 11e5acf9c8SMiquel Raynal #include <linux/mtd/nand-ecc-sw-hamming.h> 127126bd8bSAkinobu Mita 132a6a28e7SRichard Weinberger #include "mtd_test.h" 142a6a28e7SRichard Weinberger 156060fb42SAkinobu Mita /* 166060fb42SAkinobu Mita * Test the implementation for software ECC 176060fb42SAkinobu Mita * 186060fb42SAkinobu Mita * No actual MTD device is needed, So we don't need to warry about losing 196060fb42SAkinobu Mita * important data by human error. 206060fb42SAkinobu Mita * 216060fb42SAkinobu Mita * This covers possible patterns of corruption which can be reliably corrected 226060fb42SAkinobu Mita * or detected. 236060fb42SAkinobu Mita */ 246060fb42SAkinobu Mita 2572c5af00SMiquel Raynal #if IS_ENABLED(CONFIG_MTD_RAW_NAND) 267126bd8bSAkinobu Mita 276060fb42SAkinobu Mita struct nand_ecc_test { 286060fb42SAkinobu Mita const char *name; 296060fb42SAkinobu Mita void (*prepare)(void *, void *, void *, void *, const size_t); 306060fb42SAkinobu Mita int (*verify)(void *, void *, void *, const size_t); 316060fb42SAkinobu Mita }; 326060fb42SAkinobu Mita 33c092b439SAkinobu Mita /* 34c092b439SAkinobu Mita * The reason for this __change_bit_le() instead of __change_bit() is to inject 35c092b439SAkinobu Mita * bit error properly within the region which is not a multiple of 36c092b439SAkinobu Mita * sizeof(unsigned long) on big-endian systems 37c092b439SAkinobu Mita */ 38c092b439SAkinobu Mita #ifdef __LITTLE_ENDIAN 39c092b439SAkinobu Mita #define __change_bit_le(nr, addr) __change_bit(nr, addr) 40c092b439SAkinobu Mita #elif defined(__BIG_ENDIAN) 41c092b439SAkinobu Mita #define __change_bit_le(nr, addr) \ 42c092b439SAkinobu Mita __change_bit((nr) ^ ((BITS_PER_LONG - 1) & ~0x7), addr) 43c092b439SAkinobu Mita #else 44c092b439SAkinobu Mita #error "Unknown byte order" 45c092b439SAkinobu Mita #endif 46c092b439SAkinobu Mita 476060fb42SAkinobu Mita static void single_bit_error_data(void *error_data, void *correct_data, 486060fb42SAkinobu Mita size_t size) 497126bd8bSAkinobu Mita { 50aca662a3SAkinobu Mita unsigned int offset = prandom_u32() % (size * BITS_PER_BYTE); 517126bd8bSAkinobu Mita 526060fb42SAkinobu Mita memcpy(error_data, correct_data, size); 536060fb42SAkinobu Mita __change_bit_le(offset, error_data); 547126bd8bSAkinobu Mita } 557126bd8bSAkinobu Mita 566ed089c0SAkinobu Mita static void double_bit_error_data(void *error_data, void *correct_data, 576ed089c0SAkinobu Mita size_t size) 586ed089c0SAkinobu Mita { 596ed089c0SAkinobu Mita unsigned int offset[2]; 606ed089c0SAkinobu Mita 61aca662a3SAkinobu Mita offset[0] = prandom_u32() % (size * BITS_PER_BYTE); 626ed089c0SAkinobu Mita do { 63aca662a3SAkinobu Mita offset[1] = prandom_u32() % (size * BITS_PER_BYTE); 646ed089c0SAkinobu Mita } while (offset[0] == offset[1]); 656ed089c0SAkinobu Mita 666ed089c0SAkinobu Mita memcpy(error_data, correct_data, size); 676ed089c0SAkinobu Mita 686ed089c0SAkinobu Mita __change_bit_le(offset[0], error_data); 696ed089c0SAkinobu Mita __change_bit_le(offset[1], error_data); 706ed089c0SAkinobu Mita } 716ed089c0SAkinobu Mita 72200ab845SAkinobu Mita static unsigned int random_ecc_bit(size_t size) 73200ab845SAkinobu Mita { 74aca662a3SAkinobu Mita unsigned int offset = prandom_u32() % (3 * BITS_PER_BYTE); 75200ab845SAkinobu Mita 76200ab845SAkinobu Mita if (size == 256) { 77200ab845SAkinobu Mita /* 78200ab845SAkinobu Mita * Don't inject a bit error into the insignificant bits (16th 79200ab845SAkinobu Mita * and 17th bit) in ECC code for 256 byte data block 80200ab845SAkinobu Mita */ 81200ab845SAkinobu Mita while (offset == 16 || offset == 17) 82aca662a3SAkinobu Mita offset = prandom_u32() % (3 * BITS_PER_BYTE); 83200ab845SAkinobu Mita } 84200ab845SAkinobu Mita 85200ab845SAkinobu Mita return offset; 86200ab845SAkinobu Mita } 87200ab845SAkinobu Mita 88200ab845SAkinobu Mita static void single_bit_error_ecc(void *error_ecc, void *correct_ecc, 89200ab845SAkinobu Mita size_t size) 90200ab845SAkinobu Mita { 91200ab845SAkinobu Mita unsigned int offset = random_ecc_bit(size); 92200ab845SAkinobu Mita 93200ab845SAkinobu Mita memcpy(error_ecc, correct_ecc, 3); 94200ab845SAkinobu Mita __change_bit_le(offset, error_ecc); 95200ab845SAkinobu Mita } 96200ab845SAkinobu Mita 976ed089c0SAkinobu Mita static void double_bit_error_ecc(void *error_ecc, void *correct_ecc, 986ed089c0SAkinobu Mita size_t size) 996ed089c0SAkinobu Mita { 1006ed089c0SAkinobu Mita unsigned int offset[2]; 1016ed089c0SAkinobu Mita 1026ed089c0SAkinobu Mita offset[0] = random_ecc_bit(size); 1036ed089c0SAkinobu Mita do { 1046ed089c0SAkinobu Mita offset[1] = random_ecc_bit(size); 1056ed089c0SAkinobu Mita } while (offset[0] == offset[1]); 1066ed089c0SAkinobu Mita 1076ed089c0SAkinobu Mita memcpy(error_ecc, correct_ecc, 3); 1086ed089c0SAkinobu Mita __change_bit_le(offset[0], error_ecc); 1096ed089c0SAkinobu Mita __change_bit_le(offset[1], error_ecc); 1106ed089c0SAkinobu Mita } 1116ed089c0SAkinobu Mita 112ccaa6795SAkinobu Mita static void no_bit_error(void *error_data, void *error_ecc, 113ccaa6795SAkinobu Mita void *correct_data, void *correct_ecc, const size_t size) 114ccaa6795SAkinobu Mita { 115ccaa6795SAkinobu Mita memcpy(error_data, correct_data, size); 116ccaa6795SAkinobu Mita memcpy(error_ecc, correct_ecc, 3); 117ccaa6795SAkinobu Mita } 118ccaa6795SAkinobu Mita 119ccaa6795SAkinobu Mita static int no_bit_error_verify(void *error_data, void *error_ecc, 120ccaa6795SAkinobu Mita void *correct_data, const size_t size) 121ccaa6795SAkinobu Mita { 122*90ccf0a0SMiquel Raynal bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC); 123ccaa6795SAkinobu Mita unsigned char calc_ecc[3]; 124ccaa6795SAkinobu Mita int ret; 125ccaa6795SAkinobu Mita 126*90ccf0a0SMiquel Raynal ecc_sw_hamming_calculate(error_data, size, calc_ecc, sm_order); 127*90ccf0a0SMiquel Raynal ret = ecc_sw_hamming_correct(error_data, error_ecc, calc_ecc, size, 128*90ccf0a0SMiquel Raynal sm_order); 129ccaa6795SAkinobu Mita if (ret == 0 && !memcmp(correct_data, error_data, size)) 130ccaa6795SAkinobu Mita return 0; 131ccaa6795SAkinobu Mita 132ccaa6795SAkinobu Mita return -EINVAL; 133ccaa6795SAkinobu Mita } 134ccaa6795SAkinobu Mita 1356060fb42SAkinobu Mita static void single_bit_error_in_data(void *error_data, void *error_ecc, 1366060fb42SAkinobu Mita void *correct_data, void *correct_ecc, const size_t size) 1376060fb42SAkinobu Mita { 1386060fb42SAkinobu Mita single_bit_error_data(error_data, correct_data, size); 1396060fb42SAkinobu Mita memcpy(error_ecc, correct_ecc, 3); 1406060fb42SAkinobu Mita } 1416060fb42SAkinobu Mita 142200ab845SAkinobu Mita static void single_bit_error_in_ecc(void *error_data, void *error_ecc, 143200ab845SAkinobu Mita void *correct_data, void *correct_ecc, const size_t size) 144200ab845SAkinobu Mita { 145200ab845SAkinobu Mita memcpy(error_data, correct_data, size); 146200ab845SAkinobu Mita single_bit_error_ecc(error_ecc, correct_ecc, size); 147200ab845SAkinobu Mita } 148200ab845SAkinobu Mita 1496060fb42SAkinobu Mita static int single_bit_error_correct(void *error_data, void *error_ecc, 1506060fb42SAkinobu Mita void *correct_data, const size_t size) 1516060fb42SAkinobu Mita { 152*90ccf0a0SMiquel Raynal bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC); 1536060fb42SAkinobu Mita unsigned char calc_ecc[3]; 1546060fb42SAkinobu Mita int ret; 1556060fb42SAkinobu Mita 156*90ccf0a0SMiquel Raynal ecc_sw_hamming_calculate(error_data, size, calc_ecc, sm_order); 157*90ccf0a0SMiquel Raynal ret = ecc_sw_hamming_correct(error_data, error_ecc, calc_ecc, size, 158*90ccf0a0SMiquel Raynal sm_order); 1596060fb42SAkinobu Mita if (ret == 1 && !memcmp(correct_data, error_data, size)) 1606060fb42SAkinobu Mita return 0; 1616060fb42SAkinobu Mita 1626060fb42SAkinobu Mita return -EINVAL; 1636060fb42SAkinobu Mita } 1646060fb42SAkinobu Mita 1656ed089c0SAkinobu Mita static void double_bit_error_in_data(void *error_data, void *error_ecc, 1666ed089c0SAkinobu Mita void *correct_data, void *correct_ecc, const size_t size) 1676ed089c0SAkinobu Mita { 1686ed089c0SAkinobu Mita double_bit_error_data(error_data, correct_data, size); 1696ed089c0SAkinobu Mita memcpy(error_ecc, correct_ecc, 3); 1706ed089c0SAkinobu Mita } 1716ed089c0SAkinobu Mita 1726ed089c0SAkinobu Mita static void single_bit_error_in_data_and_ecc(void *error_data, void *error_ecc, 1736ed089c0SAkinobu Mita void *correct_data, void *correct_ecc, const size_t size) 1746ed089c0SAkinobu Mita { 1756ed089c0SAkinobu Mita single_bit_error_data(error_data, correct_data, size); 1766ed089c0SAkinobu Mita single_bit_error_ecc(error_ecc, correct_ecc, size); 1776ed089c0SAkinobu Mita } 1786ed089c0SAkinobu Mita 1796ed089c0SAkinobu Mita static void double_bit_error_in_ecc(void *error_data, void *error_ecc, 1806ed089c0SAkinobu Mita void *correct_data, void *correct_ecc, const size_t size) 1816ed089c0SAkinobu Mita { 1826ed089c0SAkinobu Mita memcpy(error_data, correct_data, size); 1836ed089c0SAkinobu Mita double_bit_error_ecc(error_ecc, correct_ecc, size); 1846ed089c0SAkinobu Mita } 1856ed089c0SAkinobu Mita 1866ed089c0SAkinobu Mita static int double_bit_error_detect(void *error_data, void *error_ecc, 1876ed089c0SAkinobu Mita void *correct_data, const size_t size) 1886ed089c0SAkinobu Mita { 189*90ccf0a0SMiquel Raynal bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC); 1906ed089c0SAkinobu Mita unsigned char calc_ecc[3]; 1916ed089c0SAkinobu Mita int ret; 1926ed089c0SAkinobu Mita 193*90ccf0a0SMiquel Raynal ecc_sw_hamming_calculate(error_data, size, calc_ecc, sm_order); 194*90ccf0a0SMiquel Raynal ret = ecc_sw_hamming_correct(error_data, error_ecc, calc_ecc, size, 195*90ccf0a0SMiquel Raynal sm_order); 1966ed089c0SAkinobu Mita 197c57753d4SJorge Ramirez-Ortiz return (ret == -EBADMSG) ? 0 : -EINVAL; 1986ed089c0SAkinobu Mita } 1996ed089c0SAkinobu Mita 2006060fb42SAkinobu Mita static const struct nand_ecc_test nand_ecc_test[] = { 2016060fb42SAkinobu Mita { 202ccaa6795SAkinobu Mita .name = "no-bit-error", 203ccaa6795SAkinobu Mita .prepare = no_bit_error, 204ccaa6795SAkinobu Mita .verify = no_bit_error_verify, 205ccaa6795SAkinobu Mita }, 206ccaa6795SAkinobu Mita { 2076060fb42SAkinobu Mita .name = "single-bit-error-in-data-correct", 2086060fb42SAkinobu Mita .prepare = single_bit_error_in_data, 2096060fb42SAkinobu Mita .verify = single_bit_error_correct, 2106060fb42SAkinobu Mita }, 211200ab845SAkinobu Mita { 212200ab845SAkinobu Mita .name = "single-bit-error-in-ecc-correct", 213200ab845SAkinobu Mita .prepare = single_bit_error_in_ecc, 214200ab845SAkinobu Mita .verify = single_bit_error_correct, 215200ab845SAkinobu Mita }, 2166ed089c0SAkinobu Mita { 2176ed089c0SAkinobu Mita .name = "double-bit-error-in-data-detect", 2186ed089c0SAkinobu Mita .prepare = double_bit_error_in_data, 2196ed089c0SAkinobu Mita .verify = double_bit_error_detect, 2206ed089c0SAkinobu Mita }, 2216ed089c0SAkinobu Mita { 2226ed089c0SAkinobu Mita .name = "single-bit-error-in-data-and-ecc-detect", 2236ed089c0SAkinobu Mita .prepare = single_bit_error_in_data_and_ecc, 2246ed089c0SAkinobu Mita .verify = double_bit_error_detect, 2256ed089c0SAkinobu Mita }, 2266ed089c0SAkinobu Mita { 2276ed089c0SAkinobu Mita .name = "double-bit-error-in-ecc-detect", 2286ed089c0SAkinobu Mita .prepare = double_bit_error_in_ecc, 2296ed089c0SAkinobu Mita .verify = double_bit_error_detect, 2306ed089c0SAkinobu Mita }, 2316060fb42SAkinobu Mita }; 2326060fb42SAkinobu Mita 233c5b8384aSAkinobu Mita static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data, 234c5b8384aSAkinobu Mita void *correct_ecc, const size_t size) 235c5b8384aSAkinobu Mita { 236c5b8384aSAkinobu Mita pr_info("hexdump of error data:\n"); 237c5b8384aSAkinobu Mita print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, 238c5b8384aSAkinobu Mita error_data, size, false); 239c5b8384aSAkinobu Mita print_hex_dump(KERN_INFO, "hexdump of error ecc: ", 240c5b8384aSAkinobu Mita DUMP_PREFIX_NONE, 16, 1, error_ecc, 3, false); 241c5b8384aSAkinobu Mita 242c5b8384aSAkinobu Mita pr_info("hexdump of correct data:\n"); 243c5b8384aSAkinobu Mita print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4, 244c5b8384aSAkinobu Mita correct_data, size, false); 245c5b8384aSAkinobu Mita print_hex_dump(KERN_INFO, "hexdump of correct ecc: ", 246c5b8384aSAkinobu Mita DUMP_PREFIX_NONE, 16, 1, correct_ecc, 3, false); 247c5b8384aSAkinobu Mita } 248c5b8384aSAkinobu Mita 2496060fb42SAkinobu Mita static int nand_ecc_test_run(const size_t size) 2507126bd8bSAkinobu Mita { 251*90ccf0a0SMiquel Raynal bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC); 2526060fb42SAkinobu Mita int i; 2531749c00fSAkinobu Mita int err = 0; 2541749c00fSAkinobu Mita void *error_data; 2551749c00fSAkinobu Mita void *error_ecc; 2561749c00fSAkinobu Mita void *correct_data; 2571749c00fSAkinobu Mita void *correct_ecc; 2587126bd8bSAkinobu Mita 2591749c00fSAkinobu Mita error_data = kmalloc(size, GFP_KERNEL); 2601749c00fSAkinobu Mita error_ecc = kmalloc(3, GFP_KERNEL); 2611749c00fSAkinobu Mita correct_data = kmalloc(size, GFP_KERNEL); 2621749c00fSAkinobu Mita correct_ecc = kmalloc(3, GFP_KERNEL); 2631749c00fSAkinobu Mita 2641749c00fSAkinobu Mita if (!error_data || !error_ecc || !correct_data || !correct_ecc) { 2651749c00fSAkinobu Mita err = -ENOMEM; 2661749c00fSAkinobu Mita goto error; 2671749c00fSAkinobu Mita } 2687126bd8bSAkinobu Mita 269459a86d8SAkinobu Mita prandom_bytes(correct_data, size); 270*90ccf0a0SMiquel Raynal ecc_sw_hamming_calculate(correct_data, size, correct_ecc, sm_order); 2716060fb42SAkinobu Mita for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) { 2726060fb42SAkinobu Mita nand_ecc_test[i].prepare(error_data, error_ecc, 2736060fb42SAkinobu Mita correct_data, correct_ecc, size); 2746060fb42SAkinobu Mita err = nand_ecc_test[i].verify(error_data, error_ecc, 2756060fb42SAkinobu Mita correct_data, size); 2766060fb42SAkinobu Mita 2776060fb42SAkinobu Mita if (err) { 278b6489d97SVikram Narayanan pr_err("not ok - %s-%zd\n", 2796060fb42SAkinobu Mita nand_ecc_test[i].name, size); 2806060fb42SAkinobu Mita dump_data_ecc(error_data, error_ecc, 2816060fb42SAkinobu Mita correct_data, correct_ecc, size); 2826060fb42SAkinobu Mita break; 2831749c00fSAkinobu Mita } 284b6489d97SVikram Narayanan pr_info("ok - %s-%zd\n", 2856060fb42SAkinobu Mita nand_ecc_test[i].name, size); 2862a6a28e7SRichard Weinberger 2872a6a28e7SRichard Weinberger err = mtdtest_relax(); 2882a6a28e7SRichard Weinberger if (err) 2892a6a28e7SRichard Weinberger break; 2906060fb42SAkinobu Mita } 2911749c00fSAkinobu Mita error: 2921749c00fSAkinobu Mita kfree(error_data); 2931749c00fSAkinobu Mita kfree(error_ecc); 2941749c00fSAkinobu Mita kfree(correct_data); 2951749c00fSAkinobu Mita kfree(correct_ecc); 2967126bd8bSAkinobu Mita 2971749c00fSAkinobu Mita return err; 2987126bd8bSAkinobu Mita } 2997126bd8bSAkinobu Mita 3007126bd8bSAkinobu Mita #else 3017126bd8bSAkinobu Mita 3026060fb42SAkinobu Mita static int nand_ecc_test_run(const size_t size) 3037126bd8bSAkinobu Mita { 3047126bd8bSAkinobu Mita return 0; 3057126bd8bSAkinobu Mita } 3067126bd8bSAkinobu Mita 3077126bd8bSAkinobu Mita #endif 3087126bd8bSAkinobu Mita 3097126bd8bSAkinobu Mita static int __init ecc_test_init(void) 3107126bd8bSAkinobu Mita { 311f45c2990SAkinobu Mita int err; 3127126bd8bSAkinobu Mita 3136060fb42SAkinobu Mita err = nand_ecc_test_run(256); 314f45c2990SAkinobu Mita if (err) 315f45c2990SAkinobu Mita return err; 316f45c2990SAkinobu Mita 3176060fb42SAkinobu Mita return nand_ecc_test_run(512); 3187126bd8bSAkinobu Mita } 3197126bd8bSAkinobu Mita 3207126bd8bSAkinobu Mita static void __exit ecc_test_exit(void) 3217126bd8bSAkinobu Mita { 3227126bd8bSAkinobu Mita } 3237126bd8bSAkinobu Mita 3247126bd8bSAkinobu Mita module_init(ecc_test_init); 3257126bd8bSAkinobu Mita module_exit(ecc_test_exit); 3267126bd8bSAkinobu Mita 3277126bd8bSAkinobu Mita MODULE_DESCRIPTION("NAND ECC function test module"); 3287126bd8bSAkinobu Mita MODULE_AUTHOR("Akinobu Mita"); 3297126bd8bSAkinobu Mita MODULE_LICENSE("GPL"); 330