diff mbox series

[v2,01/15] mtd: nand: Add max_bad_eraseblocks_per_lun info to memorg

Message ID 20190304201522.11323-2-miquel.raynal@bootlin.com (mailing list archive)
State New, archived
Headers show
Series mtd: rawnand: 5th batch of cleanups | expand

Commit Message

Miquel Raynal March 4, 2019, 8:15 p.m. UTC
From: Boris Brezillon <bbrezillon@kernel.org>

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           | 34 +++++++++++++++++++++++++++++++
 drivers/mtd/nand/spi/gigadevice.c |  6 +++---
 drivers/mtd/nand/spi/macronix.c   |  4 ++--
 drivers/mtd/nand/spi/micron.c     |  2 +-
 drivers/mtd/nand/spi/toshiba.c    |  2 +-
 drivers/mtd/nand/spi/winbond.c    |  4 ++--
 include/linux/mtd/nand.h          |  6 +++++-
 7 files changed, 48 insertions(+), 10 deletions(-)

Comments

Emil Lenngren June 4, 2019, 8:01 a.m. UTC | #1
Hi Miquel,

>  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,
> @@ -103,7 +103,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),

Maybe a bit late to the discussion, but shouldn't 20 and 40 be swapped
here, i.e. isn't it the larger flash that has more max bad blocks than
the smaller one?

/Emil
Frieder Schrempf June 6, 2019, 8:27 a.m. UTC | #2
Hi Emil,

On 04.06.19 10:01, Emil Lenngren wrote:
> Hi Miquel,
> 
>>   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,
>> @@ -103,7 +103,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),
> 
> Maybe a bit late to the discussion, but shouldn't 20 and 40 be swapped
> here, i.e. isn't it the larger flash that has more max bad blocks than
> the smaller one?

I think Miquel is out of office for some days, so I just checked and you 
are right, the maximum number of bad blocks should be swapped.

Actually there is also a wrong value in the GigaDevice driver: For the 
GD5F4GQ4xA it should be 80 instead of 40.

Would you mind sending a patch with a "Fixes:" tag, that fixes both, the 
Macronix and the GigaDevice driver? Or should I send one?

Thanks,
Frieder
Boris Brezillon June 6, 2019, 8:39 a.m. UTC | #3
On Thu, 6 Jun 2019 08:27:11 +0000
Schrempf Frieder <frieder.schrempf@kontron.de> wrote:

> Hi Emil,
> 
> On 04.06.19 10:01, Emil Lenngren wrote:
> > Hi Miquel,
> >   
> >>   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,
> >> @@ -103,7 +103,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),  
> > 
> > Maybe a bit late to the discussion, but shouldn't 20 and 40 be swapped
> > here, i.e. isn't it the larger flash that has more max bad blocks than
> > the smaller one?  
> 
> I think Miquel is out of office for some days, so I just checked and you 
> are right, the maximum number of bad blocks should be swapped.
> 
> Actually there is also a wrong value in the GigaDevice driver: For the 
> GD5F4GQ4xA it should be 80 instead of 40.

Haven't checked the datasheet, but keep in mind that this is the max
number of eraseblock per LUN.
Frieder Schrempf June 6, 2019, 8:52 a.m. UTC | #4
On 06.06.19 10:39, Boris Brezillon wrote:
> On Thu, 6 Jun 2019 08:27:11 +0000
> Schrempf Frieder <frieder.schrempf@kontron.de> wrote:
> 
>> Hi Emil,
>>
>> On 04.06.19 10:01, Emil Lenngren wrote:
>>> Hi Miquel,
>>>    
>>>>    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,
>>>> @@ -103,7 +103,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),
>>>
>>> Maybe a bit late to the discussion, but shouldn't 20 and 40 be swapped
>>> here, i.e. isn't it the larger flash that has more max bad blocks than
>>> the smaller one?
>>
>> I think Miquel is out of office for some days, so I just checked and you
>> are right, the maximum number of bad blocks should be swapped.
>>
>> Actually there is also a wrong value in the GigaDevice driver: For the
>> GD5F4GQ4xA it should be 80 instead of 40.
> 
> Haven't checked the datasheet, but keep in mind that this is the max
> number of eraseblock per LUN.

The datasheet gives 20 for the 1G type and 40 for the 2G type. Both 
types have only one LUN. Only the 2G type has 2 planes, but that 
shouldn't make a difference, right?
Frieder Schrempf June 6, 2019, 8:57 a.m. UTC | #5
On 06.06.19 10:52, Frieder Schrempf wrote:
> On 06.06.19 10:39, Boris Brezillon wrote:
>> On Thu, 6 Jun 2019 08:27:11 +0000
>> Schrempf Frieder <frieder.schrempf@kontron.de> wrote:
>>
>>> Hi Emil,
>>>
>>> On 04.06.19 10:01, Emil Lenngren wrote:
>>>> Hi Miquel,
>>>>>    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,
>>>>> @@ -103,7 +103,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),
>>>>
>>>> Maybe a bit late to the discussion, but shouldn't 20 and 40 be swapped
>>>> here, i.e. isn't it the larger flash that has more max bad blocks than
>>>> the smaller one?
>>>
>>> I think Miquel is out of office for some days, so I just checked and you
>>> are right, the maximum number of bad blocks should be swapped.
>>>
>>> Actually there is also a wrong value in the GigaDevice driver: For the
>>> GD5F4GQ4xA it should be 80 instead of 40.
>>
>> Haven't checked the datasheet, but keep in mind that this is the max
>> number of eraseblock per LUN.
> 
> The datasheet gives 20 for the 1G type and 40 for the 2G type. Both 
> types have only one LUN. Only the 2G type has 2 planes, but that 
> shouldn't make a difference, right?

Sorry, I was referring to the Macronix chips. You were probably talking 
about the GigaDevice. But they all have only one LUN, too. So I think I 
got it right.
Boris Brezillon June 6, 2019, 9:05 a.m. UTC | #6
On Thu, 6 Jun 2019 08:57:32 +0000
Schrempf Frieder <frieder.schrempf@kontron.de> wrote:

> On 06.06.19 10:52, Frieder Schrempf wrote:
> > On 06.06.19 10:39, Boris Brezillon wrote:  
> >> On Thu, 6 Jun 2019 08:27:11 +0000
> >> Schrempf Frieder <frieder.schrempf@kontron.de> wrote:
> >>  
> >>> Hi Emil,
> >>>
> >>> On 04.06.19 10:01, Emil Lenngren wrote:  
> >>>> Hi Miquel,  
> >>>>>    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,
> >>>>> @@ -103,7 +103,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),  
> >>>>
> >>>> Maybe a bit late to the discussion, but shouldn't 20 and 40 be swapped
> >>>> here, i.e. isn't it the larger flash that has more max bad blocks than
> >>>> the smaller one?  
> >>>
> >>> I think Miquel is out of office for some days, so I just checked and you
> >>> are right, the maximum number of bad blocks should be swapped.
> >>>
> >>> Actually there is also a wrong value in the GigaDevice driver: For the
> >>> GD5F4GQ4xA it should be 80 instead of 40.  
> >>
> >> Haven't checked the datasheet, but keep in mind that this is the max
> >> number of eraseblock per LUN.  
> > 
> > The datasheet gives 20 for the 1G type and 40 for the 2G type. Both 
> > types have only one LUN. Only the 2G type has 2 planes, but that 
> > shouldn't make a difference, right?  
> 
> Sorry, I was referring to the Macronix chips. You were probably talking 
> about the GigaDevice. But they all have only one LUN, too. So I think I 
> got it right.

Good, just wanted to make sure you were aware of that fact. As I said,
I didn't check the datasheet, so I trust you on this one.
Emil Lenngren June 6, 2019, 1:06 p.m. UTC | #7
Hi Schrempf,

Den tors 6 juni 2019 kl 10:27 skrev Schrempf Frieder
<frieder.schrempf@kontron.de>:
>
> Hi Emil,
>
> On 04.06.19 10:01, Emil Lenngren wrote:
> > Hi Miquel,
> >
> >>   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,
> >> @@ -103,7 +103,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),
> >
> > Maybe a bit late to the discussion, but shouldn't 20 and 40 be swapped
> > here, i.e. isn't it the larger flash that has more max bad blocks than
> > the smaller one?
>
> I think Miquel is out of office for some days, so I just checked and you
> are right, the maximum number of bad blocks should be swapped.
>
> Actually there is also a wrong value in the GigaDevice driver: For the
> GD5F4GQ4xA it should be 80 instead of 40.
>
> Would you mind sending a patch with a "Fixes:" tag, that fixes both, the
> Macronix and the GigaDevice driver? Or should I send one?

Please go ahead :)

/Emil
diff mbox series

Patch

diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
index e6554b401813..0a2be5e6d669 100644
--- a/drivers/mtd/nand/core.c
+++ b/drivers/mtd/nand/core.c
@@ -173,6 +173,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
diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
index e4141c20947a..c434fbed3ce5 100644
--- a/drivers/mtd/nand/spi/gigadevice.c
+++ b/drivers/mtd/nand/spi/gigadevice.c
@@ -88,7 +88,7 @@  static const struct mtd_ooblayout_ops gd5fxgq4xa_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,
@@ -97,7 +97,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,
@@ -106,7 +106,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,
diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
index 98f6b9c4b684..c6300d9d63f9 100644
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -94,7 +94,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,
@@ -103,7 +103,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,
diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
index 9c4381d6847b..7d7b1f7fcf71 100644
--- a/drivers/mtd/nand/spi/micron.c
+++ b/drivers/mtd/nand/spi/micron.c
@@ -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,
diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
index 081265557e70..00ddab08e6c6 100644
--- a/drivers/mtd/nand/spi/toshiba.c
+++ b/drivers/mtd/nand/spi/toshiba.c
@@ -95,7 +95,7 @@  static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
 
 static const struct spinand_info toshiba_spinand_table[] = {
 	SPINAND_INFO("TC58CVG2S0H", 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,
diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
index 5d944580b898..a6c17e0cace8 100644
--- a/drivers/mtd/nand/spi/winbond.c
+++ b/drivers/mtd/nand/spi/winbond.c
@@ -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,
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 7f53ece2c039..d32bb623d532 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -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 */