From patchwork Fri May 29 13:15:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 11578629 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0D06C912 for ; Fri, 29 May 2020 13:16:32 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C026820814 for ; Fri, 29 May 2020 13:16:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="JdniQBFt" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C026820814 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=bootlin.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.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:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version: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=zE8LkW/969sCk6d02LjL3rV3wIwzOE3b5rhISmE7w+A=; b=JdniQBFtzTl/Sm x53yTosOZ4gZVO+VaZZ9Q2DWeS17tJuku4voo1sauXO0+IP0PCPqgjwt3ov5Qyv9xOyXxWwUuiGVM Tf+SOycCu534tMKCsGoxoMCiRkQ79WRxxSntTdwInFsaIacXj6uoR14AFUyebd+4YXgUaS3OBUvqw GlfD859wWP55F86oylCHEWu8Qy0NjIRVCrXTJ1KsiQZr7Cr5qd/lFElXPxFOwxCuvOZwazgO4UDJO /NFXG8sqRj/4+UXnz0nn2dUoRsKUCos8z82YY/xWjmYnA30gM6LZ8j3+j+EZRrj/Ldjj2aR6J2OZj +MIa0gNYoB5SkVVFNZ4w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jees9-0001PR-55; Fri, 29 May 2020 13:16:29 +0000 Received: from relay9-d.mail.gandi.net ([217.70.183.199]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jeert-0001F3-5h; Fri, 29 May 2020 13:16:15 +0000 X-Originating-IP: 91.224.148.103 Received: from localhost.localdomain (unknown [91.224.148.103]) (Authenticated sender: miquel.raynal@bootlin.com) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id A97B9FF817; Fri, 29 May 2020 13:16:08 +0000 (UTC) From: Miquel Raynal To: Richard Weinberger , Vignesh Raghavendra , Tudor Ambarus , , Rob Herring , Mark Rutland , Subject: [PATCH v8 1/5] mtd: nand: Convert generic NAND bits to use the ECC framework Date: Fri, 29 May 2020 15:15:58 +0200 Message-Id: <20200529131602.21532-2-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200529131602.21532-1-miquel.raynal@bootlin.com> References: <20200529131602.21532-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200529_061613_479083_82FFE908 X-CRM114-Status: GOOD ( 12.69 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [217.70.183.199 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [217.70.183.199 listed in wl.mailspike.net] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Julien Su , Weijie Gao , Paul Cercueil , Boris Brezillon , Thomas Petazzoni , Miquel Raynal , Mason Yang , Chuanhong Guo , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Embed a generic NAND ECC high-level object in the nand_device structure to carry all the ECC engine configuration/data. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/nand_base.c | 4 +++- include/linux/mtd/nand.h | 12 ++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index e8e22d79f422..ed0f642be993 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5984,7 +5984,9 @@ static int nand_scan_tail(struct nand_chip *chip) /* ECC sanity check: warn if it's too weak */ if (!nand_ecc_strength_good(chip)) pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n", - mtd->name, chip->ecc.strength, chip->ecc.size, + mtd->name, + nanddev_get_ecc_conf(&chip->base)->strength, + nanddev_get_ecc_conf(&chip->base)->step_size, nanddev_get_ecc_requirements(&chip->base)->strength, nanddev_get_ecc_requirements(&chip->base)->step_size); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 488d8b14b9ae..f5cc0aee565c 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -290,7 +290,7 @@ struct nand_ecc { * struct nand_device - NAND device * @mtd: MTD instance attached to the NAND device * @memorg: memory layout - * @eccreq: ECC requirements + * @ecc: NAND ECC object attached to the NAND device * @rowconv: position to row address converter * @bbt: bad block table info * @ops: NAND operations attached to the NAND device @@ -298,8 +298,8 @@ struct nand_ecc { * Generic NAND object. Specialized NAND layers (raw NAND, SPI NAND, OneNAND) * should declare their own NAND object embedding a nand_device struct (that's * how inheritance is done). - * struct_nand_device->memorg and struct_nand_device->eccreq should be filled - * at device detection time to reflect the NAND device + * struct_nand_device->memorg and struct_nand_device->ecc.requirements should + * be filled at device detection time to reflect the NAND device * capabilities/requirements. Once this is done nanddev_init() can be called. * It will take care of converting NAND information into MTD ones, which means * the specialized NAND layers should never manually tweak @@ -308,7 +308,7 @@ struct nand_ecc { struct nand_device { struct mtd_info mtd; struct nand_memory_organization memorg; - struct nand_ecc_props eccreq; + struct nand_ecc ecc; struct nand_row_converter rowconv; struct nand_bbt bbt; const struct nand_ops *ops; @@ -519,7 +519,7 @@ nanddev_get_memorg(struct nand_device *nand) const struct nand_ecc_props * nanddev_get_ecc_conf(struct nand_device *nand) { - return &nand->eccreq; + return &nand->ecc.ctx.conf; } /** @@ -530,7 +530,7 @@ nanddev_get_ecc_conf(struct nand_device *nand) const struct nand_ecc_props * nanddev_get_ecc_requirements(struct nand_device *nand) { - return &nand->eccreq; + return &nand->ecc.requirements; } int nanddev_init(struct nand_device *nand, const struct nand_ops *ops, From patchwork Fri May 29 13:15:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 11578631 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 94AF1912 for ; Fri, 29 May 2020 13:17:29 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6F293206F1 for ; Fri, 29 May 2020 13:17:29 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="qSocz8FV" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6F293206F1 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=bootlin.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.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:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version: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=I5yxIpM1G+u9H73PvClt5mPf5bwS2xhj3mAW55GYcPg=; b=qSocz8FVB4iZ8t ntQZDZx0TdCleOvPIwNXGyB+9446tPOPkr9Q4bN1DeDEN0zBvIKnSRMfcXoWYQLW8GYO/COHoFHh4 iiJCpyV8gNyf+IMFkp8zoGGjFzv0YA1HpEDO28vbucK1lgqM/t+8xcLlYgQvbblRZq6TjpHJyXt06 Bv1I/6KvIRtCHKEvR6OMtXus78H5QpxffBgVBYDQg6bLZOWqwUO24T5VgaPZpDSVk1Jx3Xa9tlJcU I5yNtk9VpDEwIpH7zJWONboSKPyQQKMPMd7NL4mzdC9TvHlJ3iH1+QtZ44tSJw3vGzgCkcAq6AVXp WFNdYXh1Cq+MCe61OuWw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jeet4-00028I-0d; Fri, 29 May 2020 13:17:26 +0000 Received: from relay9-d.mail.gandi.net ([217.70.183.199]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jeeru-0001F8-Da; Fri, 29 May 2020 13:16:17 +0000 X-Originating-IP: 91.224.148.103 Received: from localhost.localdomain (unknown [91.224.148.103]) (Authenticated sender: miquel.raynal@bootlin.com) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 96C5BFF80B; Fri, 29 May 2020 13:16:10 +0000 (UTC) From: Miquel Raynal To: Richard Weinberger , Vignesh Raghavendra , Tudor Ambarus , , Rob Herring , Mark Rutland , Subject: [PATCH v8 2/5] mtd: rawnand: Hide the generic OOB layout objects behind helpers Date: Fri, 29 May 2020 15:15:59 +0200 Message-Id: <20200529131602.21532-3-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200529131602.21532-1-miquel.raynal@bootlin.com> References: <20200529131602.21532-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200529_061614_727814_E6E199CB X-CRM114-Status: GOOD ( 15.44 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [217.70.183.199 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [217.70.183.199 listed in wl.mailspike.net] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Julien Su , Weijie Gao , Paul Cercueil , Boris Brezillon , Thomas Petazzoni , Miquel Raynal , Mason Yang , Chuanhong Guo , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Stop exposing these objects, create helpers to retrieve them instead. Also export an helper for the Hamming large page ops for later use. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/arasan-nand-controller.c | 2 +- drivers/mtd/nand/raw/atmel/nand-controller.c | 2 +- drivers/mtd/nand/raw/davinci_nand.c | 3 +- .../mtd/nand/raw/ingenic/ingenic_nand_drv.c | 6 ++-- drivers/mtd/nand/raw/nand_base.c | 35 ++++++++++++++----- drivers/mtd/nand/raw/nand_toshiba.c | 2 +- drivers/mtd/nand/raw/vf610_nfc.c | 2 +- include/linux/mtd/rawnand.h | 5 +-- 8 files changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/mtd/nand/raw/arasan-nand-controller.c b/drivers/mtd/nand/raw/arasan-nand-controller.c index a0b5c539ca73..6fe61393bd26 100644 --- a/drivers/mtd/nand/raw/arasan-nand-controller.c +++ b/drivers/mtd/nand/raw/arasan-nand-controller.c @@ -980,7 +980,7 @@ static int anfc_init_hw_ecc_controller(struct arasan_nfc *nfc, return -EINVAL; } - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); ecc->steps = mtd->writesize / ecc->size; ecc->algo = NAND_ECC_ALGO_BCH; diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 3fba91d7991a..08df7f23b859 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1108,7 +1108,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip) chip->options |= NAND_NO_SUBPAGE_WRITE; - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); return 0; } diff --git a/drivers/mtd/nand/raw/davinci_nand.c b/drivers/mtd/nand/raw/davinci_nand.c index 58966a9706b1..427f320fb79b 100644 --- a/drivers/mtd/nand/raw/davinci_nand.c +++ b/drivers/mtd/nand/raw/davinci_nand.c @@ -645,7 +645,8 @@ static int davinci_nand_attach_chip(struct nand_chip *chip) mtd_set_ooblayout(mtd, &hwecc4_small_ooblayout_ops); } else if (chunks == 4 || chunks == 8) { - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, + nand_get_large_page_ooblayout()); info->chip.ecc.read_page = nand_davinci_read_page_hwecc_oob_first; } else { return -EIO; diff --git a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c index 70309f18124c..0e9d426fe4f2 100644 --- a/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c +++ b/drivers/mtd/nand/raw/ingenic/ingenic_nand_drv.c @@ -243,8 +243,10 @@ static int ingenic_nand_attach_chip(struct nand_chip *chip) /* For legacy reasons we use a different layout on the qi,lb60 board. */ if (of_machine_is_compatible("qi,lb60")) mtd_set_ooblayout(mtd, &qi_lb60_ooblayout_ops); - else + else if (nfc->soc_info->oob_layout) mtd_set_ooblayout(mtd, nfc->soc_info->oob_layout); + else + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); return 0; } @@ -532,7 +534,6 @@ static const struct jz_soc_info jz4740_soc_info = { .data_offset = 0x00000000, .cmd_offset = 0x00008000, .addr_offset = 0x00010000, - .oob_layout = &nand_ooblayout_lp_ops, }; static const struct jz_soc_info jz4725b_soc_info = { @@ -546,7 +547,6 @@ static const struct jz_soc_info jz4780_soc_info = { .data_offset = 0x00000000, .cmd_offset = 0x00400000, .addr_offset = 0x00800000, - .oob_layout = &nand_ooblayout_lp_ops, }; static const struct of_device_id ingenic_nand_dt_match[] = { diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index ed0f642be993..f120b0b4f591 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -95,11 +95,16 @@ static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section, return 0; } -const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = { +static const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = { .ecc = nand_ooblayout_ecc_sp, .free = nand_ooblayout_free_sp, }; -EXPORT_SYMBOL_GPL(nand_ooblayout_sp_ops); + +const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void) +{ + return &nand_ooblayout_sp_ops; +} +EXPORT_SYMBOL_GPL(nand_get_small_page_ooblayout); static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) @@ -131,11 +136,16 @@ static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section, return 0; } -const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = { +static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = { .ecc = nand_ooblayout_ecc_lp, .free = nand_ooblayout_free_lp, }; -EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops); + +const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void) +{ + return &nand_ooblayout_lp_ops; +} +EXPORT_SYMBOL_GPL(nand_get_large_page_ooblayout); /* * Support the old "large page" layout used for 1-bit Hamming ECC where ECC @@ -205,6 +215,12 @@ static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { .free = nand_ooblayout_free_lp_hamming, }; +const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void) +{ + return &nand_ooblayout_lp_hamming_ops; +} +EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout); + static int nand_pairing_dist3_get_info(struct mtd_info *mtd, int page, struct mtd_pairing_info *info) { @@ -5382,7 +5398,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip) return -EINVAL; } - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); } @@ -5391,7 +5407,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip) * used, otherwise we don't know how many bytes can really be * used. */ - if (mtd->ooblayout == &nand_ooblayout_lp_ops && + if (mtd->ooblayout == nand_get_large_page_ooblayout() && ecc->options & NAND_ECC_MAXIMIZE) { int steps, bytes; @@ -5793,11 +5809,12 @@ static int nand_scan_tail(struct nand_chip *chip) switch (mtd->oobsize) { case 8: case 16: - mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops); + mtd_set_ooblayout(mtd, nand_get_small_page_ooblayout()); break; case 64: case 128: - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops); + mtd_set_ooblayout(mtd, + nand_get_large_page_hamming_ooblayout()); break; default: /* @@ -5809,7 +5826,7 @@ static int nand_scan_tail(struct nand_chip *chip) */ if (ecc->engine_type == NAND_ECC_ENGINE_TYPE_NONE) { mtd_set_ooblayout(mtd, - &nand_ooblayout_lp_ops); + nand_get_large_page_ooblayout()); break; } diff --git a/drivers/mtd/nand/raw/nand_toshiba.c b/drivers/mtd/nand/raw/nand_toshiba.c index 8fcf40d0ba0a..3174914e33e0 100644 --- a/drivers/mtd/nand/raw/nand_toshiba.c +++ b/drivers/mtd/nand/raw/nand_toshiba.c @@ -140,7 +140,7 @@ static void toshiba_nand_benand_init(struct nand_chip *chip) chip->options |= NAND_SUBPAGE_READ; - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); } static void toshiba_nand_decode_id(struct nand_chip *chip) diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 8ee2c1f539c4..50dc0c93140c 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -779,7 +779,7 @@ static int vf610_nfc_attach_chip(struct nand_chip *chip) mtd->oobsize = 64; /* Use default large page ECC layout defined in NAND core */ - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); if (chip->ecc.strength == 32) { nfc->ecc_mode = ECC_60_BYTE; chip->ecc.bytes = 60; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 8f7f1cce3b4b..f3eb47c09e57 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -1159,8 +1159,9 @@ struct nand_chip { int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len); }; -extern const struct mtd_ooblayout_ops nand_ooblayout_sp_ops; -extern const struct mtd_ooblayout_ops nand_ooblayout_lp_ops; +const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void); +const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void); +const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void); static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) { From patchwork Fri May 29 13:16:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 11578633 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1595E912 for ; Fri, 29 May 2020 13:17:54 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C04B5206F1 for ; Fri, 29 May 2020 13:17:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="LYl6zQhl" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C04B5206F1 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=bootlin.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.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:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version: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=kuFb2brmg49y1cOz81fYiXwW0D3UG6IZgmswDkK9hgc=; b=LYl6zQhlUGEQnX BjIUTb7JOo+V9wJDQ7dHg3RbuL+MMGZ42PA5Q7nKDswY6zcds+y0yEIWI2/5SVvO0qwsQoR+Axasl DYCaPvCzeYjGmslzssJ9rE45YNL42Urck9pTFda524dGm7i61isf3OqfvZ2WXbZIDeWrWhB+aa4cY xEHH0fZH/yFxke0kzu7AtYijJiErsuXIPFe93ShpiaAK6b936Pt67PFMsBhuDhf6ELkbP3Atzb806 PakGi9lnmX/IHwcnyTmT+oRFRhFLu345xJWgEtjNE2KhcqJydEVTV6PeqnSzc3pq8FGrHayVsrw+8 9mVBBu8ojbLS5N3DwypA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jeetP-0002dh-NJ; Fri, 29 May 2020 13:17:47 +0000 Received: from relay9-d.mail.gandi.net ([217.70.183.199]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jeerw-0001Fk-Ae; Fri, 29 May 2020 13:16:18 +0000 X-Originating-IP: 91.224.148.103 Received: from localhost.localdomain (unknown [91.224.148.103]) (Authenticated sender: miquel.raynal@bootlin.com) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 1C839FF808; Fri, 29 May 2020 13:16:13 +0000 (UTC) From: Miquel Raynal To: Richard Weinberger , Vignesh Raghavendra , Tudor Ambarus , , Rob Herring , Mark Rutland , Subject: [PATCH v8 3/5] mtd: rawnand: Write a compatibility layer Date: Fri, 29 May 2020 15:16:00 +0200 Message-Id: <20200529131602.21532-4-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200529131602.21532-1-miquel.raynal@bootlin.com> References: <20200529131602.21532-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200529_061616_637531_316E3F3A X-CRM114-Status: GOOD ( 16.67 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [217.70.183.199 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [217.70.183.199 listed in wl.mailspike.net] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Julien Su , Weijie Gao , Paul Cercueil , Boris Brezillon , Thomas Petazzoni , Miquel Raynal , Mason Yang , Chuanhong Guo , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Before moving generic bits from the raw NAND core to the generic NAND core, let's disociate clearly what is a rawnand legacy property, and what should be made public to other NAND users. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/raw/nand_base.c | 158 +++++++++++++++++++++---------- include/linux/mtd/rawnand.h | 12 --- 2 files changed, 107 insertions(+), 63 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index f120b0b4f591..8dc230892b90 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5029,14 +5029,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) return ret; } -static const char * const nand_ecc_modes[] = { - [NAND_ECC_NONE] = "none", - [NAND_ECC_SOFT] = "soft", - [NAND_ECC_HW] = "hw", - [NAND_ECC_HW_SYNDROME] = "hw_syndrome", - [NAND_ECC_ON_DIE] = "on-die", -}; - static const char * const nand_ecc_placement[] = { [NAND_ECC_PLACEMENT_OOB] = "oob", [NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved", @@ -5045,7 +5037,30 @@ static const char * const nand_ecc_placement[] = { static enum nand_ecc_engine_type of_get_nand_ecc_engine_type(struct device_node *np) { - enum nand_ecc_mode eng_type; + return NAND_ECC_ENGINE_TYPE_INVALID; +} + +static enum nand_ecc_engine_type +of_get_rawnand_ecc_engine_type_legacy(struct device_node *np) +{ + enum nand_ecc_legacy_mode { + NAND_ECC_INVALID, + NAND_ECC_NONE, + NAND_ECC_SOFT, + NAND_ECC_SOFT_BCH, + NAND_ECC_HW, + NAND_ECC_HW_SYNDROME, + NAND_ECC_ON_DIE, + }; + const char * const nand_ecc_legacy_modes[] = { + [NAND_ECC_NONE] = "none", + [NAND_ECC_SOFT] = "soft", + [NAND_ECC_SOFT_BCH] = "soft_bch", + [NAND_ECC_HW] = "hw", + [NAND_ECC_HW_SYNDROME] = "hw_syndrome", + [NAND_ECC_ON_DIE] = "on-die", + }; + enum nand_ecc_legacy_mode eng_type; const char *pm; int err; @@ -5054,12 +5069,13 @@ of_get_nand_ecc_engine_type(struct device_node *np) return NAND_ECC_ENGINE_TYPE_INVALID; for (eng_type = NAND_ECC_NONE; - eng_type < ARRAY_SIZE(nand_ecc_modes); eng_type++) { - if (!strcasecmp(pm, nand_ecc_modes[eng_type])) { + eng_type < ARRAY_SIZE(nand_ecc_legacy_modes); eng_type++) { + if (!strcasecmp(pm, nand_ecc_legacy_modes[eng_type])) { switch (eng_type) { case NAND_ECC_NONE: return NAND_ECC_ENGINE_TYPE_NONE; case NAND_ECC_SOFT: + case NAND_ECC_SOFT_BCH: return NAND_ECC_ENGINE_TYPE_SOFT; case NAND_ECC_HW: case NAND_ECC_HW_SYNDROME: @@ -5072,14 +5088,6 @@ of_get_nand_ecc_engine_type(struct device_node *np) } } - /* - * For backward compatibility we support few obsoleted values that don't - * have their mappings into the nand_ecc_engine_providers enum anymore - * (they were merged with other enums). - */ - if (!strcasecmp(pm, "soft_bch")) - return NAND_ECC_ENGINE_TYPE_SOFT; - return NAND_ECC_ENGINE_TYPE_INVALID; } @@ -5091,17 +5099,22 @@ enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np) err = of_property_read_string(np, "nand-ecc-placement", &pm); if (!err) { - for (placement = NAND_ECC_PLACEMENT_INTERLEAVED; + for (placement = NAND_ECC_PLACEMENT_OOB; placement < ARRAY_SIZE(nand_ecc_placement); placement++) { if (!strcasecmp(pm, nand_ecc_placement[placement])) return placement; } } - /* - * For backward compatibility we support few obsoleted values that don't - * have their mappings into the nand_ecc_placement enum anymore. - */ + return NAND_ECC_PLACEMENT_UNKNOWN; +} + +enum nand_ecc_placement +of_get_rawnand_ecc_placement_legacy(struct device_node *np) +{ + const char *pm; + int err; + err = of_property_read_string(np, "nand-ecc-mode", &pm); if (!err) { if (!strcasecmp(pm, "hw_syndrome")) @@ -5133,10 +5146,14 @@ static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np) } } - /* - * For backward compatibility we also read "nand-ecc-mode" checking - * for some obsoleted values that were specifying ECC algorithm. - */ + return NAND_ECC_ALGO_UNKNOWN; +} + +static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np) +{ + const char *pm; + int err; + err = of_property_read_string(np, "nand-ecc-mode", &pm); if (!err) { if (!strcasecmp(pm, "soft")) @@ -5166,6 +5183,41 @@ static int of_get_nand_ecc_strength(struct device_node *np) return ret ? ret : val; } +static void nand_ecc_read_user_conf(struct nand_chip *chip) +{ + struct device_node *dn = nand_get_flash_node(chip); + struct nand_device *nand = &chip->base; + int strength, size; + + nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn); + nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn); + nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn); + + strength = of_get_nand_ecc_strength(dn); + if (strength >= 0) + nand->ecc.user_conf.strength = strength; + + size = of_get_nand_ecc_step_size(dn); + if (size >= 0) + nand->ecc.user_conf.step_size = size; +} + +static void rawnand_ecc_read_legacy_user_conf(struct nand_chip *chip) +{ + struct device_node *dn = nand_get_flash_node(chip); + struct nand_device *nand = &chip->base; + struct nand_ecc_props *user_conf = &nand->ecc.user_conf; + + if (user_conf->engine_type != NAND_ECC_ENGINE_TYPE_INVALID) + user_conf->engine_type = of_get_rawnand_ecc_engine_type_legacy(dn); + + if (user_conf->algo != NAND_ECC_ALGO_UNKNOWN) + user_conf->algo = of_get_rawnand_ecc_algo_legacy(dn); + + if (user_conf->placement != NAND_ECC_PLACEMENT_UNKNOWN) + user_conf->placement = of_get_rawnand_ecc_placement_legacy(dn); +} + static int of_get_nand_bus_width(struct device_node *np) { u32 val; @@ -5187,12 +5239,10 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np) return of_property_read_bool(np, "nand-on-flash-bbt"); } -static int nand_dt_init(struct nand_chip *chip) +static int rawnand_dt_init(struct nand_chip *chip) { + struct nand_device *nand = mtd_to_nanddev(nand_to_mtd(chip)); struct device_node *dn = nand_get_flash_node(chip); - enum nand_ecc_engine_type ecc_type; - enum nand_ecc_algo ecc_algo; - int ecc_strength, ecc_step; if (!dn) return 0; @@ -5206,27 +5256,33 @@ static int nand_dt_init(struct nand_chip *chip) if (of_get_nand_on_flash_bbt(dn)) chip->bbt_options |= NAND_BBT_USE_FLASH; - ecc_type = of_get_nand_ecc_engine_type(dn); - ecc_algo = of_get_nand_ecc_algo(dn); - chip->ecc.placement = of_get_nand_ecc_placement(dn); - ecc_strength = of_get_nand_ecc_strength(dn); - ecc_step = of_get_nand_ecc_step_size(dn); - - if (ecc_type != NAND_ECC_ENGINE_TYPE_INVALID) - chip->ecc.engine_type = ecc_type; - - if (ecc_algo != NAND_ECC_ALGO_UNKNOWN) - chip->ecc.algo = ecc_algo; - - if (ecc_strength >= 0) - chip->ecc.strength = ecc_strength; - - if (ecc_step > 0) - chip->ecc.size = ecc_step; - if (of_property_read_bool(dn, "nand-ecc-maximize")) chip->ecc.options |= NAND_ECC_MAXIMIZE; + nand_ecc_read_user_conf(chip); + rawnand_ecc_read_legacy_user_conf(chip); + + /* + * If neither the user nor the NAND controller have requested a specific + * ECC engine type, we will default to NAND_ECC_ENGINE_TYPE_ON_HOST. + */ + nand->ecc.defaults.engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST; + + /* + * Use the user requested engine type, unless there is none, in this + * case default to the NAND controller choice, otherwise fallback to + * the raw NAND default one. + */ + if (nand->ecc.user_conf.engine_type != NAND_ECC_ENGINE_TYPE_INVALID) + chip->ecc.engine_type = nand->ecc.user_conf.engine_type; + if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_INVALID) + chip->ecc.engine_type = nand->ecc.defaults.engine_type; + + chip->ecc.placement = nand->ecc.user_conf.placement; + chip->ecc.algo = nand->ecc.user_conf.algo; + chip->ecc.strength = nand->ecc.user_conf.strength; + chip->ecc.size = nand->ecc.user_conf.step_size; + return 0; } @@ -5263,7 +5319,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips, /* Enforce the right timings for reset/detection */ onfi_fill_data_interface(chip, NAND_SDR_IFACE, 0); - ret = nand_dt_init(chip); + ret = rawnand_dt_init(chip); if (ret) return ret; diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index f3eb47c09e57..b455cb22168f 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -80,18 +80,6 @@ struct nand_chip; #define NAND_DATA_IFACE_CHECK_ONLY -1 -/* - * Constants for ECC_MODES - */ -enum nand_ecc_mode { - NAND_ECC_INVALID, - NAND_ECC_NONE, - NAND_ECC_SOFT, - NAND_ECC_HW, - NAND_ECC_HW_SYNDROME, - NAND_ECC_ON_DIE, -}; - /* * Constants for Hardware ECC */ From patchwork Fri May 29 13:16:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 11578637 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 73E49139A for ; Fri, 29 May 2020 13:18:21 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 37773207F5 for ; Fri, 29 May 2020 13:18:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="dMLx3GfD" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 37773207F5 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=bootlin.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.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:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version: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=Z8+/+doZ6IxMp8KQTkfMAlIt4P1y53UGkN7HJqpCneU=; b=dMLx3GfDjbAAy9 kzzOJniwjZPtWRS6fLtw6+QoeLHq7xutF7V6Lf7sOL8pr6qv5WRXu4YhvyzoQd0iNjXfC5xlqQvTM BGqKC2Fg+9gPqEsY+77rZFiqXYZ+qF4C3mMQthOd81c+0PWm0p8/UJysPJnskOd7Up+Am/xPiUp+l b9H/J3/mIQ+ZsA8F+8F/+O51Q570tRvaic+Kp1DwXFxgvrjoHLXjM2+YCxMphQTPCTh35RqzxhNmk Dt3nLbmKpKg9YmFRl4hedIm2E4G3GbtrFMRA0Q8iIkr93VNrNX8kH9SdHofTWsKj+a805+JgNAkO/ BM2n191xP4AbrI47KtEA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jeets-00036l-Ee; Fri, 29 May 2020 13:18:16 +0000 Received: from relay9-d.mail.gandi.net ([217.70.183.199]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jeery-0001GK-7o; Fri, 29 May 2020 13:16:20 +0000 X-Originating-IP: 91.224.148.103 Received: from localhost.localdomain (unknown [91.224.148.103]) (Authenticated sender: miquel.raynal@bootlin.com) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id F2D33FF80A; Fri, 29 May 2020 13:16:14 +0000 (UTC) From: Miquel Raynal To: Richard Weinberger , Vignesh Raghavendra , Tudor Ambarus , , Rob Herring , Mark Rutland , Subject: [PATCH v8 4/5] mtd: rawnand: Move generic OOB layouts to the ECC framework Date: Fri, 29 May 2020 15:16:01 +0200 Message-Id: <20200529131602.21532-5-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200529131602.21532-1-miquel.raynal@bootlin.com> References: <20200529131602.21532-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200529_061618_548135_A2335890 X-CRM114-Status: GOOD ( 17.41 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [217.70.183.199 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [217.70.183.199 listed in wl.mailspike.net] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Julien Su , Weijie Gao , Paul Cercueil , Boris Brezillon , Thomas Petazzoni , Miquel Raynal , Mason Yang , Chuanhong Guo , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org These layouts can be used by any driver, move them to the ECC core. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/ecc.c | 176 ++++++++++++++++++++++++++++++ drivers/mtd/nand/raw/Kconfig | 1 + drivers/mtd/nand/raw/nand_base.c | 177 +------------------------------ include/linux/mtd/nand.h | 4 + include/linux/mtd/rawnand.h | 5 +- 5 files changed, 183 insertions(+), 180 deletions(-) diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c index f7300ba37167..ad08a047dfc5 100644 --- a/drivers/mtd/nand/ecc.c +++ b/drivers/mtd/nand/ecc.c @@ -152,6 +152,182 @@ int nand_ecc_finish_io_req(struct nand_device *nand, } EXPORT_SYMBOL(nand_ecc_finish_io_req); +/* Define default oob placement schemes for large and small page devices */ +static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + unsigned int total_ecc_bytes = nand->ecc.ctx.total; + + if (section > 1) + return -ERANGE; + + if (!section) { + oobregion->offset = 0; + if (mtd->oobsize == 16) + oobregion->length = 4; + else + oobregion->length = 3; + } else { + if (mtd->oobsize == 8) + return -ERANGE; + + oobregion->offset = 6; + oobregion->length = total_ecc_bytes - 4; + } + + return 0; +} + +static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + if (section > 1) + return -ERANGE; + + if (mtd->oobsize == 16) { + if (section) + return -ERANGE; + + oobregion->length = 8; + oobregion->offset = 8; + } else { + oobregion->length = 2; + if (!section) + oobregion->offset = 3; + else + oobregion->offset = 6; + } + + return 0; +} + +static const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = { + .ecc = nand_ooblayout_ecc_sp, + .free = nand_ooblayout_free_sp, +}; + +const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void) +{ + return &nand_ooblayout_sp_ops; +} +EXPORT_SYMBOL_GPL(nand_get_small_page_ooblayout); + +static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + unsigned int total_ecc_bytes = nand->ecc.ctx.total; + + if (section || !total_ecc_bytes) + return -ERANGE; + + oobregion->length = total_ecc_bytes; + oobregion->offset = mtd->oobsize - oobregion->length; + + return 0; +} + +static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + unsigned int total_ecc_bytes = nand->ecc.ctx.total; + + if (section) + return -ERANGE; + + oobregion->length = mtd->oobsize - total_ecc_bytes - 2; + oobregion->offset = 2; + + return 0; +} + +static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = { + .ecc = nand_ooblayout_ecc_lp, + .free = nand_ooblayout_free_lp, +}; + +const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void) +{ + return &nand_ooblayout_lp_ops; +} +EXPORT_SYMBOL_GPL(nand_get_large_page_ooblayout); + +/* + * Support the old "large page" layout used for 1-bit Hamming ECC where ECC + * are placed at a fixed offset. + */ +static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + unsigned int total_ecc_bytes = nand->ecc.ctx.total; + + if (section) + return -ERANGE; + + switch (mtd->oobsize) { + case 64: + oobregion->offset = 40; + break; + case 128: + oobregion->offset = 80; + break; + default: + return -EINVAL; + } + + oobregion->length = total_ecc_bytes; + if (oobregion->offset + oobregion->length > mtd->oobsize) + return -ERANGE; + + return 0; +} + +static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + unsigned int total_ecc_bytes = nand->ecc.ctx.total; + int ecc_offset = 0; + + if (section < 0 || section > 1) + return -ERANGE; + + switch (mtd->oobsize) { + case 64: + ecc_offset = 40; + break; + case 128: + ecc_offset = 80; + break; + default: + return -EINVAL; + } + + if (section == 0) { + oobregion->offset = 2; + oobregion->length = ecc_offset - 2; + } else { + oobregion->offset = ecc_offset + total_ecc_bytes; + oobregion->length = mtd->oobsize - oobregion->offset; + } + + return 0; +} + +static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { + .ecc = nand_ooblayout_ecc_lp_hamming, + .free = nand_ooblayout_free_lp_hamming, +}; + +const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void) +{ + return &nand_ooblayout_lp_hamming_ops; +} +EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Miquel Raynal "); MODULE_DESCRIPTION("Generic ECC engine"); diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 85280e327bfe..6ab3184ca8eb 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -13,6 +13,7 @@ config MTD_NAND_ECC_SW_HAMMING_SMC menuconfig MTD_RAW_NAND tristate "Raw/Parallel NAND Device Support" select MTD_NAND_CORE + select MTD_NAND_ECC select MTD_NAND_ECC_SW_HAMMING help This enables support for accessing all type of raw/parallel diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 8dc230892b90..afc3506468ba 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -45,182 +46,6 @@ #include "internals.h" -/* Define default oob placement schemes for large and small page devices */ -static int nand_ooblayout_ecc_sp(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &chip->ecc; - - if (section > 1) - return -ERANGE; - - if (!section) { - oobregion->offset = 0; - if (mtd->oobsize == 16) - oobregion->length = 4; - else - oobregion->length = 3; - } else { - if (mtd->oobsize == 8) - return -ERANGE; - - oobregion->offset = 6; - oobregion->length = ecc->total - 4; - } - - return 0; -} - -static int nand_ooblayout_free_sp(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - if (section > 1) - return -ERANGE; - - if (mtd->oobsize == 16) { - if (section) - return -ERANGE; - - oobregion->length = 8; - oobregion->offset = 8; - } else { - oobregion->length = 2; - if (!section) - oobregion->offset = 3; - else - oobregion->offset = 6; - } - - return 0; -} - -static const struct mtd_ooblayout_ops nand_ooblayout_sp_ops = { - .ecc = nand_ooblayout_ecc_sp, - .free = nand_ooblayout_free_sp, -}; - -const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void) -{ - return &nand_ooblayout_sp_ops; -} -EXPORT_SYMBOL_GPL(nand_get_small_page_ooblayout); - -static int nand_ooblayout_ecc_lp(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &chip->ecc; - - if (section || !ecc->total) - return -ERANGE; - - oobregion->length = ecc->total; - oobregion->offset = mtd->oobsize - oobregion->length; - - return 0; -} - -static int nand_ooblayout_free_lp(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &chip->ecc; - - if (section) - return -ERANGE; - - oobregion->length = mtd->oobsize - ecc->total - 2; - oobregion->offset = 2; - - return 0; -} - -static const struct mtd_ooblayout_ops nand_ooblayout_lp_ops = { - .ecc = nand_ooblayout_ecc_lp, - .free = nand_ooblayout_free_lp, -}; - -const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void) -{ - return &nand_ooblayout_lp_ops; -} -EXPORT_SYMBOL_GPL(nand_get_large_page_ooblayout); - -/* - * Support the old "large page" layout used for 1-bit Hamming ECC where ECC - * are placed at a fixed offset. - */ -static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &chip->ecc; - - if (section) - return -ERANGE; - - switch (mtd->oobsize) { - case 64: - oobregion->offset = 40; - break; - case 128: - oobregion->offset = 80; - break; - default: - return -EINVAL; - } - - oobregion->length = ecc->total; - if (oobregion->offset + oobregion->length > mtd->oobsize) - return -ERANGE; - - return 0; -} - -static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section, - struct mtd_oob_region *oobregion) -{ - struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_ecc_ctrl *ecc = &chip->ecc; - int ecc_offset = 0; - - if (section < 0 || section > 1) - return -ERANGE; - - switch (mtd->oobsize) { - case 64: - ecc_offset = 40; - break; - case 128: - ecc_offset = 80; - break; - default: - return -EINVAL; - } - - if (section == 0) { - oobregion->offset = 2; - oobregion->length = ecc_offset - 2; - } else { - oobregion->offset = ecc_offset + ecc->total; - oobregion->length = mtd->oobsize - oobregion->offset; - } - - return 0; -} - -static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { - .ecc = nand_ooblayout_ecc_lp_hamming, - .free = nand_ooblayout_free_lp_hamming, -}; - -const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void) -{ - return &nand_ooblayout_lp_hamming_ops; -} -EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout); - static int nand_pairing_dist3_get_info(struct mtd_info *mtd, int page, struct mtd_pairing_info *info) { diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index f5cc0aee565c..77757aabeba2 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -127,6 +127,10 @@ struct nand_page_io_req { int mode; }; +const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void); +const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void); +const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void); + /** * enum nand_ecc_engine_type - NAND ECC engine type * @NAND_ECC_ENGINE_TYPE_INVALID: Invalid value diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index b455cb22168f..66f69a1d27a5 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -14,6 +14,7 @@ #define __LINUX_MTD_RAWNAND_H #include +#include #include #include #include @@ -1147,10 +1148,6 @@ struct nand_chip { int (*unlock_area)(struct nand_chip *chip, loff_t ofs, uint64_t len); }; -const struct mtd_ooblayout_ops *nand_get_small_page_ooblayout(void); -const struct mtd_ooblayout_ops *nand_get_large_page_ooblayout(void); -const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void); - static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) { return container_of(mtd, struct nand_chip, base.mtd); From patchwork Fri May 29 13:16:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miquel Raynal X-Patchwork-Id: 11578641 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6FE5E912 for ; Fri, 29 May 2020 13:18:52 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 48A36207F5 for ; Fri, 29 May 2020 13:18:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="ZSYXiAIw" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 48A36207F5 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=bootlin.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.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:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version: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=5XmHTSgp3wn6PdezJZGnhPxzbse3HccqXsyA7nwv/m4=; b=ZSYXiAIwXfMNNn E/e+tYzXcGajl8QSbtNAggNYl0WOolnrtlw/dr8PvZ1Z9TbYtQmraGI09rG9HGzn8QQBMXSVYr9dk m631UEPO5JwFWcR+WES8qCqRbMs7tuLsJbpUIvEl4EEDU9V10jAxfH1dtegkNToXS16sniI+GlSLP A8QRqYlRgXM+k00Ilu1Ztrym9vgUC56QKpYISaoy6u6Buhtc41bFM2KAtNEkl8kGeYwADcDZQOZpZ B54uGTVwvJlXXTtyvAhEn48n3jGhDJBmCSJ3WZ+XzQGaiSK3OkZU4Ex/byfIuDBnyz9Dq76PgSShh F0aPWjyOO40QXwCrsTqQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1jeeuQ-0003Y1-1m; Fri, 29 May 2020 13:18:50 +0000 Received: from relay9-d.mail.gandi.net ([217.70.183.199]) by bombadil.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1jees0-0001Hm-Ch; Fri, 29 May 2020 13:16:23 +0000 X-Originating-IP: 91.224.148.103 Received: from localhost.localdomain (unknown [91.224.148.103]) (Authenticated sender: miquel.raynal@bootlin.com) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id D6E5CFF818; Fri, 29 May 2020 13:16:16 +0000 (UTC) From: Miquel Raynal To: Richard Weinberger , Vignesh Raghavendra , Tudor Ambarus , , Rob Herring , Mark Rutland , Subject: [PATCH v8 5/5] mtd: rawnand: Move the user input parsing bits to the ECC framework Date: Fri, 29 May 2020 15:16:02 +0200 Message-Id: <20200529131602.21532-6-miquel.raynal@bootlin.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200529131602.21532-1-miquel.raynal@bootlin.com> References: <20200529131602.21532-1-miquel.raynal@bootlin.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200529_061620_719094_72F2F28E X-CRM114-Status: GOOD ( 21.07 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.4.4 on bombadil.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [217.70.183.199 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2) [217.70.183.199 listed in wl.mailspike.net] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Julien Su , Weijie Gao , Paul Cercueil , Boris Brezillon , Thomas Petazzoni , Miquel Raynal , Mason Yang , Chuanhong Guo , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Many helpers are generic to all NAND chips, they should not be restricted to be only used by raw NAND controller drivers. They might later be used by generic ECC engines and SPI-NAND devices as well so move them into a more generic place. To avoid moving all the raw NAND core "history" into the generic NAND layer, we already moved certain bits into legacy helpers in the raw NAND core to ensure backward compatibility. Signed-off-by: Miquel Raynal --- drivers/mtd/nand/ecc.c | 138 +++++++++++++++++ drivers/mtd/nand/raw/atmel/nand-controller.c | 3 +- drivers/mtd/nand/raw/denali.c | 3 + drivers/mtd/nand/raw/nand_base.c | 150 ++----------------- drivers/mtd/nand/raw/sunxi_nand.c | 3 +- drivers/mtd/nand/raw/tegra_nand.c | 5 +- include/linux/mtd/nand.h | 7 + include/linux/mtd/rawnand.h | 1 - 8 files changed, 166 insertions(+), 144 deletions(-) diff --git a/drivers/mtd/nand/ecc.c b/drivers/mtd/nand/ecc.c index ad08a047dfc5..1ac7aaa6c6c2 100644 --- a/drivers/mtd/nand/ecc.c +++ b/drivers/mtd/nand/ecc.c @@ -328,6 +328,144 @@ const struct mtd_ooblayout_ops *nand_get_large_page_hamming_ooblayout(void) } EXPORT_SYMBOL_GPL(nand_get_large_page_hamming_ooblayout); +static enum nand_ecc_engine_type +of_get_nand_ecc_engine_type(struct device_node *np) +{ + return NAND_ECC_ENGINE_TYPE_INVALID; +} + +static const char * const nand_ecc_placement[] = { + [NAND_ECC_PLACEMENT_OOB] = "oob", + [NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved", +}; + +enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np) +{ + enum nand_ecc_placement placement; + const char *pm; + int err; + + err = of_property_read_string(np, "nand-ecc-placement", &pm); + if (!err) { + for (placement = NAND_ECC_PLACEMENT_OOB; + placement < ARRAY_SIZE(nand_ecc_placement); placement++) { + if (!strcasecmp(pm, nand_ecc_placement[placement])) + return placement; + } + } + + return NAND_ECC_PLACEMENT_UNKNOWN; +} + +static const char * const nand_ecc_algos[] = { + [NAND_ECC_ALGO_HAMMING] = "hamming", + [NAND_ECC_ALGO_BCH] = "bch", + [NAND_ECC_ALGO_RS] = "rs", +}; + +static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np) +{ + enum nand_ecc_algo ecc_algo; + const char *pm; + int err; + + err = of_property_read_string(np, "nand-ecc-algo", &pm); + if (!err) { + for (ecc_algo = NAND_ECC_ALGO_HAMMING; + ecc_algo < ARRAY_SIZE(nand_ecc_algos); + ecc_algo++) { + if (!strcasecmp(pm, nand_ecc_algos[ecc_algo])) + return ecc_algo; + } + } + + return NAND_ECC_ALGO_UNKNOWN; +} + +static int of_get_nand_ecc_step_size(struct device_node *np) +{ + int ret; + u32 val; + + ret = of_property_read_u32(np, "nand-ecc-step-size", &val); + return ret ? ret : val; +} + +static int of_get_nand_ecc_strength(struct device_node *np) +{ + int ret; + u32 val; + + ret = of_property_read_u32(np, "nand-ecc-strength", &val); + return ret ? ret : val; +} + +static inline bool of_get_nand_ecc_maximize(struct device_node *np) +{ + return of_property_read_bool(np, "nand-ecc-maximize"); +} + +void nand_ecc_read_user_conf(struct nand_device *nand) +{ + struct device_node *dn = nanddev_get_of_node(nand); + int strength, size; + + nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn); + nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn); + nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn); + + strength = of_get_nand_ecc_strength(dn); + if (strength >= 0) + nand->ecc.user_conf.strength = strength; + + size = of_get_nand_ecc_step_size(dn); + if (size >= 0) + nand->ecc.user_conf.step_size = size; + + if (of_get_nand_ecc_maximize(dn)) + nand->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE; +} +EXPORT_SYMBOL(nand_ecc_read_user_conf); + +/** + * nand_ecc_correction_is_enough - Check if the chip configuration meets the + * datasheet requirements. + * + * @nand: Device to check + * + * If our configuration corrects A bits per B bytes and the minimum + * required correction level is X bits per Y bytes, then we must ensure + * both of the following are true: + * + * (1) A / B >= X / Y + * (2) A >= X + * + * Requirement (1) ensures we can correct for the required bitflip density. + * Requirement (2) ensures we can correct even when all bitflips are clumped + * in the same sector. + */ +bool nand_ecc_correction_is_enough(struct nand_device *nand) +{ + const struct nand_ecc_props *reqs = nanddev_get_ecc_requirements(nand); + const struct nand_ecc_props *conf = nanddev_get_ecc_conf(nand); + struct mtd_info *mtd = nanddev_to_mtd(nand); + int corr, ds_corr; + + if (conf->step_size == 0 || reqs->step_size == 0) + /* Not enough information */ + return true; + + /* + * We get the number of corrected bits per page to compare + * the correction density. + */ + corr = (mtd->writesize * conf->strength) / conf->step_size; + ds_corr = (mtd->writesize * reqs->strength) / reqs->step_size; + + return corr >= ds_corr && conf->strength >= reqs->strength; +} +EXPORT_SYMBOL(nand_ecc_correction_is_enough); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Miquel Raynal "); MODULE_DESCRIPTION("Generic ECC engine"); diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 08df7f23b859..39d8fe15b8ab 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1046,6 +1046,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip) const struct nand_ecc_props *requirements = nanddev_get_ecc_requirements(&chip->base); struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_device *nanddev = mtd_to_nanddev(mtd); struct atmel_nand *nand = to_atmel_nand(chip); struct atmel_nand_controller *nc; struct atmel_pmecc_user_req req; @@ -1070,7 +1071,7 @@ static int atmel_nand_pmecc_init(struct nand_chip *chip) chip->ecc.size = val; } - if (chip->ecc.options & NAND_ECC_MAXIMIZE) + if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE) req.ecc.strength = ATMEL_PMECC_MAXIMIZE_ECC_STRENGTH; else if (chip->ecc.strength) req.ecc.strength = chip->ecc.strength; diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c index a6a6464974ec..51bc014ebc0a 100644 --- a/drivers/mtd/nand/raw/denali.c +++ b/drivers/mtd/nand/raw/denali.c @@ -1181,6 +1181,7 @@ int denali_chip_init(struct denali_controller *denali, { struct nand_chip *chip = &dchip->chip; struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_device *nanddev = mtd_to_nanddev(mtd); struct denali_chip *dchip2; int i, j, ret; @@ -1248,6 +1249,8 @@ int denali_chip_init(struct denali_controller *denali, mtd_set_ooblayout(mtd, &denali_ooblayout_ops); + nanddev->ecc.user_conf.flags |= NAND_ECC_MAXIMIZE; + ret = nand_scan(chip, dchip->nsels); if (ret) return ret; diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index afc3506468ba..036e88cb52a1 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -4854,17 +4854,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) return ret; } -static const char * const nand_ecc_placement[] = { - [NAND_ECC_PLACEMENT_OOB] = "oob", - [NAND_ECC_PLACEMENT_INTERLEAVED] = "interleaved", -}; - -static enum nand_ecc_engine_type -of_get_nand_ecc_engine_type(struct device_node *np) -{ - return NAND_ECC_ENGINE_TYPE_INVALID; -} - static enum nand_ecc_engine_type of_get_rawnand_ecc_engine_type_legacy(struct device_node *np) { @@ -4916,24 +4905,6 @@ of_get_rawnand_ecc_engine_type_legacy(struct device_node *np) return NAND_ECC_ENGINE_TYPE_INVALID; } -enum nand_ecc_placement of_get_nand_ecc_placement(struct device_node *np) -{ - enum nand_ecc_placement placement; - const char *pm; - int err; - - err = of_property_read_string(np, "nand-ecc-placement", &pm); - if (!err) { - for (placement = NAND_ECC_PLACEMENT_OOB; - placement < ARRAY_SIZE(nand_ecc_placement); placement++) { - if (!strcasecmp(pm, nand_ecc_placement[placement])) - return placement; - } - } - - return NAND_ECC_PLACEMENT_UNKNOWN; -} - enum nand_ecc_placement of_get_rawnand_ecc_placement_legacy(struct device_node *np) { @@ -4949,31 +4920,6 @@ of_get_rawnand_ecc_placement_legacy(struct device_node *np) return NAND_ECC_PLACEMENT_UNKNOWN; } -static const char * const nand_ecc_algos[] = { - [NAND_ECC_ALGO_HAMMING] = "hamming", - [NAND_ECC_ALGO_BCH] = "bch", - [NAND_ECC_ALGO_RS] = "rs", -}; - -static enum nand_ecc_algo of_get_nand_ecc_algo(struct device_node *np) -{ - enum nand_ecc_algo ecc_algo; - const char *pm; - int err; - - err = of_property_read_string(np, "nand-ecc-algo", &pm); - if (!err) { - for (ecc_algo = NAND_ECC_ALGO_HAMMING; - ecc_algo < ARRAY_SIZE(nand_ecc_algos); - ecc_algo++) { - if (!strcasecmp(pm, nand_ecc_algos[ecc_algo])) - return ecc_algo; - } - } - - return NAND_ECC_ALGO_UNKNOWN; -} - static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np) { const char *pm; @@ -4990,48 +4936,10 @@ static enum nand_ecc_algo of_get_rawnand_ecc_algo_legacy(struct device_node *np) return NAND_ECC_ALGO_UNKNOWN; } -static int of_get_nand_ecc_step_size(struct device_node *np) -{ - int ret; - u32 val; - - ret = of_property_read_u32(np, "nand-ecc-step-size", &val); - return ret ? ret : val; -} - -static int of_get_nand_ecc_strength(struct device_node *np) -{ - int ret; - u32 val; - - ret = of_property_read_u32(np, "nand-ecc-strength", &val); - return ret ? ret : val; -} - -static void nand_ecc_read_user_conf(struct nand_chip *chip) -{ - struct device_node *dn = nand_get_flash_node(chip); - struct nand_device *nand = &chip->base; - int strength, size; - - nand->ecc.user_conf.engine_type = of_get_nand_ecc_engine_type(dn); - nand->ecc.user_conf.algo = of_get_nand_ecc_algo(dn); - nand->ecc.user_conf.placement = of_get_nand_ecc_placement(dn); - - strength = of_get_nand_ecc_strength(dn); - if (strength >= 0) - nand->ecc.user_conf.strength = strength; - - size = of_get_nand_ecc_step_size(dn); - if (size >= 0) - nand->ecc.user_conf.step_size = size; -} - static void rawnand_ecc_read_legacy_user_conf(struct nand_chip *chip) { struct device_node *dn = nand_get_flash_node(chip); - struct nand_device *nand = &chip->base; - struct nand_ecc_props *user_conf = &nand->ecc.user_conf; + struct nand_ecc_props *user_conf = &chip->base.ecc.user_conf; if (user_conf->engine_type != NAND_ECC_ENGINE_TYPE_INVALID) user_conf->engine_type = of_get_rawnand_ecc_engine_type_legacy(dn); @@ -5081,10 +4989,7 @@ static int rawnand_dt_init(struct nand_chip *chip) if (of_get_nand_on_flash_bbt(dn)) chip->bbt_options |= NAND_BBT_USE_FLASH; - if (of_property_read_bool(dn, "nand-ecc-maximize")) - chip->ecc.options |= NAND_ECC_MAXIMIZE; - - nand_ecc_read_user_conf(chip); + nand_ecc_read_user_conf(nand); rawnand_ecc_read_legacy_user_conf(chip); /* @@ -5214,6 +5119,7 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip) static int nand_set_ecc_soft_ops(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_device *nanddev = mtd_to_nanddev(mtd); struct nand_ecc_ctrl *ecc = &chip->ecc; if (WARN_ON(ecc->engine_type != NAND_ECC_ENGINE_TYPE_SOFT)) @@ -5289,7 +5195,7 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip) * used. */ if (mtd->ooblayout == nand_get_large_page_ooblayout() && - ecc->options & NAND_ECC_MAXIMIZE) { + nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE) { int steps, bytes; /* Always prefer 1k blocks over 512bytes ones */ @@ -5529,11 +5435,12 @@ nand_maximize_ecc(struct nand_chip *chip, * @caps: ECC engine caps info structure * @oobavail: OOB size that the ECC engine can use * - * Choose the ECC configuration according to following logic + * Choose the ECC configuration according to following logic. * * 1. If both ECC step size and ECC strength are already set (usually by DT) * then check if it is supported by this controller. - * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength. + * 2. If the user provided the nand-ecc-maximize property, then select maximum + * ECC strength. * 3. Otherwise, try to match the ECC step size and ECC strength closest * to the chip's requirement. If available OOB size can't fit the chip * requirement then fallback to the maximum ECC step size and ECC strength. @@ -5544,6 +5451,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip, const struct nand_ecc_caps *caps, int oobavail) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_device *nanddev = mtd_to_nanddev(mtd); if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize)) return -EINVAL; @@ -5551,7 +5459,7 @@ int nand_ecc_choose_conf(struct nand_chip *chip, if (chip->ecc.size && chip->ecc.strength) return nand_check_ecc_caps(chip, caps, oobavail); - if (chip->ecc.options & NAND_ECC_MAXIMIZE) + if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE) return nand_maximize_ecc(chip, caps, oobavail); if (!nand_match_ecc_req(chip, caps, oobavail)) @@ -5561,43 +5469,6 @@ int nand_ecc_choose_conf(struct nand_chip *chip, } EXPORT_SYMBOL_GPL(nand_ecc_choose_conf); -/* - * Check if the chip configuration meet the datasheet requirements. - - * If our configuration corrects A bits per B bytes and the minimum - * required correction level is X bits per Y bytes, then we must ensure - * both of the following are true: - * - * (1) A / B >= X / Y - * (2) A >= X - * - * Requirement (1) ensures we can correct for the required bitflip density. - * Requirement (2) ensures we can correct even when all bitflips are clumped - * in the same sector. - */ -static bool nand_ecc_strength_good(struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - struct nand_ecc_ctrl *ecc = &chip->ecc; - const struct nand_ecc_props *requirements = - nanddev_get_ecc_requirements(&chip->base); - int corr, ds_corr; - - if (ecc->size == 0 || requirements->step_size == 0) - /* Not enough information */ - return true; - - /* - * We get the number of corrected bits per page to compare - * the correction density. - */ - corr = (mtd->writesize * ecc->strength) / ecc->size; - ds_corr = (mtd->writesize * requirements->strength) / - requirements->step_size; - - return corr >= ds_corr && ecc->strength >= requirements->strength; -} - static int rawnand_erase(struct nand_device *nand, const struct nand_pos *pos) { struct nand_chip *chip = container_of(nand, struct nand_chip, @@ -5653,6 +5524,7 @@ static const struct nand_ops rawnand_ops = { static int nand_scan_tail(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); + struct nand_device *nanddev = mtd_to_nanddev(mtd); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i; @@ -5880,7 +5752,7 @@ static int nand_scan_tail(struct nand_chip *chip) mtd->oobavail = ret; /* ECC sanity check: warn if it's too weak */ - if (!nand_ecc_strength_good(chip)) + if (!nand_ecc_correction_is_enough(nanddev)) pr_warn("WARNING: %s: the ECC used on your system (%db/%dB) is too weak compared to the one required by the NAND chip (%db/%dB)\n", mtd->name, nanddev_get_ecc_conf(&chip->base)->strength, diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index 490ba485e939..f863fabb8610 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -1609,12 +1609,13 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct nand_chip *nand, static const u8 strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); struct mtd_info *mtd = nand_to_mtd(nand); + struct nand_device *nanddev = mtd_to_nanddev(mtd); struct sunxi_nand_hw_ecc *data; int nsectors; int ret; int i; - if (ecc->options & NAND_ECC_MAXIMIZE) { + if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE) { int bytes; ecc->size = 1024; diff --git a/drivers/mtd/nand/raw/tegra_nand.c b/drivers/mtd/nand/raw/tegra_nand.c index fecdb7e8f9e8..1267e7529ca2 100644 --- a/drivers/mtd/nand/raw/tegra_nand.c +++ b/drivers/mtd/nand/raw/tegra_nand.c @@ -840,9 +840,10 @@ static int tegra_nand_get_strength(struct nand_chip *chip, const int *strength, int strength_len, int bits_per_step, int oobsize) { + struct nand_device *base = mtd_to_nanddev(nand_to_mtd(chip)); const struct nand_ecc_props *requirements = - nanddev_get_ecc_requirements(&chip->base); - bool maximize = chip->ecc.options & NAND_ECC_MAXIMIZE; + nanddev_get_ecc_requirements(base); + bool maximize = base->ecc.user_conf.flags & NAND_ECC_MAXIMIZE; int i; /* diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 77757aabeba2..3484374fb0cd 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -182,6 +182,7 @@ enum nand_ecc_algo { * @algo: ECC algorithm (if relevant) * @strength: ECC strength * @step_size: Number of bytes per step + * @flags: Misc properties */ struct nand_ecc_props { enum nand_ecc_engine_type engine_type; @@ -189,10 +190,14 @@ struct nand_ecc_props { enum nand_ecc_algo algo; unsigned int strength; unsigned int step_size; + unsigned int flags; }; #define NAND_ECCREQ(str, stp) { .strength = (str), .step_size = (stp) } +/* NAND ECC misc flags */ +#define NAND_ECC_MAXIMIZE BIT(0) + /** * struct nand_bbt - bad block table object * @cache: in memory BBT cache @@ -264,12 +269,14 @@ struct nand_ecc_engine { struct nand_ecc_engine_ops *ops; }; +void nand_ecc_read_user_conf(struct nand_device *nand); int nand_ecc_init_ctx(struct nand_device *nand); void nand_ecc_cleanup_ctx(struct nand_device *nand); int nand_ecc_prepare_io_req(struct nand_device *nand, struct nand_page_io_req *req); int nand_ecc_finish_io_req(struct nand_device *nand, struct nand_page_io_req *req); +bool nand_ecc_correction_is_enough(struct nand_device *nand); /** * struct nand_ecc - Information relative to the ECC diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h index 66f69a1d27a5..9d69fa6608ae 100644 --- a/include/linux/mtd/rawnand.h +++ b/include/linux/mtd/rawnand.h @@ -98,7 +98,6 @@ struct nand_chip; * pages and you want to rely on the default implementation. */ #define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) -#define NAND_ECC_MAXIMIZE BIT(1) /* * Option constants for bizarre disfunctionality and real