diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index b661bc44212b4..343693c8ffd47 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -50,6 +50,15 @@ config FTL_READAHEAD default n depends on DRVR_READAHEAD +config FTL_BBM + bool "Enable bad block management in the FTL layer" + default y if MTD_NAND + ---help--- + Enable logical to physical erase-block mapping in the FTL layer for + MTD devices that expose bad blocks via the MTD isbad/markbad methods. + + This is needed for devices that require software bad block management. + config MTD_SECT512 bool "512B sector conversion" default n @@ -1442,6 +1451,7 @@ config MTD_GD5F bool "SPI-based GD5F nand FLASH" default n select SPI + select FTL_BBM if MTD_GD5F diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 83c027e06a7ea..f175f4f5076aa 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -80,10 +80,12 @@ struct ftl_struct_s FAR uint8_t *eblock; /* One, in-memory erase block */ int oflags; - /* The nand block map between logic block and physical block */ +#ifdef CONFIG_FTL_BBM + /* The block map between logic block and physical block */ FAR off_t *lptable; off_t lpcount; +#endif }; /**************************************************************************** @@ -133,12 +135,14 @@ static const struct block_operations g_bops = * Private Functions ****************************************************************************/ +#ifdef CONFIG_FTL_BBM + /**************************************************************************** * Name: ftl_init_map * * Description: Allocate logical block and physical block mapping table - * space, and scan the entire nand flash device to establish - * the mapping relationship between logical block and physical + * space, and scan the entire MTD device to establish the + * mapping relationship between logical block and physical * good block. * ****************************************************************************/ @@ -207,6 +211,7 @@ static size_t ftl_get_cblock(FAR struct ftl_struct_s *dev, off_t start, return count; } +#endif /**************************************************************************** * Name: ftl_open @@ -273,11 +278,15 @@ static int ftl_close(FAR struct inode *inode) static ssize_t ftl_mtd_bread(FAR struct ftl_struct_s *dev, off_t startblock, size_t nblocks, FAR uint8_t *buffer) { +#ifdef CONFIG_FTL_BBM off_t mask = dev->blkper - 1; size_t nread = nblocks; +#endif ssize_t ret = OK; +#ifdef CONFIG_FTL_BBM if (dev->lptable == NULL) +#endif { ret = MTD_BREAD(dev->mtd, startblock, nblocks, buffer); if (ret != nblocks) @@ -289,6 +298,7 @@ static ssize_t ftl_mtd_bread(FAR struct ftl_struct_s *dev, off_t startblock, return ret; } +#ifdef CONFIG_FTL_BBM while (nblocks > 0) { off_t startphysicalblock; @@ -324,6 +334,7 @@ static ssize_t ftl_mtd_bread(FAR struct ftl_struct_s *dev, off_t startblock, } return nblocks != nread ? nread - nblocks : ret; +#endif } /**************************************************************************** @@ -339,10 +350,14 @@ static ssize_t ftl_mtd_bread(FAR struct ftl_struct_s *dev, off_t startblock, static ssize_t ftl_mtd_bwrite(FAR struct ftl_struct_s *dev, off_t startblock, FAR const uint8_t *buffer) { +#ifdef CONFIG_FTL_BBM off_t starteraseblock; +#endif ssize_t ret; +#ifdef CONFIG_FTL_BBM if (dev->lptable == NULL) +#endif { ret = MTD_BWRITE(dev->mtd, startblock, dev->blkper, buffer); if (ret != dev->blkper) @@ -354,6 +369,7 @@ static ssize_t ftl_mtd_bwrite(FAR struct ftl_struct_s *dev, off_t startblock, return ret; } +#ifdef CONFIG_FTL_BBM starteraseblock = startblock / dev->blkper; while (1) { @@ -372,6 +388,7 @@ static ssize_t ftl_mtd_bwrite(FAR struct ftl_struct_s *dev, off_t startblock, MTD_MARKBAD(dev->mtd, dev->lptable[starteraseblock]); ftl_update_map(dev, starteraseblock); } +#endif } /**************************************************************************** @@ -389,7 +406,9 @@ static ssize_t ftl_mtd_erase(FAR struct ftl_struct_s *dev, off_t startblock) { ssize_t ret; +#ifdef CONFIG_FTL_BBM if (dev->lptable == NULL) +#endif { ret = MTD_ERASE(dev->mtd, startblock, 1); if (ret < 0 && ret != -ENOSYS) @@ -402,6 +421,7 @@ static ssize_t ftl_mtd_erase(FAR struct ftl_struct_s *dev, off_t startblock) return OK; } +#ifdef CONFIG_FTL_BBM while (1) { if (startblock >= dev->lpcount) @@ -418,6 +438,7 @@ static ssize_t ftl_mtd_erase(FAR struct ftl_struct_s *dev, off_t startblock) MTD_MARKBAD(dev->mtd, dev->lptable[startblock]); ftl_update_map(dev, startblock); } +#endif } /**************************************************************************** @@ -517,7 +538,9 @@ static ssize_t ftl_flush_direct(FAR struct ftl_struct_s *dev, } } +#ifdef CONFIG_FTL_BBM if (dev->lptable == NULL) +#endif { ret = MTD_BWRITE(dev->mtd, startblock, count, buffer); if (ret != count) @@ -527,6 +550,7 @@ static ssize_t ftl_flush_direct(FAR struct ftl_struct_s *dev, return ret; } } +#ifdef CONFIG_FTL_BBM else { if (starteraseblock >= dev->lpcount) @@ -544,6 +568,7 @@ static ssize_t ftl_flush_direct(FAR struct ftl_struct_s *dev, continue; } } +#endif nblocks -= count; startblock += count; @@ -567,7 +592,11 @@ static ssize_t ftl_flush(FAR void *priv, FAR const uint8_t *buffer, int nbytes; int ret; +#ifdef CONFIG_FTL_BBM if (dev->mtd->erase == NULL && dev->lptable == NULL) +#else + if (dev->mtd->erase == NULL) +#endif { ret = MTD_BWRITE(dev->mtd, startblock, nblocks, buffer); if (ret != nblocks) @@ -922,6 +951,15 @@ int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd, finfo("path=\"%s\"\n", path); +#ifndef CONFIG_FTL_BBM + /* It is likely a configuration error if the mtd driver implements + * the bad block management, but it is still disabled by the + * configuration. + */ + + DEBUGASSERT(mtd->isbad == NULL && mtd->markbad == NULL); +#endif + /* Allocate a FTL device structure */ dev = kmm_zalloc(sizeof(struct ftl_struct_s)); @@ -978,6 +1016,7 @@ int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd, } #endif +#ifdef CONFIG_FTL_BBM if (MTD_ISBAD(dev->mtd, 0) != -ENOSYS) { ret = ftl_init_map(dev); @@ -986,6 +1025,7 @@ int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd, goto out; } } +#endif /* Inode private data is a reference to the FTL device structure */ @@ -993,8 +1033,10 @@ int ftl_initialize_by_path(FAR const char *path, FAR struct mtd_dev_s *mtd, if (ret < 0) { ferr("ERROR: register_blockdriver failed: %d\n", -ret); +#ifdef CONFIG_FTL_BBM kmm_free(dev->lptable); out: +#endif #ifdef FTL_HAVE_RWBUFFER rwb_uninitialize(&dev->rwb); #endif