From 5f82a6327cd8f8ff7e50d431213610052f5ad1c4 Mon Sep 17 00:00:00 2001 From: HatsyRei Date: Wed, 23 Apr 2025 10:44:47 +0800 Subject: [PATCH 1/4] Revert "ARM: pl35x-nand-controller: Fix subpage read performance" This reverts commit b9fd08cd6611c45f08f11ecd528949ae520be2d6. Signed-off-by: HatsyRei --- drivers/mtd/nand/raw/pl35x-nand-controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index bd8420f4c3430..09f12b2d3b74e 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -670,7 +670,7 @@ static int pl35x_nand_read_page_hwecc(struct nand_chip *chip, static int pl35x_nand_read_subpage_raw(struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page) { - return nand_read_page_op(chip, page, data_offs, bufpoi + data_offs, readlen); + return nand_monolithic_read_page_raw(chip, bufpoi, 0, page); } static int pl35x_nand_exec_op(struct nand_chip *chip, From 40eed261a7b8f8426780b3f235dc9374cdd6d72c Mon Sep 17 00:00:00 2001 From: HatsyRei Date: Wed, 23 Apr 2025 10:45:13 +0800 Subject: [PATCH 2/4] Revert "pl35x-nand-controller: Enable on-die ECC subpage operations" This reverts commit 3b791177bed18f4eb4b92adb19cfdf05ec578753. Signed-off-by: HatsyRei --- drivers/mtd/nand/raw/pl35x-nand-controller.c | 38 -------------------- 1 file changed, 38 deletions(-) diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index 09f12b2d3b74e..d65563523afb8 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -499,14 +499,6 @@ static int pl35x_nand_recover_data_hwecc(struct pl35x_nandc *nfc, return max_bitflips; } -static int pl35x_nand_write_subpage_raw(struct nand_chip *chip, - uint32_t offset, uint32_t data_len, - const uint8_t *data_buf, - int oob_required, int page) -{ - return nand_monolithic_write_page_raw(chip, data_buf, oob_required, page); -} - static int pl35x_nand_write_page_hwecc(struct nand_chip *chip, const u8 *buf, int oob_required, int page) @@ -667,12 +659,6 @@ static int pl35x_nand_read_page_hwecc(struct nand_chip *chip, return ret; } -static int pl35x_nand_read_subpage_raw(struct nand_chip *chip, uint32_t data_offs, - uint32_t readlen, uint8_t *bufpoi, int page) -{ - return nand_monolithic_read_page_raw(chip, bufpoi, 0, page); -} - static int pl35x_nand_exec_op(struct nand_chip *chip, const struct nand_subop *subop) { @@ -991,29 +977,6 @@ static int pl35x_nand_init_hw_ecc_controller(struct pl35x_nandc *nfc, return ret; } -static void pl35x_nand_init_ondie_ecc(struct pl35x_nandc *nfc, - struct nand_chip *chip) -{ - struct mtd_info *mtd = nand_to_mtd(chip); - - /* Bypass the controller ECC block */ - pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS); - - chip->ecc.strength = 1; - chip->ecc.bytes = 0; - chip->ecc.read_page = nand_monolithic_read_page_raw; - chip->ecc.read_page_raw = nand_monolithic_read_page_raw; - chip->ecc.read_subpage = pl35x_nand_read_subpage_raw; - chip->ecc.write_page = nand_monolithic_write_page_raw; - chip->ecc.write_page_raw = nand_monolithic_write_page_raw; - chip->ecc.write_subpage = pl35x_nand_write_subpage_raw; - chip->ecc.size = mtd->writesize; - - /* NAND with on-die ECC supports subpage reads and writes */ - chip->options |= NAND_SUBPAGE_READ; - chip->options &= ~(NAND_NO_SUBPAGE_WRITE); -} - static int pl35x_nand_attach_chip(struct nand_chip *chip) { const struct nand_ecc_props *requirements = @@ -1048,7 +1011,6 @@ static int pl35x_nand_attach_chip(struct nand_chip *chip) switch (chip->ecc.engine_type) { case NAND_ECC_ENGINE_TYPE_ON_DIE: - pl35x_nand_init_ondie_ecc(nfc, chip); /* Keep these legacy BBT descriptors for ON_DIE situations */ chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; From ecd37c40ca1262f6cc49fe1aa6b22bddfc0d9555 Mon Sep 17 00:00:00 2001 From: Haris Okanovic Date: Wed, 7 Sep 2016 11:16:52 -0500 Subject: [PATCH 3/4] pl353_nand: Add module params to disable subpage read and write Add `enable_subpage_read` and `enable_subpage_write` load-time options to toggle subpage read/write operations on pl353 chips. Both options are enabled by default, and may be toggled in the boot loader. Signed-off-by: Haris Okanovic Acked-by: Gratian Crisan Acked-by: Jeff Westfahl Natinst-CAR-ID: 599280 Natinst-ReviewBoard-ID: 151758 (cherry picked from commit 311a5711cfdbfa20e3f4ec2dbd429f96b9f76c2f) (cherry picked from commit f261b4b6df120eda51a83a876448bcfc14919eab) Signed-off-by: HatsyRei (cherry picked from commit 118d09c47934983a23c15e803dcf337c8e663b31) Signed-off-by: HatsyRei --- drivers/mtd/nand/raw/pl35x-nand-controller.c | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index d65563523afb8..dd3a5181c89f3 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -144,6 +144,14 @@ struct pl35x_nandc { u8 *ecc_buf; }; +static bool enable_subpage_read = 1; +module_param(enable_subpage_read, bool, 0444); +MODULE_PARM_DESC(enable_subpage_read, "Load-time parameter to toggle subpage reads on supported nand chips. Enabled by default."); + +static bool enable_subpage_write = 1; +module_param(enable_subpage_write, bool, 0444); +MODULE_PARM_DESC(enable_subpage_write, "Load-time parameter to toggle subpage writes on supported nand chips. Enabled by default."); + static inline struct pl35x_nandc *to_pl35x_nandc(struct nand_controller *ctrl) { return container_of(ctrl, struct pl35x_nandc, controller); @@ -977,6 +985,21 @@ static int pl35x_nand_init_hw_ecc_controller(struct pl35x_nandc *nfc, return ret; } +static void pl35x_nand_setup_ondie_ecc(struct nand_chip *chip) +{ + /* NAND with on-die ECC supports subpage reads */ + if (enable_subpage_read) + chip->options |= NAND_SUBPAGE_READ; + else + chip->options &= ~(NAND_SUBPAGE_READ); + + /* NAND with on-die ECC may support subpage writes */ + if (enable_subpage_write) + chip->options &= ~(NAND_NO_SUBPAGE_WRITE); + else + chip->options |= NAND_NO_SUBPAGE_WRITE; +} + static int pl35x_nand_attach_chip(struct nand_chip *chip) { const struct nand_ecc_props *requirements = @@ -1011,6 +1034,7 @@ static int pl35x_nand_attach_chip(struct nand_chip *chip) switch (chip->ecc.engine_type) { case NAND_ECC_ENGINE_TYPE_ON_DIE: + pl35x_nand_setup_ondie_ecc(chip); /* Keep these legacy BBT descriptors for ON_DIE situations */ chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; From 220bad6c1a76c63aaa4ded2b61d309ffed471fa7 Mon Sep 17 00:00:00 2001 From: HatsyRei Date: Tue, 22 Apr 2025 14:59:11 +0800 Subject: [PATCH 4/4] mtd: nand_micron: Enable subpage operations Existing devices which utilize Micron NAND may contain partitions formatted with subpages. Support this use case by implementing hooks for subpage read and write in Micron NAND driver. Signed-off-by: HatsyRei (cherry picked from commit bc5d81525799d4ff42b5f40b89368778a1a648c8) Signed-off-by: HatsyRei --- drivers/mtd/nand/raw/nand_micron.c | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c index c0192881906b8..3af30d4eae149 100644 --- a/drivers/mtd/nand/raw/nand_micron.c +++ b/drivers/mtd/nand/raw/nand_micron.c @@ -365,6 +365,46 @@ micron_nand_read_page_on_die_ecc(struct nand_chip *chip, uint8_t *buf, return ret ? ret : max_bitflips; } +static int +micron_nand_read_subpage_on_die_ecc(struct nand_chip *chip, uint32_t data_offs, + uint32_t readlen, uint8_t *bufpoi, int page) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + u8 status; + int ret, max_bitflips = 0; + + ret = micron_nand_on_die_ecc_setup(chip, true); + if (ret) + return ret; + + ret = nand_status_op(chip, &status); + if (ret) + goto out; + + ret = nand_read_page_op(chip, page, data_offs, + bufpoi + data_offs, readlen); + if (ret) + goto out; + + ret = nand_status_op(chip, &status); + if (ret) + goto out; + + if (status & NAND_STATUS_FAIL) { + /* uncorrected */ + mtd->ecc_stats.failed++; + } else if (status & NAND_ECC_STATUS_WRITE_RECOMMENDED) { + /* corrected */ + max_bitflips = mtd->bitflip_threshold; + mtd->ecc_stats.corrected += max_bitflips; + } + +out: + micron_nand_on_die_ecc_setup(chip, false); + + return ret ? ret : max_bitflips; +} + static int micron_nand_write_page_on_die_ecc(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page) @@ -381,6 +421,15 @@ micron_nand_write_page_on_die_ecc(struct nand_chip *chip, const uint8_t *buf, return ret; } +static int +micron_nand_write_subpage_on_die_ecc(struct nand_chip *chip, + uint32_t offset, uint32_t data_len, + const uint8_t *data_buf, + int oob_required, int page) +{ + return micron_nand_write_page_on_die_ecc(chip, data_buf, oob_required, page); +} + enum { /* The NAND flash doesn't support on-die ECC */ MICRON_ON_DIE_UNSUPPORTED, @@ -550,7 +599,9 @@ static int micron_nand_init(struct nand_chip *chip) chip->ecc.strength = requirements->strength; chip->ecc.algo = NAND_ECC_ALGO_BCH; chip->ecc.read_page = micron_nand_read_page_on_die_ecc; + chip->ecc.read_subpage = micron_nand_read_subpage_on_die_ecc; chip->ecc.write_page = micron_nand_write_page_on_die_ecc; + chip->ecc.write_subpage = micron_nand_write_subpage_on_die_ecc; if (ondie == MICRON_ON_DIE_MANDATORY) { chip->ecc.read_page_raw = nand_read_page_raw_notsupp;