From patchwork Wed Mar 22 14:07:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 95755 Delivered-To: patch@linaro.org Received: by 10.182.3.34 with SMTP id 2csp233033obz; Wed, 22 Mar 2017 07:10:18 -0700 (PDT) X-Received: by 10.98.96.65 with SMTP id u62mr46989360pfb.219.1490191817597; Wed, 22 Mar 2017 07:10:17 -0700 (PDT) Return-Path: Received: from bombadil.infradead.org (bombadil.infradead.org. [65.50.211.133]) by mx.google.com with ESMTPS id b31si1954063pli.254.2017.03.22.07.10.16 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 22 Mar 2017 07:10:17 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-mtd-bounces+patch=linaro.org@lists.infradead.org designates 65.50.211.133 as permitted sender) client-ip=65.50.211.133; Authentication-Results: mx.google.com; dkim=pass header.i=@lists.infradead.org; dkim=neutral (body hash did not verify) header.i=@nifty.com; spf=pass (google.com: best guess record for domain of linux-mtd-bounces+patch=linaro.org@lists.infradead.org designates 65.50.211.133 as permitted sender) smtp.mailfrom=linux-mtd-bounces+patch=linaro.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=zafh2ykx1rRX+t4kuGwsUSKFheJv1jW+5Zs9iGoktmE=; b=Z0rg/CAGJOCD1PuKLZWnzoeq16 N9g0ICU2L8q7h0snV8qt+9jvy+Pn7G0eWtf2sGpGM5U6NsGlAy1CTxO3nu21t5eCc9a16DtHk1vTD rJyD0WvzfUQSdfYnbYDtzPhiPHlZaN+b6q/W78VNdeUNQgMO+gQ/qJUNxpfMx583hBdKVtfInb6JA wCDxTEovAk0sEGzuf7iq69fOANDCw0uZP3diPAqFrHHoTLEkBUrQohCAy2Mk6irG9gEQJ3c2/xOuQ 3E1eD1LJiCsCIDgQC91tWYUIaA2PwbmiR9U4kD/Imbk7LXXGOWD0hQPqlnlV9BrLyyw8i7nia52gv qSwVKZGg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1cqgxq-00083z-Hj; Wed, 22 Mar 2017 14:10:14 +0000 Received: from conuserg-07.nifty.com ([210.131.2.74]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1cqgx3-0005xG-OS for linux-mtd@lists.infradead.org; Wed, 22 Mar 2017 14:09:28 +0000 Received: from pug.jp.socionext.com (p14092-ipngnfx01kyoto.kyoto.ocn.ne.jp [153.142.97.92]) (authenticated) by conuserg-07.nifty.com with ESMTP id v2ME8LDV010154; Wed, 22 Mar 2017 23:08:40 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-07.nifty.com v2ME8LDV010154 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1490191721; bh=bIjoQT1mwHplizobDSyXhZ4bT5hlB/Yxmrw0Og+ZLJI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bn9oLcmronCGJAzpV2vY3/9pvR2M6M/sCiJfwHLOHXDORXcVziP16muw+V/YsvQ64 wXlgQYBNETTGJ4k/ODiEGQY1A6wU9h8YkHJWZjW2oHDE0BkZx+4zkn9+36W0eV2jZO A2JPUR6DSewSf0R8SbDLkkzYTg8xEdg061n0D6rOedkc+BpqkzLQ7kg4Xau2EK9sMv KDHyFAJ7+5734gN0HaUMU0ycIOfamtnp9wlvSaP+ehfZkg3SMQaDs/4c1lBjsRitxh ovOo+M2hkxnXdWGZnjOJ+UnerJMMkuvjpoPGdtOaC0rKOTgcye3L8974ksn4iHI6NL jkSkR4ugWWoOA== X-Nifty-SrcIP: [153.142.97.92] From: Masahiro Yamada To: linux-mtd@lists.infradead.org Subject: [PATCH v2 12/53] mtd: nand: denali: support HW_ECC_FIXUP capability Date: Wed, 22 Mar 2017 23:07:19 +0900 Message-Id: <1490191680-14481-13-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1490191680-14481-1-git-send-email-yamada.masahiro@socionext.com> References: <1490191680-14481-1-git-send-email-yamada.masahiro@socionext.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170322_070926_163158_DF90803A X-CRM114-Status: GOOD ( 19.99 ) X-Spam-Score: -1.2 (-) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-1.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.7 SPF_SOFTFAIL SPF: sender does not match SPF record (softfail) -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: laurent.monat@idquantique.com, Boris Brezillon , thorsten.christiansson@idquantique.com, Richard Weinberger , Marek Vasut , Masahiro Yamada , Artem Bityutskiy , Cyrille Pitchen , Jason Roberts , linux-kernel@vger.kernel.org, Dinh Nguyen , Masami Hiramatsu , Chuanxiao Dong , Jassi Brar , Brian Norris , Enrico Jorns , David Woodhouse , Graham Moore MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+patch=linaro.org@lists.infradead.org Some old versions of the Denali IP (perhaps used only for Intel?) detects ECC errors and provides correct data via a register, but does not touch the transferred data. So, the software must fixup the data in the buffer according to the provided ECC correction information. Newer versions perform ECC correction before transferring the data. No more software intervention is needed. The ECC_ERROR_ADDRESS and ECC_CORRECTION_INFO registers were deprecated. Instead, the number of corrected bit-flips can be read from the ECC_COR_INFO register. When an uncorrectable ECC error happens, a status flag is set to the INTR_STATUS and ECC_COR_INFO registers. As is often the case with this IP, the register view of INTR_STATUS had broken compatibility. For older versions (SW ECC fixup): bit 0: ECC_TRANSACTION_DONE bit 1: ECC_ERR For newer versions (HW ECC fixup): bit 0: ECC_UNCOR_ERR bit 1: Reserved Due to this difference, the irq_mask must be fixed too. The comment block in handle_ecc() has been moved to the common part because the comment applies to both cases. The existing handle_ecc() has been renamed to denali_sw_ecc_fixup() for clarification. The U-Boot port of this driver already supports the HW ECC fixup. I borrowed the comment "Some versions of ..." in denali.h from U-Boot. Signed-off-by: Masahiro Yamada --- Changes in v2: - Change the capability prefix DENALI_CAPS_ -> DENALI_CAP_ drivers/mtd/nand/denali.c | 52 ++++++++++++++++++++++++++++++++++++----------- drivers/mtd/nand/denali.h | 14 +++++++++++++ 2 files changed, 54 insertions(+), 12 deletions(-) -- 2.7.4 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/ diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 608fe6f..91f0def 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -883,6 +883,32 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) } } +static int denali_hw_ecc_fixup(struct mtd_info *mtd, + struct denali_nand_info *denali) +{ + int bank = denali->flash_bank; + uint32_t ecc_cor; + unsigned int max_bitflips; + + ecc_cor = ioread32(denali->flash_reg + ECC_COR_INFO(bank)); + ecc_cor >>= ECC_COR_INFO__SHIFT(bank); + + if (ecc_cor & ECC_COR_INFO__UNCOR_ERR) + return -EBADMSG; + + max_bitflips = ecc_cor & ECC_COR_INFO__MAX_ERRORS; + + /* + * The register holds the maximum of the number of corrected bitflips + * per sector. This can be returned from ecc->read_page() as-is. + * Unfortunately, we can not know the total number of corrected bits + * in the page. mtd->ecc_stats.corrected is compromised here. + */ + mtd->ecc_stats.corrected += max_bitflips; + + return max_bitflips; +} + #define ECC_SECTOR_SIZE 512 #define ECC_SECTOR(x) (((x) & ECC_ERROR_ADDRESS__SECTOR_NR) >> 12) @@ -892,8 +918,8 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page) #define ECC_ERR_DEVICE(x) (((x) & ERR_CORRECTION_INFO__DEVICE_NR) >> 8) #define ECC_LAST_ERR(x) ((x) & ERR_CORRECTION_INFO__LAST_ERR_INFO) -static int handle_ecc(struct mtd_info *mtd, - struct denali_nand_info *denali, uint8_t *buf) +static int denali_sw_ecc_fixup(struct mtd_info *mtd, + struct denali_nand_info *denali, uint8_t *buf) { unsigned int bitflips = 0; unsigned int max_bitflips = 0; @@ -921,11 +947,6 @@ static int handle_ecc(struct mtd_info *mtd, bitflips = 0; if (ECC_ERROR_UNCORRECTABLE(err_cor_info)) { - /* - * if the error is not correctable, need to look at the - * page to see if it is an erased page. if so, then - * it's not a real ECC error - */ ret = -EBADMSG; } else if (err_byte < ECC_SECTOR_SIZE) { /* @@ -1105,12 +1126,12 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); - dma_addr_t addr = denali->buf.dma_buf; size_t size = mtd->writesize + mtd->oobsize; - uint32_t irq_status; - uint32_t irq_mask = INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR; + uint32_t irq_mask = denali->caps & DENALI_CAP_HW_ECC_FIXUP ? + INTR__DMA_CMD_COMP | INTR__ECC_UNCOR_ERR : + INTR__ECC_TRANSACTION_DONE | INTR__ECC_ERR; int stat = 0; if (page != denali->page) { @@ -1135,11 +1156,18 @@ static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, memcpy(buf, denali->buf.buf, mtd->writesize); - if (irq_status & INTR__ECC_ERR) - stat = handle_ecc(mtd, denali, buf); + if (denali->caps & DENALI_CAP_HW_ECC_FIXUP) + stat = denali_hw_ecc_fixup(mtd, denali); + else if (irq_status & INTR__ECC_ERR) + stat = denali_sw_ecc_fixup(mtd, denali, buf); denali_enable_dma(denali, false); if (stat == -EBADMSG) { + /* + * If the error is not correctable, need to look at the page to + * see if it is an erased page. If so, then it's not a real ECC + * error. + */ read_oob_data(mtd, chip->oob_poi, denali->page); stat = nand_check_erased_ecc_chunk( diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 7b2d785..ed42b16 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -20,6 +20,7 @@ #ifndef __DENALI_H__ #define __DENALI_H__ +#include #include #define DEVICE_RESET 0x0 @@ -218,6 +219,13 @@ #define INTR_STATUS(__bank) (0x410 + ((__bank) * 0x50)) #define INTR_EN(__bank) (0x420 + ((__bank) * 0x50)) +/* + * Some versions of the IP have the ECC fixup handled in hardware. In this + * configuration we only get interrupted when the error is uncorrectable. + * Unfortunately this bit replaces INTR_STATUS__ECC_TRANSACTION_DONE from the + * old IP. + */ +#define INTR__ECC_UNCOR_ERR 0x0001 #define INTR__ECC_TRANSACTION_DONE 0x0001 #define INTR__ECC_ERR 0x0002 #define INTR__DMA_CMD_COMP 0x0004 @@ -259,6 +267,11 @@ #define ERR_CORRECTION_INFO__ERROR_TYPE 0x4000 #define ERR_CORRECTION_INFO__LAST_ERR_INFO 0x8000 +#define ECC_COR_INFO(bank) (0x650 + (bank) / 2 * 0x10) +#define ECC_COR_INFO__SHIFT(bank) ((bank) % 2 * 8) +#define ECC_COR_INFO__MAX_ERRORS 0x007f +#define ECC_COR_INFO__UNCOR_ERR 0x0080 + #define DMA_ENABLE 0x700 #define DMA_ENABLE__FLAG 0x0001 @@ -339,6 +352,7 @@ struct denali_nand_info { int bbtskipbytes; int max_banks; unsigned int caps; +#define DENALI_CAP_HW_ECC_FIXUP BIT(0) }; extern int denali_init(struct denali_nand_info *denali);