]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 4 May 2018 22:12:19 +0000 (15:12 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 4 May 2018 22:12:19 +0000 (15:12 -0700)
added patches:
gpmi-nand-handle-ecc-errors-in-erased-pages.patch

queue-4.4/gpmi-nand-handle-ecc-errors-in-erased-pages.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/gpmi-nand-handle-ecc-errors-in-erased-pages.patch b/queue-4.4/gpmi-nand-handle-ecc-errors-in-erased-pages.patch
new file mode 100644 (file)
index 0000000..cd3f872
--- /dev/null
@@ -0,0 +1,140 @@
+From bd2e778c9ee361c23ccb2b10591712e129d97893 Mon Sep 17 00:00:00 2001
+From: Markus Pargmann <mpa@pengutronix.de>
+Date: Mon, 25 Apr 2016 14:35:12 +0200
+Subject: gpmi-nand: Handle ECC Errors in erased pages
+
+From: Markus Pargmann <mpa@pengutronix.de>
+
+commit bd2e778c9ee361c23ccb2b10591712e129d97893 upstream.
+
+ECC is only calculated for written pages. As erased pages are not
+actively written the ECC is always invalid. For this purpose the
+Hardware BCH unit is able to check for erased pages and does not raise
+an ECC error in this case. This behaviour can be influenced using the
+BCH_MODE register which sets the number of allowed bitflips in an erased
+page. Unfortunately the unit is not capable of fixing the bitflips in
+memory.
+
+To avoid complete software checks for erased pages, we can simply check
+buffers with uncorrectable ECC errors because we know that any erased
+page with errors is uncorrectable by the BCH unit.
+
+This patch adds the generic nand_check_erased_ecc_chunk() to gpmi-nand
+to correct erased pages. To have the valid data in the buffer before
+using them, this patch moves the read_page_swap_end() call before the
+ECC status checking for-loop.
+
+Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
+[Squashed patches by Stefan and Boris to check ECC area]
+Tested-by: Stefan Christ <s.christ@phytec.de>
+Acked-by: Han xu <han.xu@nxp.com>
+Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mtd/nand/gpmi-nand/gpmi-nand.c |   78 ++++++++++++++++++++++++++++++---
+ 1 file changed, 73 insertions(+), 5 deletions(-)
+
+--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
++++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+@@ -1032,14 +1032,87 @@ static int gpmi_ecc_read_page(struct mtd
+       /* Loop over status bytes, accumulating ECC status. */
+       status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
++      read_page_swap_end(this, buf, nfc_geo->payload_size,
++                         this->payload_virt, this->payload_phys,
++                         nfc_geo->payload_size,
++                         payload_virt, payload_phys);
++
+       for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
+               if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
+                       continue;
+               if (*status == STATUS_UNCORRECTABLE) {
++                      int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
++                      u8 *eccbuf = this->raw_buffer;
++                      int offset, bitoffset;
++                      int eccbytes;
++                      int flips;
++
++                      /* Read ECC bytes into our internal raw_buffer */
++                      offset = nfc_geo->metadata_size * 8;
++                      offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
++                      offset -= eccbits;
++                      bitoffset = offset % 8;
++                      eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
++                      offset /= 8;
++                      eccbytes -= offset;
++                      chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
++                      chip->read_buf(mtd, eccbuf, eccbytes);
++
++                      /*
++                       * ECC data are not byte aligned and we may have
++                       * in-band data in the first and last byte of
++                       * eccbuf. Set non-eccbits to one so that
++                       * nand_check_erased_ecc_chunk() does not count them
++                       * as bitflips.
++                       */
++                      if (bitoffset)
++                              eccbuf[0] |= GENMASK(bitoffset - 1, 0);
++
++                      bitoffset = (bitoffset + eccbits) % 8;
++                      if (bitoffset)
++                              eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
++
++                      /*
++                       * The ECC hardware has an uncorrectable ECC status
++                       * code in case we have bitflips in an erased page. As
++                       * nothing was written into this subpage the ECC is
++                       * obviously wrong and we can not trust it. We assume
++                       * at this point that we are reading an erased page and
++                       * try to correct the bitflips in buffer up to
++                       * ecc_strength bitflips. If this is a page with random
++                       * data, we exceed this number of bitflips and have a
++                       * ECC failure. Otherwise we use the corrected buffer.
++                       */
++                      if (i == 0) {
++                              /* The first block includes metadata */
++                              flips = nand_check_erased_ecc_chunk(
++                                              buf + i * nfc_geo->ecc_chunk_size,
++                                              nfc_geo->ecc_chunk_size,
++                                              eccbuf, eccbytes,
++                                              auxiliary_virt,
++                                              nfc_geo->metadata_size,
++                                              nfc_geo->ecc_strength);
++                      } else {
++                              flips = nand_check_erased_ecc_chunk(
++                                              buf + i * nfc_geo->ecc_chunk_size,
++                                              nfc_geo->ecc_chunk_size,
++                                              eccbuf, eccbytes,
++                                              NULL, 0,
++                                              nfc_geo->ecc_strength);
++                      }
++
++                      if (flips > 0) {
++                              max_bitflips = max_t(unsigned int, max_bitflips,
++                                                   flips);
++                              mtd->ecc_stats.corrected += flips;
++                              continue;
++                      }
++
+                       mtd->ecc_stats.failed++;
+                       continue;
+               }
++
+               mtd->ecc_stats.corrected += *status;
+               max_bitflips = max_t(unsigned int, max_bitflips, *status);
+       }
+@@ -1062,11 +1135,6 @@ static int gpmi_ecc_read_page(struct mtd
+               chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
+       }
+-      read_page_swap_end(this, buf, nfc_geo->payload_size,
+-                      this->payload_virt, this->payload_phys,
+-                      nfc_geo->payload_size,
+-                      payload_virt, payload_phys);
+-
+       return max_bitflips;
+ }
index 7a1e90179eb5d93a4d7da7ffc6823b9dc17b6210..1860096857364cbab7a552a4cf155e616a1dfcb2 100644 (file)
@@ -9,3 +9,4 @@ mac80211-allow-same-pn-for-amsdu-sub-frames.patch
 mac80211-add-rx-flag-to-indicate-icv-stripped.patch
 ath10k-fix-rfc1042-header-retrieval-in-qca4019-with-eth-decap-mode.patch
 ath10k-rebuild-crypto-header-in-rx-data-frames.patch
+gpmi-nand-handle-ecc-errors-in-erased-pages.patch