From 7670ee78d558259e7f11dd1e7ad3c49e15bd8bc0 Mon Sep 17 00:00:00 2001 From: HatsyRei Date: Tue, 22 Apr 2025 13:46:00 +0800 Subject: [PATCH 1/4] Revert "ARM: pl35x-nand-controller: Fix subpage read performance" This reverts commit bdc6c248dd26d79a45ff7383c13a28d7e4cd738e. 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 5f6115db7c3cf..cfe599adba4de 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 6bcfd963e1a09c7709492a3761c1530b6abfc0f8 Mon Sep 17 00:00:00 2001 From: HatsyRei Date: Tue, 22 Apr 2025 13:46:10 +0800 Subject: [PATCH 2/4] Revert "pl35x-nand-controller: Enable on-die ECC subpage operations" This reverts commit 0bd6d367feaba9de4d70e0e71c497e13b31f0040. 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 cfe599adba4de..d4f2d69bc755a 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 fc2fbd738c97506149efc65e620320478344a57d 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 --- 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 d4f2d69bc755a..6024718ce3b98 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 2fa802930bb513571431b73fd98d349026357188 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 --- 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;