Skip to content

Commit 94beaa2

Browse files
saschahauermiquelraynal
authored andcommitted
mtd: rawnand: mxc: separate page read from ecc calc
Our read_page hook currently reads out a page and also counts and returns the number of bitflips. In upcoming exec_op conversion we'll need to read the page data in exec_op, but the bitflip information will be needed in mxc_nand_read_page(). To ease exec_op conversion separate the page read out from the bitflip evaluation. For the v2/v3 controllers we can leave the bitflip information in the status register for later evaluation. For the v1 controller this is not possible, because the status register is overwritten with each subpage read. We therefore store the bitflip information in the private data. Signed-off-by: Sascha Hauer <[email protected]> Signed-off-by: Miquel Raynal <[email protected]> Link: https://lore.kernel.org/linux-mtd/20240522-mtd-nand-mxc-nand-exec-op-v4-1-75b611e0ac44@pengutronix.de
1 parent 04a81b4 commit 94beaa2

File tree

1 file changed

+86
-54
lines changed

1 file changed

+86
-54
lines changed

drivers/mtd/nand/raw/mxc_nand.c

Lines changed: 86 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/irq.h>
2121
#include <linux/completion.h>
2222
#include <linux/of.h>
23+
#include <linux/bitfield.h>
2324

2425
#define DRIVER_NAME "mxc_nand"
2526

@@ -47,6 +48,8 @@
4748
#define NFC_V1_V2_CONFIG1 (host->regs + 0x1a)
4849
#define NFC_V1_V2_CONFIG2 (host->regs + 0x1c)
4950

51+
#define NFC_V1_V2_ECC_STATUS_RESULT_ERM GENMASK(3, 2)
52+
5053
#define NFC_V2_CONFIG1_ECC_MODE_4 (1 << 0)
5154
#define NFC_V1_V2_CONFIG1_SP_EN (1 << 2)
5255
#define NFC_V1_V2_CONFIG1_ECC_EN (1 << 3)
@@ -132,7 +135,7 @@ struct mxc_nand_devtype_data {
132135
uint16_t (*get_dev_status)(struct mxc_nand_host *);
133136
int (*check_int)(struct mxc_nand_host *);
134137
void (*irq_control)(struct mxc_nand_host *, int);
135-
u32 (*get_ecc_status)(struct mxc_nand_host *);
138+
u32 (*get_ecc_status)(struct nand_chip *);
136139
const struct mtd_ooblayout_ops *ooblayout;
137140
void (*select_chip)(struct nand_chip *chip, int cs);
138141
int (*setup_interface)(struct nand_chip *chip, int csline,
@@ -175,6 +178,7 @@ struct mxc_nand_host {
175178
int eccsize;
176179
int used_oobsize;
177180
int active_cs;
181+
unsigned int ecc_stats_v1;
178182

179183
struct completion op_completion;
180184

@@ -406,19 +410,81 @@ static void irq_control(struct mxc_nand_host *host, int activate)
406410
}
407411
}
408412

409-
static u32 get_ecc_status_v1(struct mxc_nand_host *host)
413+
static u32 get_ecc_status_v1(struct nand_chip *chip)
410414
{
411-
return readw(NFC_V1_V2_ECC_STATUS_RESULT);
415+
struct mtd_info *mtd = nand_to_mtd(chip);
416+
struct mxc_nand_host *host = nand_get_controller_data(chip);
417+
unsigned int ecc_stats, max_bitflips = 0;
418+
int no_subpages, i;
419+
420+
no_subpages = mtd->writesize >> 9;
421+
422+
ecc_stats = host->ecc_stats_v1;
423+
424+
for (i = 0; i < no_subpages; i++) {
425+
switch (ecc_stats & 0x3) {
426+
case 0:
427+
default:
428+
break;
429+
case 1:
430+
mtd->ecc_stats.corrected++;
431+
max_bitflips = 1;
432+
break;
433+
case 2:
434+
mtd->ecc_stats.failed++;
435+
break;
436+
}
437+
438+
ecc_stats >>= 2;
439+
}
440+
441+
return max_bitflips;
412442
}
413443

414-
static u32 get_ecc_status_v2(struct mxc_nand_host *host)
444+
static u32 get_ecc_status_v2_v3(struct nand_chip *chip, unsigned int ecc_stat)
415445
{
416-
return readl(NFC_V1_V2_ECC_STATUS_RESULT);
446+
struct mtd_info *mtd = nand_to_mtd(chip);
447+
struct mxc_nand_host *host = nand_get_controller_data(chip);
448+
u8 ecc_bit_mask, err_limit;
449+
unsigned int max_bitflips = 0;
450+
int no_subpages, err;
451+
452+
ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
453+
err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
454+
455+
no_subpages = mtd->writesize >> 9;
456+
457+
do {
458+
err = ecc_stat & ecc_bit_mask;
459+
if (err > err_limit) {
460+
mtd->ecc_stats.failed++;
461+
} else {
462+
mtd->ecc_stats.corrected += err;
463+
max_bitflips = max_t(unsigned int, max_bitflips, err);
464+
}
465+
466+
ecc_stat >>= 4;
467+
} while (--no_subpages);
468+
469+
return max_bitflips;
417470
}
418471

419-
static u32 get_ecc_status_v3(struct mxc_nand_host *host)
472+
static u32 get_ecc_status_v2(struct nand_chip *chip)
420473
{
421-
return readl(NFC_V3_ECC_STATUS_RESULT);
474+
struct mxc_nand_host *host = nand_get_controller_data(chip);
475+
476+
u32 ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT);
477+
478+
return get_ecc_status_v2_v3(chip, ecc_stat);
479+
}
480+
481+
static u32 get_ecc_status_v3(struct nand_chip *chip)
482+
{
483+
struct mxc_nand_host *host = nand_get_controller_data(chip);
484+
485+
u32 ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT);
486+
487+
return get_ecc_status_v2_v3(chip, ecc_stat);
422488
}
423489

424490
static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
@@ -712,9 +778,9 @@ static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob,
712778
{
713779
struct mtd_info *mtd = nand_to_mtd(chip);
714780
struct mxc_nand_host *host = nand_get_controller_data(chip);
715-
unsigned int bitflips_corrected = 0;
716781
int no_subpages;
717782
int i;
783+
unsigned int ecc_stats = 0;
718784

719785
host->devtype_data->enable_hwecc(chip, ecc);
720786

@@ -727,8 +793,6 @@ static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob,
727793
no_subpages = mtd->writesize >> 9;
728794

729795
for (i = 0; i < no_subpages; i++) {
730-
uint16_t ecc_stats;
731-
732796
/* NANDFC buffer 0 is used for page read/write */
733797
writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
734798

@@ -737,43 +801,25 @@ static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob,
737801
/* Wait for operation to complete */
738802
wait_op_done(host, true);
739803

740-
ecc_stats = get_ecc_status_v1(host);
741-
742-
ecc_stats >>= 2;
743-
744-
if (buf && ecc) {
745-
switch (ecc_stats & 0x3) {
746-
case 0:
747-
default:
748-
break;
749-
case 1:
750-
mtd->ecc_stats.corrected++;
751-
bitflips_corrected = 1;
752-
break;
753-
case 2:
754-
mtd->ecc_stats.failed++;
755-
break;
756-
}
757-
}
804+
ecc_stats |= FIELD_GET(NFC_V1_V2_ECC_STATUS_RESULT_ERM,
805+
readw(NFC_V1_V2_ECC_STATUS_RESULT)) << i * 2;
758806
}
759807

808+
host->ecc_stats_v1 = ecc_stats;
809+
760810
if (buf)
761811
memcpy32_fromio(buf, host->main_area0, mtd->writesize);
762812
if (oob)
763813
copy_spare(mtd, true, oob);
764814

765-
return bitflips_corrected;
815+
return 0;
766816
}
767817

768818
static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
769819
void *oob, bool ecc, int page)
770820
{
771821
struct mtd_info *mtd = nand_to_mtd(chip);
772822
struct mxc_nand_host *host = nand_get_controller_data(chip);
773-
unsigned int max_bitflips = 0;
774-
u32 ecc_stat, err;
775-
int no_subpages;
776-
u8 ecc_bit_mask, err_limit;
777823

778824
host->devtype_data->enable_hwecc(chip, ecc);
779825

@@ -791,40 +837,26 @@ static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
791837
if (oob)
792838
copy_spare(mtd, true, oob);
793839

794-
ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
795-
err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
796-
797-
no_subpages = mtd->writesize >> 9;
798-
799-
ecc_stat = host->devtype_data->get_ecc_status(host);
800-
801-
do {
802-
err = ecc_stat & ecc_bit_mask;
803-
if (err > err_limit) {
804-
mtd->ecc_stats.failed++;
805-
} else {
806-
mtd->ecc_stats.corrected += err;
807-
max_bitflips = max_t(unsigned int, max_bitflips, err);
808-
}
809-
810-
ecc_stat >>= 4;
811-
} while (--no_subpages);
812-
813-
return max_bitflips;
840+
return 0;
814841
}
815842

816843
static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf,
817844
int oob_required, int page)
818845
{
819846
struct mxc_nand_host *host = nand_get_controller_data(chip);
820847
void *oob_buf;
848+
int ret;
821849

822850
if (oob_required)
823851
oob_buf = chip->oob_poi;
824852
else
825853
oob_buf = NULL;
826854

827-
return host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
855+
ret = host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
856+
if (ret)
857+
return ret;
858+
859+
return host->devtype_data->get_ecc_status(chip);
828860
}
829861

830862
static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf,

0 commit comments

Comments
 (0)