// SPDX-License-Identifier: GPL-2.0-only /* * Copyright © 2012 NetCommWireless * Iwo Mergler <[email protected]> * * Test for multi-bit error recovery on a NAND page This mostly tests the * ECC controller / driver. * * There are two test modes: * * 0 - artificially inserting bit errors until the ECC fails * This is the default method and fairly quick. It should * be independent of the quality of the FLASH. * * 1 - re-writing the same pattern repeatedly until the ECC fails. * This method relies on the physics of NAND FLASH to eventually * generate '0' bits if '1' has been written sufficient times. * Depending on the NAND, the first bit errors will appear after * 1000 or more writes and then will usually snowball, reaching the * limits of the ECC quickly. * * The test stops after 10000 cycles, should your FLASH be * exceptionally good and not generate bit errors before that. Try * a different page in that case. * * Please note that neither of these tests will significantly 'use up' any * FLASH endurance. Only a maximum of two erase operations will be performed. */ #define pr_fmt(fmt) … #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/mtd/mtd.h> #include <linux/err.h> #include <linux/mtd/rawnand.h> #include <linux/slab.h> #include "mtd_test.h" static int dev; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(…) …; static unsigned page_offset; module_param(page_offset, uint, S_IRUGO); MODULE_PARM_DESC(…) …; static unsigned seed; module_param(seed, uint, S_IRUGO); MODULE_PARM_DESC(…) …; static int mode; module_param(mode, int, S_IRUGO); MODULE_PARM_DESC(…) …; static unsigned max_overwrite = …; static loff_t offset; /* Offset of the page we're using. */ static unsigned eraseblock; /* Eraseblock number for our page. */ /* We assume that the ECC can correct up to a certain number * of biterrors per subpage. */ static unsigned subsize; /* Size of subpages */ static unsigned subcount; /* Number of subpages per page */ static struct mtd_info *mtd; /* MTD device */ static uint8_t *wbuffer; /* One page write / compare buffer */ static uint8_t *rbuffer; /* One page read buffer */ /* 'random' bytes from known offsets */ static uint8_t hash(unsigned offset) { … } /* Writes wbuffer to page */ static int write_page(int log) { … } /* Re-writes the data area while leaving the OOB alone. */ static int rewrite_page(int log) { … } /* Reads page into rbuffer. Returns number of corrected bit errors (>=0) * or error (<0) */ static int read_page(int log) { … } /* Verifies rbuffer against random sequence */ static int verify_page(int log) { … } #define CBIT(v, n) … #define BCLR(v, n) … /* Finds the first '1' bit in wbuffer starting at offset 'byte' * and sets it to '0'. */ static int insert_biterror(unsigned byte) { … } /* Writes 'random' data to page and then introduces deliberate bit * errors into the page, while verifying each step. */ static int incremental_errors_test(void) { … } /* Writes 'random' data to page and then re-writes that same data repeatedly. This eventually develops bit errors (bits written as '1' will slowly become '0'), which are corrected as far as the ECC is capable of. */ static int overwrite_test(void) { … } static int __init mtd_nandbiterrs_init(void) { … } static void __exit mtd_nandbiterrs_exit(void) { … } module_init(mtd_nandbiterrs_init); module_exit(mtd_nandbiterrs_exit); MODULE_DESCRIPTION(…) …; MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …;