mtd: nand: ecc-hamming: Move Hamming code to the generic NAND layer
authorMiquel Raynal <miquel.raynal@bootlin.com>
Tue, 29 Sep 2020 23:01:15 +0000 (01:01 +0200)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Thu, 10 Dec 2020 21:37:29 +0000 (22:37 +0100)
Hamming ECC code might be later re-used by the SPI NAND layer.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200929230124.31491-12-miquel.raynal@bootlin.com
38 files changed:
arch/arm/mach-s3c/common-smdk-s3c24xx.c
arch/arm/mach-s3c/mach-anubis.c
arch/arm/mach-s3c/mach-at2440evb.c
arch/arm/mach-s3c/mach-bast.c
arch/arm/mach-s3c/mach-gta02.c
arch/arm/mach-s3c/mach-jive.c
arch/arm/mach-s3c/mach-mini2440.c
arch/arm/mach-s3c/mach-osiris.c
arch/arm/mach-s3c/mach-qt2410.c
arch/arm/mach-s3c/mach-rx3715.c
arch/arm/mach-s3c/mach-vstms.c
drivers/mtd/Kconfig
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/ecc-sw-hamming.c [new file with mode: 0644]
drivers/mtd/nand/raw/Kconfig
drivers/mtd/nand/raw/Makefile
drivers/mtd/nand/raw/cs553x_nand.c
drivers/mtd/nand/raw/fsl_elbc_nand.c
drivers/mtd/nand/raw/fsl_ifc_nand.c
drivers/mtd/nand/raw/fsl_upm.c
drivers/mtd/nand/raw/fsmc_nand.c
drivers/mtd/nand/raw/lpc32xx_mlc.c
drivers/mtd/nand/raw/lpc32xx_slc.c
drivers/mtd/nand/raw/mxic_nand.c
drivers/mtd/nand/raw/nand_base.c
drivers/mtd/nand/raw/nand_ecc.c [deleted file]
drivers/mtd/nand/raw/ndfc.c
drivers/mtd/nand/raw/pasemi_nand.c
drivers/mtd/nand/raw/s3c2410.c
drivers/mtd/nand/raw/sharpsl.c
drivers/mtd/nand/raw/tmio_nand.c
drivers/mtd/nand/raw/txx9ndfmc.c
drivers/mtd/sm_ftl.c
drivers/mtd/tests/mtd_nandecctest.c
include/linux/mtd/nand-ecc-sw-hamming.h [new file with mode: 0644]
include/linux/mtd/nand_ecc.h [deleted file]
include/linux/mtd/sharpsl.h

index f860d8bcba0e75b0b9e41422e80bc5dbe14e9c6d..6d124bbd384c7485094d353435bc93a902fe91b3 100644 (file)
@@ -20,7 +20,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 
index 90e3fd98a3ac8f16c652d3f9f47aab3d1a41c733..04147cc0adcc7afb03409e710f87cefabc7b6714 100644 (file)
@@ -34,7 +34,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include <net/ax88796.h>
index 5fa49d4e26506362d3dc0d3d53e9430add24992b..c6a5a51d84aa7a90617c9e2355db6b40d6aab7b4 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include "devs.h"
index 328f5d9ae9f9b8a2bad6ccc335b91cb7d1e706b7..27e8d595022865d590a614874fbdf5e9680cb193 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include <linux/platform_data/asoc-s3c24xx_simtec.h>
index 3c75c7d112ea74abdf4c665e9c51521a131ff5f1..aec8b451c0167a42cd28bc9fc2d691e4ef4b1a01 100644 (file)
@@ -37,7 +37,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 
index 2a29c3eca559eb6bf1c2448d9a5cfd12d522e216..0785638a9069bbc9dff76776a6b7b3f0253d3f59 100644 (file)
@@ -40,7 +40,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include "gpio-cfg.h"
index dc22ab839b95f46ef8cd1a59d46b49c5054c16cc..4100905dfbd0c1e7627739d638b57abc73c7f4e5 100644 (file)
@@ -44,7 +44,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include "gpio-cfg.h"
index 81744ca67d1dc75457bb478d45bc412470f2a307..3aefb9d22340f6ebe633f7ead73fca01c7b3f85f 100644 (file)
@@ -33,7 +33,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include "cpu.h"
index 151e8e373d407a7839b8dcf09b4cdfe83e750038..f88b961798fd6f95ba7d989406e9cff85e75fb77 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/mach/arch.h>
index a03662a47b3852695f32d0fcb71fc396b1aec03f..9fd2d9dc36896c5e7bef5fb224e4a88afb0ee92e 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/mach/arch.h>
index 05f19f5ffabbbcc9bdf054219402559c020cc3d6..ec024af7b0ce49f18978b90274298c4b50f54a3b 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/memblock.h>
 
index 6ddab796216db9c1295555a377f09a5be8da6eea..8bab6f8718a9f23d715c7185cd1e90d3a1e3b35e 100644 (file)
@@ -152,6 +152,7 @@ config SM_FTL
        tristate "SmartMedia/xD new translation layer"
        depends on BLOCK
        select MTD_BLKDEVS
+       select MTD_NAND_CORE
        select MTD_NAND_ECC_SW_HAMMING
        help
          This enables EXPERIMENTAL R/W support for SmartMedia/xD
index 55c17fb0dee12e14ac803b8375c009a9a92bf74c..306c33ca3448ca24a6d96ae2db5811fdbb8651b1 100644 (file)
@@ -15,6 +15,17 @@ config MTD_NAND_ECC
        bool
        depends on MTD_NAND_CORE
 
+config MTD_NAND_ECC_SW_HAMMING
+       bool
+
+config MTD_NAND_ECC_SW_HAMMING_SMC
+       bool "NAND ECC Smart Media byte order"
+       depends on MTD_NAND_ECC_SW_HAMMING
+       default n
+       help
+         Software ECC according to the Smart Media Specification.
+         The original Linux implementation had byte 0 and 1 swapped.
+
 config MTD_NAND_ECC_SW_BCH
        bool "Software BCH ECC engine"
        select BCH
index c7179ff237532e53efd32c8143e81ee15d10f479..1c0b46960eb1fde295f28fc559ba993afa6b8265 100644 (file)
@@ -8,4 +8,5 @@ obj-y   += raw/
 obj-y  += spi/
 
 nandcore-$(CONFIG_MTD_NAND_ECC) += ecc.o
+nandcore-$(CONFIG_MTD_NAND_ECC_SW_HAMMING) += ecc-sw-hamming.o
 nandcore-$(CONFIG_MTD_NAND_ECC_SW_BCH) += ecc-sw-bch.o
diff --git a/drivers/mtd/nand/ecc-sw-hamming.c b/drivers/mtd/nand/ecc-sw-hamming.c
new file mode 100644 (file)
index 0000000..76966f5
--- /dev/null
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * This file contains an ECC algorithm that detects and corrects 1 bit
+ * errors in a 256 byte block of data.
+ *
+ * Copyright © 2008 Koninklijke Philips Electronics NV.
+ *                  Author: Frans Meulenbroeks
+ *
+ * Completely replaces the previous ECC implementation which was written by:
+ *   Steven J. Hill (sjhill@realitydiluted.com)
+ *   Thomas Gleixner (tglx@linutronix.de)
+ *
+ * Information on how this algorithm works and how it was developed
+ * can be found in Documentation/driver-api/mtd/nand_ecc.rst
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
+#include <asm/byteorder.h>
+
+/*
+ * invparity is a 256 byte table that contains the odd parity
+ * for each byte. So if the number of bits in a byte is even,
+ * the array element is 1, and when the number of bits is odd
+ * the array eleemnt is 0.
+ */
+static const char invparity[256] = {
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
+};
+
+/*
+ * bitsperbyte contains the number of bits per byte
+ * this is only used for testing and repairing parity
+ * (a precalculated value slightly improves performance)
+ */
+static const char bitsperbyte[256] = {
+       0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+       4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
+};
+
+/*
+ * addressbits is a lookup table to filter out the bits from the xor-ed
+ * ECC data that identify the faulty location.
+ * this is only used for repairing parity
+ * see the comments in nand_correct_data for more details
+ */
+static const char addressbits[256] = {
+       0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+       0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+       0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+       0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+       0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+       0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+       0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+       0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+       0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+       0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+       0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
+       0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
+       0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+       0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+       0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
+       0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
+       0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+       0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+       0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+       0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+       0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+       0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+       0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+       0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+       0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+       0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+       0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
+       0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
+       0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+       0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
+       0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
+       0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
+};
+
+/**
+ * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+ *                      block
+ * @buf:       input buffer with raw data
+ * @eccsize:   data bytes per ECC step (256 or 512)
+ * @code:      output buffer with ECC
+ * @sm_order:  Smart Media byte ordering
+ */
+void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
+                         unsigned char *code, bool sm_order)
+{
+       int i;
+       const uint32_t *bp = (uint32_t *)buf;
+       /* 256 or 512 bytes/ecc  */
+       const uint32_t eccsize_mult = eccsize >> 8;
+       uint32_t cur;           /* current value in buffer */
+       /* rp0..rp15..rp17 are the various accumulated parities (per byte) */
+       uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
+       uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
+       uint32_t rp17;
+       uint32_t par;           /* the cumulative parity for all data */
+       uint32_t tmppar;        /* the cumulative parity for this iteration;
+                                  for rp12, rp14 and rp16 at the end of the
+                                  loop */
+
+       par = 0;
+       rp4 = 0;
+       rp6 = 0;
+       rp8 = 0;
+       rp10 = 0;
+       rp12 = 0;
+       rp14 = 0;
+       rp16 = 0;
+
+       /*
+        * The loop is unrolled a number of times;
+        * This avoids if statements to decide on which rp value to update
+        * Also we process the data by longwords.
+        * Note: passing unaligned data might give a performance penalty.
+        * It is assumed that the buffers are aligned.
+        * tmppar is the cumulative sum of this iteration.
+        * needed for calculating rp12, rp14, rp16 and par
+        * also used as a performance improvement for rp6, rp8 and rp10
+        */
+       for (i = 0; i < eccsize_mult << 2; i++) {
+               cur = *bp++;
+               tmppar = cur;
+               rp4 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp6 ^= tmppar;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp4 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp8 ^= tmppar;
+
+               cur = *bp++;
+               tmppar ^= cur;
+               rp4 ^= cur;
+               rp6 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp6 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp4 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp10 ^= tmppar;
+
+               cur = *bp++;
+               tmppar ^= cur;
+               rp4 ^= cur;
+               rp6 ^= cur;
+               rp8 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp6 ^= cur;
+               rp8 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp4 ^= cur;
+               rp8 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp8 ^= cur;
+
+               cur = *bp++;
+               tmppar ^= cur;
+               rp4 ^= cur;
+               rp6 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp6 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+               rp4 ^= cur;
+               cur = *bp++;
+               tmppar ^= cur;
+
+               par ^= tmppar;
+               if ((i & 0x1) == 0)
+                       rp12 ^= tmppar;
+               if ((i & 0x2) == 0)
+                       rp14 ^= tmppar;
+               if (eccsize_mult == 2 && (i & 0x4) == 0)
+                       rp16 ^= tmppar;
+       }
+
+       /*
+        * handle the fact that we use longword operations
+        * we'll bring rp4..rp14..rp16 back to single byte entities by
+        * shifting and xoring first fold the upper and lower 16 bits,
+        * then the upper and lower 8 bits.
+        */
+       rp4 ^= (rp4 >> 16);
+       rp4 ^= (rp4 >> 8);
+       rp4 &= 0xff;
+       rp6 ^= (rp6 >> 16);
+       rp6 ^= (rp6 >> 8);
+       rp6 &= 0xff;
+       rp8 ^= (rp8 >> 16);
+       rp8 ^= (rp8 >> 8);
+       rp8 &= 0xff;
+       rp10 ^= (rp10 >> 16);
+       rp10 ^= (rp10 >> 8);
+       rp10 &= 0xff;
+       rp12 ^= (rp12 >> 16);
+       rp12 ^= (rp12 >> 8);
+       rp12 &= 0xff;
+       rp14 ^= (rp14 >> 16);
+       rp14 ^= (rp14 >> 8);
+       rp14 &= 0xff;
+       if (eccsize_mult == 2) {
+               rp16 ^= (rp16 >> 16);
+               rp16 ^= (rp16 >> 8);
+               rp16 &= 0xff;
+       }
+
+       /*
+        * we also need to calculate the row parity for rp0..rp3
+        * This is present in par, because par is now
+        * rp3 rp3 rp2 rp2 in little endian and
+        * rp2 rp2 rp3 rp3 in big endian
+        * as well as
+        * rp1 rp0 rp1 rp0 in little endian and
+        * rp0 rp1 rp0 rp1 in big endian
+        * First calculate rp2 and rp3
+        */
+#ifdef __BIG_ENDIAN
+       rp2 = (par >> 16);
+       rp2 ^= (rp2 >> 8);
+       rp2 &= 0xff;
+       rp3 = par & 0xffff;
+       rp3 ^= (rp3 >> 8);
+       rp3 &= 0xff;
+#else
+       rp3 = (par >> 16);
+       rp3 ^= (rp3 >> 8);
+       rp3 &= 0xff;
+       rp2 = par & 0xffff;
+       rp2 ^= (rp2 >> 8);
+       rp2 &= 0xff;
+#endif
+
+       /* reduce par to 16 bits then calculate rp1 and rp0 */
+       par ^= (par >> 16);
+#ifdef __BIG_ENDIAN
+       rp0 = (par >> 8) & 0xff;
+       rp1 = (par & 0xff);
+#else
+       rp1 = (par >> 8) & 0xff;
+       rp0 = (par & 0xff);
+#endif
+
+       /* finally reduce par to 8 bits */
+       par ^= (par >> 8);
+       par &= 0xff;
+
+       /*
+        * and calculate rp5..rp15..rp17
+        * note that par = rp4 ^ rp5 and due to the commutative property
+        * of the ^ operator we can say:
+        * rp5 = (par ^ rp4);
+        * The & 0xff seems superfluous, but benchmarking learned that
+        * leaving it out gives slightly worse results. No idea why, probably
+        * it has to do with the way the pipeline in pentium is organized.
+        */
+       rp5 = (par ^ rp4) & 0xff;
+       rp7 = (par ^ rp6) & 0xff;
+       rp9 = (par ^ rp8) & 0xff;
+       rp11 = (par ^ rp10) & 0xff;
+       rp13 = (par ^ rp12) & 0xff;
+       rp15 = (par ^ rp14) & 0xff;
+       if (eccsize_mult == 2)
+               rp17 = (par ^ rp16) & 0xff;
+
+       /*
+        * Finally calculate the ECC bits.
+        * Again here it might seem that there are performance optimisations
+        * possible, but benchmarks showed that on the system this is developed
+        * the code below is the fastest
+        */
+       if (sm_order) {
+               code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
+                         (invparity[rp5] << 5) | (invparity[rp4] << 4) |
+                         (invparity[rp3] << 3) | (invparity[rp2] << 2) |
+                         (invparity[rp1] << 1) | (invparity[rp0]);
+               code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
+                         (invparity[rp13] << 5) | (invparity[rp12] << 4) |
+                         (invparity[rp11] << 3) | (invparity[rp10] << 2) |
+                         (invparity[rp9] << 1) | (invparity[rp8]);
+       } else {
+               code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
+                         (invparity[rp5] << 5) | (invparity[rp4] << 4) |
+                         (invparity[rp3] << 3) | (invparity[rp2] << 2) |
+                         (invparity[rp1] << 1) | (invparity[rp0]);
+               code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
+                         (invparity[rp13] << 5) | (invparity[rp12] << 4) |
+                         (invparity[rp11] << 3) | (invparity[rp10] << 2) |
+                         (invparity[rp9] << 1) | (invparity[rp8]);
+       }
+
+       if (eccsize_mult == 1)
+               code[2] =
+                   (invparity[par & 0xf0] << 7) |
+                   (invparity[par & 0x0f] << 6) |
+                   (invparity[par & 0xcc] << 5) |
+                   (invparity[par & 0x33] << 4) |
+                   (invparity[par & 0xaa] << 3) |
+                   (invparity[par & 0x55] << 2) |
+                   3;
+       else
+               code[2] =
+                   (invparity[par & 0xf0] << 7) |
+                   (invparity[par & 0x0f] << 6) |
+                   (invparity[par & 0xcc] << 5) |
+                   (invparity[par & 0x33] << 4) |
+                   (invparity[par & 0xaa] << 3) |
+                   (invparity[par & 0x55] << 2) |
+                   (invparity[rp17] << 1) |
+                   (invparity[rp16] << 0);
+}
+EXPORT_SYMBOL(__nand_calculate_ecc);
+
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
+ *                      block
+ * @chip:      NAND chip object
+ * @buf:       input buffer with raw data
+ * @code:      output buffer with ECC
+ */
+int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
+                      unsigned char *code)
+{
+       bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
+       __nand_calculate_ecc(buf, chip->ecc.size, code, sm_order);
+
+       return 0;
+}
+EXPORT_SYMBOL(nand_calculate_ecc);
+
+/**
+ * __nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @buf:       raw data read from the chip
+ * @read_ecc:  ECC from the chip
+ * @calc_ecc:  the ECC calculated from raw data
+ * @eccsize:   data bytes per ECC step (256 or 512)
+ * @sm_order:  Smart Media byte order
+ *
+ * Detect and correct a 1 bit error for eccsize byte block
+ */
+int __nand_correct_data(unsigned char *buf,
+                       unsigned char *read_ecc, unsigned char *calc_ecc,
+                       unsigned int eccsize, bool sm_order)
+{
+       unsigned char b0, b1, b2, bit_addr;
+       unsigned int byte_addr;
+       /* 256 or 512 bytes/ecc  */
+       const uint32_t eccsize_mult = eccsize >> 8;
+
+       /*
+        * b0 to b2 indicate which bit is faulty (if any)
+        * we might need the xor result  more than once,
+        * so keep them in a local var
+       */
+       if (sm_order) {
+               b0 = read_ecc[0] ^ calc_ecc[0];
+               b1 = read_ecc[1] ^ calc_ecc[1];
+       } else {
+               b0 = read_ecc[1] ^ calc_ecc[1];
+               b1 = read_ecc[0] ^ calc_ecc[0];
+       }
+
+       b2 = read_ecc[2] ^ calc_ecc[2];
+
+       /* check if there are any bitfaults */
+
+       /* repeated if statements are slightly more efficient than switch ... */
+       /* ordered in order of likelihood */
+
+       if ((b0 | b1 | b2) == 0)
+               return 0;       /* no error */
+
+       if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
+           (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
+           ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
+            (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
+       /* single bit error */
+               /*
+                * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty
+                * byte, cp 5/3/1 indicate the faulty bit.
+                * A lookup table (called addressbits) is used to filter
+                * the bits from the byte they are in.
+                * A marginal optimisation is possible by having three
+                * different lookup tables.
+                * One as we have now (for b0), one for b2
+                * (that would avoid the >> 1), and one for b1 (with all values
+                * << 4). However it was felt that introducing two more tables
+                * hardly justify the gain.
+                *
+                * The b2 shift is there to get rid of the lowest two bits.
+                * We could also do addressbits[b2] >> 1 but for the
+                * performance it does not make any difference
+                */
+               if (eccsize_mult == 1)
+                       byte_addr = (addressbits[b1] << 4) + addressbits[b0];
+               else
+                       byte_addr = (addressbits[b2 & 0x3] << 8) +
+                                   (addressbits[b1] << 4) + addressbits[b0];
+               bit_addr = addressbits[b2 >> 2];
+               /* flip the bit */
+               buf[byte_addr] ^= (1 << bit_addr);
+               return 1;
+
+       }
+       /* count nr of bits; use table lookup, faster than calculating it */
+       if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
+               return 1;       /* error in ECC data; no action needed */
+
+       pr_err("%s: uncorrectable ECC error\n", __func__);
+       return -EBADMSG;
+}
+EXPORT_SYMBOL(__nand_correct_data);
+
+/**
+ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @chip:      NAND chip object
+ * @buf:       raw data read from the chip
+ * @read_ecc:  ECC from the chip
+ * @calc_ecc:  the ECC calculated from raw data
+ *
+ * Detect and correct a 1 bit error for 256/512 byte block
+ */
+int nand_correct_data(struct nand_chip *chip, unsigned char *buf,
+                     unsigned char *read_ecc, unsigned char *calc_ecc)
+{
+       bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+
+       return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size,
+                                  sm_order);
+}
+EXPORT_SYMBOL(nand_correct_data);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
+MODULE_DESCRIPTION("Generic NAND ECC support");
index b73860aa77c642fd5f2905af2b31fff2c496b0d9..6149096e32cb64c34823b16ad93b58e24aa0364f 100644 (file)
@@ -1,15 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
-config MTD_NAND_ECC_SW_HAMMING
-       tristate
-
-config MTD_NAND_ECC_SW_HAMMING_SMC
-       bool "NAND ECC Smart Media byte order"
-       depends on MTD_NAND_ECC_SW_HAMMING
-       default n
-       help
-         Software ECC according to the Smart Media Specification.
-         The original Linux implementation had byte 0 and 1 swapped.
-
 menuconfig MTD_RAW_NAND
        tristate "Raw/Parallel NAND Device Support"
        select MTD_NAND_CORE
index 76904305d091f341b27b96eaa941876436ca36a3..dc38c087c693d564bdb6bd6e665487d36cbe37de 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_MTD_RAW_NAND)             += nand.o
-obj-$(CONFIG_MTD_NAND_ECC_SW_HAMMING)  += nand_ecc.o
 obj-$(CONFIG_MTD_SM_COMMON)            += sm_common.o
 
 obj-$(CONFIG_MTD_NAND_CAFE)            += cafe_nand.o
index 282203debd0cc2327fb4b698b3b836624165e159..9a2bdb45a7718e106c12a9e96b9d5529ec319bfa 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/iopoll.h>
 
index b2af7f81fdf8f1360f5d8686aba707bd4c104db7..eb255cf83e328dc958c3c7653fa74c90676fca02 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/io.h>
index e345f9d9f8e8dc2c2038fcbef3171a579575f67a..d2f84917fa8b3887e4bc3e03cebded3e95e487e2 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/fsl_ifc.h>
 #include <linux/iopoll.h>
 
index d5813b9abc8e7092a39727a977a7dbb29c85095a..3824361928a17dff97640e823826e5b75c3ea08a 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/mtd.h>
 #include <linux/of_platform.h>
index 984b05e6bd387cbbdfc8ba8589cb06be3a2b8bdb..e880db5852d8193bbd4fcef28f78c23f6c5e38da 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/mtd/partitions.h>
index 9e728c7317956f60ce515ae6c55cce54fdb136d3..885b03b7af52ade2fb2c7f7853bc38af528ffd9e 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 
 #define DRV_NAME "lpc32xx_mlc"
 
index dc7785e30d2f6cbc6d7905c946f0e8ff035085a1..0bf9c3fbcd82bb20329294053b7e2fd8de8c3816 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
index d66b5b0971fab7b813c359386ba2280661ffaa28..da10709939948053a9e703869bfc9e13f5702d99 100644 (file)
@@ -12,8 +12,8 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
 #include <linux/platform_device.h>
 
 #include "internals.h"
index ebaf3bbfc1b266ea51cb03bfb15e73454b768924..bee7c64a0a4ec726c11b9ef7d2ba0ba06444de91 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/nand-ecc-sw-bch.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
diff --git a/drivers/mtd/nand/raw/nand_ecc.c b/drivers/mtd/nand/raw/nand_ecc.c
deleted file mode 100644 (file)
index b6a46b1..0000000
+++ /dev/null
@@ -1,484 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * This file contains an ECC algorithm that detects and corrects 1 bit
- * errors in a 256 byte block of data.
- *
- * Copyright © 2008 Koninklijke Philips Electronics NV.
- *                  Author: Frans Meulenbroeks
- *
- * Completely replaces the previous ECC implementation which was written by:
- *   Steven J. Hill (sjhill@realitydiluted.com)
- *   Thomas Gleixner (tglx@linutronix.de)
- *
- * Information on how this algorithm works and how it was developed
- * can be found in Documentation/driver-api/mtd/nand_ecc.rst
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <asm/byteorder.h>
-
-/*
- * invparity is a 256 byte table that contains the odd parity
- * for each byte. So if the number of bits in a byte is even,
- * the array element is 1, and when the number of bits is odd
- * the array eleemnt is 0.
- */
-static const char invparity[256] = {
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
-       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
-};
-
-/*
- * bitsperbyte contains the number of bits per byte
- * this is only used for testing and repairing parity
- * (a precalculated value slightly improves performance)
- */
-static const char bitsperbyte[256] = {
-       0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
-       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-       1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
-       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-       2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
-       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-       3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
-       4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
-};
-
-/*
- * addressbits is a lookup table to filter out the bits from the xor-ed
- * ECC data that identify the faulty location.
- * this is only used for repairing parity
- * see the comments in nand_correct_data for more details
- */
-static const char addressbits[256] = {
-       0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
-       0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
-       0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
-       0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
-       0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
-       0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
-       0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
-       0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
-       0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
-       0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
-       0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
-       0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03,
-       0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
-       0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
-       0x04, 0x04, 0x05, 0x05, 0x04, 0x04, 0x05, 0x05,
-       0x06, 0x06, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07,
-       0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
-       0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
-       0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
-       0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
-       0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
-       0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
-       0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
-       0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
-       0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
-       0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
-       0x08, 0x08, 0x09, 0x09, 0x08, 0x08, 0x09, 0x09,
-       0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b,
-       0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
-       0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f,
-       0x0c, 0x0c, 0x0d, 0x0d, 0x0c, 0x0c, 0x0d, 0x0d,
-       0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
-};
-
-/**
- * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
- *                      block
- * @buf:       input buffer with raw data
- * @eccsize:   data bytes per ECC step (256 or 512)
- * @code:      output buffer with ECC
- * @sm_order:  Smart Media byte ordering
- */
-void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
-                         unsigned char *code, bool sm_order)
-{
-       int i;
-       const uint32_t *bp = (uint32_t *)buf;
-       /* 256 or 512 bytes/ecc  */
-       const uint32_t eccsize_mult = eccsize >> 8;
-       uint32_t cur;           /* current value in buffer */
-       /* rp0..rp15..rp17 are the various accumulated parities (per byte) */
-       uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
-       uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
-       uint32_t rp17;
-       uint32_t par;           /* the cumulative parity for all data */
-       uint32_t tmppar;        /* the cumulative parity for this iteration;
-                                  for rp12, rp14 and rp16 at the end of the
-                                  loop */
-
-       par = 0;
-       rp4 = 0;
-       rp6 = 0;
-       rp8 = 0;
-       rp10 = 0;
-       rp12 = 0;
-       rp14 = 0;
-       rp16 = 0;
-
-       /*
-        * The loop is unrolled a number of times;
-        * This avoids if statements to decide on which rp value to update
-        * Also we process the data by longwords.
-        * Note: passing unaligned data might give a performance penalty.
-        * It is assumed that the buffers are aligned.
-        * tmppar is the cumulative sum of this iteration.
-        * needed for calculating rp12, rp14, rp16 and par
-        * also used as a performance improvement for rp6, rp8 and rp10
-        */
-       for (i = 0; i < eccsize_mult << 2; i++) {
-               cur = *bp++;
-               tmppar = cur;
-               rp4 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp6 ^= tmppar;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp4 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp8 ^= tmppar;
-
-               cur = *bp++;
-               tmppar ^= cur;
-               rp4 ^= cur;
-               rp6 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp6 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp4 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp10 ^= tmppar;
-
-               cur = *bp++;
-               tmppar ^= cur;
-               rp4 ^= cur;
-               rp6 ^= cur;
-               rp8 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp6 ^= cur;
-               rp8 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp4 ^= cur;
-               rp8 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp8 ^= cur;
-
-               cur = *bp++;
-               tmppar ^= cur;
-               rp4 ^= cur;
-               rp6 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp6 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-               rp4 ^= cur;
-               cur = *bp++;
-               tmppar ^= cur;
-
-               par ^= tmppar;
-               if ((i & 0x1) == 0)
-                       rp12 ^= tmppar;
-               if ((i & 0x2) == 0)
-                       rp14 ^= tmppar;
-               if (eccsize_mult == 2 && (i & 0x4) == 0)
-                       rp16 ^= tmppar;
-       }
-
-       /*
-        * handle the fact that we use longword operations
-        * we'll bring rp4..rp14..rp16 back to single byte entities by
-        * shifting and xoring first fold the upper and lower 16 bits,
-        * then the upper and lower 8 bits.
-        */
-       rp4 ^= (rp4 >> 16);
-       rp4 ^= (rp4 >> 8);
-       rp4 &= 0xff;
-       rp6 ^= (rp6 >> 16);
-       rp6 ^= (rp6 >> 8);
-       rp6 &= 0xff;
-       rp8 ^= (rp8 >> 16);
-       rp8 ^= (rp8 >> 8);
-       rp8 &= 0xff;
-       rp10 ^= (rp10 >> 16);
-       rp10 ^= (rp10 >> 8);
-       rp10 &= 0xff;
-       rp12 ^= (rp12 >> 16);
-       rp12 ^= (rp12 >> 8);
-       rp12 &= 0xff;
-       rp14 ^= (rp14 >> 16);
-       rp14 ^= (rp14 >> 8);
-       rp14 &= 0xff;
-       if (eccsize_mult == 2) {
-               rp16 ^= (rp16 >> 16);
-               rp16 ^= (rp16 >> 8);
-               rp16 &= 0xff;
-       }
-
-       /*
-        * we also need to calculate the row parity for rp0..rp3
-        * This is present in par, because par is now
-        * rp3 rp3 rp2 rp2 in little endian and
-        * rp2 rp2 rp3 rp3 in big endian
-        * as well as
-        * rp1 rp0 rp1 rp0 in little endian and
-        * rp0 rp1 rp0 rp1 in big endian
-        * First calculate rp2 and rp3
-        */
-#ifdef __BIG_ENDIAN
-       rp2 = (par >> 16);
-       rp2 ^= (rp2 >> 8);
-       rp2 &= 0xff;
-       rp3 = par & 0xffff;
-       rp3 ^= (rp3 >> 8);
-       rp3 &= 0xff;
-#else
-       rp3 = (par >> 16);
-       rp3 ^= (rp3 >> 8);
-       rp3 &= 0xff;
-       rp2 = par & 0xffff;
-       rp2 ^= (rp2 >> 8);
-       rp2 &= 0xff;
-#endif
-
-       /* reduce par to 16 bits then calculate rp1 and rp0 */
-       par ^= (par >> 16);
-#ifdef __BIG_ENDIAN
-       rp0 = (par >> 8) & 0xff;
-       rp1 = (par & 0xff);
-#else
-       rp1 = (par >> 8) & 0xff;
-       rp0 = (par & 0xff);
-#endif
-
-       /* finally reduce par to 8 bits */
-       par ^= (par >> 8);
-       par &= 0xff;
-
-       /*
-        * and calculate rp5..rp15..rp17
-        * note that par = rp4 ^ rp5 and due to the commutative property
-        * of the ^ operator we can say:
-        * rp5 = (par ^ rp4);
-        * The & 0xff seems superfluous, but benchmarking learned that
-        * leaving it out gives slightly worse results. No idea why, probably
-        * it has to do with the way the pipeline in pentium is organized.
-        */
-       rp5 = (par ^ rp4) & 0xff;
-       rp7 = (par ^ rp6) & 0xff;
-       rp9 = (par ^ rp8) & 0xff;
-       rp11 = (par ^ rp10) & 0xff;
-       rp13 = (par ^ rp12) & 0xff;
-       rp15 = (par ^ rp14) & 0xff;
-       if (eccsize_mult == 2)
-               rp17 = (par ^ rp16) & 0xff;
-
-       /*
-        * Finally calculate the ECC bits.
-        * Again here it might seem that there are performance optimisations
-        * possible, but benchmarks showed that on the system this is developed
-        * the code below is the fastest
-        */
-       if (sm_order) {
-               code[0] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
-                         (invparity[rp5] << 5) | (invparity[rp4] << 4) |
-                         (invparity[rp3] << 3) | (invparity[rp2] << 2) |
-                         (invparity[rp1] << 1) | (invparity[rp0]);
-               code[1] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
-                         (invparity[rp13] << 5) | (invparity[rp12] << 4) |
-                         (invparity[rp11] << 3) | (invparity[rp10] << 2) |
-                         (invparity[rp9] << 1) | (invparity[rp8]);
-       } else {
-               code[1] = (invparity[rp7] << 7) | (invparity[rp6] << 6) |
-                         (invparity[rp5] << 5) | (invparity[rp4] << 4) |
-                         (invparity[rp3] << 3) | (invparity[rp2] << 2) |
-                         (invparity[rp1] << 1) | (invparity[rp0]);
-               code[0] = (invparity[rp15] << 7) | (invparity[rp14] << 6) |
-                         (invparity[rp13] << 5) | (invparity[rp12] << 4) |
-                         (invparity[rp11] << 3) | (invparity[rp10] << 2) |
-                         (invparity[rp9] << 1) | (invparity[rp8]);
-       }
-
-       if (eccsize_mult == 1)
-               code[2] =
-                   (invparity[par & 0xf0] << 7) |
-                   (invparity[par & 0x0f] << 6) |
-                   (invparity[par & 0xcc] << 5) |
-                   (invparity[par & 0x33] << 4) |
-                   (invparity[par & 0xaa] << 3) |
-                   (invparity[par & 0x55] << 2) |
-                   3;
-       else
-               code[2] =
-                   (invparity[par & 0xf0] << 7) |
-                   (invparity[par & 0x0f] << 6) |
-                   (invparity[par & 0xcc] << 5) |
-                   (invparity[par & 0x33] << 4) |
-                   (invparity[par & 0xaa] << 3) |
-                   (invparity[par & 0x55] << 2) |
-                   (invparity[rp17] << 1) |
-                   (invparity[rp16] << 0);
-}
-EXPORT_SYMBOL(__nand_calculate_ecc);
-
-/**
- * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
- *                      block
- * @chip:      NAND chip object
- * @buf:       input buffer with raw data
- * @code:      output buffer with ECC
- */
-int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
-                      unsigned char *code)
-{
-       bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
-
-       __nand_calculate_ecc(buf, chip->ecc.size, code, sm_order);
-
-       return 0;
-}
-EXPORT_SYMBOL(nand_calculate_ecc);
-
-/**
- * __nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @buf:       raw data read from the chip
- * @read_ecc:  ECC from the chip
- * @calc_ecc:  the ECC calculated from raw data
- * @eccsize:   data bytes per ECC step (256 or 512)
- * @sm_order:  Smart Media byte order
- *
- * Detect and correct a 1 bit error for eccsize byte block
- */
-int __nand_correct_data(unsigned char *buf,
-                       unsigned char *read_ecc, unsigned char *calc_ecc,
-                       unsigned int eccsize, bool sm_order)
-{
-       unsigned char b0, b1, b2, bit_addr;
-       unsigned int byte_addr;
-       /* 256 or 512 bytes/ecc  */
-       const uint32_t eccsize_mult = eccsize >> 8;
-
-       /*
-        * b0 to b2 indicate which bit is faulty (if any)
-        * we might need the xor result  more than once,
-        * so keep them in a local var
-       */
-       if (sm_order) {
-               b0 = read_ecc[0] ^ calc_ecc[0];
-               b1 = read_ecc[1] ^ calc_ecc[1];
-       } else {
-               b0 = read_ecc[1] ^ calc_ecc[1];
-               b1 = read_ecc[0] ^ calc_ecc[0];
-       }
-
-       b2 = read_ecc[2] ^ calc_ecc[2];
-
-       /* check if there are any bitfaults */
-
-       /* repeated if statements are slightly more efficient than switch ... */
-       /* ordered in order of likelihood */
-
-       if ((b0 | b1 | b2) == 0)
-               return 0;       /* no error */
-
-       if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
-           (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
-           ((eccsize_mult == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
-            (eccsize_mult == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
-       /* single bit error */
-               /*
-                * rp17/rp15/13/11/9/7/5/3/1 indicate which byte is the faulty
-                * byte, cp 5/3/1 indicate the faulty bit.
-                * A lookup table (called addressbits) is used to filter
-                * the bits from the byte they are in.
-                * A marginal optimisation is possible by having three
-                * different lookup tables.
-                * One as we have now (for b0), one for b2
-                * (that would avoid the >> 1), and one for b1 (with all values
-                * << 4). However it was felt that introducing two more tables
-                * hardly justify the gain.
-                *
-                * The b2 shift is there to get rid of the lowest two bits.
-                * We could also do addressbits[b2] >> 1 but for the
-                * performance it does not make any difference
-                */
-               if (eccsize_mult == 1)
-                       byte_addr = (addressbits[b1] << 4) + addressbits[b0];
-               else
-                       byte_addr = (addressbits[b2 & 0x3] << 8) +
-                                   (addressbits[b1] << 4) + addressbits[b0];
-               bit_addr = addressbits[b2 >> 2];
-               /* flip the bit */
-               buf[byte_addr] ^= (1 << bit_addr);
-               return 1;
-
-       }
-       /* count nr of bits; use table lookup, faster than calculating it */
-       if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
-               return 1;       /* error in ECC data; no action needed */
-
-       pr_err("%s: uncorrectable ECC error\n", __func__);
-       return -EBADMSG;
-}
-EXPORT_SYMBOL(__nand_correct_data);
-
-/**
- * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @chip:      NAND chip object
- * @buf:       raw data read from the chip
- * @read_ecc:  ECC from the chip
- * @calc_ecc:  the ECC calculated from raw data
- *
- * Detect and correct a 1 bit error for 256/512 byte block
- */
-int nand_correct_data(struct nand_chip *chip, unsigned char *buf,
-                     unsigned char *read_ecc, unsigned char *calc_ecc)
-{
-       bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
-
-       return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size,
-                                  sm_order);
-}
-EXPORT_SYMBOL(nand_correct_data);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
-MODULE_DESCRIPTION("Generic NAND ECC support");
index 0fb4ba93c41e031d93c4a258f14283d9505c1785..8cda6633280b47e978b0413bec7bafd2548b7273 100644 (file)
@@ -18,7 +18,7 @@
  */
 #include <linux/module.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/ndfc.h>
 #include <linux/slab.h>
index 4dfff34800f4e5ac127b1d3df8f5c1bbf9eef63f..2dddbdca9e9426dea348f9e27770d5409d6162c5 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
index fbd0fa48e063d94e4d0f5baeb57975d898278df7..f7eb3b5fa792227761f06d0717e885391bb02320 100644 (file)
@@ -30,7 +30,7 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 #include <linux/platform_data/mtd-nand-s3c2410.h>
index af98bcc9d689c481d3015e473863cc44882c0e7d..2fae6ade8b139c034d451cb9f307c25a6625b198 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/sharpsl.h>
 #include <linux/interrupt.h>
index aa6c7e7bbf1b59f36f50f0b1725a7b2a5136de2f..fadca0b9e21fd066b8b2baea5c50e5c4f906b14d 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/ioport.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/slab.h>
 
index fe8ed24415885effb69372dfd1f4497d67787421..68b920eab6c8339b145df6498bcb1b6bc561ad96 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/platform_data/txx9/ndfmc.h>
index b9f272408c4d5f57b61dcc781e83c70fc76337e1..db430ae6a1a2ae95f7d590c88d78bca4cd7ee6af 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/sysfs.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include "nand/raw/sm_common.h"
 #include "sm_ftl.h"
 
index 13bca9ea0caef87929b1372ef322a304e5fd22bf..e92e3fb287b680eef47e7331f4bdcb4500319d7e 100644 (file)
@@ -8,7 +8,7 @@
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 
 #include "mtd_test.h"
 
diff --git a/include/linux/mtd/nand-ecc-sw-hamming.h b/include/linux/mtd/nand-ecc-sw-hamming.h
new file mode 100644 (file)
index 0000000..30a0cfa
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ *  Copyright (C) 2000-2010 Steven J. Hill <sjhill@realitydiluted.com>
+ *                         David Woodhouse <dwmw2@infradead.org>
+ *                         Thomas Gleixner <tglx@linutronix.de>
+ *
+ * This file is the header for the ECC algorithm.
+ */
+
+#ifndef __MTD_NAND_ECC_SW_HAMMING_H__
+#define __MTD_NAND_ECC_SW_HAMMING_H__
+
+struct nand_chip;
+
+/*
+ * Calculate 3 byte ECC code for eccsize byte block
+ */
+void __nand_calculate_ecc(const u_char *dat, unsigned int eccsize,
+                         u_char *ecc_code, bool sm_order);
+
+/*
+ * Calculate 3 byte ECC code for 256/512 byte block
+ */
+int nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
+                      u_char *ecc_code);
+
+/*
+ * Detect and correct a 1 bit error for eccsize byte block
+ */
+int __nand_correct_data(u_char *dat, u_char *read_ecc, u_char *calc_ecc,
+                       unsigned int eccsize, bool sm_order);
+
+/*
+ * Detect and correct a 1 bit error for 256/512 byte block
+ */
+int nand_correct_data(struct nand_chip *chip, u_char *dat, u_char *read_ecc,
+                     u_char *calc_ecc);
+
+#endif /* __MTD_NAND_ECC_SW_HAMMING_H__ */
diff --git a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h
deleted file mode 100644 (file)
index d423916..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- *  Copyright (C) 2000-2010 Steven J. Hill <sjhill@realitydiluted.com>
- *                         David Woodhouse <dwmw2@infradead.org>
- *                         Thomas Gleixner <tglx@linutronix.de>
- *
- * This file is the header for the ECC algorithm.
- */
-
-#ifndef __MTD_NAND_ECC_H__
-#define __MTD_NAND_ECC_H__
-
-struct nand_chip;
-
-/*
- * Calculate 3 byte ECC code for eccsize byte block
- */
-void __nand_calculate_ecc(const u_char *dat, unsigned int eccsize,
-                         u_char *ecc_code, bool sm_order);
-
-/*
- * Calculate 3 byte ECC code for 256/512 byte block
- */
-int nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
-                      u_char *ecc_code);
-
-/*
- * Detect and correct a 1 bit error for eccsize byte block
- */
-int __nand_correct_data(u_char *dat, u_char *read_ecc, u_char *calc_ecc,
-                       unsigned int eccsize, bool sm_order);
-
-/*
- * Detect and correct a 1 bit error for 256/512 byte block
- */
-int nand_correct_data(struct nand_chip *chip, u_char *dat, u_char *read_ecc,
-                     u_char *calc_ecc);
-
-#endif /* __MTD_NAND_ECC_H__ */
index d2c3cf29e0d17ca03b2552dfca9f78890b6c02da..3762a90077d66410e8ad0d016a9d98380b01720e 100644 (file)
@@ -9,7 +9,7 @@
 #define _MTD_SHARPSL_H
 
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/nand-ecc-sw-hamming.h>
 #include <linux/mtd/partitions.h>
 
 struct sharpsl_nand_platform_data {