From: Greg Kroah-Hartman Date: Fri, 4 May 2018 22:12:19 +0000 (-0700) Subject: 4.4-stable patches X-Git-Tag: v4.9.99~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8a1745dfbef07f941552ad7bda6f2fbfd1d7c97f;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: gpmi-nand-handle-ecc-errors-in-erased-pages.patch --- 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 index 00000000000..cd3f87245a9 --- /dev/null +++ b/queue-4.4/gpmi-nand-handle-ecc-errors-in-erased-pages.patch @@ -0,0 +1,140 @@ +From bd2e778c9ee361c23ccb2b10591712e129d97893 Mon Sep 17 00:00:00 2001 +From: Markus Pargmann +Date: Mon, 25 Apr 2016 14:35:12 +0200 +Subject: gpmi-nand: Handle ECC Errors in erased pages + +From: Markus Pargmann + +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 +[Squashed patches by Stefan and Boris to check ECC area] +Tested-by: Stefan Christ +Acked-by: Han xu +Signed-off-by: Boris Brezillon +Cc: Sascha Hauer +Signed-off-by: Greg Kroah-Hartman + +--- + 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; + } + diff --git a/queue-4.4/series b/queue-4.4/series index 7a1e90179eb..18600968573 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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