mtd: nand: Add max_bad_eraseblocks_per_lun info to memorg
authorBoris Brezillon <bbrezillon@kernel.org>
Sun, 4 Nov 2018 13:43:37 +0000 (14:43 +0100)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Mon, 8 Apr 2019 08:21:08 +0000 (10:21 +0200)
NAND datasheets usually give the maximum number of bad blocks per LUN
and this number can be used to help upper layers decide how much blocks
they should reserve for bad block handling.

Add a max_bad_eraseblocks_per_lun to the nand_memory_organization
struct and update the NAND_MEMORG() macro (and its users) accordingly.

We also provide a default mtd->_max_bad_blocks() implementation.

Signed-off-by: Boris Brezillon <bbrezillon@kernel.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
drivers/mtd/nand/core.c
drivers/mtd/nand/spi/gigadevice.c
drivers/mtd/nand/spi/macronix.c
drivers/mtd/nand/spi/micron.c
drivers/mtd/nand/spi/toshiba.c
drivers/mtd/nand/spi/winbond.c
include/linux/mtd/nand.h

index 9c9f893..b6de955 100644 (file)
@@ -174,6 +174,40 @@ int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo)
 EXPORT_SYMBOL_GPL(nanddev_mtd_erase);
 
 /**
+ * nanddev_mtd_max_bad_blocks() - Get the maximum number of bad eraseblock on
+ *                               a specific region of the NAND device
+ * @mtd: MTD device
+ * @offs: offset of the NAND region
+ * @len: length of the NAND region
+ *
+ * Default implementation for mtd->_max_bad_blocks(). Only works if
+ * nand->memorg.max_bad_eraseblocks_per_lun is > 0.
+ *
+ * Return: a positive number encoding the maximum number of eraseblocks on a
+ * portion of memory, a negative error code otherwise.
+ */
+int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
+{
+       struct nand_device *nand = mtd_to_nanddev(mtd);
+       struct nand_pos pos, end;
+       unsigned int max_bb = 0;
+
+       if (!nand->memorg.max_bad_eraseblocks_per_lun)
+               return -ENOTSUPP;
+
+       nanddev_offs_to_pos(nand, offs, &pos);
+       nanddev_offs_to_pos(nand, offs + len, &end);
+
+       for (nanddev_offs_to_pos(nand, offs, &pos);
+            nanddev_pos_cmp(&pos, &end) < 0;
+            nanddev_pos_next_lun(nand, &pos))
+               max_bb += nand->memorg.max_bad_eraseblocks_per_lun;
+
+       return max_bb;
+}
+EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
+
+/**
  * nanddev_init() - Initialize a NAND device
  * @nand: NAND device
  * @ops: NAND device operations
index 0b49d82..e558639 100644 (file)
@@ -162,7 +162,7 @@ static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
 
 static const struct spinand_info gigadevice_spinand_table[] = {
        SPINAND_INFO("GD5F1GQ4xA", 0xF1,
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -171,7 +171,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
        SPINAND_INFO("GD5F2GQ4xA", 0xF2,
-                    NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -180,7 +180,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
        SPINAND_INFO("GD5F4GQ4xA", 0xF4,
-                    NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 4096, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -189,7 +189,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
                     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
                                     gd5fxgq4xa_ecc_get_status)),
        SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index d16b570..6502727 100644 (file)
@@ -100,7 +100,7 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
 
 static const struct spinand_info macronix_spinand_table[] = {
        SPINAND_INFO("MX35LF1GE4AB", 0x12,
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 40, 1, 1, 1),
                     NAND_ECCREQ(4, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -109,7 +109,7 @@ static const struct spinand_info macronix_spinand_table[] = {
                     SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
                                     mx35lf1ge4ab_ecc_get_status)),
        SPINAND_INFO("MX35LF2GE4AB", 0x22,
-                    NAND_MEMORG(1, 2048, 64, 64, 2048, 2, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 2048, 20, 2, 1, 1),
                     NAND_ECCREQ(4, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index 9c4381d..7d7b1f7 100644 (file)
@@ -92,7 +92,7 @@ static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand,
 
 static const struct spinand_info micron_spinand_table[] = {
        SPINAND_INFO("MT29F2G01ABAGD", 0x24,
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 2, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index db8021d..1cb3760 100644 (file)
@@ -96,7 +96,7 @@ static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
 static const struct spinand_info toshiba_spinand_table[] = {
        /* 3.3V 1Gb */
        SPINAND_INFO("TC58CVG0S3", 0xC2,
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -106,7 +106,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 3.3V 2Gb */
        SPINAND_INFO("TC58CVG1S3", 0xCB,
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -116,7 +116,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 3.3V 4Gb */
        SPINAND_INFO("TC58CVG2S0", 0xCD,
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -126,7 +126,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 1.8V 1Gb */
        SPINAND_INFO("TC58CYG0S3", 0xB2,
-                    NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -136,7 +136,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 1.8V 2Gb */
        SPINAND_INFO("TC58CYG1S3", 0xBB,
-                    NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -146,7 +146,7 @@ static const struct spinand_info toshiba_spinand_table[] = {
                                     tc58cxgxsx_ecc_get_status)),
        /* 1.8V 4Gb */
        SPINAND_INFO("TC58CYG2S0", 0xBD,
-                    NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
+                    NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
                     NAND_ECCREQ(8, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index 5d94458..a6c17e0 100644 (file)
@@ -76,7 +76,7 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
 
 static const struct spinand_info winbond_spinand_table[] = {
        SPINAND_INFO("W25M02GV", 0xAB,
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
                     NAND_ECCREQ(1, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
@@ -85,7 +85,7 @@ static const struct spinand_info winbond_spinand_table[] = {
                     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
                     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
        SPINAND_INFO("W25N01GV", 0xAA,
-                    NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
+                    NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
                     NAND_ECCREQ(1, 512),
                     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
                                              &write_cache_variants,
index 7f53ece..d32bb62 100644 (file)
@@ -19,6 +19,7 @@
  * @oobsize: OOB area size
  * @pages_per_eraseblock: number of pages per eraseblock
  * @eraseblocks_per_lun: number of eraseblocks per LUN (Logical Unit Number)
+ * @max_bad_eraseblocks_per_lun: maximum number of eraseblocks per LUN
  * @planes_per_lun: number of planes per LUN
  * @luns_per_target: number of LUN per target (target is a synonym for die)
  * @ntargets: total number of targets exposed by the NAND device
@@ -29,18 +30,20 @@ struct nand_memory_organization {
        unsigned int oobsize;
        unsigned int pages_per_eraseblock;
        unsigned int eraseblocks_per_lun;
+       unsigned int max_bad_eraseblocks_per_lun;
        unsigned int planes_per_lun;
        unsigned int luns_per_target;
        unsigned int ntargets;
 };
 
-#define NAND_MEMORG(bpc, ps, os, ppe, epl, ppl, lpt, nt)       \
+#define NAND_MEMORG(bpc, ps, os, ppe, epl, mbb, ppl, lpt, nt)  \
        {                                                       \
                .bits_per_cell = (bpc),                         \
                .pagesize = (ps),                               \
                .oobsize = (os),                                \
                .pages_per_eraseblock = (ppe),                  \
                .eraseblocks_per_lun = (epl),                   \
+               .max_bad_eraseblocks_per_lun = (mbb),           \
                .planes_per_lun = (ppl),                        \
                .luns_per_target = (lpt),                       \
                .ntargets = (nt),                               \
@@ -729,5 +732,6 @@ static inline bool nanddev_bbt_is_initialized(struct nand_device *nand)
 
 /* MTD -> NAND helper functions. */
 int nanddev_mtd_erase(struct mtd_info *mtd, struct erase_info *einfo);
+int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len);
 
 #endif /* __LINUX_MTD_NAND_H */