From 28b8b26b308e656edfa9467867d5f79212da2ec3 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 30 Oct 2015 20:33:20 -0700 Subject: mtd: add get/set of_node/flash_node helpers We are going to begin using the mtd->dev.of_node field for MTD device nodes, so let's add helpers for it. Also, we'll be making some conversions on spi_nor (and nand_chip eventually) too, so get that ready with their own helpers. Signed-off-by: Brian Norris Reviewed-by: Boris Brezillon --- include/linux/mtd/mtd.h | 11 +++++++++++ include/linux/mtd/nand.h | 11 +++++++++++ include/linux/mtd/spi-nor.h | 11 +++++++++++ 3 files changed, 33 insertions(+) (limited to 'include') diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index f17fa75809aa..cc84923011c0 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -254,6 +254,17 @@ struct mtd_info { int usecount; }; +static inline void mtd_set_of_node(struct mtd_info *mtd, + struct device_node *np) +{ + mtd->dev.of_node = np; +} + +static inline struct device_node *mtd_get_of_node(struct mtd_info *mtd) +{ + return mtd->dev.of_node; +} + int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); int mtd_point(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 5a9d1d4c2487..4f7c9b97982f 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -719,6 +719,17 @@ struct nand_chip { void *priv; }; +static inline void nand_set_flash_node(struct nand_chip *chip, + struct device_node *np) +{ + chip->flash_node = np; +} + +static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) +{ + return chip->flash_node; +} + /* * NAND Flash Manufacturer ID Codes */ diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index c8723b62c4cd..6d991df8f986 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -185,6 +185,17 @@ struct spi_nor { void *priv; }; +static inline void spi_nor_set_flash_node(struct spi_nor *nor, + struct device_node *np) +{ + nor->flash_node = np; +} + +static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor) +{ + return nor->flash_node; +} + /** * spi_nor_scan() - scan the SPI NOR * @nor: the spi_nor structure -- cgit v1.2.3 From 3b6521eab0386a4854d47b1a01947d7dc46ec98d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 30 Oct 2015 20:33:21 -0700 Subject: mtd: ofpart: grab device tree node directly from master device node It seems more logical to use a device node directly associated with the MTD master device (i.e., mtd->dev.of_node field) rather than requiring auxiliary partition parser information to be passed in by the driver in a separate struct. This patch supports the mtd->dev.of_node field and deprecates the parser data 'of_node' field Driver conversions may now follow. Additional side benefit to assigning mtd->dev.of_node rather than using parser data: the driver core will automatically create a device -> node symlink for us. Signed-off-by: Brian Norris Reviewed-by: Boris Brezillon --- drivers/mtd/ofpart.c | 18 ++++++++++-------- include/linux/mtd/partitions.h | 4 +++- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 669c3452f278..7bf996a4cf5e 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -37,10 +37,11 @@ static int parse_ofpart_partitions(struct mtd_info *master, bool dedicated = true; - if (!data) - return 0; - - mtd_node = data->of_node; + /* + * of_node can be provided through auxiliary parser data or (preferred) + * by assigning the master device node + */ + mtd_node = data && data->of_node ? data->of_node : mtd_get_of_node(master); if (!mtd_node) return 0; @@ -149,10 +150,11 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, } *part; const char *names; - if (!data) - return 0; - - dp = data->of_node; + /* + * of_node can be provided through auxiliary parser data or (preferred) + * by assigning the master device node + */ + dp = data && data->of_node ? data->of_node : mtd_get_of_node(master); if (!dp) return 0; diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 6a35e6de5da1..e742f34b67eb 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -56,7 +56,9 @@ struct device_node; /** * struct mtd_part_parser_data - used to pass data to MTD partition parsers. * @origin: for RedBoot, start address of MTD device - * @of_node: for OF parsers, device node containing partitioning information + * @of_node: for OF parsers, device node containing partitioning information. + * This field is deprecated, as the device node should simply be + * assigned to the master struct device. */ struct mtd_part_parser_data { unsigned long origin; -- cgit v1.2.3 From 30069af7348b56eb8c5e1dda7788a531c5f24ca2 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 30 Oct 2015 20:33:27 -0700 Subject: mtd: spi-nor: drop flash_node field We can just alias to the MTD of_node. Signed-off-by: Brian Norris Reviewed-by: Boris Brezillon --- drivers/mtd/spi-nor/spi-nor.c | 1 - include/linux/mtd/spi-nor.h | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 924d455dadb5..12041e181630 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1258,7 +1258,6 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) mtd->flags |= MTD_NO_ERASE; mtd->dev.parent = dev; - mtd_set_of_node(mtd, np); nor->page_size = info->page_size; mtd->writebufsize = nor->page_size; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 6d991df8f986..955f268d159a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -124,7 +124,6 @@ struct mtd_info; * @mtd: point to a mtd_info structure * @lock: the lock for the read/write/erase/lock/unlock operations * @dev: point to a spi device, or a spi nor controller device. - * @flash_node: point to a device node describing this flash instance. * @page_size: the page size of the SPI NOR * @addr_width: number of address bytes * @erase_opcode: the opcode for erasing a sector @@ -155,7 +154,6 @@ struct spi_nor { struct mtd_info mtd; struct mutex lock; struct device *dev; - struct device_node *flash_node; u32 page_size; u8 addr_width; u8 erase_opcode; @@ -188,12 +186,12 @@ struct spi_nor { static inline void spi_nor_set_flash_node(struct spi_nor *nor, struct device_node *np) { - nor->flash_node = np; + mtd_set_of_node(&nor->mtd, np); } static inline struct device_node *spi_nor_get_flash_node(struct spi_nor *nor) { - return nor->flash_node; + return mtd_get_of_node(&nor->mtd); } /** -- cgit v1.2.3 From e270bca531b40cd0a143176eb093d173b9c6f418 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 30 Oct 2015 20:33:29 -0700 Subject: mtd: ofpart: drop 'of_node' partition parser data This field is no longer used anywhere, as it is superseded by mtd->dev.of_node. Signed-off-by: Brian Norris Reviewed-by: Boris Brezillon --- drivers/mtd/ofpart.c | 14 ++++---------- include/linux/mtd/partitions.h | 4 ---- 2 files changed, 4 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 7bf996a4cf5e..f78d2aea5545 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -37,11 +37,8 @@ static int parse_ofpart_partitions(struct mtd_info *master, bool dedicated = true; - /* - * of_node can be provided through auxiliary parser data or (preferred) - * by assigning the master device node - */ - mtd_node = data && data->of_node ? data->of_node : mtd_get_of_node(master); + /* Pull of_node from the master device node */ + mtd_node = mtd_get_of_node(master); if (!mtd_node) return 0; @@ -150,11 +147,8 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, } *part; const char *names; - /* - * of_node can be provided through auxiliary parser data or (preferred) - * by assigning the master device node - */ - dp = data && data->of_node ? data->of_node : mtd_get_of_node(master); + /* Pull of_node from the master device node */ + dp = mtd_get_of_node(master); if (!dp) return 0; diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index e742f34b67eb..773975a3c9e6 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -56,13 +56,9 @@ struct device_node; /** * struct mtd_part_parser_data - used to pass data to MTD partition parsers. * @origin: for RedBoot, start address of MTD device - * @of_node: for OF parsers, device node containing partitioning information. - * This field is deprecated, as the device node should simply be - * assigned to the master struct device. */ struct mtd_part_parser_data { unsigned long origin; - struct device_node *of_node; }; -- cgit v1.2.3 From 26add94cd535d1e000e7871fe69c7bb89e942d67 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 11 Nov 2015 17:05:56 -0800 Subject: mtd: partitions: kill unused ecclayout struct This field is not used. Reported here: http://lists.infradead.org/pipermail/linux-mtd/2015-October/062417.html Reported-by: Brian Foster Cc: Brian Foster Signed-off-by: Brian Norris Reviewed-by: Boris Brezillon --- include/linux/mtd/partitions.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 773975a3c9e6..8421520c10eb 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -41,7 +41,6 @@ struct mtd_partition { uint64_t size; /* partition size */ uint64_t offset; /* offset within the master MTD space */ uint32_t mask_flags; /* master MTD flags to mask out for this partition */ - struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only) */ }; #define MTDPART_OFS_RETAIN (-3) -- cgit v1.2.3 From 9eba47ddd8fee8a21f45e6e1d707103f040d90c7 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Mon, 16 Nov 2015 14:37:35 +0100 Subject: mtd: nand: add an mtd_to_nand() helper Some drivers are retrieving the nand_chip pointer using the container_of macro on a struct wrapping both the nand_chip and the mtd_info struct while the standard way of retrieving this pointer is through mtd->priv. Provide an helper to do that. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 5a9d1d4c2487..a4839b3f27da 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -719,6 +719,11 @@ struct nand_chip { void *priv; }; +static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) +{ + return mtd->priv; +} + /* * NAND Flash Manufacturer ID Codes */ -- cgit v1.2.3 From c67cbb839da9cc2757eabfa128556db6a2baf160 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 10 Nov 2015 12:15:27 -0800 Subject: mtd: spi-nor: provide default erase_sector implementation Some spi-nor drivers perform sector erase by duplicating their write_reg() command. Let's not require that the driver fill this out, and provide a default instead. Tested on m25p80.c and Medatek's MT8173 SPI NOR flash driver. Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 37 +++++++++++++++++++++++++++++++++---- include/linux/mtd/spi-nor.h | 3 ++- 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 16c9f5522b8f..a38ec01a1e06 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -38,6 +38,7 @@ #define CHIP_ERASE_2MB_READY_WAIT_JIFFIES (40UL * HZ) #define SPI_NOR_MAX_ID_LEN 6 +#define SPI_NOR_MAX_ADDR_WIDTH 4 struct flash_info { char *name; @@ -312,6 +313,29 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops) mutex_unlock(&nor->lock); } +/* + * Initiate the erasure of a single sector + */ +static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) +{ + u8 buf[SPI_NOR_MAX_ADDR_WIDTH]; + int i; + + if (nor->erase) + return nor->erase(nor, addr); + + /* + * Default implementation, if driver doesn't have a specialized HW + * control + */ + for (i = nor->addr_width - 1; i >= 0; i--) { + buf[i] = addr & 0xff; + addr >>= 8; + } + + return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); +} + /* * Erase an address range on the nor chip. The address range may extend * one or more erase sectors. Return an error is there is a problem erasing. @@ -371,10 +395,9 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) while (len) { write_enable(nor); - if (nor->erase(nor, addr)) { - ret = -EIO; + ret = spi_nor_erase_sector(nor, addr); + if (ret) goto erase_err; - } addr += mtd->erasesize; len -= mtd->erasesize; @@ -1138,7 +1161,7 @@ static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) static int spi_nor_check(struct spi_nor *nor) { if (!nor->dev || !nor->read || !nor->write || - !nor->read_reg || !nor->write_reg || !nor->erase) { + !nor->read_reg || !nor->write_reg) { pr_err("spi-nor: please fill all the necessary fields!\n"); return -EINVAL; } @@ -1340,6 +1363,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) nor->addr_width = 3; } + if (nor->addr_width > SPI_NOR_MAX_ADDR_WIDTH) { + dev_err(dev, "address width is too large: %u\n", + nor->addr_width); + return -EINVAL; + } + nor->read_dummy = spi_nor_read_dummy_cycles(nor); dev_info(dev, "%s (%lld Kbytes)\n", info->name, diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 955f268d159a..7bed97471e53 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -143,7 +143,8 @@ struct mtd_info; * @read: [DRIVER-SPECIFIC] read data from the SPI NOR * @write: [DRIVER-SPECIFIC] write data to the SPI NOR * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR - * at the offset @offs + * at the offset @offs; if not provided by the driver, + * spi-nor will send the erase opcode via write_reg() * @flash_lock: [FLASH-SPECIFIC] lock a region of the SPI NOR * @flash_unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR * @flash_is_locked: [FLASH-SPECIFIC] check if a region of the SPI NOR is -- cgit v1.2.3 From b9eab01125bf3cb6f5fbab1811402d16c9fcf4ec Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 11 Nov 2015 19:13:29 -0800 Subject: mtd: partitions: add module_mtd_part_parser() helper This can help eliminate some boilerplate by generating the module_init() and module_exit() functions, and by automatically assigning the module owner. Signed-off-by: Brian Norris --- drivers/mtd/mtdpart.c | 8 ++++++-- include/linux/mtd/partitions.h | 14 +++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 46dfbf5629c3..1fa3ca95d9c1 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -703,13 +703,17 @@ static struct mtd_part_parser *get_partition_parser(const char *name) #define put_partition_parser(p) do { module_put((p)->owner); } while (0) -void register_mtd_parser(struct mtd_part_parser *p) +int __register_mtd_parser(struct mtd_part_parser *p, struct module *owner) { + p->owner = owner; + spin_lock(&part_parser_lock); list_add(&p->list, &part_parsers); spin_unlock(&part_parser_lock); + + return 0; } -EXPORT_SYMBOL_GPL(register_mtd_parser); +EXPORT_SYMBOL_GPL(__register_mtd_parser); void deregister_mtd_parser(struct mtd_part_parser *p) { diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 8421520c10eb..d002d9b5d797 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -73,9 +73,21 @@ struct mtd_part_parser { struct mtd_part_parser_data *); }; -extern void register_mtd_parser(struct mtd_part_parser *parser); +extern int __register_mtd_parser(struct mtd_part_parser *parser, + struct module *owner); +#define register_mtd_parser(parser) __register_mtd_parser(parser, THIS_MODULE) + extern void deregister_mtd_parser(struct mtd_part_parser *parser); +/* + * module_mtd_part_parser() - Helper macro for MTD partition parsers that don't + * do anything special in module init/exit. Each driver may only use this macro + * once, and calling it replaces module_init() and module_exit(). + */ +#define module_mtd_part_parser(__mtd_part_parser) \ + module_driver(__mtd_part_parser, register_mtd_parser, \ + deregister_mtd_parser) + int mtd_is_partition(const struct mtd_info *mtd); int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length); -- cgit v1.2.3 From 2c81de771f38e54324ede3f24118f4852570b384 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Thu, 26 Nov 2015 09:05:04 +0100 Subject: mtd: spi-nor: include mtd.h header for struct mtd_info definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far struct spi_nor was using just a pointer to struct mtd_info so it wasn't needed to have it fully defined there. After recent change we embed whole struct so we need to include a proper header. Fixes: 1976367173a4 ("mtd: spi-nor: embed struct mtd_info within struct spi_nor") Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris --- include/linux/mtd/spi-nor.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 7bed97471e53..fac3f6f53981 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -12,6 +12,7 @@ #include #include +#include /* * Manufacturer IDs @@ -117,8 +118,6 @@ enum spi_nor_option_flags { SNOR_F_USE_FSR = BIT(0), }; -struct mtd_info; - /** * struct spi_nor - Structure for defining a the SPI NOR layer * @mtd: point to a mtd_info structure -- cgit v1.2.3 From fe7579d6122f2869d00b55842bca9e2a9be51607 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 24 Nov 2015 23:09:02 +0100 Subject: mtd: cfi: don't warn about broken geometry for !CONFIG_MTD The linux/mtd/map.h header file is included by a couple of platform specific files that are built even when CONFIG_MTD is disabled, and we always get warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work" in that case. This adds an #ifdef around the pointless warning, as everything is really fine when we don't build the drivers anyway. Signed-off-by: Arnd Bergmann Signed-off-by: Brian Norris --- include/linux/mtd/map.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 366cf77953b5..58f3ba709ade 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -142,7 +142,9 @@ #endif #ifndef map_bankwidth +#ifdef CONFIG_MTD #warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work" +#endif static inline int map_bankwidth(void *map) { BUG(); -- cgit v1.2.3 From de64aa9ec129ba627634088f662a4d09e356ddb6 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Mon, 23 Nov 2015 11:23:07 +0100 Subject: mtd: nand: fix ONFI parameter page layout src_ssync_features field is only 1 byte large, and the 4th reserved area is actually 8 bytes large. Fixes: d1e1f4e42b5 ("mtd: nand: add support for reading ONFI parameters from NAND device") Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 056d1650eb89..eaf48b5a95dd 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -276,7 +276,7 @@ struct nand_onfi_params { __le16 t_r; __le16 t_ccs; __le16 src_sync_timing_mode; - __le16 src_ssync_features; + u8 src_ssync_features; __le16 clk_pin_capacitance_typ; __le16 io_pin_capacitance_typ; __le16 input_pin_capacitance_typ; @@ -284,7 +284,7 @@ struct nand_onfi_params { u8 driver_strength_support; __le16 t_int_r; __le16 t_ald; - u8 reserved4[7]; + u8 reserved4[8]; /* vendor */ __le16 vendor_revision; -- cgit v1.2.3 From 74e98be45fe069fcdb00f35eccbb179309ab65cd Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 1 Dec 2015 11:08:32 -0800 Subject: mtd: nand: fix typo (t_ald -> t_adl) It's "ADL" ("ALE to data loading" time) not "ALD". Signed-off-by: Brian Norris Reviewed-by: Boris Brezillon --- include/linux/mtd/nand.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index eaf48b5a95dd..fad634ea1685 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -283,7 +283,7 @@ struct nand_onfi_params { u8 input_pin_capacitance_max; u8 driver_strength_support; __le16 t_int_r; - __le16 t_ald; + __le16 t_adl; u8 reserved4[8]; /* vendor */ @@ -407,7 +407,7 @@ struct nand_jedec_params { __le16 input_pin_capacitance_typ; __le16 clk_pin_capacitance_typ; u8 driver_strength_support; - __le16 t_ald; + __le16 t_adl; u8 reserved4[36]; /* ECC and endurance block */ -- cgit v1.2.3 From ed4f85c03cc7460a2f76afb73c22b8894b44ee20 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 1 Dec 2015 12:03:06 +0100 Subject: mtd: nand: embed an mtd_info structure into nand_chip Currently all NAND controller drivers are providing both the mtd_info and nand_chip struct and then let the NAND subsystem to initialize a few things before registering the mtd instance to the MTD layer. Embed an mtd_info field into nand_chip to add some consistency to all NAND controller drivers. This change will also help factorizing boilerplate code copied in all NAND drivers. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index fad634ea1685..d6710575ddb6 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -540,6 +540,7 @@ struct nand_buffers { /** * struct nand_chip - NAND Private Flash Chip Data + * @mtd: MTD device registered to the MTD framework * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the * flash device * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the @@ -640,6 +641,7 @@ struct nand_buffers { */ struct nand_chip { + struct mtd_info mtd; void __iomem *IO_ADDR_R; void __iomem *IO_ADDR_W; -- cgit v1.2.3 From ffd014f43fdcb6edb5a7f302de1e717e8c0673d5 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Tue, 1 Dec 2015 12:03:07 +0100 Subject: mtd: nand: add nand_to_mtd() helper Add a new helper to retrieve the MTD device attached to a NAND chip. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index d6710575ddb6..b614ed2105ac 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -737,6 +737,11 @@ static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) return mtd->priv; } +static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) +{ + return &chip->mtd; +} + /* * NAND Flash Manufacturer ID Codes */ -- cgit v1.2.3 From b9adf469f8abb8a66f5795bbd8fe50fe201a14a1 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 4 Dec 2015 15:25:14 -0800 Subject: mtd: partitions: make parsers return 'const' partition arrays We only want to modify these arrays inside the parser "drivers", so the drivers should construct them however they like, then return them as immutable arrays. This will make other refactorings easier. Signed-off-by: Brian Norris Reviewed-by: Boris Brezillon --- drivers/mtd/afs.c | 2 +- drivers/mtd/ar7part.c | 2 +- drivers/mtd/bcm47xxpart.c | 2 +- drivers/mtd/bcm63xxpart.c | 2 +- drivers/mtd/cmdlinepart.c | 2 +- drivers/mtd/ofpart.c | 4 ++-- drivers/mtd/redboot.c | 2 +- include/linux/mtd/partitions.h | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index e02dae3b739b..d61b7edfc938 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -162,7 +162,7 @@ afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr) } static int parse_afs_partitions(struct mtd_info *mtd, - struct mtd_partition **pparts, + const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { struct mtd_partition *parts; diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index 9203b96fd789..90575deff0ae 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -43,7 +43,7 @@ struct ar7_bin_rec { }; static int create_mtd_partitions(struct mtd_info *master, - struct mtd_partition **pparts, + const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { struct ar7_bin_rec header; diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 92a6dd18198b..8282f47bcf5d 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -82,7 +82,7 @@ out_default: } static int bcm47xxpart_parse(struct mtd_info *master, - struct mtd_partition **pparts, + const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { struct mtd_partition *parts; diff --git a/drivers/mtd/bcm63xxpart.c b/drivers/mtd/bcm63xxpart.c index cf02135320bc..440936998593 100644 --- a/drivers/mtd/bcm63xxpart.c +++ b/drivers/mtd/bcm63xxpart.c @@ -68,7 +68,7 @@ static int bcm63xx_detect_cfe(struct mtd_info *master) } static int bcm63xx_parse_cfe_partitions(struct mtd_info *master, - struct mtd_partition **pparts, + const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { /* CFE, NVRAM and global Linux are always present */ diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 420489864bc2..fbd5affc0acf 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -304,7 +304,7 @@ static int mtdpart_setup_real(char *s) * the first one in the chain if a NULL mtd_id is passed in. */ static int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, + const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { unsigned long long offset; diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index c7df2f1dd6b8..ede407d6e106 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -26,7 +26,7 @@ static bool node_has_compatible(struct device_node *pp) } static int parse_ofpart_partitions(struct mtd_info *master, - struct mtd_partition **pparts, + const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { struct mtd_partition *parts; @@ -145,7 +145,7 @@ static struct mtd_part_parser ofpart_parser = { }; static int parse_ofoldpart_partitions(struct mtd_info *master, - struct mtd_partition **pparts, + const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { struct mtd_partition *parts; diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 11c3447eb8ff..7623ac5fc586 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -57,7 +57,7 @@ static inline int redboot_checksum(struct fis_image_desc *img) } static int parse_redboot_partitions(struct mtd_info *master, - struct mtd_partition **pparts, + const struct mtd_partition **pparts, struct mtd_part_parser_data *data) { int nrparts = 0; diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index d002d9b5d797..6185536daacc 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -69,7 +69,7 @@ struct mtd_part_parser { struct list_head list; struct module *owner; const char *name; - int (*parse_fn)(struct mtd_info *, struct mtd_partition **, + int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, struct mtd_part_parser_data *); }; -- cgit v1.2.3 From 07fd2f871c5e3dfb8ff5eb9c4b44fdb4cf1aeff5 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 4 Dec 2015 15:25:17 -0800 Subject: mtd: partitions: pass around 'mtd_partitions' wrapper struct For some of the core partitioning code, it helps to keep info about the parsed partition (and who parsed them) together in one place. Signed-off-by: Brian Norris --- drivers/mtd/mtdcore.c | 33 +++++++++++++++++++-------------- drivers/mtd/mtdcore.h | 5 ++++- drivers/mtd/mtdpart.c | 15 ++++++++------- include/linux/mtd/partitions.h | 7 +++++++ 4 files changed, 38 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 868ee52d5063..20b2b38247b6 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -532,9 +532,10 @@ out_error: } static int mtd_add_device_partitions(struct mtd_info *mtd, - const struct mtd_partition *real_parts, - int nbparts) + struct mtd_partitions *parts) { + const struct mtd_partition *real_parts = parts->parts; + int nbparts = parts->nr_parts; int ret; if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { @@ -588,23 +589,27 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, const struct mtd_partition *parts, int nr_parts) { + struct mtd_partitions parsed; int ret; - const struct mtd_partition *real_parts = NULL; - ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data); - if (ret <= 0 && nr_parts && parts) { - real_parts = parts; - ret = nr_parts; - } - /* Didn't come up with either parsed OR fallback partitions */ - if (ret < 0) { + memset(&parsed, 0, sizeof(parsed)); + + ret = parse_mtd_partitions(mtd, types, &parsed, parser_data); + if ((ret < 0 || parsed.nr_parts == 0) && parts && nr_parts) { + /* Fall back to driver-provided partitions */ + parsed = (struct mtd_partitions){ + .parts = parts, + .nr_parts = nr_parts, + }; + } else if (ret < 0) { + /* Didn't come up with parsed OR fallback partitions */ pr_info("mtd: failed to find partitions; one or more parsers reports errors (%d)\n", ret); /* Don't abort on errors; we can still use unpartitioned MTD */ - ret = 0; + memset(&parsed, 0, sizeof(parsed)); } - ret = mtd_add_device_partitions(mtd, real_parts, ret); + ret = mtd_add_device_partitions(mtd, &parsed); if (ret) goto out; @@ -625,8 +630,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, out: /* Cleanup any parsed partitions */ - if (real_parts != parts) - kfree(real_parts); + if (parsed.parser) + kfree(parsed.parts); return ret; } EXPORT_SYMBOL_GPL(mtd_device_parse_register); diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index 537ec66f9cfd..ce81cc2002f4 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -10,8 +10,11 @@ int add_mtd_device(struct mtd_info *mtd); int del_mtd_device(struct mtd_info *mtd); int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); int del_mtd_partitions(struct mtd_info *); + +struct mtd_partitions; + int parse_mtd_partitions(struct mtd_info *master, const char * const *types, - const struct mtd_partition **pparts, + struct mtd_partitions *pparts, struct mtd_part_parser_data *data); int __init init_mtdchar(void); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 898999c5aea1..53517d7653cb 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -743,7 +743,7 @@ static const char * const default_mtd_part_types[] = { * parse_mtd_partitions - parse MTD partitions * @master: the master partition (describes whole MTD device) * @types: names of partition parsers to try or %NULL - * @pparts: array of partitions found is returned here + * @pparts: info about partitions found is returned here * @data: MTD partition parser-specific data * * This function tries to find partition on MTD device @master. It uses MTD @@ -755,12 +755,11 @@ static const char * const default_mtd_part_types[] = { * * This function may return: * o a negative error code in case of failure - * o zero if no partitions were found - * o a positive number of found partitions, in which case on exit @pparts will - * point to an array containing this number of &struct mtd_info objects. + * o zero otherwise, and @pparts will describe the partitions, number of + * partitions, and the parser which parsed them */ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, - const struct mtd_partition **pparts, + struct mtd_partitions *pparts, struct mtd_part_parser_data *data) { struct mtd_part_parser *parser; @@ -778,14 +777,16 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, parser ? parser->name : NULL); if (!parser) continue; - ret = (*parser->parse_fn)(master, pparts, data); + ret = (*parser->parse_fn)(master, &pparts->parts, data); pr_debug("%s: parser %s: %i\n", master->name, parser->name, ret); mtd_part_parser_put(parser); if (ret > 0) { printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", ret, parser->name, master->name); - return ret; + pparts->nr_parts = ret; + pparts->parser = parser; + return 0; } /* * Stash the first error we see; only report it if no parser diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index 6185536daacc..cceaf7bd1537 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -73,6 +73,13 @@ struct mtd_part_parser { struct mtd_part_parser_data *); }; +/* Container for passing around a set of parsed partitions */ +struct mtd_partitions { + const struct mtd_partition *parts; + int nr_parts; + const struct mtd_part_parser *parser; +}; + extern int __register_mtd_parser(struct mtd_part_parser *parser, struct module *owner); #define register_mtd_parser(parser) __register_mtd_parser(parser, THIS_MODULE) -- cgit v1.2.3 From adc83bf8896353603213754353dd66dae69e3d7f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 9 Dec 2015 10:24:03 -0800 Subject: mtd: partitions: support a cleanup callback for parsers If partition parsers need to clean up their resources, we shouldn't assume that all memory will fit in a single kmalloc() that the caller can kfree(). We should allow the parser to provide a proper cleanup routine. Note that this means we need to keep a hold on the parser's module for a bit longer, and release it later with mtd_part_parser_put(). Alongside this, define a default callback that we'll automatically use if the parser doesn't provide one, so we can still retain the old behavior. Signed-off-by: Brian Norris Reviewed-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 3 +-- drivers/mtd/mtdcore.h | 2 ++ drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++++++++++-- include/linux/mtd/partitions.h | 1 + 4 files changed, 37 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 20b2b38247b6..89d811e7b04a 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -630,8 +630,7 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, out: /* Cleanup any parsed partitions */ - if (parsed.parser) - kfree(parsed.parts); + mtd_part_parser_cleanup(&parsed); return ret; } EXPORT_SYMBOL_GPL(mtd_device_parse_register); diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index ce81cc2002f4..55fdb8e1fd2a 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -17,6 +17,8 @@ int parse_mtd_partitions(struct mtd_info *master, const char * const *types, struct mtd_partitions *pparts, struct mtd_part_parser_data *data); +void mtd_part_parser_cleanup(struct mtd_partitions *parts); + int __init init_mtdchar(void); void __exit cleanup_mtdchar(void); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 53517d7653cb..10bf304027dd 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -709,10 +709,23 @@ static inline void mtd_part_parser_put(const struct mtd_part_parser *p) module_put(p->owner); } +/* + * Many partition parsers just expected the core to kfree() all their data in + * one chunk. Do that by default. + */ +static void mtd_part_parser_cleanup_default(const struct mtd_partition *pparts, + int nr_parts) +{ + kfree(pparts); +} + int __register_mtd_parser(struct mtd_part_parser *p, struct module *owner) { p->owner = owner; + if (!p->cleanup) + p->cleanup = &mtd_part_parser_cleanup_default; + spin_lock(&part_parser_lock); list_add(&p->list, &part_parsers); spin_unlock(&part_parser_lock); @@ -756,7 +769,9 @@ static const char * const default_mtd_part_types[] = { * This function may return: * o a negative error code in case of failure * o zero otherwise, and @pparts will describe the partitions, number of - * partitions, and the parser which parsed them + * partitions, and the parser which parsed them. Caller must release + * resources with mtd_part_parser_cleanup() when finished with the returned + * data. */ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, struct mtd_partitions *pparts, @@ -780,7 +795,6 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, ret = (*parser->parse_fn)(master, &pparts->parts, data); pr_debug("%s: parser %s: %i\n", master->name, parser->name, ret); - mtd_part_parser_put(parser); if (ret > 0) { printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", ret, parser->name, master->name); @@ -788,6 +802,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, pparts->parser = parser; return 0; } + mtd_part_parser_put(parser); /* * Stash the first error we see; only report it if no parser * succeeds @@ -798,6 +813,22 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types, return err; } +void mtd_part_parser_cleanup(struct mtd_partitions *parts) +{ + const struct mtd_part_parser *parser; + + if (!parts) + return; + + parser = parts->parser; + if (parser) { + if (parser->cleanup) + parser->cleanup(parts->parts, parts->nr_parts); + + mtd_part_parser_put(parser); + } +} + int mtd_is_partition(const struct mtd_info *mtd) { struct mtd_part *part; diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index cceaf7bd1537..70736e1e6c8f 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -71,6 +71,7 @@ struct mtd_part_parser { const char *name; int (*parse_fn)(struct mtd_info *, const struct mtd_partition **, struct mtd_part_parser_data *); + void (*cleanup)(const struct mtd_partition *pparts, int nr_parts); }; /* Container for passing around a set of parsed partitions */ -- cgit v1.2.3 From 665d2c2848f14c0c2a2e89192bde9073c4d352f7 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 8 Dec 2015 17:04:59 -0800 Subject: mtd: bcm47xxnflash: really unregister NAND on device removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The field bcma_nflash::mtd is never set to be non-zero anywhere, but we test for it in the removal path. So the MTD is never unregistered. Also, we should use nand_release(), not mtd_device_unregister(). Finally, we don't need to use the 'platdata' for stashing/retrieving our *driver* data -- that's what *_{get,set}_drvdata() are for. So, kill off bcm_nflash::mtd, and stash the struct bcm47xxnflash in drvdata instead. Also move the forward declaration of mtd_info up a bit, since struct bcma_sflash should be using it. Caught while inspecting other changes being made to this driver. Compile tested only. Signed-off-by: Brian Norris Cc: "Rafał Miłecki" Cc: linux-wireless@vger.kernel.org Acked-by: Boris Brezillon --- drivers/mtd/nand/bcm47xxnflash/main.c | 7 ++++--- include/linux/bcma/bcma_driver_chipcommon.h | 6 ++---- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/bcm47xxnflash/main.c b/drivers/mtd/nand/bcm47xxnflash/main.c index 9ba0c0f2cd9b..0b3acc439181 100644 --- a/drivers/mtd/nand/bcm47xxnflash/main.c +++ b/drivers/mtd/nand/bcm47xxnflash/main.c @@ -49,6 +49,8 @@ static int bcm47xxnflash_probe(struct platform_device *pdev) return err; } + platform_set_drvdata(pdev, b47n); + err = mtd_device_parse_register(&b47n->mtd, probes, NULL, NULL, 0); if (err) { pr_err("Failed to register MTD device: %d\n", err); @@ -60,10 +62,9 @@ static int bcm47xxnflash_probe(struct platform_device *pdev) static int bcm47xxnflash_remove(struct platform_device *pdev) { - struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev); + struct bcm47xxnflash *nflash = platform_get_drvdata(pdev); - if (nflash->mtd) - mtd_device_unregister(nflash->mtd); + nand_release(&nflash->mtd); return 0; } diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index cf038431a5cc..db51a6ffb7d6 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -579,6 +579,8 @@ struct bcma_pflash { }; #ifdef CONFIG_BCMA_SFLASH +struct mtd_info; + struct bcma_sflash { bool present; u32 window; @@ -592,13 +594,9 @@ struct bcma_sflash { #endif #ifdef CONFIG_BCMA_NFLASH -struct mtd_info; - struct bcma_nflash { bool present; bool boot; /* This is the flash the SoC boots from */ - - struct mtd_info *mtd; }; #endif -- cgit v1.2.3 From 9c9eef89ec74433f00593938f8af5113383d898a Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Thu, 10 Dec 2015 09:00:23 +0100 Subject: mtd: nand: sh_flctl: use the mtd instance embedded in struct nand_chip struct nand_chip now embeds an mtd device. Make use of this mtd instance. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/nand/sh_flctl.c | 8 ++++---- include/linux/mtd/sh_flctl.h | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 57dc52578e07..0ec4b04b3536 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -607,13 +607,13 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr) case FL_REPAIRABLE: dev_info(&flctl->pdev->dev, "applied ecc on page 0x%x", page_addr); - flctl->mtd.ecc_stats.corrected++; + mtd->ecc_stats.corrected++; break; case FL_ERROR: dev_warn(&flctl->pdev->dev, "page 0x%x contains corrupted data\n", page_addr); - flctl->mtd.ecc_stats.failed++; + mtd->ecc_stats.failed++; break; default: ; @@ -1120,8 +1120,8 @@ static int flctl_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, flctl); - flctl_mtd = &flctl->mtd; nand = &flctl->chip; + flctl_mtd = nand_to_mtd(nand); nand_set_flash_node(nand, pdev->dev.of_node); flctl_mtd->priv = nand; flctl_mtd->dev.parent = &pdev->dev; @@ -1178,7 +1178,7 @@ static int flctl_remove(struct platform_device *pdev) struct sh_flctl *flctl = platform_get_drvdata(pdev); flctl_release_dma(flctl); - nand_release(&flctl->mtd); + nand_release(nand_to_mtd(&flctl->chip)); pm_runtime_disable(&pdev->dev); return 0; diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 1c28f8879b1c..76e3e88bedfe 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -143,7 +143,6 @@ enum flctl_ecc_res_t { struct dma_chan; struct sh_flctl { - struct mtd_info mtd; struct nand_chip chip; struct platform_device *pdev; struct dev_pm_qos_request pm_qos; @@ -186,7 +185,7 @@ struct sh_flctl_platform_data { static inline struct sh_flctl *mtd_to_flctl(struct mtd_info *mtdinfo) { - return container_of(mtdinfo, struct sh_flctl, mtd); + return container_of(mtd_to_nand(mtdinfo), struct sh_flctl, chip); } #endif /* __SH_FLCTL_H__ */ -- cgit v1.2.3 From 2d3b77bac34bf99d7fdfd712ec2dc4317b3e850b Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Thu, 10 Dec 2015 09:00:33 +0100 Subject: mtd: nand: update mtd_to_nand() Now that all drivers are using the mtd instance embedded in the nand_chip struct we can safely update the mtd_to_nand() implementation to use the container_of macro instead of returning the content of mtd->priv. This will allow us to remove mtd->priv = chip assignments done in all NAND controller drivers. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index b614ed2105ac..9cb7ace6fb1f 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -734,7 +734,7 @@ static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) { - return mtd->priv; + return container_of(mtd, struct nand_chip, mtd); } static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) -- cgit v1.2.3 From 29574ede097438c560e8115caff9b6b8668730be Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Thu, 10 Dec 2015 09:00:38 +0100 Subject: mtd: nand: kill the chip->flash_node field Now that the nand_chip struct directly embeds an mtd_info struct we can get rid of the ->flash_node field and forward set/get_flash_node requests to the MTD layer. As a side effect, we no longer need the mtd_set_of_node() call done in nand_dt_init(). Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 3 --- include/linux/mtd/nand.h | 7 ++----- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ae3fd2a8c2f5..8bb8ebd62aaa 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3945,9 +3945,6 @@ static int nand_dt_init(struct nand_chip *chip) if (!dn) return 0; - /* MTD can automatically handle DT partitions, etc. */ - mtd_set_of_node(nand_to_mtd(chip), dn); - if (of_get_nand_bus_width(dn) == 16) chip->options |= NAND_BUSWIDTH_16; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 9cb7ace6fb1f..2bee2e42ae2f 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -545,7 +545,6 @@ struct nand_buffers { * flash device * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the * flash device. - * @flash_node: [BOARDSPECIFIC] device node describing this instance * @read_byte: [REPLACEABLE] read one byte from the chip * @read_word: [REPLACEABLE] read one word from the chip * @write_byte: [REPLACEABLE] write a single byte to the chip on the @@ -645,8 +644,6 @@ struct nand_chip { void __iomem *IO_ADDR_R; void __iomem *IO_ADDR_W; - struct device_node *flash_node; - uint8_t (*read_byte)(struct mtd_info *mtd); u16 (*read_word)(struct mtd_info *mtd); void (*write_byte)(struct mtd_info *mtd, uint8_t byte); @@ -724,12 +721,12 @@ struct nand_chip { static inline void nand_set_flash_node(struct nand_chip *chip, struct device_node *np) { - chip->flash_node = np; + mtd_set_of_node(&chip->mtd, np); } static inline struct device_node *nand_get_flash_node(struct nand_chip *chip) { - return chip->flash_node; + return mtd_get_of_node(&chip->mtd); } static inline struct nand_chip *mtd_to_nand(struct mtd_info *mtd) -- cgit v1.2.3 From 8142b47ef33c655a34e08efd46b65732fe190675 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Mon, 14 Dec 2015 16:13:31 +0100 Subject: mtd: nand: remove unused and buggy get_platform_nandchip() helper function Nobody uses the get_platform_nandchip() helper function which is supposed to return a pointer to a platform_nand_chip struct from an mtd_info pointer. Moreover, this function is buggy since the introduction of the plat_nand layer (chip->priv is now storing a pointer to an intermediate plat_nand_data structure allocated in plat_nand_probe(), and we have no way to retrieve a pointer to the provided platform_nand_chip struct from this plat_nand_data pointer). While we are at it, remove the useless (and buggy, since it's pointing to something stored on the stack) data->chip.priv assignment. Signed-off-by: Boris Brezillon Fixes: 711fdf627ce1 ("[MTD] [NAND] platform NAND driver: add driver") Cc: Vitaly Wool Signed-off-by: Brian Norris --- drivers/mtd/nand/plat_nand.c | 1 - include/linux/mtd/nand.h | 9 --------- 2 files changed, 10 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index dc88a58d5cde..a0e26dea1424 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -56,7 +56,6 @@ static int plat_nand_probe(struct platform_device *pdev) if (IS_ERR(data->io_base)) return PTR_ERR(data->io_base); - data->chip.priv = &data; nand_set_flash_node(&data->chip, pdev->dev.of_node); mtd = nand_to_mtd(&data->chip); mtd->dev.parent = &pdev->dev; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 2bee2e42ae2f..3e92be1d2d43 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -927,15 +927,6 @@ struct platform_nand_data { struct platform_nand_ctrl ctrl; }; -/* Some helpers to access the data structures */ -static inline -struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - return chip->priv; -} - /* return the supported features. */ static inline int onfi_feature(struct nand_chip *chip) { -- cgit v1.2.3 From 1873315fb156cbc8e46f28e8b128f17ff6c31728 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Dec 2015 16:38:12 +0100 Subject: mtd: sh_flctl: pass FIFO as physical address By convention, the FIFO address we pass using dmaengine_slave_config is a physical address in the form that is understood by the DMA engine, as a dma_addr_t, phys_addr_t or resource_size_t. The sh_flctl driver however passes a virtual __iomem address that gets cast to dma_addr_t in the slave driver. This happens to work on shmobile because that platform sets up an identity mapping for its MMIO regions, but such code is not portable to other platforms, and prevents us from ever changing the platform mapping or reusing the driver on other architectures like ARM64 that might not have the mapping. We also get a warning about a type mismatch for the case that dma_addr_t is wider than a pointer, i.e. when CONFIG_LPAE is set: drivers/mtd/nand/sh_flctl.c: In function 'flctl_setup_dma': drivers/mtd/nand/sh_flctl.c:163:17: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl); This changes the driver to instead pass the physical address of the FIFO that is extracted from the MMIO resource, making the code more portable and avoiding the warning. Signed-off-by: Arnd Bergmann Signed-off-by: Brian Norris --- drivers/mtd/nand/sh_flctl.c | 5 +++-- include/linux/mtd/sh_flctl.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index c7126b75fb01..4814402902f9 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -160,7 +160,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl) memset(&cfg, 0, sizeof(cfg)); cfg.direction = DMA_MEM_TO_DEV; - cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl); + cfg.dst_addr = flctl->fifo; cfg.src_addr = 0; ret = dmaengine_slave_config(flctl->chan_fifo0_tx, &cfg); if (ret < 0) @@ -176,7 +176,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl) cfg.direction = DMA_DEV_TO_MEM; cfg.dst_addr = 0; - cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl); + cfg.src_addr = flctl->fifo; ret = dmaengine_slave_config(flctl->chan_fifo0_rx, &cfg); if (ret < 0) goto err; @@ -1095,6 +1095,7 @@ static int flctl_probe(struct platform_device *pdev) flctl->reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(flctl->reg)) return PTR_ERR(flctl->reg); + flctl->fifo = res->start + 0x24; /* FLDTFIFO */ irq = platform_get_irq(pdev, 0); if (irq < 0) { diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index 76e3e88bedfe..2251add65fa7 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h @@ -147,6 +147,7 @@ struct sh_flctl { struct platform_device *pdev; struct dev_pm_qos_request pm_qos; void __iomem *reg; + resource_size_t fifo; uint8_t done_buff[2048 + 64]; /* max size 2048 + 64 */ int read_bytes; -- cgit v1.2.3 From 6e9411923b8f4c0e568cbae0f35b7ee4eb989914 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Wed, 30 Dec 2015 20:32:03 +0100 Subject: mtd: nand: return consistent error codes in ecc.correct() implementations The error code returned by the ecc.correct() are not consistent over the all implementations. Document the expected behavior in include/linux/mtd/nand.h and fix offending implementations. [Brian: this looks like a bugfix for the ECC reporting in the bf5xx_nand driver, but we haven't seen any testing results for it] Signed-off-by: Boris Brezillon Tested-by: Franklin S Cooper Jr. Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 2 +- drivers/mtd/nand/bf5xx_nand.c | 20 ++++++++++++++------ drivers/mtd/nand/davinci_nand.c | 6 +++--- drivers/mtd/nand/jz4740_nand.c | 4 ++-- drivers/mtd/nand/mxc_nand.c | 4 ++-- drivers/mtd/nand/nand_bch.c | 2 +- drivers/mtd/nand/nand_ecc.c | 2 +- drivers/mtd/nand/omap2.c | 6 +++--- drivers/mtd/nand/r852.c | 4 ++-- include/linux/mtd/nand.h | 8 +++++++- include/linux/mtd/nand_bch.h | 2 +- 11 files changed, 37 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 18c4e14ec29f..b216bf521349 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1445,7 +1445,7 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, * We can't correct so many errors */ dev_dbg(host->dev, "atmel_nand : multiple errors detected." " Unable to correct.\n"); - return -EIO; + return -EBADMSG; } /* if there's a single bit error : we can correct it */ diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index 9514e136542f..89d9414c5593 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c @@ -252,7 +252,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, */ if (hweight32(syndrome[0]) == 1) { dev_err(info->device, "ECC data was incorrect!\n"); - return 1; + return -EBADMSG; } syndrome[1] = (calced & 0x7FF) ^ (stored & 0x7FF); @@ -285,7 +285,7 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, data = data ^ (0x1 << failing_bit); *(dat + failing_byte) = data; - return 0; + return 1; } /* @@ -298,26 +298,34 @@ static int bf5xx_nand_correct_data_256(struct mtd_info *mtd, u_char *dat, dev_err(info->device, "Please discard data, mark bad block\n"); - return 1; + return -EBADMSG; } static int bf5xx_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { struct nand_chip *chip = mtd_to_nand(mtd); - int ret; + int ret, bitflips = 0; ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + if (ret < 0) + return ret; + + bitflips = ret; /* If ecc size is 512, correct second 256 bytes */ if (chip->ecc.size == 512) { dat += 256; read_ecc += 3; calc_ecc += 3; - ret |= bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + ret = bf5xx_nand_correct_data_256(mtd, dat, read_ecc, calc_ecc); + if (ret < 0) + return ret; + + bitflips += ret; } - return ret; + return bitflips; } static void bf5xx_nand_enable_hwecc(struct mtd_info *mtd, int mode) diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 3b49fe86625d..ddb73c331936 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -207,7 +207,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat, dat[diff >> (12 + 3)] ^= BIT((diff >> 12) & 7); return 1; } else { - return -1; + return -EBADMSG; } } else if (!(diff & (diff - 1))) { /* Single bit ECC error in the ECC itself, @@ -215,7 +215,7 @@ static int nand_davinci_correct_1bit(struct mtd_info *mtd, u_char *dat, return 1; } else { /* Uncorrectable error */ - return -1; + return -EBADMSG; } } @@ -391,7 +391,7 @@ compare: return 0; case 1: /* five or more errors detected */ davinci_nand_readl(info, NAND_ERR_ERRVAL1_OFFSET); - return -EIO; + return -EBADMSG; case 2: /* error addresses computed */ case 3: num_errors = 1 + ((fsr >> 16) & 0x03); diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index a2363d33cecc..adccae3da120 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -254,7 +254,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout); if (timeout == 0) - return -1; + return -ETIMEDOUT; reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); reg &= ~JZ_NAND_ECC_CTRL_ENABLE; @@ -262,7 +262,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, if (status & JZ_NAND_STATUS_ERROR) { if (status & JZ_NAND_STATUS_UNCOR_ERROR) - return -1; + return -EBADMSG; error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 95400992c3e9..66e56bb22c0f 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -674,7 +674,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); - return -1; + return -EBADMSG; } return 0; @@ -701,7 +701,7 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat, err = ecc_stat & ecc_bit_mask; if (err > err_limit) { printk(KERN_WARNING "UnCorrectable RS-ECC Error\n"); - return -1; + return -EBADMSG; } else { ret += err; } diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index e5758d885943..a87c1b628dfc 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -98,7 +98,7 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, } } else if (count < 0) { printk(KERN_ERR "ecc unrecoverable error\n"); - count = -1; + count = -EBADMSG; } return count; } diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index e6129851bfd8..d1770b066396 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *buf, return 1; /* error in ECC data; no action needed */ pr_err("%s: uncorrectable ECC error\n", __func__); - return -1; + return -EBADMSG; } EXPORT_SYMBOL(__nand_correct_data); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index e9cbbc63c566..c553f78ab83f 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -826,12 +826,12 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ case 1: /* Uncorrectable error */ pr_debug("ECC UNCORRECTED_ERROR 1\n"); - return -1; + return -EBADMSG; case 11: /* UN-Correctable error */ pr_debug("ECC UNCORRECTED_ERROR B\n"); - return -1; + return -EBADMSG; case 12: /* Correctable error */ @@ -861,7 +861,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ return 0; } pr_debug("UNCORRECTED_ERROR default\n"); - return -1; + return -EBADMSG; } } diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index cb0bf09214d5..5b15f2faee38 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -477,7 +477,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, if (dev->dma_error) { dev->dma_error = 0; - return -1; + return -EIO; } r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS); @@ -491,7 +491,7 @@ static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, /* ecc uncorrectable error */ if (ecc_status & R852_ECC_FAIL) { dbg("ecc: unrecoverable error, in half %d", i); - error = -1; + error = -EBADMSG; goto exit; } diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 3e92be1d2d43..518958115182 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -456,7 +456,13 @@ struct nand_hw_control { * @hwctl: function to control hardware ECC generator. Must only * be provided if an hardware ECC is available * @calculate: function for ECC calculation or readback from ECC hardware - * @correct: function for ECC correction, matching to ECC generator (sw/hw) + * @correct: function for ECC correction, matching to ECC generator (sw/hw). + * Should return a positive number representing the number of + * corrected bitflips, -EBADMSG if the number of bitflips exceed + * ECC strength, or any other error code if the error is not + * directly related to correction. + * If -EBADMSG is returned the input buffers should be left + * untouched. * @read_page_raw: function to read a raw page without ECC. This function * should hide the specific layout used by the ECC * controller and always return contiguous in-band and diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h index 74acf5367556..fb0bc3420a10 100644 --- a/include/linux/mtd/nand_bch.h +++ b/include/linux/mtd/nand_bch.h @@ -55,7 +55,7 @@ static inline int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { - return -1; + return -ENOTSUPP; } static inline struct nand_bch_control * -- cgit v1.2.3 From 40cbe6eee97b706f27bcc4c6aa1018bbe4f1e577 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Wed, 30 Dec 2015 20:32:04 +0100 Subject: mtd: nand: use nand_check_erased_ecc_chunk in default ECC read functions The default NAND read functions are relying on the underlying controller driver to correct bitflips, but some of those controllers cannot properly fix bitflips in erased pages. Check for bitflips in erased pages in default core functions if the driver delegated the this check by setting the NAND_ECC_GENERIC_ERASED_CHECK flag. Signed-off-by: Boris Brezillon Tested-by: Franklin S Cooper Jr. Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 53 ++++++++++++++++++++++++++++++++++++++------ include/linux/mtd/nand.h | 10 +++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 50514f2501bb..f2c8ff398d6c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1426,6 +1426,16 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, chip->ecc.size, + &chip->buffers->ecccode[i], + chip->ecc.bytes, + NULL, 0, + chip->ecc.strength); + } + if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -1475,6 +1485,15 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, int stat; stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, eccsize, + &ecc_code[i], eccbytes, + NULL, 0, + chip->ecc.strength); + } + if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -1527,6 +1546,15 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, chip->ecc.calculate(mtd, p, &ecc_calc[i]); stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, eccsize, + &ecc_code[i], eccbytes, + NULL, 0, + chip->ecc.strength); + } + if (stat < 0) { mtd->ecc_stats.failed++; } else { @@ -1554,6 +1582,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; + int eccpadbytes = eccbytes + chip->ecc.prepad + chip->ecc.postpad; uint8_t *p = buf; uint8_t *oob = chip->oob_poi; unsigned int max_bitflips = 0; @@ -1573,19 +1602,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, chip->read_buf(mtd, oob, eccbytes); stat = chip->ecc.correct(mtd, p, oob, NULL); - if (stat < 0) { - mtd->ecc_stats.failed++; - } else { - mtd->ecc_stats.corrected += stat; - max_bitflips = max_t(unsigned int, max_bitflips, stat); - } - oob += eccbytes; if (chip->ecc.postpad) { chip->read_buf(mtd, oob, chip->ecc.postpad); oob += chip->ecc.postpad; } + + if (stat == -EBADMSG && + (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) { + /* check for empty pages with bitflips */ + stat = nand_check_erased_ecc_chunk(p, chip->ecc.size, + oob - eccpadbytes, + eccpadbytes, + NULL, 0, + chip->ecc.strength); + } + + if (stat < 0) { + mtd->ecc_stats.failed++; + } else { + mtd->ecc_stats.corrected += stat; + max_bitflips = max_t(unsigned int, max_bitflips, stat); + } } /* Calculate remaining oob bytes */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 518958115182..86487dbe7358 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -129,6 +129,14 @@ typedef enum { /* Enable Hardware ECC before syndrome is read back from flash */ #define NAND_ECC_READSYN 2 +/* + * Enable generic NAND 'page erased' check. This check is only done when + * ecc.correct() returns -EBADMSG. + * Set this flag if your implementation does not fix bitflips in erased + * pages and you want to rely on the default implementation. + */ +#define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) + /* Bit mask for flags passed to do_nand_read_ecc */ #define NAND_GET_DEVICE 0x80 @@ -451,6 +459,7 @@ struct nand_hw_control { * @total: total number of ECC bytes per page * @prepad: padding information for syndrome based ECC generators * @postpad: padding information for syndrome based ECC generators + * @options: ECC specific options (see NAND_ECC_XXX flags defined above) * @layout: ECC layout control struct pointer * @priv: pointer to private ECC control data * @hwctl: function to control hardware ECC generator. Must only @@ -500,6 +509,7 @@ struct nand_ecc_ctrl { int strength; int prepad; int postpad; + unsigned int options; struct nand_ecclayout *layout; void *priv; void (*hwctl)(struct mtd_info *mtd, int mode); -- cgit v1.2.3 From d39ddbd9ef70949bb78283a067e1b3366111dd90 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Thu, 10 Dec 2015 09:00:39 +0100 Subject: mtd: nand: add helpers to access ->priv Add two helpers to access the field reserved for private controller data. This makes it clearer what this field is reserved for and ease future refactoring. Signed-off-by: Boris Brezillon Signed-off-by: Brian Norris --- include/linux/mtd/nand.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 86487dbe7358..bdd68e22b5a5 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -755,6 +755,16 @@ static inline struct mtd_info *nand_to_mtd(struct nand_chip *chip) return &chip->mtd; } +static inline void *nand_get_controller_data(struct nand_chip *chip) +{ + return chip->priv; +} + +static inline void nand_set_controller_data(struct nand_chip *chip, void *priv) +{ + chip->priv = priv; +} + /* * NAND Flash Manufacturer ID Codes */ -- cgit v1.2.3