diff options
42 files changed, 642 insertions, 320 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-mtd b/Documentation/ABI/testing/sysfs-class-mtd index 76ee192f80a0..3b5c3bca9186 100644 --- a/Documentation/ABI/testing/sysfs-class-mtd +++ b/Documentation/ABI/testing/sysfs-class-mtd | |||
| @@ -222,3 +222,13 @@ Description: | |||
| 222 | The number of blocks that are marked as reserved, if any, in | 222 | The number of blocks that are marked as reserved, if any, in |
| 223 | this partition. These are typically used to store the in-flash | 223 | this partition. These are typically used to store the in-flash |
| 224 | bad block table (BBT). | 224 | bad block table (BBT). |
| 225 | |||
| 226 | What: /sys/class/mtd/mtdX/offset | ||
| 227 | Date: March 2015 | ||
| 228 | KernelVersion: 4.1 | ||
| 229 | Contact: linux-mtd@lists.infradead.org | ||
| 230 | Description: | ||
| 231 | For a partition, the offset of that partition from the start | ||
| 232 | of the master device in bytes. This attribute is absent on | ||
| 233 | main devices, so it can be used to distinguish between | ||
| 234 | partitions and devices that aren't partitions. | ||
diff --git a/Documentation/devicetree/bindings/mtd/m25p80.txt b/Documentation/devicetree/bindings/mtd/m25p80.txt index 4611aa83531b..f20b111b502a 100644 --- a/Documentation/devicetree/bindings/mtd/m25p80.txt +++ b/Documentation/devicetree/bindings/mtd/m25p80.txt | |||
| @@ -3,10 +3,13 @@ | |||
| 3 | Required properties: | 3 | Required properties: |
| 4 | - #address-cells, #size-cells : Must be present if the device has sub-nodes | 4 | - #address-cells, #size-cells : Must be present if the device has sub-nodes |
| 5 | representing partitions. | 5 | representing partitions. |
| 6 | - compatible : Should be the manufacturer and the name of the chip. Bear in mind | 6 | - compatible : May include a device-specific string consisting of the |
| 7 | the DT binding is not Linux-only, but in case of Linux, see the | 7 | manufacturer and name of the chip. Bear in mind the DT binding |
| 8 | "spi_nor_ids" table in drivers/mtd/spi-nor/spi-nor.c for the list | 8 | is not Linux-only, but in case of Linux, see the "m25p_ids" |
| 9 | of supported chips. | 9 | table in drivers/mtd/devices/m25p80.c for the list of supported |
| 10 | chips. | ||
| 11 | Must also include "nor-jedec" for any SPI NOR flash that can be | ||
| 12 | identified by the JEDEC READ ID opcode (0x9F). | ||
| 10 | - reg : Chip-Select number | 13 | - reg : Chip-Select number |
| 11 | - spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at | 14 | - spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at |
| 12 | 15 | ||
| @@ -22,7 +25,7 @@ Example: | |||
| 22 | flash: m25p80@0 { | 25 | flash: m25p80@0 { |
| 23 | #address-cells = <1>; | 26 | #address-cells = <1>; |
| 24 | #size-cells = <1>; | 27 | #size-cells = <1>; |
| 25 | compatible = "spansion,m25p80"; | 28 | compatible = "spansion,m25p80", "nor-jedec"; |
| 26 | reg = <0>; | 29 | reg = <0>; |
| 27 | spi-max-frequency = <40000000>; | 30 | spi-max-frequency = <40000000>; |
| 28 | m25p,fast-read; | 31 | m25p,fast-read; |
diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt index de8b517a5521..4f833e3c4f51 100644 --- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt | |||
| @@ -14,7 +14,7 @@ Optional properties: | |||
| 14 | - marvell,nand-enable-arbiter: Set to enable the bus arbiter | 14 | - marvell,nand-enable-arbiter: Set to enable the bus arbiter |
| 15 | - marvell,nand-keep-config: Set to keep the NAND controller config as set | 15 | - marvell,nand-keep-config: Set to keep the NAND controller config as set |
| 16 | by the bootloader | 16 | by the bootloader |
| 17 | - num-cs: Number of chipselect lines to usw | 17 | - num-cs: Number of chipselect lines to use |
| 18 | - nand-on-flash-bbt: boolean to enable on flash bbt option if | 18 | - nand-on-flash-bbt: boolean to enable on flash bbt option if |
| 19 | not present false | 19 | not present false |
| 20 | - nand-ecc-strength: number of bits to correct per ECC step | 20 | - nand-ecc-strength: number of bits to correct per ECC step |
diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt index 0273adb8638c..086d6f44c4b9 100644 --- a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt +++ b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt | |||
| @@ -21,7 +21,7 @@ Optional properties: | |||
| 21 | - nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft", | 21 | - nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft", |
| 22 | "soft_bch" or "none") | 22 | "soft_bch" or "none") |
| 23 | 23 | ||
| 24 | see Documentation/devicetree/mtd/nand.txt for generic bindings. | 24 | see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings. |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | Examples: | 27 | Examples: |
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 71fea895ce38..a03ad2951c7b 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
| @@ -309,6 +309,19 @@ config MTD_SWAP | |||
| 309 | The driver provides wear leveling by storing erase counter into the | 309 | The driver provides wear leveling by storing erase counter into the |
| 310 | OOB. | 310 | OOB. |
| 311 | 311 | ||
| 312 | config MTD_PARTITIONED_MASTER | ||
| 313 | bool "Retain master device when partitioned" | ||
| 314 | default n | ||
| 315 | depends on MTD | ||
| 316 | help | ||
| 317 | For historical reasons, by default, either a master is present or | ||
| 318 | several partitions are present, but not both. The concern was that | ||
| 319 | data listed in multiple partitions was dangerous; however, SCSI does | ||
| 320 | this and it is frequently useful for applications. This config option | ||
| 321 | leaves the master in even if the device is partitioned. It also makes | ||
| 322 | the parent of the partition device be the master device, rather than | ||
| 323 | what lies behind the master. | ||
| 324 | |||
| 312 | source "drivers/mtd/chips/Kconfig" | 325 | source "drivers/mtd/chips/Kconfig" |
| 313 | 326 | ||
| 314 | source "drivers/mtd/maps/Kconfig" | 327 | source "drivers/mtd/maps/Kconfig" |
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 423666b51efb..9a1a6ffd16b8 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
| @@ -206,23 +206,23 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) | |||
| 206 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; | 206 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; |
| 207 | } | 207 | } |
| 208 | offset += (ersize * ernum); | 208 | offset += (ersize * ernum); |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | if (offset != devsize) { | 211 | if (offset != devsize) { |
| 212 | /* Argh */ | 212 | /* Argh */ |
| 213 | printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); | 213 | printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); |
| 214 | kfree(mtd->eraseregions); | 214 | kfree(mtd->eraseregions); |
| 215 | kfree(cfi->cmdset_priv); | 215 | kfree(cfi->cmdset_priv); |
| 216 | kfree(mtd); | 216 | kfree(mtd); |
| 217 | return NULL; | 217 | return NULL; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | for (i=0; i<mtd->numeraseregions;i++){ | 220 | for (i=0; i<mtd->numeraseregions;i++){ |
| 221 | printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n", | 221 | printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n", |
| 222 | i, (unsigned long long)mtd->eraseregions[i].offset, | 222 | i, (unsigned long long)mtd->eraseregions[i].offset, |
| 223 | mtd->eraseregions[i].erasesize, | 223 | mtd->eraseregions[i].erasesize, |
| 224 | mtd->eraseregions[i].numblocks); | 224 | mtd->eraseregions[i].numblocks); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | /* Also select the correct geometry setup too */ | 227 | /* Also select the correct geometry setup too */ |
| 228 | mtd->_erase = cfi_staa_erase_varsize; | 228 | mtd->_erase = cfi_staa_erase_varsize; |
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 66f0405f7e53..b16f3cda97ff 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
| @@ -9,7 +9,15 @@ | |||
| 9 | 9 | ||
| 10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 11 | 11 | ||
| 12 | /* | ||
| 13 | * When the first attempt at device initialization fails, we may need to | ||
| 14 | * wait a little bit and retry. This timeout, by default 3 seconds, gives | ||
| 15 | * device time to start up. Required on BCM2708 and a few other chipsets. | ||
| 16 | */ | ||
| 17 | #define MTD_DEFAULT_TIMEOUT 3 | ||
| 18 | |||
| 12 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/delay.h> | ||
| 13 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
| 14 | #include <linux/blkdev.h> | 22 | #include <linux/blkdev.h> |
| 15 | #include <linux/bio.h> | 23 | #include <linux/bio.h> |
| @@ -209,10 +217,14 @@ static void block2mtd_free_device(struct block2mtd_dev *dev) | |||
| 209 | } | 217 | } |
| 210 | 218 | ||
| 211 | 219 | ||
| 212 | static struct block2mtd_dev *add_device(char *devname, int erase_size) | 220 | static struct block2mtd_dev *add_device(char *devname, int erase_size, |
| 221 | int timeout) | ||
| 213 | { | 222 | { |
| 223 | #ifndef MODULE | ||
| 224 | int i; | ||
| 225 | #endif | ||
| 214 | const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; | 226 | const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; |
| 215 | struct block_device *bdev; | 227 | struct block_device *bdev = ERR_PTR(-ENODEV); |
| 216 | struct block2mtd_dev *dev; | 228 | struct block2mtd_dev *dev; |
| 217 | char *name; | 229 | char *name; |
| 218 | 230 | ||
| @@ -225,15 +237,28 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) | |||
| 225 | 237 | ||
| 226 | /* Get a handle on the device */ | 238 | /* Get a handle on the device */ |
| 227 | bdev = blkdev_get_by_path(devname, mode, dev); | 239 | bdev = blkdev_get_by_path(devname, mode, dev); |
| 228 | #ifndef MODULE | ||
| 229 | if (IS_ERR(bdev)) { | ||
| 230 | |||
| 231 | /* We might not have rootfs mounted at this point. Try | ||
| 232 | to resolve the device name by other means. */ | ||
| 233 | 240 | ||
| 234 | dev_t devt = name_to_dev_t(devname); | 241 | #ifndef MODULE |
| 235 | if (devt) | 242 | /* |
| 236 | bdev = blkdev_get_by_dev(devt, mode, dev); | 243 | * We might not have the root device mounted at this point. |
| 244 | * Try to resolve the device name by other means. | ||
| 245 | */ | ||
| 246 | for (i = 0; IS_ERR(bdev) && i <= timeout; i++) { | ||
| 247 | dev_t devt; | ||
| 248 | |||
| 249 | if (i) | ||
| 250 | /* | ||
| 251 | * Calling wait_for_device_probe in the first loop | ||
| 252 | * was not enough, sleep for a bit in subsequent | ||
| 253 | * go-arounds. | ||
| 254 | */ | ||
| 255 | msleep(1000); | ||
| 256 | wait_for_device_probe(); | ||
| 257 | |||
| 258 | devt = name_to_dev_t(devname); | ||
| 259 | if (!devt) | ||
| 260 | continue; | ||
| 261 | bdev = blkdev_get_by_dev(devt, mode, dev); | ||
| 237 | } | 262 | } |
| 238 | #endif | 263 | #endif |
| 239 | 264 | ||
| @@ -280,6 +305,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) | |||
| 280 | /* Device didn't get added, so free the entry */ | 305 | /* Device didn't get added, so free the entry */ |
| 281 | goto err_destroy_mutex; | 306 | goto err_destroy_mutex; |
| 282 | } | 307 | } |
| 308 | |||
| 283 | list_add(&dev->list, &blkmtd_device_list); | 309 | list_add(&dev->list, &blkmtd_device_list); |
| 284 | pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", | 310 | pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", |
| 285 | dev->mtd.index, | 311 | dev->mtd.index, |
| @@ -348,16 +374,19 @@ static inline void kill_final_newline(char *str) | |||
| 348 | 374 | ||
| 349 | #ifndef MODULE | 375 | #ifndef MODULE |
| 350 | static int block2mtd_init_called = 0; | 376 | static int block2mtd_init_called = 0; |
| 351 | static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */ | 377 | /* 80 for device, 12 for erase size */ |
| 378 | static char block2mtd_paramline[80 + 12]; | ||
| 352 | #endif | 379 | #endif |
| 353 | 380 | ||
| 354 | static int block2mtd_setup2(const char *val) | 381 | static int block2mtd_setup2(const char *val) |
| 355 | { | 382 | { |
| 356 | char buf[80 + 12]; /* 80 for device, 12 for erase size */ | 383 | /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ |
| 384 | char buf[80 + 12 + 80 + 8]; | ||
| 357 | char *str = buf; | 385 | char *str = buf; |
| 358 | char *token[2]; | 386 | char *token[2]; |
| 359 | char *name; | 387 | char *name; |
| 360 | size_t erase_size = PAGE_SIZE; | 388 | size_t erase_size = PAGE_SIZE; |
| 389 | unsigned long timeout = MTD_DEFAULT_TIMEOUT; | ||
| 361 | int i, ret; | 390 | int i, ret; |
| 362 | 391 | ||
| 363 | if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { | 392 | if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { |
| @@ -395,7 +424,7 @@ static int block2mtd_setup2(const char *val) | |||
| 395 | } | 424 | } |
| 396 | } | 425 | } |
| 397 | 426 | ||
| 398 | add_device(name, erase_size); | 427 | add_device(name, erase_size, timeout); |
| 399 | 428 | ||
| 400 | return 0; | 429 | return 0; |
| 401 | } | 430 | } |
| @@ -463,8 +492,7 @@ static void block2mtd_exit(void) | |||
| 463 | } | 492 | } |
| 464 | } | 493 | } |
| 465 | 494 | ||
| 466 | 495 | late_initcall(block2mtd_init); | |
| 467 | module_init(block2mtd_init); | ||
| 468 | module_exit(block2mtd_exit); | 496 | module_exit(block2mtd_exit); |
| 469 | 497 | ||
| 470 | MODULE_LICENSE("GPL"); | 498 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 448ce42f951e..866d31904475 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c | |||
| @@ -1805,7 +1805,7 @@ static int __init doc_dbg_register(struct docg3 *docg3) | |||
| 1805 | } | 1805 | } |
| 1806 | } | 1806 | } |
| 1807 | 1807 | ||
| 1808 | static void __exit doc_dbg_unregister(struct docg3 *docg3) | 1808 | static void doc_dbg_unregister(struct docg3 *docg3) |
| 1809 | { | 1809 | { |
| 1810 | debugfs_remove_recursive(docg3->debugfs_root); | 1810 | debugfs_remove_recursive(docg3->debugfs_root); |
| 1811 | } | 1811 | } |
| @@ -2033,7 +2033,7 @@ static int __init docg3_probe(struct platform_device *pdev) | |||
| 2033 | struct mtd_info *mtd; | 2033 | struct mtd_info *mtd; |
| 2034 | struct resource *ress; | 2034 | struct resource *ress; |
| 2035 | void __iomem *base; | 2035 | void __iomem *base; |
| 2036 | int ret, floor, found = 0; | 2036 | int ret, floor; |
| 2037 | struct docg3_cascade *cascade; | 2037 | struct docg3_cascade *cascade; |
| 2038 | 2038 | ||
| 2039 | ret = -ENXIO; | 2039 | ret = -ENXIO; |
| @@ -2073,14 +2073,11 @@ static int __init docg3_probe(struct platform_device *pdev) | |||
| 2073 | 0); | 2073 | 0); |
| 2074 | if (ret) | 2074 | if (ret) |
| 2075 | goto err_probe; | 2075 | goto err_probe; |
| 2076 | found++; | ||
| 2077 | } | 2076 | } |
| 2078 | 2077 | ||
| 2079 | ret = doc_register_sysfs(pdev, cascade); | 2078 | ret = doc_register_sysfs(pdev, cascade); |
| 2080 | if (ret) | 2079 | if (ret) |
| 2081 | goto err_probe; | 2080 | goto err_probe; |
| 2082 | if (!found) | ||
| 2083 | goto notfound; | ||
| 2084 | 2081 | ||
| 2085 | platform_set_drvdata(pdev, cascade); | 2082 | platform_set_drvdata(pdev, cascade); |
| 2086 | doc_dbg_register(cascade->floors[0]->priv); | 2083 | doc_dbg_register(cascade->floors[0]->priv); |
| @@ -2103,7 +2100,7 @@ err_probe: | |||
| 2103 | * | 2100 | * |
| 2104 | * Returns 0 | 2101 | * Returns 0 |
| 2105 | */ | 2102 | */ |
| 2106 | static int __exit docg3_release(struct platform_device *pdev) | 2103 | static int docg3_release(struct platform_device *pdev) |
| 2107 | { | 2104 | { |
| 2108 | struct docg3_cascade *cascade = platform_get_drvdata(pdev); | 2105 | struct docg3_cascade *cascade = platform_get_drvdata(pdev); |
| 2109 | struct docg3 *docg3 = cascade->floors[0]->priv; | 2106 | struct docg3 *docg3 = cascade->floors[0]->priv; |
| @@ -2134,7 +2131,7 @@ static struct platform_driver g3_driver = { | |||
| 2134 | }, | 2131 | }, |
| 2135 | .suspend = docg3_suspend, | 2132 | .suspend = docg3_suspend, |
| 2136 | .resume = docg3_resume, | 2133 | .resume = docg3_resume, |
| 2137 | .remove = __exit_p(docg3_release), | 2134 | .remove = docg3_release, |
| 2138 | }; | 2135 | }; |
| 2139 | 2136 | ||
| 2140 | module_platform_driver_probe(g3_driver, docg3_probe); | 2137 | module_platform_driver_probe(g3_driver, docg3_probe); |
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 85e35467fba6..7c8b1694a134 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
| @@ -223,6 +223,8 @@ static int m25p_probe(struct spi_device *spi) | |||
| 223 | */ | 223 | */ |
| 224 | if (data && data->type) | 224 | if (data && data->type) |
| 225 | flash_name = data->type; | 225 | flash_name = data->type; |
| 226 | else if (!strcmp(spi->modalias, "nor-jedec")) | ||
| 227 | flash_name = NULL; /* auto-detect */ | ||
| 226 | else | 228 | else |
| 227 | flash_name = spi->modalias; | 229 | flash_name = spi->modalias; |
| 228 | 230 | ||
| @@ -247,9 +249,16 @@ static int m25p_remove(struct spi_device *spi) | |||
| 247 | } | 249 | } |
| 248 | 250 | ||
| 249 | /* | 251 | /* |
| 250 | * XXX This needs to be kept in sync with spi_nor_ids. We can't share | 252 | * Do NOT add to this array without reading the following: |
| 251 | * it with spi-nor, because if this is built as a module then modpost | 253 | * |
| 252 | * won't be able to read it and add appropriate aliases. | 254 | * Historically, many flash devices are bound to this driver by their name. But |
| 255 | * since most of these flash are compatible to some extent, and their | ||
| 256 | * differences can often be differentiated by the JEDEC read-ID command, we | ||
| 257 | * encourage new users to add support to the spi-nor library, and simply bind | ||
| 258 | * against a generic string here (e.g., "nor-jedec"). | ||
| 259 | * | ||
| 260 | * Many flash names are kept here in this list (as well as in spi-nor.c) to | ||
| 261 | * keep them available as module aliases for existing platforms. | ||
| 253 | */ | 262 | */ |
| 254 | static const struct spi_device_id m25p_ids[] = { | 263 | static const struct spi_device_id m25p_ids[] = { |
| 255 | {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, | 264 | {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, |
| @@ -291,6 +300,12 @@ static const struct spi_device_id m25p_ids[] = { | |||
| 291 | {"w25x64"}, {"w25q64"}, {"w25q80"}, {"w25q80bl"}, | 300 | {"w25x64"}, {"w25q64"}, {"w25q80"}, {"w25q80bl"}, |
| 292 | {"w25q128"}, {"w25q256"}, {"cat25c11"}, | 301 | {"w25q128"}, {"w25q256"}, {"cat25c11"}, |
| 293 | {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, | 302 | {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, |
| 303 | |||
| 304 | /* | ||
| 305 | * Generic support for SPI NOR that can be identified by the JEDEC READ | ||
| 306 | * ID opcode (0x9F). Use this, if possible. | ||
| 307 | */ | ||
| 308 | {"nor-jedec"}, | ||
| 294 | { }, | 309 | { }, |
| 295 | }; | 310 | }; |
| 296 | MODULE_DEVICE_TABLE(spi, m25p_ids); | 311 | MODULE_DEVICE_TABLE(spi, m25p_ids); |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index ba801d2c6dcc..e715ae90632f 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
| @@ -242,7 +242,7 @@ config MTD_L440GX | |||
| 242 | 242 | ||
| 243 | config MTD_CFI_FLAGADM | 243 | config MTD_CFI_FLAGADM |
| 244 | tristate "CFI Flash device mapping on FlagaDM" | 244 | tristate "CFI Flash device mapping on FlagaDM" |
| 245 | depends on 8xx && MTD_CFI | 245 | depends on PPC_8xx && MTD_CFI |
| 246 | help | 246 | help |
| 247 | Mapping for the Flaga digital module. If you don't have one, ignore | 247 | Mapping for the Flaga digital module. If you don't have one, ignore |
| 248 | this setting. | 248 | this setting. |
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index ea697202935a..892ad6ac63f2 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c | |||
| @@ -274,7 +274,7 @@ static int sa1100_mtd_probe(struct platform_device *pdev) | |||
| 274 | return err; | 274 | return err; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | static int __exit sa1100_mtd_remove(struct platform_device *pdev) | 277 | static int sa1100_mtd_remove(struct platform_device *pdev) |
| 278 | { | 278 | { |
| 279 | struct sa_info *info = platform_get_drvdata(pdev); | 279 | struct sa_info *info = platform_get_drvdata(pdev); |
| 280 | struct flash_platform_data *plat = dev_get_platdata(&pdev->dev); | 280 | struct flash_platform_data *plat = dev_get_platdata(&pdev->dev); |
| @@ -286,7 +286,7 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev) | |||
| 286 | 286 | ||
| 287 | static struct platform_driver sa1100_mtd_driver = { | 287 | static struct platform_driver sa1100_mtd_driver = { |
| 288 | .probe = sa1100_mtd_probe, | 288 | .probe = sa1100_mtd_probe, |
| 289 | .remove = __exit_p(sa1100_mtd_remove), | 289 | .remove = sa1100_mtd_remove, |
| 290 | .driver = { | 290 | .driver = { |
| 291 | .name = "sa1100-mtd", | 291 | .name = "sa1100-mtd", |
| 292 | }, | 292 | }, |
diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index d1d671daf235..9969fedb1f13 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c | |||
| @@ -117,5 +117,5 @@ module_exit(cleanup_ts5500_map); | |||
| 117 | 117 | ||
| 118 | MODULE_LICENSE("GPL"); | 118 | MODULE_LICENSE("GPL"); |
| 119 | MODULE_AUTHOR("Sean Young <sean@mess.org>"); | 119 | MODULE_AUTHOR("Sean Young <sean@mess.org>"); |
| 120 | MODULE_DESCRIPTION("MTD map driver for Techology Systems TS-5500 board"); | 120 | MODULE_DESCRIPTION("MTD map driver for Technology Systems TS-5500 board"); |
| 121 | 121 | ||
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index d08229eb44d8..2b0c52870999 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
| @@ -171,9 +171,6 @@ static void mtd_blktrans_work(struct work_struct *work) | |||
| 171 | background_done = 0; | 171 | background_done = 0; |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | if (req) | ||
| 175 | __blk_end_request_all(req, -EIO); | ||
| 176 | |||
| 177 | spin_unlock_irq(rq->queue_lock); | 174 | spin_unlock_irq(rq->queue_lock); |
| 178 | } | 175 | } |
| 179 | 176 | ||
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 11883bd26d9d..d172195fbd15 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/gfp.h> | 38 | #include <linux/gfp.h> |
| 39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
| 40 | #include <linux/reboot.h> | 40 | #include <linux/reboot.h> |
| 41 | #include <linux/kconfig.h> | ||
| 41 | 42 | ||
| 42 | #include <linux/mtd/mtd.h> | 43 | #include <linux/mtd/mtd.h> |
| 43 | #include <linux/mtd/partitions.h> | 44 | #include <linux/mtd/partitions.h> |
| @@ -501,6 +502,29 @@ out_error: | |||
| 501 | return ret; | 502 | return ret; |
| 502 | } | 503 | } |
| 503 | 504 | ||
| 505 | static int mtd_add_device_partitions(struct mtd_info *mtd, | ||
| 506 | struct mtd_partition *real_parts, | ||
| 507 | int nbparts) | ||
| 508 | { | ||
| 509 | int ret; | ||
| 510 | |||
| 511 | if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { | ||
| 512 | ret = add_mtd_device(mtd); | ||
| 513 | if (ret == 1) | ||
| 514 | return -ENODEV; | ||
| 515 | } | ||
| 516 | |||
| 517 | if (nbparts > 0) { | ||
| 518 | ret = add_mtd_partitions(mtd, real_parts, nbparts); | ||
| 519 | if (ret && IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) | ||
| 520 | del_mtd_device(mtd); | ||
| 521 | return ret; | ||
| 522 | } | ||
| 523 | |||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | |||
| 504 | /** | 528 | /** |
| 505 | * mtd_device_parse_register - parse partitions and register an MTD device. | 529 | * mtd_device_parse_register - parse partitions and register an MTD device. |
| 506 | * | 530 | * |
| @@ -523,7 +547,8 @@ out_error: | |||
| 523 | * found this functions tries to fallback to information specified in | 547 | * found this functions tries to fallback to information specified in |
| 524 | * @parts/@nr_parts. | 548 | * @parts/@nr_parts. |
| 525 | * * If any partitioning info was found, this function registers the found | 549 | * * If any partitioning info was found, this function registers the found |
| 526 | * partitions. | 550 | * partitions. If the MTD_PARTITIONED_MASTER option is set, then the device |
| 551 | * as a whole is registered first. | ||
| 527 | * * If no partitions were found this function just registers the MTD device | 552 | * * If no partitions were found this function just registers the MTD device |
| 528 | * @mtd and exits. | 553 | * @mtd and exits. |
| 529 | * | 554 | * |
| @@ -534,27 +559,21 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, | |||
| 534 | const struct mtd_partition *parts, | 559 | const struct mtd_partition *parts, |
| 535 | int nr_parts) | 560 | int nr_parts) |
| 536 | { | 561 | { |
| 537 | int err; | 562 | int ret; |
| 538 | struct mtd_partition *real_parts; | 563 | struct mtd_partition *real_parts = NULL; |
| 539 | 564 | ||
| 540 | err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); | 565 | ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data); |
| 541 | if (err <= 0 && nr_parts && parts) { | 566 | if (ret <= 0 && nr_parts && parts) { |
| 542 | real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, | 567 | real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, |
| 543 | GFP_KERNEL); | 568 | GFP_KERNEL); |
| 544 | if (!real_parts) | 569 | if (!real_parts) |
| 545 | err = -ENOMEM; | 570 | ret = -ENOMEM; |
| 546 | else | 571 | else |
| 547 | err = nr_parts; | 572 | ret = nr_parts; |
| 548 | } | 573 | } |
| 549 | 574 | ||
| 550 | if (err > 0) { | 575 | if (ret >= 0) |
| 551 | err = add_mtd_partitions(mtd, real_parts, err); | 576 | ret = mtd_add_device_partitions(mtd, real_parts, ret); |
| 552 | kfree(real_parts); | ||
| 553 | } else if (err == 0) { | ||
| 554 | err = add_mtd_device(mtd); | ||
| 555 | if (err == 1) | ||
| 556 | err = -ENODEV; | ||
| 557 | } | ||
| 558 | 577 | ||
| 559 | /* | 578 | /* |
| 560 | * FIXME: some drivers unfortunately call this function more than once. | 579 | * FIXME: some drivers unfortunately call this function more than once. |
| @@ -569,7 +588,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, | |||
| 569 | register_reboot_notifier(&mtd->reboot_notifier); | 588 | register_reboot_notifier(&mtd->reboot_notifier); |
| 570 | } | 589 | } |
| 571 | 590 | ||
| 572 | return err; | 591 | kfree(real_parts); |
| 592 | return ret; | ||
| 573 | } | 593 | } |
| 574 | EXPORT_SYMBOL_GPL(mtd_device_parse_register); | 594 | EXPORT_SYMBOL_GPL(mtd_device_parse_register); |
| 575 | 595 | ||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index e779de315ade..cafdb8855a79 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/mtd/mtd.h> | 30 | #include <linux/mtd/mtd.h> |
| 31 | #include <linux/mtd/partitions.h> | 31 | #include <linux/mtd/partitions.h> |
| 32 | #include <linux/err.h> | 32 | #include <linux/err.h> |
| 33 | #include <linux/kconfig.h> | ||
| 33 | 34 | ||
| 34 | #include "mtdcore.h" | 35 | #include "mtdcore.h" |
| 35 | 36 | ||
| @@ -379,10 +380,17 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, | |||
| 379 | slave->mtd.name = name; | 380 | slave->mtd.name = name; |
| 380 | slave->mtd.owner = master->owner; | 381 | slave->mtd.owner = master->owner; |
| 381 | 382 | ||
| 382 | /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone | 383 | /* NOTE: Historically, we didn't arrange MTDs as a tree out of |
| 383 | * to have the same data be in two different partitions. | 384 | * concern for showing the same data in multiple partitions. |
| 385 | * However, it is very useful to have the master node present, | ||
| 386 | * so the MTD_PARTITIONED_MASTER option allows that. The master | ||
| 387 | * will have device nodes etc only if this is set, so make the | ||
| 388 | * parent conditional on that option. Note, this is a way to | ||
| 389 | * distinguish between the master and the partition in sysfs. | ||
| 384 | */ | 390 | */ |
| 385 | slave->mtd.dev.parent = master->dev.parent; | 391 | slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ? |
| 392 | &master->dev : | ||
| 393 | master->dev.parent; | ||
| 386 | 394 | ||
| 387 | slave->mtd._read = part_read; | 395 | slave->mtd._read = part_read; |
| 388 | slave->mtd._write = part_write; | 396 | slave->mtd._write = part_write; |
| @@ -546,12 +554,35 @@ out_register: | |||
| 546 | return slave; | 554 | return slave; |
| 547 | } | 555 | } |
| 548 | 556 | ||
| 557 | static ssize_t mtd_partition_offset_show(struct device *dev, | ||
| 558 | struct device_attribute *attr, char *buf) | ||
| 559 | { | ||
| 560 | struct mtd_info *mtd = dev_get_drvdata(dev); | ||
| 561 | struct mtd_part *part = PART(mtd); | ||
| 562 | return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset); | ||
| 563 | } | ||
| 564 | |||
| 565 | static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL); | ||
| 566 | |||
| 567 | static const struct attribute *mtd_partition_attrs[] = { | ||
| 568 | &dev_attr_offset.attr, | ||
| 569 | NULL | ||
| 570 | }; | ||
| 571 | |||
| 572 | static int mtd_add_partition_attrs(struct mtd_part *new) | ||
| 573 | { | ||
| 574 | int ret = sysfs_create_files(&new->mtd.dev.kobj, mtd_partition_attrs); | ||
| 575 | if (ret) | ||
| 576 | printk(KERN_WARNING | ||
| 577 | "mtd: failed to create partition attrs, err=%d\n", ret); | ||
| 578 | return ret; | ||
| 579 | } | ||
| 580 | |||
| 549 | int mtd_add_partition(struct mtd_info *master, const char *name, | 581 | int mtd_add_partition(struct mtd_info *master, const char *name, |
| 550 | long long offset, long long length) | 582 | long long offset, long long length) |
| 551 | { | 583 | { |
| 552 | struct mtd_partition part; | 584 | struct mtd_partition part; |
| 553 | struct mtd_part *p, *new; | 585 | struct mtd_part *new; |
| 554 | uint64_t start, end; | ||
| 555 | int ret = 0; | 586 | int ret = 0; |
| 556 | 587 | ||
| 557 | /* the direct offset is expected */ | 588 | /* the direct offset is expected */ |
| @@ -575,31 +606,15 @@ int mtd_add_partition(struct mtd_info *master, const char *name, | |||
| 575 | if (IS_ERR(new)) | 606 | if (IS_ERR(new)) |
| 576 | return PTR_ERR(new); | 607 | return PTR_ERR(new); |
| 577 | 608 | ||
| 578 | start = offset; | ||
| 579 | end = offset + length; | ||
| 580 | |||
| 581 | mutex_lock(&mtd_partitions_mutex); | 609 | mutex_lock(&mtd_partitions_mutex); |
| 582 | list_for_each_entry(p, &mtd_partitions, list) | ||
| 583 | if (p->master == master) { | ||
| 584 | if ((start >= p->offset) && | ||
| 585 | (start < (p->offset + p->mtd.size))) | ||
| 586 | goto err_inv; | ||
| 587 | |||
| 588 | if ((end >= p->offset) && | ||
| 589 | (end < (p->offset + p->mtd.size))) | ||
| 590 | goto err_inv; | ||
| 591 | } | ||
| 592 | |||
| 593 | list_add(&new->list, &mtd_partitions); | 610 | list_add(&new->list, &mtd_partitions); |
| 594 | mutex_unlock(&mtd_partitions_mutex); | 611 | mutex_unlock(&mtd_partitions_mutex); |
| 595 | 612 | ||
| 596 | add_mtd_device(&new->mtd); | 613 | add_mtd_device(&new->mtd); |
| 597 | 614 | ||
| 615 | mtd_add_partition_attrs(new); | ||
| 616 | |||
| 598 | return ret; | 617 | return ret; |
| 599 | err_inv: | ||
| 600 | mutex_unlock(&mtd_partitions_mutex); | ||
| 601 | free_partition(new); | ||
| 602 | return -EINVAL; | ||
| 603 | } | 618 | } |
| 604 | EXPORT_SYMBOL_GPL(mtd_add_partition); | 619 | EXPORT_SYMBOL_GPL(mtd_add_partition); |
| 605 | 620 | ||
| @@ -612,6 +627,8 @@ int mtd_del_partition(struct mtd_info *master, int partno) | |||
| 612 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) | 627 | list_for_each_entry_safe(slave, next, &mtd_partitions, list) |
| 613 | if ((slave->master == master) && | 628 | if ((slave->master == master) && |
| 614 | (slave->mtd.index == partno)) { | 629 | (slave->mtd.index == partno)) { |
| 630 | sysfs_remove_files(&slave->mtd.dev.kobj, | ||
| 631 | mtd_partition_attrs); | ||
| 615 | ret = del_mtd_device(&slave->mtd); | 632 | ret = del_mtd_device(&slave->mtd); |
| 616 | if (ret < 0) | 633 | if (ret < 0) |
| 617 | break; | 634 | break; |
| @@ -631,8 +648,8 @@ EXPORT_SYMBOL_GPL(mtd_del_partition); | |||
| 631 | * and registers slave MTD objects which are bound to the master according to | 648 | * and registers slave MTD objects which are bound to the master according to |
| 632 | * the partition definitions. | 649 | * the partition definitions. |
| 633 | * | 650 | * |
| 634 | * We don't register the master, or expect the caller to have done so, | 651 | * For historical reasons, this function's caller only registers the master |
| 635 | * for reasons of data integrity. | 652 | * if the MTD_PARTITIONED_MASTER config option is set. |
| 636 | */ | 653 | */ |
| 637 | 654 | ||
| 638 | int add_mtd_partitions(struct mtd_info *master, | 655 | int add_mtd_partitions(struct mtd_info *master, |
| @@ -655,6 +672,7 @@ int add_mtd_partitions(struct mtd_info *master, | |||
| 655 | mutex_unlock(&mtd_partitions_mutex); | 672 | mutex_unlock(&mtd_partitions_mutex); |
| 656 | 673 | ||
| 657 | add_mtd_device(&slave->mtd); | 674 | add_mtd_device(&slave->mtd); |
| 675 | mtd_add_partition_attrs(slave); | ||
| 658 | 676 | ||
| 659 | cur_offset = slave->offset + slave->mtd.size; | 677 | cur_offset = slave->offset + slave->mtd.size; |
| 660 | } | 678 | } |
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index d93c849b70b5..46010bd895b1 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c | |||
| @@ -485,7 +485,7 @@ static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, | |||
| 485 | for (i = 0; i < ecc_len; i++) | 485 | for (i = 0; i < ecc_len; i++) |
| 486 | layout->eccpos[i] = oobsize - ecc_len + i; | 486 | layout->eccpos[i] = oobsize - ecc_len + i; |
| 487 | 487 | ||
| 488 | layout->oobfree[0].offset = 2; | 488 | layout->oobfree[0].offset = PMECC_OOB_RESERVED_BYTES; |
| 489 | layout->oobfree[0].length = | 489 | layout->oobfree[0].length = |
| 490 | oobsize - ecc_len - layout->oobfree[0].offset; | 490 | oobsize - ecc_len - layout->oobfree[0].offset; |
| 491 | } | 491 | } |
| @@ -1204,14 +1204,14 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, | |||
| 1204 | goto err; | 1204 | goto err; |
| 1205 | } | 1205 | } |
| 1206 | 1206 | ||
| 1207 | regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); | 1207 | if (!host->has_no_lookup_table) { |
| 1208 | host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); | 1208 | regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); |
| 1209 | if (IS_ERR(host->pmecc_rom_base)) { | 1209 | host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, |
| 1210 | if (!host->has_no_lookup_table) | 1210 | regs_rom); |
| 1211 | /* Don't display the information again */ | 1211 | if (IS_ERR(host->pmecc_rom_base)) { |
| 1212 | dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); | 1212 | dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); |
| 1213 | 1213 | host->has_no_lookup_table = true; | |
| 1214 | host->has_no_lookup_table = true; | 1214 | } |
| 1215 | } | 1215 | } |
| 1216 | 1216 | ||
| 1217 | if (host->has_no_lookup_table) { | 1217 | if (host->has_no_lookup_table) { |
| @@ -1254,7 +1254,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, | |||
| 1254 | nand_chip->ecc.steps = mtd->writesize / sector_size; | 1254 | nand_chip->ecc.steps = mtd->writesize / sector_size; |
| 1255 | nand_chip->ecc.total = nand_chip->ecc.bytes * | 1255 | nand_chip->ecc.total = nand_chip->ecc.bytes * |
| 1256 | nand_chip->ecc.steps; | 1256 | nand_chip->ecc.steps; |
| 1257 | if (nand_chip->ecc.total > mtd->oobsize - 2) { | 1257 | if (nand_chip->ecc.total > |
| 1258 | mtd->oobsize - PMECC_OOB_RESERVED_BYTES) { | ||
| 1258 | dev_err(host->dev, "No room for ECC bytes\n"); | 1259 | dev_err(host->dev, "No room for ECC bytes\n"); |
| 1259 | err_no = -EINVAL; | 1260 | err_no = -EINVAL; |
| 1260 | goto err; | 1261 | goto err; |
| @@ -1719,7 +1720,7 @@ static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag) | |||
| 1719 | comp[index++] = &host->nfc->comp_cmd_done; | 1720 | comp[index++] = &host->nfc->comp_cmd_done; |
| 1720 | 1721 | ||
| 1721 | if (index == 0) { | 1722 | if (index == 0) { |
| 1722 | dev_err(host->dev, "Unkown interrupt flag: 0x%08x\n", flag); | 1723 | dev_err(host->dev, "Unknown interrupt flag: 0x%08x\n", flag); |
| 1723 | return -EINVAL; | 1724 | return -EINVAL; |
| 1724 | } | 1725 | } |
| 1725 | 1726 | ||
| @@ -1752,11 +1753,10 @@ static int nfc_send_command(struct atmel_nand_host *host, | |||
| 1752 | cmd, addr, cycle0); | 1753 | cmd, addr, cycle0); |
| 1753 | 1754 | ||
| 1754 | timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS); | 1755 | timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS); |
| 1755 | while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs) | 1756 | while (nfc_readl(host->nfc->hsmc_regs, SR) & NFC_SR_BUSY) { |
| 1756 | & NFCADDR_CMD_NFCBUSY) { | ||
| 1757 | if (time_after(jiffies, timeout)) { | 1757 | if (time_after(jiffies, timeout)) { |
| 1758 | dev_err(host->dev, | 1758 | dev_err(host->dev, |
| 1759 | "Time out to wait CMD_NFCBUSY ready!\n"); | 1759 | "Time out to wait for NFC ready!\n"); |
| 1760 | return -ETIMEDOUT; | 1760 | return -ETIMEDOUT; |
| 1761 | } | 1761 | } |
| 1762 | } | 1762 | } |
diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h index d4035e335ad8..668e7358f19b 100644 --- a/drivers/mtd/nand/atmel_nand_ecc.h +++ b/drivers/mtd/nand/atmel_nand_ecc.h | |||
| @@ -152,4 +152,7 @@ | |||
| 152 | /* Time out value for reading PMECC status register */ | 152 | /* Time out value for reading PMECC status register */ |
| 153 | #define PMECC_MAX_TIMEOUT_MS 100 | 153 | #define PMECC_MAX_TIMEOUT_MS 100 |
| 154 | 154 | ||
| 155 | /* Reserved bytes in oob area */ | ||
| 156 | #define PMECC_OOB_RESERVED_BYTES 2 | ||
| 157 | |||
| 155 | #endif | 158 | #endif |
diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h index 85b8ca6af7d2..4d5d26221a7e 100644 --- a/drivers/mtd/nand/atmel_nand_nfc.h +++ b/drivers/mtd/nand/atmel_nand_nfc.h | |||
| @@ -35,6 +35,7 @@ | |||
| 35 | #define NFC_CTRL_DISABLE (1 << 1) | 35 | #define NFC_CTRL_DISABLE (1 << 1) |
| 36 | 36 | ||
| 37 | #define ATMEL_HSMC_NFC_SR 0x08 /* NFC Status Register */ | 37 | #define ATMEL_HSMC_NFC_SR 0x08 /* NFC Status Register */ |
| 38 | #define NFC_SR_BUSY (1 << 8) | ||
| 38 | #define NFC_SR_XFR_DONE (1 << 16) | 39 | #define NFC_SR_XFR_DONE (1 << 16) |
| 39 | #define NFC_SR_CMD_DONE (1 << 17) | 40 | #define NFC_SR_CMD_DONE (1 << 17) |
| 40 | #define NFC_SR_DTOE (1 << 20) | 41 | #define NFC_SR_DTOE (1 << 20) |
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index f44c6061536a..870c7fc0f759 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c | |||
| @@ -225,7 +225,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, | |||
| 225 | uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60}; | 225 | uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60}; |
| 226 | uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15}; | 226 | uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15}; |
| 227 | 227 | ||
| 228 | uint16_t TclsRising = 1; | ||
| 229 | uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid; | 228 | uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid; |
| 230 | uint16_t dv_window = 0; | 229 | uint16_t dv_window = 0; |
| 231 | uint16_t en_lo, en_hi; | 230 | uint16_t en_lo, en_hi; |
| @@ -276,8 +275,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, | |||
| 276 | re_2_re = CEIL_DIV(Trhz[mode], CLK_X); | 275 | re_2_re = CEIL_DIV(Trhz[mode], CLK_X); |
| 277 | we_2_re = CEIL_DIV(Twhr[mode], CLK_X); | 276 | we_2_re = CEIL_DIV(Twhr[mode], CLK_X); |
| 278 | cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X); | 277 | cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X); |
| 279 | if (!TclsRising) | ||
| 280 | cs_cnt = CEIL_DIV(Tcs[mode], CLK_X); | ||
| 281 | if (cs_cnt == 0) | 278 | if (cs_cnt == 0) |
| 282 | cs_cnt = 1; | 279 | cs_cnt = 1; |
| 283 | 280 | ||
| @@ -1536,6 +1533,9 @@ int denali_init(struct denali_nand_info *denali) | |||
| 1536 | denali->nand.options |= NAND_SKIP_BBTSCAN; | 1533 | denali->nand.options |= NAND_SKIP_BBTSCAN; |
| 1537 | denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; | 1534 | denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; |
| 1538 | 1535 | ||
| 1536 | /* no subpage writes on denali */ | ||
| 1537 | denali->nand.options |= NAND_NO_SUBPAGE_WRITE; | ||
| 1538 | |||
| 1539 | /* | 1539 | /* |
| 1540 | * Denali Controller only support 15bit and 8bit ECC in MRST, | 1540 | * Denali Controller only support 15bit and 8bit ECC in MRST, |
| 1541 | * so just let controller do 15bit ECC for MLC and 8bit ECC for | 1541 | * so just let controller do 15bit ECC for MLC and 8bit ECC for |
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 4c05f4f6a5c6..51394e59901b 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c | |||
| @@ -317,7 +317,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) | |||
| 317 | 317 | ||
| 318 | /* wait for command complete flag or timeout */ | 318 | /* wait for command complete flag or timeout */ |
| 319 | wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, | 319 | wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, |
| 320 | IFC_TIMEOUT_MSECS * HZ/1000); | 320 | msecs_to_jiffies(IFC_TIMEOUT_MSECS)); |
| 321 | 321 | ||
| 322 | /* ctrl->nand_stat will be updated from IRQ context */ | 322 | /* ctrl->nand_stat will be updated from IRQ context */ |
| 323 | if (!ctrl->nand_stat) | 323 | if (!ctrl->nand_stat) |
| @@ -860,7 +860,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) | |||
| 860 | 860 | ||
| 861 | /* wait for command complete flag or timeout */ | 861 | /* wait for command complete flag or timeout */ |
| 862 | wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, | 862 | wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, |
| 863 | IFC_TIMEOUT_MSECS * HZ/1000); | 863 | msecs_to_jiffies(IFC_TIMEOUT_MSECS)); |
| 864 | 864 | ||
| 865 | if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) | 865 | if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) |
| 866 | printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n"); | 866 | printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n"); |
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index edfaa21b1817..e58af4bfa8c8 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c | |||
| @@ -873,6 +873,7 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, | |||
| 873 | { | 873 | { |
| 874 | struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); | 874 | struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); |
| 875 | u32 val; | 875 | u32 val; |
| 876 | int ret; | ||
| 876 | 877 | ||
| 877 | /* Set default NAND width to 8 bits */ | 878 | /* Set default NAND width to 8 bits */ |
| 878 | pdata->width = 8; | 879 | pdata->width = 8; |
| @@ -891,8 +892,12 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, | |||
| 891 | sizeof(*pdata->nand_timings), GFP_KERNEL); | 892 | sizeof(*pdata->nand_timings), GFP_KERNEL); |
| 892 | if (!pdata->nand_timings) | 893 | if (!pdata->nand_timings) |
| 893 | return -ENOMEM; | 894 | return -ENOMEM; |
| 894 | of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, | 895 | ret = of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, |
| 895 | sizeof(*pdata->nand_timings)); | 896 | sizeof(*pdata->nand_timings)); |
| 897 | if (ret) { | ||
| 898 | dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n"); | ||
| 899 | pdata->nand_timings = NULL; | ||
| 900 | } | ||
| 896 | 901 | ||
| 897 | /* Set default NAND bank to 0 */ | 902 | /* Set default NAND bank to 0 */ |
| 898 | pdata->bank = 0; | 903 | pdata->bank = 0; |
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 33f3c3c54dbc..1b8f3500e6d2 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c | |||
| @@ -446,7 +446,7 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, | |||
| 446 | struct dma_async_tx_descriptor *desc) | 446 | struct dma_async_tx_descriptor *desc) |
| 447 | { | 447 | { |
| 448 | struct completion *dma_c = &this->dma_done; | 448 | struct completion *dma_c = &this->dma_done; |
| 449 | int err; | 449 | unsigned long timeout; |
| 450 | 450 | ||
| 451 | init_completion(dma_c); | 451 | init_completion(dma_c); |
| 452 | 452 | ||
| @@ -456,8 +456,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, | |||
| 456 | dma_async_issue_pending(get_dma_chan(this)); | 456 | dma_async_issue_pending(get_dma_chan(this)); |
| 457 | 457 | ||
| 458 | /* Wait for the interrupt from the DMA block. */ | 458 | /* Wait for the interrupt from the DMA block. */ |
| 459 | err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); | 459 | timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); |
| 460 | if (!err) { | 460 | if (!timeout) { |
| 461 | dev_err(this->dev, "DMA timeout, last DMA :%d\n", | 461 | dev_err(this->dev, "DMA timeout, last DMA :%d\n", |
| 462 | this->last_dma_type); | 462 | this->last_dma_type); |
| 463 | gpmi_dump_info(this); | 463 | gpmi_dump_info(this); |
| @@ -477,7 +477,7 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, | |||
| 477 | struct dma_async_tx_descriptor *desc) | 477 | struct dma_async_tx_descriptor *desc) |
| 478 | { | 478 | { |
| 479 | struct completion *bch_c = &this->bch_done; | 479 | struct completion *bch_c = &this->bch_done; |
| 480 | int err; | 480 | unsigned long timeout; |
| 481 | 481 | ||
| 482 | /* Prepare to receive an interrupt from the BCH block. */ | 482 | /* Prepare to receive an interrupt from the BCH block. */ |
| 483 | init_completion(bch_c); | 483 | init_completion(bch_c); |
| @@ -486,8 +486,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, | |||
| 486 | start_dma_without_bch_irq(this, desc); | 486 | start_dma_without_bch_irq(this, desc); |
| 487 | 487 | ||
| 488 | /* Wait for the interrupt from the BCH block. */ | 488 | /* Wait for the interrupt from the BCH block. */ |
| 489 | err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); | 489 | timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); |
| 490 | if (!err) { | 490 | if (!timeout) { |
| 491 | dev_err(this->dev, "BCH timeout, last DMA :%d\n", | 491 | dev_err(this->dev, "BCH timeout, last DMA :%d\n", |
| 492 | this->last_dma_type); | 492 | this->last_dma_type); |
| 493 | gpmi_dump_info(this); | 493 | gpmi_dump_info(this); |
| @@ -1950,7 +1950,9 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) | |||
| 1950 | ret = nand_boot_init(this); | 1950 | ret = nand_boot_init(this); |
| 1951 | if (ret) | 1951 | if (ret) |
| 1952 | goto err_out; | 1952 | goto err_out; |
| 1953 | chip->scan_bbt(mtd); | 1953 | ret = chip->scan_bbt(mtd); |
| 1954 | if (ret) | ||
| 1955 | goto err_out; | ||
| 1954 | 1956 | ||
| 1955 | ppdata.of_node = this->pdev->dev.of_node; | 1957 | ppdata.of_node = this->pdev->dev.of_node; |
| 1956 | ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); | 1958 | ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); |
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a8f550fec35e..372e0e38f59b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c | |||
| @@ -386,26 +386,51 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) | |||
| 386 | /* This function polls the NANDFC to wait for the basic operation to | 386 | /* This function polls the NANDFC to wait for the basic operation to |
| 387 | * complete by checking the INT bit of config2 register. | 387 | * complete by checking the INT bit of config2 register. |
| 388 | */ | 388 | */ |
| 389 | static void wait_op_done(struct mxc_nand_host *host, int useirq) | 389 | static int wait_op_done(struct mxc_nand_host *host, int useirq) |
| 390 | { | 390 | { |
| 391 | int max_retries = 8000; | 391 | int ret = 0; |
| 392 | |||
| 393 | /* | ||
| 394 | * If operation is already complete, don't bother to setup an irq or a | ||
| 395 | * loop. | ||
| 396 | */ | ||
| 397 | if (host->devtype_data->check_int(host)) | ||
| 398 | return 0; | ||
| 392 | 399 | ||
| 393 | if (useirq) { | 400 | if (useirq) { |
| 394 | if (!host->devtype_data->check_int(host)) { | 401 | unsigned long timeout; |
| 395 | reinit_completion(&host->op_completion); | 402 | |
| 396 | irq_control(host, 1); | 403 | reinit_completion(&host->op_completion); |
| 397 | wait_for_completion(&host->op_completion); | 404 | |
| 405 | irq_control(host, 1); | ||
| 406 | |||
| 407 | timeout = wait_for_completion_timeout(&host->op_completion, HZ); | ||
| 408 | if (!timeout && !host->devtype_data->check_int(host)) { | ||
| 409 | dev_dbg(host->dev, "timeout waiting for irq\n"); | ||
| 410 | ret = -ETIMEDOUT; | ||
| 398 | } | 411 | } |
| 399 | } else { | 412 | } else { |
| 400 | while (max_retries-- > 0) { | 413 | int max_retries = 8000; |
| 401 | if (host->devtype_data->check_int(host)) | 414 | int done; |
| 402 | break; | ||
| 403 | 415 | ||
| 416 | do { | ||
| 404 | udelay(1); | 417 | udelay(1); |
| 418 | |||
| 419 | done = host->devtype_data->check_int(host); | ||
| 420 | if (done) | ||
| 421 | break; | ||
| 422 | |||
| 423 | } while (--max_retries); | ||
| 424 | |||
| 425 | if (!done) { | ||
| 426 | dev_dbg(host->dev, "timeout polling for completion\n"); | ||
| 427 | ret = -ETIMEDOUT; | ||
| 405 | } | 428 | } |
| 406 | if (max_retries < 0) | ||
| 407 | pr_debug("%s: INT not set\n", __func__); | ||
| 408 | } | 429 | } |
| 430 | |||
| 431 | WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq); | ||
| 432 | |||
| 433 | return ret; | ||
| 409 | } | 434 | } |
| 410 | 435 | ||
| 411 | static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) | 436 | static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) |
| @@ -527,30 +552,17 @@ static void send_page_v1(struct mtd_info *mtd, unsigned int ops) | |||
| 527 | 552 | ||
| 528 | static void send_read_id_v3(struct mxc_nand_host *host) | 553 | static void send_read_id_v3(struct mxc_nand_host *host) |
| 529 | { | 554 | { |
| 530 | struct nand_chip *this = &host->nand; | ||
| 531 | |||
| 532 | /* Read ID into main buffer */ | 555 | /* Read ID into main buffer */ |
| 533 | writel(NFC_ID, NFC_V3_LAUNCH); | 556 | writel(NFC_ID, NFC_V3_LAUNCH); |
| 534 | 557 | ||
| 535 | wait_op_done(host, true); | 558 | wait_op_done(host, true); |
| 536 | 559 | ||
| 537 | memcpy32_fromio(host->data_buf, host->main_area0, 16); | 560 | memcpy32_fromio(host->data_buf, host->main_area0, 16); |
| 538 | |||
| 539 | if (this->options & NAND_BUSWIDTH_16) { | ||
| 540 | /* compress the ID info */ | ||
| 541 | host->data_buf[1] = host->data_buf[2]; | ||
| 542 | host->data_buf[2] = host->data_buf[4]; | ||
| 543 | host->data_buf[3] = host->data_buf[6]; | ||
| 544 | host->data_buf[4] = host->data_buf[8]; | ||
| 545 | host->data_buf[5] = host->data_buf[10]; | ||
| 546 | } | ||
| 547 | } | 561 | } |
| 548 | 562 | ||
| 549 | /* Request the NANDFC to perform a read of the NAND device ID. */ | 563 | /* Request the NANDFC to perform a read of the NAND device ID. */ |
| 550 | static void send_read_id_v1_v2(struct mxc_nand_host *host) | 564 | static void send_read_id_v1_v2(struct mxc_nand_host *host) |
| 551 | { | 565 | { |
| 552 | struct nand_chip *this = &host->nand; | ||
| 553 | |||
| 554 | /* NANDFC buffer 0 is used for device ID output */ | 566 | /* NANDFC buffer 0 is used for device ID output */ |
| 555 | writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); | 567 | writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); |
| 556 | 568 | ||
| @@ -560,15 +572,6 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host) | |||
| 560 | wait_op_done(host, true); | 572 | wait_op_done(host, true); |
| 561 | 573 | ||
| 562 | memcpy32_fromio(host->data_buf, host->main_area0, 16); | 574 | memcpy32_fromio(host->data_buf, host->main_area0, 16); |
| 563 | |||
| 564 | if (this->options & NAND_BUSWIDTH_16) { | ||
| 565 | /* compress the ID info */ | ||
| 566 | host->data_buf[1] = host->data_buf[2]; | ||
| 567 | host->data_buf[2] = host->data_buf[4]; | ||
| 568 | host->data_buf[3] = host->data_buf[6]; | ||
| 569 | host->data_buf[4] = host->data_buf[8]; | ||
| 570 | host->data_buf[5] = host->data_buf[10]; | ||
| 571 | } | ||
| 572 | } | 575 | } |
| 573 | 576 | ||
| 574 | static uint16_t get_dev_status_v3(struct mxc_nand_host *host) | 577 | static uint16_t get_dev_status_v3(struct mxc_nand_host *host) |
| @@ -694,9 +697,17 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) | |||
| 694 | if (host->status_request) | 697 | if (host->status_request) |
| 695 | return host->devtype_data->get_dev_status(host) & 0xFF; | 698 | return host->devtype_data->get_dev_status(host) & 0xFF; |
| 696 | 699 | ||
| 697 | ret = *(uint8_t *)(host->data_buf + host->buf_start); | 700 | if (nand_chip->options & NAND_BUSWIDTH_16) { |
| 698 | host->buf_start++; | 701 | /* only take the lower byte of each word */ |
| 702 | ret = *(uint16_t *)(host->data_buf + host->buf_start); | ||
| 703 | |||
| 704 | host->buf_start += 2; | ||
| 705 | } else { | ||
| 706 | ret = *(uint8_t *)(host->data_buf + host->buf_start); | ||
| 707 | host->buf_start++; | ||
| 708 | } | ||
| 699 | 709 | ||
| 710 | pr_debug("%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start); | ||
| 700 | return ret; | 711 | return ret; |
| 701 | } | 712 | } |
| 702 | 713 | ||
| @@ -825,6 +836,12 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom) | |||
| 825 | } | 836 | } |
| 826 | } | 837 | } |
| 827 | 838 | ||
| 839 | /* | ||
| 840 | * MXC NANDFC can only perform full page+spare or spare-only read/write. When | ||
| 841 | * the upper layers perform a read/write buf operation, the saved column address | ||
| 842 | * is used to index into the full page. So usually this function is called with | ||
| 843 | * column == 0 (unless no column cycle is needed indicated by column == -1) | ||
| 844 | */ | ||
| 828 | static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) | 845 | static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) |
| 829 | { | 846 | { |
| 830 | struct nand_chip *nand_chip = mtd->priv; | 847 | struct nand_chip *nand_chip = mtd->priv; |
| @@ -832,16 +849,13 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) | |||
| 832 | 849 | ||
| 833 | /* Write out column address, if necessary */ | 850 | /* Write out column address, if necessary */ |
| 834 | if (column != -1) { | 851 | if (column != -1) { |
| 835 | /* | 852 | host->devtype_data->send_addr(host, column & 0xff, |
| 836 | * MXC NANDFC can only perform full page+spare or | 853 | page_addr == -1); |
| 837 | * spare-only read/write. When the upper layers | ||
| 838 | * perform a read/write buf operation, the saved column | ||
| 839 | * address is used to index into the full page. | ||
| 840 | */ | ||
| 841 | host->devtype_data->send_addr(host, 0, page_addr == -1); | ||
| 842 | if (mtd->writesize > 512) | 854 | if (mtd->writesize > 512) |
| 843 | /* another col addr cycle for 2k page */ | 855 | /* another col addr cycle for 2k page */ |
| 844 | host->devtype_data->send_addr(host, 0, false); | 856 | host->devtype_data->send_addr(host, |
| 857 | (column >> 8) & 0xff, | ||
| 858 | false); | ||
| 845 | } | 859 | } |
| 846 | 860 | ||
| 847 | /* Write out page address, if necessary */ | 861 | /* Write out page address, if necessary */ |
| @@ -903,7 +917,7 @@ static void preset_v1(struct mtd_info *mtd) | |||
| 903 | struct mxc_nand_host *host = nand_chip->priv; | 917 | struct mxc_nand_host *host = nand_chip->priv; |
| 904 | uint16_t config1 = 0; | 918 | uint16_t config1 = 0; |
| 905 | 919 | ||
| 906 | if (nand_chip->ecc.mode == NAND_ECC_HW) | 920 | if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize) |
| 907 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | 921 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; |
| 908 | 922 | ||
| 909 | if (!host->devtype_data->irqpending_quirk) | 923 | if (!host->devtype_data->irqpending_quirk) |
| @@ -931,9 +945,6 @@ static void preset_v2(struct mtd_info *mtd) | |||
| 931 | struct mxc_nand_host *host = nand_chip->priv; | 945 | struct mxc_nand_host *host = nand_chip->priv; |
| 932 | uint16_t config1 = 0; | 946 | uint16_t config1 = 0; |
| 933 | 947 | ||
| 934 | if (nand_chip->ecc.mode == NAND_ECC_HW) | ||
| 935 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | ||
| 936 | |||
| 937 | config1 |= NFC_V2_CONFIG1_FP_INT; | 948 | config1 |= NFC_V2_CONFIG1_FP_INT; |
| 938 | 949 | ||
| 939 | if (!host->devtype_data->irqpending_quirk) | 950 | if (!host->devtype_data->irqpending_quirk) |
| @@ -942,6 +953,9 @@ static void preset_v2(struct mtd_info *mtd) | |||
| 942 | if (mtd->writesize) { | 953 | if (mtd->writesize) { |
| 943 | uint16_t pages_per_block = mtd->erasesize / mtd->writesize; | 954 | uint16_t pages_per_block = mtd->erasesize / mtd->writesize; |
| 944 | 955 | ||
| 956 | if (nand_chip->ecc.mode == NAND_ECC_HW) | ||
| 957 | config1 |= NFC_V1_V2_CONFIG1_ECC_EN; | ||
| 958 | |||
| 945 | host->eccsize = get_eccsize(mtd); | 959 | host->eccsize = get_eccsize(mtd); |
| 946 | if (host->eccsize == 4) | 960 | if (host->eccsize == 4) |
| 947 | config1 |= NFC_V2_CONFIG1_ECC_MODE_4; | 961 | config1 |= NFC_V2_CONFIG1_ECC_MODE_4; |
| @@ -999,9 +1013,6 @@ static void preset_v3(struct mtd_info *mtd) | |||
| 999 | NFC_V3_CONFIG2_INT_MSK | | 1013 | NFC_V3_CONFIG2_INT_MSK | |
| 1000 | NFC_V3_CONFIG2_NUM_ADDR_PHASE0; | 1014 | NFC_V3_CONFIG2_NUM_ADDR_PHASE0; |
| 1001 | 1015 | ||
| 1002 | if (chip->ecc.mode == NAND_ECC_HW) | ||
| 1003 | config2 |= NFC_V3_CONFIG2_ECC_EN; | ||
| 1004 | |||
| 1005 | addr_phases = fls(chip->pagemask) >> 3; | 1016 | addr_phases = fls(chip->pagemask) >> 3; |
| 1006 | 1017 | ||
| 1007 | if (mtd->writesize == 2048) { | 1018 | if (mtd->writesize == 2048) { |
| @@ -1016,6 +1027,9 @@ static void preset_v3(struct mtd_info *mtd) | |||
| 1016 | } | 1027 | } |
| 1017 | 1028 | ||
| 1018 | if (mtd->writesize) { | 1029 | if (mtd->writesize) { |
| 1030 | if (chip->ecc.mode == NAND_ECC_HW) | ||
| 1031 | config2 |= NFC_V3_CONFIG2_ECC_EN; | ||
| 1032 | |||
| 1019 | config2 |= NFC_V3_CONFIG2_PPB( | 1033 | config2 |= NFC_V3_CONFIG2_PPB( |
| 1020 | ffs(mtd->erasesize / mtd->writesize) - 6, | 1034 | ffs(mtd->erasesize / mtd->writesize) - 6, |
| 1021 | host->devtype_data->ppb_shift); | 1035 | host->devtype_data->ppb_shift); |
| @@ -1066,6 +1080,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 1066 | host->status_request = true; | 1080 | host->status_request = true; |
| 1067 | 1081 | ||
| 1068 | host->devtype_data->send_cmd(host, command, true); | 1082 | host->devtype_data->send_cmd(host, command, true); |
| 1083 | WARN_ONCE(column != -1 || page_addr != -1, | ||
| 1084 | "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", | ||
| 1085 | command, column, page_addr); | ||
| 1069 | mxc_do_addr_cycle(mtd, column, page_addr); | 1086 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 1070 | break; | 1087 | break; |
| 1071 | 1088 | ||
| @@ -1079,7 +1096,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 1079 | command = NAND_CMD_READ0; /* only READ0 is valid */ | 1096 | command = NAND_CMD_READ0; /* only READ0 is valid */ |
| 1080 | 1097 | ||
| 1081 | host->devtype_data->send_cmd(host, command, false); | 1098 | host->devtype_data->send_cmd(host, command, false); |
| 1082 | mxc_do_addr_cycle(mtd, column, page_addr); | 1099 | WARN_ONCE(column < 0, |
| 1100 | "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", | ||
| 1101 | command, column, page_addr); | ||
| 1102 | mxc_do_addr_cycle(mtd, 0, page_addr); | ||
| 1083 | 1103 | ||
| 1084 | if (mtd->writesize > 512) | 1104 | if (mtd->writesize > 512) |
| 1085 | host->devtype_data->send_cmd(host, | 1105 | host->devtype_data->send_cmd(host, |
| @@ -1100,7 +1120,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 1100 | host->buf_start = column; | 1120 | host->buf_start = column; |
| 1101 | 1121 | ||
| 1102 | host->devtype_data->send_cmd(host, command, false); | 1122 | host->devtype_data->send_cmd(host, command, false); |
| 1103 | mxc_do_addr_cycle(mtd, column, page_addr); | 1123 | WARN_ONCE(column < -1, |
| 1124 | "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", | ||
| 1125 | command, column, page_addr); | ||
| 1126 | mxc_do_addr_cycle(mtd, 0, page_addr); | ||
| 1104 | break; | 1127 | break; |
| 1105 | 1128 | ||
| 1106 | case NAND_CMD_PAGEPROG: | 1129 | case NAND_CMD_PAGEPROG: |
| @@ -1108,6 +1131,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 1108 | copy_spare(mtd, false); | 1131 | copy_spare(mtd, false); |
| 1109 | host->devtype_data->send_page(mtd, NFC_INPUT); | 1132 | host->devtype_data->send_page(mtd, NFC_INPUT); |
| 1110 | host->devtype_data->send_cmd(host, command, true); | 1133 | host->devtype_data->send_cmd(host, command, true); |
| 1134 | WARN_ONCE(column != -1 || page_addr != -1, | ||
| 1135 | "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", | ||
| 1136 | command, column, page_addr); | ||
| 1111 | mxc_do_addr_cycle(mtd, column, page_addr); | 1137 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 1112 | break; | 1138 | break; |
| 1113 | 1139 | ||
| @@ -1115,15 +1141,29 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, | |||
| 1115 | host->devtype_data->send_cmd(host, command, true); | 1141 | host->devtype_data->send_cmd(host, command, true); |
| 1116 | mxc_do_addr_cycle(mtd, column, page_addr); | 1142 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 1117 | host->devtype_data->send_read_id(host); | 1143 | host->devtype_data->send_read_id(host); |
| 1118 | host->buf_start = column; | 1144 | host->buf_start = 0; |
| 1119 | break; | 1145 | break; |
| 1120 | 1146 | ||
| 1121 | case NAND_CMD_ERASE1: | 1147 | case NAND_CMD_ERASE1: |
| 1122 | case NAND_CMD_ERASE2: | 1148 | case NAND_CMD_ERASE2: |
| 1123 | host->devtype_data->send_cmd(host, command, false); | 1149 | host->devtype_data->send_cmd(host, command, false); |
| 1150 | WARN_ONCE(column != -1, | ||
| 1151 | "Unexpected column value (cmd=%u, col=%d)\n", | ||
| 1152 | command, column); | ||
| 1124 | mxc_do_addr_cycle(mtd, column, page_addr); | 1153 | mxc_do_addr_cycle(mtd, column, page_addr); |
| 1125 | 1154 | ||
| 1126 | break; | 1155 | break; |
| 1156 | case NAND_CMD_PARAM: | ||
| 1157 | host->devtype_data->send_cmd(host, command, false); | ||
| 1158 | mxc_do_addr_cycle(mtd, column, page_addr); | ||
| 1159 | host->devtype_data->send_page(mtd, NFC_OUTPUT); | ||
| 1160 | memcpy32_fromio(host->data_buf, host->main_area0, 512); | ||
| 1161 | host->buf_start = 0; | ||
| 1162 | break; | ||
| 1163 | default: | ||
| 1164 | WARN_ONCE(1, "Unimplemented command (cmd=%u)\n", | ||
| 1165 | command); | ||
| 1166 | break; | ||
| 1127 | } | 1167 | } |
| 1128 | } | 1168 | } |
| 1129 | 1169 | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index df7eb4ff07d1..c2e1232cd45c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
| @@ -386,7 +386,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
| 386 | uint8_t buf[2] = { 0, 0 }; | 386 | uint8_t buf[2] = { 0, 0 }; |
| 387 | int ret = 0, res, i = 0; | 387 | int ret = 0, res, i = 0; |
| 388 | 388 | ||
| 389 | ops.datbuf = NULL; | 389 | memset(&ops, 0, sizeof(ops)); |
| 390 | ops.oobbuf = buf; | 390 | ops.oobbuf = buf; |
| 391 | ops.ooboffs = chip->badblockpos; | 391 | ops.ooboffs = chip->badblockpos; |
| 392 | if (chip->options & NAND_BUSWIDTH_16) { | 392 | if (chip->options & NAND_BUSWIDTH_16) { |
| @@ -566,6 +566,25 @@ void nand_wait_ready(struct mtd_info *mtd) | |||
| 566 | EXPORT_SYMBOL_GPL(nand_wait_ready); | 566 | EXPORT_SYMBOL_GPL(nand_wait_ready); |
| 567 | 567 | ||
| 568 | /** | 568 | /** |
| 569 | * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands. | ||
| 570 | * @mtd: MTD device structure | ||
| 571 | * @timeo: Timeout in ms | ||
| 572 | * | ||
| 573 | * Wait for status ready (i.e. command done) or timeout. | ||
| 574 | */ | ||
| 575 | static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo) | ||
| 576 | { | ||
| 577 | register struct nand_chip *chip = mtd->priv; | ||
| 578 | |||
| 579 | timeo = jiffies + msecs_to_jiffies(timeo); | ||
| 580 | do { | ||
| 581 | if ((chip->read_byte(mtd) & NAND_STATUS_READY)) | ||
| 582 | break; | ||
| 583 | touch_softlockup_watchdog(); | ||
| 584 | } while (time_before(jiffies, timeo)); | ||
| 585 | }; | ||
| 586 | |||
| 587 | /** | ||
| 569 | * nand_command - [DEFAULT] Send command to NAND device | 588 | * nand_command - [DEFAULT] Send command to NAND device |
| 570 | * @mtd: MTD device structure | 589 | * @mtd: MTD device structure |
| 571 | * @command: the command to be sent | 590 | * @command: the command to be sent |
| @@ -643,8 +662,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, | |||
| 643 | NAND_CTRL_CLE | NAND_CTRL_CHANGE); | 662 | NAND_CTRL_CLE | NAND_CTRL_CHANGE); |
| 644 | chip->cmd_ctrl(mtd, | 663 | chip->cmd_ctrl(mtd, |
| 645 | NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); | 664 | NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); |
| 646 | while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) | 665 | /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ |
| 647 | ; | 666 | nand_wait_status_ready(mtd, 250); |
| 648 | return; | 667 | return; |
| 649 | 668 | ||
| 650 | /* This applies to read commands */ | 669 | /* This applies to read commands */ |
| @@ -740,8 +759,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, | |||
| 740 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); | 759 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); |
| 741 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, | 760 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, |
| 742 | NAND_NCE | NAND_CTRL_CHANGE); | 761 | NAND_NCE | NAND_CTRL_CHANGE); |
| 743 | while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) | 762 | /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ |
| 744 | ; | 763 | nand_wait_status_ready(mtd, 250); |
| 745 | return; | 764 | return; |
| 746 | 765 | ||
| 747 | case NAND_CMD_RNDOUT: | 766 | case NAND_CMD_RNDOUT: |
| @@ -968,7 +987,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
| 968 | __func__, (unsigned long long)ofs, len); | 987 | __func__, (unsigned long long)ofs, len); |
| 969 | 988 | ||
| 970 | if (check_offs_len(mtd, ofs, len)) | 989 | if (check_offs_len(mtd, ofs, len)) |
| 971 | ret = -EINVAL; | 990 | return -EINVAL; |
| 972 | 991 | ||
| 973 | /* Align to last block address if size addresses end of the device */ | 992 | /* Align to last block address if size addresses end of the device */ |
| 974 | if (ofs + len == mtd->size) | 993 | if (ofs + len == mtd->size) |
| @@ -1031,7 +1050,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
| 1031 | __func__, (unsigned long long)ofs, len); | 1050 | __func__, (unsigned long long)ofs, len); |
| 1032 | 1051 | ||
| 1033 | if (check_offs_len(mtd, ofs, len)) | 1052 | if (check_offs_len(mtd, ofs, len)) |
| 1034 | ret = -EINVAL; | 1053 | return -EINVAL; |
| 1035 | 1054 | ||
| 1036 | nand_get_device(mtd, FL_LOCKING); | 1055 | nand_get_device(mtd, FL_LOCKING); |
| 1037 | 1056 | ||
| @@ -1716,9 +1735,9 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 1716 | int ret; | 1735 | int ret; |
| 1717 | 1736 | ||
| 1718 | nand_get_device(mtd, FL_READING); | 1737 | nand_get_device(mtd, FL_READING); |
| 1738 | memset(&ops, 0, sizeof(ops)); | ||
| 1719 | ops.len = len; | 1739 | ops.len = len; |
| 1720 | ops.datbuf = buf; | 1740 | ops.datbuf = buf; |
| 1721 | ops.oobbuf = NULL; | ||
| 1722 | ops.mode = MTD_OPS_PLACE_OOB; | 1741 | ops.mode = MTD_OPS_PLACE_OOB; |
| 1723 | ret = nand_do_read_ops(mtd, from, &ops); | 1742 | ret = nand_do_read_ops(mtd, from, &ops); |
| 1724 | *retlen = ops.retlen; | 1743 | *retlen = ops.retlen; |
| @@ -2124,7 +2143,7 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
| 2124 | 2143 | ||
| 2125 | 2144 | ||
| 2126 | /** | 2145 | /** |
| 2127 | * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write | 2146 | * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write |
| 2128 | * @mtd: mtd info structure | 2147 | * @mtd: mtd info structure |
| 2129 | * @chip: nand chip info structure | 2148 | * @chip: nand chip info structure |
| 2130 | * @offset: column address of subpage within the page | 2149 | * @offset: column address of subpage within the page |
| @@ -2508,9 +2527,9 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 2508 | /* Grab the device */ | 2527 | /* Grab the device */ |
| 2509 | panic_nand_get_device(chip, mtd, FL_WRITING); | 2528 | panic_nand_get_device(chip, mtd, FL_WRITING); |
| 2510 | 2529 | ||
| 2530 | memset(&ops, 0, sizeof(ops)); | ||
| 2511 | ops.len = len; | 2531 | ops.len = len; |
| 2512 | ops.datbuf = (uint8_t *)buf; | 2532 | ops.datbuf = (uint8_t *)buf; |
| 2513 | ops.oobbuf = NULL; | ||
| 2514 | ops.mode = MTD_OPS_PLACE_OOB; | 2533 | ops.mode = MTD_OPS_PLACE_OOB; |
| 2515 | 2534 | ||
| 2516 | ret = nand_do_write_ops(mtd, to, &ops); | 2535 | ret = nand_do_write_ops(mtd, to, &ops); |
| @@ -2536,9 +2555,9 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 2536 | int ret; | 2555 | int ret; |
| 2537 | 2556 | ||
| 2538 | nand_get_device(mtd, FL_WRITING); | 2557 | nand_get_device(mtd, FL_WRITING); |
| 2558 | memset(&ops, 0, sizeof(ops)); | ||
| 2539 | ops.len = len; | 2559 | ops.len = len; |
| 2540 | ops.datbuf = (uint8_t *)buf; | 2560 | ops.datbuf = (uint8_t *)buf; |
| 2541 | ops.oobbuf = NULL; | ||
| 2542 | ops.mode = MTD_OPS_PLACE_OOB; | 2561 | ops.mode = MTD_OPS_PLACE_OOB; |
| 2543 | ret = nand_do_write_ops(mtd, to, &ops); | 2562 | ret = nand_do_write_ops(mtd, to, &ops); |
| 2544 | *retlen = ops.retlen; | 2563 | *retlen = ops.retlen; |
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 10b1f7a4fe50..a4615fcc3d00 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c | |||
| @@ -38,8 +38,8 @@ | |||
| 38 | 38 | ||
| 39 | #include <linux/platform_data/mtd-nand-pxa3xx.h> | 39 | #include <linux/platform_data/mtd-nand-pxa3xx.h> |
| 40 | 40 | ||
| 41 | #define CHIP_DELAY_TIMEOUT (2 * HZ/10) | 41 | #define CHIP_DELAY_TIMEOUT msecs_to_jiffies(200) |
| 42 | #define NAND_STOP_DELAY (2 * HZ/50) | 42 | #define NAND_STOP_DELAY msecs_to_jiffies(40) |
| 43 | #define PAGE_CHUNK_SIZE (2048) | 43 | #define PAGE_CHUNK_SIZE (2048) |
| 44 | 44 | ||
| 45 | /* | 45 | /* |
| @@ -605,11 +605,24 @@ static void start_data_dma(struct pxa3xx_nand_info *info) | |||
| 605 | {} | 605 | {} |
| 606 | #endif | 606 | #endif |
| 607 | 607 | ||
| 608 | static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data) | ||
| 609 | { | ||
| 610 | struct pxa3xx_nand_info *info = data; | ||
| 611 | |||
| 612 | handle_data_pio(info); | ||
| 613 | |||
| 614 | info->state = STATE_CMD_DONE; | ||
| 615 | nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); | ||
| 616 | |||
| 617 | return IRQ_HANDLED; | ||
| 618 | } | ||
| 619 | |||
| 608 | static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | 620 | static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) |
| 609 | { | 621 | { |
| 610 | struct pxa3xx_nand_info *info = devid; | 622 | struct pxa3xx_nand_info *info = devid; |
| 611 | unsigned int status, is_completed = 0, is_ready = 0; | 623 | unsigned int status, is_completed = 0, is_ready = 0; |
| 612 | unsigned int ready, cmd_done; | 624 | unsigned int ready, cmd_done; |
| 625 | irqreturn_t ret = IRQ_HANDLED; | ||
| 613 | 626 | ||
| 614 | if (info->cs == 0) { | 627 | if (info->cs == 0) { |
| 615 | ready = NDSR_FLASH_RDY; | 628 | ready = NDSR_FLASH_RDY; |
| @@ -651,7 +664,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | |||
| 651 | } else { | 664 | } else { |
| 652 | info->state = (status & NDSR_RDDREQ) ? | 665 | info->state = (status & NDSR_RDDREQ) ? |
| 653 | STATE_PIO_READING : STATE_PIO_WRITING; | 666 | STATE_PIO_READING : STATE_PIO_WRITING; |
| 654 | handle_data_pio(info); | 667 | ret = IRQ_WAKE_THREAD; |
| 668 | goto NORMAL_IRQ_EXIT; | ||
| 655 | } | 669 | } |
| 656 | } | 670 | } |
| 657 | if (status & cmd_done) { | 671 | if (status & cmd_done) { |
| @@ -692,7 +706,7 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) | |||
| 692 | if (is_ready) | 706 | if (is_ready) |
| 693 | complete(&info->dev_ready); | 707 | complete(&info->dev_ready); |
| 694 | NORMAL_IRQ_EXIT: | 708 | NORMAL_IRQ_EXIT: |
| 695 | return IRQ_HANDLED; | 709 | return ret; |
| 696 | } | 710 | } |
| 697 | 711 | ||
| 698 | static inline int is_buf_blank(uint8_t *buf, size_t len) | 712 | static inline int is_buf_blank(uint8_t *buf, size_t len) |
| @@ -951,7 +965,7 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
| 951 | { | 965 | { |
| 952 | struct pxa3xx_nand_host *host = mtd->priv; | 966 | struct pxa3xx_nand_host *host = mtd->priv; |
| 953 | struct pxa3xx_nand_info *info = host->info_data; | 967 | struct pxa3xx_nand_info *info = host->info_data; |
| 954 | int ret, exec_cmd; | 968 | int exec_cmd; |
| 955 | 969 | ||
| 956 | /* | 970 | /* |
| 957 | * if this is a x16 device ,then convert the input | 971 | * if this is a x16 device ,then convert the input |
| @@ -983,9 +997,8 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, | |||
| 983 | info->need_wait = 1; | 997 | info->need_wait = 1; |
| 984 | pxa3xx_nand_start(info); | 998 | pxa3xx_nand_start(info); |
| 985 | 999 | ||
| 986 | ret = wait_for_completion_timeout(&info->cmd_complete, | 1000 | if (!wait_for_completion_timeout(&info->cmd_complete, |
| 987 | CHIP_DELAY_TIMEOUT); | 1001 | CHIP_DELAY_TIMEOUT)) { |
| 988 | if (!ret) { | ||
| 989 | dev_err(&info->pdev->dev, "Wait time out!!!\n"); | 1002 | dev_err(&info->pdev->dev, "Wait time out!!!\n"); |
| 990 | /* Stop State Machine for next command cycle */ | 1003 | /* Stop State Machine for next command cycle */ |
| 991 | pxa3xx_nand_stop(info); | 1004 | pxa3xx_nand_stop(info); |
| @@ -1000,7 +1013,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, | |||
| 1000 | { | 1013 | { |
| 1001 | struct pxa3xx_nand_host *host = mtd->priv; | 1014 | struct pxa3xx_nand_host *host = mtd->priv; |
| 1002 | struct pxa3xx_nand_info *info = host->info_data; | 1015 | struct pxa3xx_nand_info *info = host->info_data; |
| 1003 | int ret, exec_cmd, ext_cmd_type; | 1016 | int exec_cmd, ext_cmd_type; |
| 1004 | 1017 | ||
| 1005 | /* | 1018 | /* |
| 1006 | * if this is a x16 device then convert the input | 1019 | * if this is a x16 device then convert the input |
| @@ -1063,9 +1076,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, | |||
| 1063 | init_completion(&info->cmd_complete); | 1076 | init_completion(&info->cmd_complete); |
| 1064 | pxa3xx_nand_start(info); | 1077 | pxa3xx_nand_start(info); |
| 1065 | 1078 | ||
| 1066 | ret = wait_for_completion_timeout(&info->cmd_complete, | 1079 | if (!wait_for_completion_timeout(&info->cmd_complete, |
| 1067 | CHIP_DELAY_TIMEOUT); | 1080 | CHIP_DELAY_TIMEOUT)) { |
| 1068 | if (!ret) { | ||
| 1069 | dev_err(&info->pdev->dev, "Wait time out!!!\n"); | 1081 | dev_err(&info->pdev->dev, "Wait time out!!!\n"); |
| 1070 | /* Stop State Machine for next command cycle */ | 1082 | /* Stop State Machine for next command cycle */ |
| 1071 | pxa3xx_nand_stop(info); | 1083 | pxa3xx_nand_stop(info); |
| @@ -1198,13 +1210,11 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) | |||
| 1198 | { | 1210 | { |
| 1199 | struct pxa3xx_nand_host *host = mtd->priv; | 1211 | struct pxa3xx_nand_host *host = mtd->priv; |
| 1200 | struct pxa3xx_nand_info *info = host->info_data; | 1212 | struct pxa3xx_nand_info *info = host->info_data; |
| 1201 | int ret; | ||
| 1202 | 1213 | ||
| 1203 | if (info->need_wait) { | 1214 | if (info->need_wait) { |
| 1204 | ret = wait_for_completion_timeout(&info->dev_ready, | ||
| 1205 | CHIP_DELAY_TIMEOUT); | ||
| 1206 | info->need_wait = 0; | 1215 | info->need_wait = 0; |
| 1207 | if (!ret) { | 1216 | if (!wait_for_completion_timeout(&info->dev_ready, |
| 1217 | CHIP_DELAY_TIMEOUT)) { | ||
| 1208 | dev_err(&info->pdev->dev, "Ready time out!!!\n"); | 1218 | dev_err(&info->pdev->dev, "Ready time out!!!\n"); |
| 1209 | return NAND_STATUS_FAIL; | 1219 | return NAND_STATUS_FAIL; |
| 1210 | } | 1220 | } |
| @@ -1508,6 +1518,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) | |||
| 1508 | return ret; | 1518 | return ret; |
| 1509 | } | 1519 | } |
| 1510 | 1520 | ||
| 1521 | memset(pxa3xx_flash_ids, 0, sizeof(pxa3xx_flash_ids)); | ||
| 1522 | |||
| 1511 | pxa3xx_flash_ids[0].name = f->name; | 1523 | pxa3xx_flash_ids[0].name = f->name; |
| 1512 | pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff; | 1524 | pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff; |
| 1513 | pxa3xx_flash_ids[0].pagesize = f->page_size; | 1525 | pxa3xx_flash_ids[0].pagesize = f->page_size; |
| @@ -1710,7 +1722,9 @@ static int alloc_nand_resource(struct platform_device *pdev) | |||
| 1710 | /* initialize all interrupts to be disabled */ | 1722 | /* initialize all interrupts to be disabled */ |
| 1711 | disable_int(info, NDSR_MASK); | 1723 | disable_int(info, NDSR_MASK); |
| 1712 | 1724 | ||
| 1713 | ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info); | 1725 | ret = request_threaded_irq(irq, pxa3xx_nand_irq, |
| 1726 | pxa3xx_nand_irq_thread, IRQF_ONESHOT, | ||
| 1727 | pdev->name, info); | ||
| 1714 | if (ret < 0) { | 1728 | if (ret < 0) { |
| 1715 | dev_err(&pdev->dev, "failed to request IRQ\n"); | 1729 | dev_err(&pdev->dev, "failed to request IRQ\n"); |
| 1716 | goto fail_free_buf; | 1730 | goto fail_free_buf; |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 35aef5edb588..0e02be47ce1d 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
| @@ -948,8 +948,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) | |||
| 948 | 948 | ||
| 949 | cpu_type = platform_get_device_id(pdev)->driver_data; | 949 | cpu_type = platform_get_device_id(pdev)->driver_data; |
| 950 | 950 | ||
| 951 | pr_debug("s3c2410_nand_probe(%p)\n", pdev); | ||
| 952 | |||
| 953 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | 951 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
| 954 | if (info == NULL) { | 952 | if (info == NULL) { |
| 955 | err = -ENOMEM; | 953 | err = -ENOMEM; |
| @@ -1045,7 +1043,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) | |||
| 1045 | s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); | 1043 | s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); |
| 1046 | } | 1044 | } |
| 1047 | 1045 | ||
| 1048 | pr_debug("initialised ok\n"); | ||
| 1049 | return 0; | 1046 | return 0; |
| 1050 | 1047 | ||
| 1051 | exit_error: | 1048 | exit_error: |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 635ee0027691..43b3392ffee7 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
| @@ -1743,7 +1743,6 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 1743 | struct onenand_chip *this = mtd->priv; | 1743 | struct onenand_chip *this = mtd->priv; |
| 1744 | int column, subpage; | 1744 | int column, subpage; |
| 1745 | int written = 0; | 1745 | int written = 0; |
| 1746 | int ret = 0; | ||
| 1747 | 1746 | ||
| 1748 | if (this->state == FL_PM_SUSPENDED) | 1747 | if (this->state == FL_PM_SUSPENDED) |
| 1749 | return -EBUSY; | 1748 | return -EBUSY; |
| @@ -1786,15 +1785,10 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 1786 | onenand_panic_wait(mtd); | 1785 | onenand_panic_wait(mtd); |
| 1787 | 1786 | ||
| 1788 | /* In partial page write we don't update bufferram */ | 1787 | /* In partial page write we don't update bufferram */ |
| 1789 | onenand_update_bufferram(mtd, to, !ret && !subpage); | 1788 | onenand_update_bufferram(mtd, to, !subpage); |
| 1790 | if (ONENAND_IS_2PLANE(this)) { | 1789 | if (ONENAND_IS_2PLANE(this)) { |
| 1791 | ONENAND_SET_BUFFERRAM1(this); | 1790 | ONENAND_SET_BUFFERRAM1(this); |
| 1792 | onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); | 1791 | onenand_update_bufferram(mtd, to + this->writesize, !subpage); |
| 1793 | } | ||
| 1794 | |||
| 1795 | if (ret) { | ||
| 1796 | printk(KERN_ERR "%s: write failed %d\n", __func__, ret); | ||
| 1797 | break; | ||
| 1798 | } | 1792 | } |
| 1799 | 1793 | ||
| 1800 | written += thislen; | 1794 | written += thislen; |
| @@ -1808,7 +1802,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 1808 | } | 1802 | } |
| 1809 | 1803 | ||
| 1810 | *retlen = written; | 1804 | *retlen = written; |
| 1811 | return ret; | 1805 | return 0; |
| 1812 | } | 1806 | } |
| 1813 | 1807 | ||
| 1814 | /** | 1808 | /** |
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 1c7308c2c77d..5d5d36272bb5 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c | |||
| @@ -460,8 +460,7 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len) | |||
| 460 | writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR); | 460 | writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR); |
| 461 | 461 | ||
| 462 | /* Wait for the interrupt. */ | 462 | /* Wait for the interrupt. */ |
| 463 | err = wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000)); | 463 | if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) { |
| 464 | if (!err) { | ||
| 465 | dev_err(q->dev, | 464 | dev_err(q->dev, |
| 466 | "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n", | 465 | "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n", |
| 467 | cmd, addr, readl(base + QUADSPI_FR), | 466 | cmd, addr, readl(base + QUADSPI_FR), |
| @@ -830,27 +829,27 @@ static int fsl_qspi_probe(struct platform_device *pdev) | |||
| 830 | 829 | ||
| 831 | ret = clk_prepare_enable(q->clk_en); | 830 | ret = clk_prepare_enable(q->clk_en); |
| 832 | if (ret) { | 831 | if (ret) { |
| 833 | dev_err(dev, "can not enable the qspi_en clock\n"); | 832 | dev_err(dev, "cannot enable the qspi_en clock: %d\n", ret); |
| 834 | return ret; | 833 | return ret; |
| 835 | } | 834 | } |
| 836 | 835 | ||
| 837 | ret = clk_prepare_enable(q->clk); | 836 | ret = clk_prepare_enable(q->clk); |
| 838 | if (ret) { | 837 | if (ret) { |
| 839 | dev_err(dev, "can not enable the qspi clock\n"); | 838 | dev_err(dev, "cannot enable the qspi clock: %d\n", ret); |
| 840 | goto clk_failed; | 839 | goto clk_failed; |
| 841 | } | 840 | } |
| 842 | 841 | ||
| 843 | /* find the irq */ | 842 | /* find the irq */ |
| 844 | ret = platform_get_irq(pdev, 0); | 843 | ret = platform_get_irq(pdev, 0); |
| 845 | if (ret < 0) { | 844 | if (ret < 0) { |
| 846 | dev_err(dev, "failed to get the irq\n"); | 845 | dev_err(dev, "failed to get the irq: %d\n", ret); |
| 847 | goto irq_failed; | 846 | goto irq_failed; |
| 848 | } | 847 | } |
| 849 | 848 | ||
| 850 | ret = devm_request_irq(dev, ret, | 849 | ret = devm_request_irq(dev, ret, |
| 851 | fsl_qspi_irq_handler, 0, pdev->name, q); | 850 | fsl_qspi_irq_handler, 0, pdev->name, q); |
| 852 | if (ret) { | 851 | if (ret) { |
| 853 | dev_err(dev, "failed to request irq.\n"); | 852 | dev_err(dev, "failed to request irq: %d\n", ret); |
| 854 | goto irq_failed; | 853 | goto irq_failed; |
| 855 | } | 854 | } |
| 856 | 855 | ||
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b6a5a0c269e1..14a5d2325dac 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c | |||
| @@ -369,17 +369,13 @@ erase_err: | |||
| 369 | return ret; | 369 | return ret; |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | 372 | static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) |
| 373 | { | 373 | { |
| 374 | struct spi_nor *nor = mtd_to_spi_nor(mtd); | 374 | struct mtd_info *mtd = nor->mtd; |
| 375 | uint32_t offset = ofs; | 375 | uint32_t offset = ofs; |
| 376 | uint8_t status_old, status_new; | 376 | uint8_t status_old, status_new; |
| 377 | int ret = 0; | 377 | int ret = 0; |
| 378 | 378 | ||
| 379 | ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); | ||
| 380 | if (ret) | ||
| 381 | return ret; | ||
| 382 | |||
| 383 | status_old = read_sr(nor); | 379 | status_old = read_sr(nor); |
| 384 | 380 | ||
| 385 | if (offset < mtd->size - (mtd->size / 2)) | 381 | if (offset < mtd->size - (mtd->size / 2)) |
| @@ -402,26 +398,18 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
| 402 | (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { | 398 | (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { |
| 403 | write_enable(nor); | 399 | write_enable(nor); |
| 404 | ret = write_sr(nor, status_new); | 400 | ret = write_sr(nor, status_new); |
| 405 | if (ret) | ||
| 406 | goto err; | ||
| 407 | } | 401 | } |
| 408 | 402 | ||
| 409 | err: | ||
| 410 | spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); | ||
| 411 | return ret; | 403 | return ret; |
| 412 | } | 404 | } |
| 413 | 405 | ||
| 414 | static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | 406 | static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) |
| 415 | { | 407 | { |
| 416 | struct spi_nor *nor = mtd_to_spi_nor(mtd); | 408 | struct mtd_info *mtd = nor->mtd; |
| 417 | uint32_t offset = ofs; | 409 | uint32_t offset = ofs; |
| 418 | uint8_t status_old, status_new; | 410 | uint8_t status_old, status_new; |
| 419 | int ret = 0; | 411 | int ret = 0; |
| 420 | 412 | ||
| 421 | ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); | ||
| 422 | if (ret) | ||
| 423 | return ret; | ||
| 424 | |||
| 425 | status_old = read_sr(nor); | 413 | status_old = read_sr(nor); |
| 426 | 414 | ||
| 427 | if (offset+len > mtd->size - (mtd->size / 64)) | 415 | if (offset+len > mtd->size - (mtd->size / 64)) |
| @@ -444,15 +432,41 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | |||
| 444 | (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { | 432 | (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { |
| 445 | write_enable(nor); | 433 | write_enable(nor); |
| 446 | ret = write_sr(nor, status_new); | 434 | ret = write_sr(nor, status_new); |
| 447 | if (ret) | ||
| 448 | goto err; | ||
| 449 | } | 435 | } |
| 450 | 436 | ||
| 451 | err: | 437 | return ret; |
| 438 | } | ||
| 439 | |||
| 440 | static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
| 441 | { | ||
| 442 | struct spi_nor *nor = mtd_to_spi_nor(mtd); | ||
| 443 | int ret; | ||
| 444 | |||
| 445 | ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); | ||
| 446 | if (ret) | ||
| 447 | return ret; | ||
| 448 | |||
| 449 | ret = nor->flash_lock(nor, ofs, len); | ||
| 450 | |||
| 452 | spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); | 451 | spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); |
| 453 | return ret; | 452 | return ret; |
| 454 | } | 453 | } |
| 455 | 454 | ||
| 455 | static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
| 456 | { | ||
| 457 | struct spi_nor *nor = mtd_to_spi_nor(mtd); | ||
| 458 | int ret; | ||
| 459 | |||
| 460 | ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); | ||
| 461 | if (ret) | ||
| 462 | return ret; | ||
| 463 | |||
| 464 | ret = nor->flash_unlock(nor, ofs, len); | ||
| 465 | |||
| 466 | spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); | ||
| 467 | return ret; | ||
| 468 | } | ||
| 469 | |||
| 456 | /* Used when the "_ext_id" is two bytes at most */ | 470 | /* Used when the "_ext_id" is two bytes at most */ |
| 457 | #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ | 471 | #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ |
| 458 | ((kernel_ulong_t)&(struct flash_info) { \ | 472 | ((kernel_ulong_t)&(struct flash_info) { \ |
| @@ -524,6 +538,7 @@ static const struct spi_device_id spi_nor_ids[] = { | |||
| 524 | { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, | 538 | { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, |
| 525 | { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, | 539 | { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, |
| 526 | { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, | 540 | { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, |
| 541 | { "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, 0) }, | ||
| 527 | 542 | ||
| 528 | /* ESMT */ | 543 | /* ESMT */ |
| 529 | { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, | 544 | { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, |
| @@ -553,6 +568,7 @@ static const struct spi_device_id spi_nor_ids[] = { | |||
| 553 | { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, | 568 | { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, |
| 554 | { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, | 569 | { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, |
| 555 | { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, | 570 | { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, |
| 571 | { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, | ||
| 556 | { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, | 572 | { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, |
| 557 | { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, | 573 | { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, |
| 558 | { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, | 574 | { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, |
| @@ -648,6 +664,7 @@ static const struct spi_device_id spi_nor_ids[] = { | |||
| 648 | { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, | 664 | { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, |
| 649 | 665 | ||
| 650 | /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ | 666 | /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ |
| 667 | { "w25x05", INFO(0xef3010, 0, 64 * 1024, 1, SECT_4K) }, | ||
| 651 | { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, | 668 | { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, |
| 652 | { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, | 669 | { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, |
| 653 | { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, | 670 | { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, |
| @@ -658,6 +675,7 @@ static const struct spi_device_id spi_nor_ids[] = { | |||
| 658 | { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, | 675 | { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, |
| 659 | { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, | 676 | { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, |
| 660 | { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, | 677 | { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, |
| 678 | { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K) }, | ||
| 661 | { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, | 679 | { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, |
| 662 | { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, | 680 | { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, |
| 663 | { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, | 681 | { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, |
| @@ -1045,6 +1063,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) | |||
| 1045 | 1063 | ||
| 1046 | /* nor protection support for STmicro chips */ | 1064 | /* nor protection support for STmicro chips */ |
| 1047 | if (JEDEC_MFR(info) == CFI_MFR_ST) { | 1065 | if (JEDEC_MFR(info) == CFI_MFR_ST) { |
| 1066 | nor->flash_lock = stm_lock; | ||
| 1067 | nor->flash_unlock = stm_unlock; | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | if (nor->flash_lock && nor->flash_unlock) { | ||
| 1048 | mtd->_lock = spi_nor_lock; | 1071 | mtd->_lock = spi_nor_lock; |
| 1049 | mtd->_unlock = spi_nor_unlock; | 1072 | mtd->_unlock = spi_nor_unlock; |
| 1050 | } | 1073 | } |
diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index e579f9027c47..79316159eec6 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | #include <linux/slab.h> | 9 | #include <linux/slab.h> |
| 10 | #include <linux/mtd/nand_ecc.h> | 10 | #include <linux/mtd/nand_ecc.h> |
| 11 | 11 | ||
| 12 | #include "mtd_test.h" | ||
| 13 | |||
| 12 | /* | 14 | /* |
| 13 | * Test the implementation for software ECC | 15 | * Test the implementation for software ECC |
| 14 | * | 16 | * |
| @@ -274,6 +276,10 @@ static int nand_ecc_test_run(const size_t size) | |||
| 274 | } | 276 | } |
| 275 | pr_info("ok - %s-%zd\n", | 277 | pr_info("ok - %s-%zd\n", |
| 276 | nand_ecc_test[i].name, size); | 278 | nand_ecc_test[i].name, size); |
| 279 | |||
| 280 | err = mtdtest_relax(); | ||
| 281 | if (err) | ||
| 282 | break; | ||
| 277 | } | 283 | } |
| 278 | error: | 284 | error: |
| 279 | kfree(error_data); | 285 | kfree(error_data); |
diff --git a/drivers/mtd/tests/mtd_test.h b/drivers/mtd/tests/mtd_test.h index f437c776c54f..4b7bee17c924 100644 --- a/drivers/mtd/tests/mtd_test.h +++ b/drivers/mtd/tests/mtd_test.h | |||
| @@ -1,4 +1,16 @@ | |||
| 1 | #include <linux/mtd/mtd.h> | 1 | #include <linux/mtd/mtd.h> |
| 2 | #include <linux/sched.h> | ||
| 3 | |||
| 4 | static inline int mtdtest_relax(void) | ||
| 5 | { | ||
| 6 | cond_resched(); | ||
| 7 | if (signal_pending(current)) { | ||
| 8 | pr_info("aborting test due to pending signal!\n"); | ||
| 9 | return -EINTR; | ||
| 10 | } | ||
| 11 | |||
| 12 | return 0; | ||
| 13 | } | ||
| 2 | 14 | ||
| 3 | int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum); | 15 | int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum); |
| 4 | int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, | 16 | int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, |
diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c index 273f7e553954..09a4ccac53a2 100644 --- a/drivers/mtd/tests/nandbiterrs.c +++ b/drivers/mtd/tests/nandbiterrs.c | |||
| @@ -320,6 +320,10 @@ static int overwrite_test(void) | |||
| 320 | break; | 320 | break; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | err = mtdtest_relax(); | ||
| 324 | if (err) | ||
| 325 | break; | ||
| 326 | |||
| 323 | opno++; | 327 | opno++; |
| 324 | } | 328 | } |
| 325 | 329 | ||
diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 5e061186eab1..8e8525f0202f 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c | |||
| @@ -70,7 +70,7 @@ static int write_eraseblock(int ebnum) | |||
| 70 | int i; | 70 | int i; |
| 71 | struct mtd_oob_ops ops; | 71 | struct mtd_oob_ops ops; |
| 72 | int err = 0; | 72 | int err = 0; |
| 73 | loff_t addr = ebnum * mtd->erasesize; | 73 | loff_t addr = (loff_t)ebnum * mtd->erasesize; |
| 74 | 74 | ||
| 75 | prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); | 75 | prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); |
| 76 | for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { | 76 | for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { |
| @@ -112,7 +112,10 @@ static int write_whole_device(void) | |||
| 112 | return err; | 112 | return err; |
| 113 | if (i % 256 == 0) | 113 | if (i % 256 == 0) |
| 114 | pr_info("written up to eraseblock %u\n", i); | 114 | pr_info("written up to eraseblock %u\n", i); |
| 115 | cond_resched(); | 115 | |
| 116 | err = mtdtest_relax(); | ||
| 117 | if (err) | ||
| 118 | return err; | ||
| 116 | } | 119 | } |
| 117 | pr_info("written %u eraseblocks\n", i); | 120 | pr_info("written %u eraseblocks\n", i); |
| 118 | return 0; | 121 | return 0; |
| @@ -141,6 +144,31 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou | |||
| 141 | return bitflips; | 144 | return bitflips; |
| 142 | } | 145 | } |
| 143 | 146 | ||
| 147 | /* | ||
| 148 | * Compare with 0xff and show the address, offset and data bytes at | ||
| 149 | * comparison failure. Return number of bitflips encountered. | ||
| 150 | */ | ||
| 151 | static size_t memffshow(loff_t addr, loff_t offset, const void *cs, | ||
| 152 | size_t count) | ||
| 153 | { | ||
| 154 | const unsigned char *su1; | ||
| 155 | int res; | ||
| 156 | size_t i = 0; | ||
| 157 | size_t bitflips = 0; | ||
| 158 | |||
| 159 | for (su1 = cs; 0 < count; ++su1, count--, i++) { | ||
| 160 | res = *su1 ^ 0xff; | ||
| 161 | if (res) { | ||
| 162 | pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0xff diff 0x%x\n", | ||
| 163 | (unsigned long)addr, (unsigned long)offset + i, | ||
| 164 | *su1, res); | ||
| 165 | bitflips += hweight8(res); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | return bitflips; | ||
| 170 | } | ||
| 171 | |||
| 144 | static int verify_eraseblock(int ebnum) | 172 | static int verify_eraseblock(int ebnum) |
| 145 | { | 173 | { |
| 146 | int i; | 174 | int i; |
| @@ -203,6 +231,15 @@ static int verify_eraseblock(int ebnum) | |||
| 203 | bitflips = memcmpshow(addr, readbuf + use_offset, | 231 | bitflips = memcmpshow(addr, readbuf + use_offset, |
| 204 | writebuf + (use_len_max * i) + use_offset, | 232 | writebuf + (use_len_max * i) + use_offset, |
| 205 | use_len); | 233 | use_len); |
| 234 | |||
| 235 | /* verify pre-offset area for 0xff */ | ||
| 236 | bitflips += memffshow(addr, 0, readbuf, use_offset); | ||
| 237 | |||
| 238 | /* verify post-(use_offset + use_len) area for 0xff */ | ||
| 239 | k = use_offset + use_len; | ||
| 240 | bitflips += memffshow(addr, k, readbuf + k, | ||
| 241 | mtd->ecclayout->oobavail - k); | ||
| 242 | |||
| 206 | if (bitflips > bitflip_limit) { | 243 | if (bitflips > bitflip_limit) { |
| 207 | pr_err("error: verify failed at %#llx\n", | 244 | pr_err("error: verify failed at %#llx\n", |
| 208 | (long long)addr); | 245 | (long long)addr); |
| @@ -212,34 +249,8 @@ static int verify_eraseblock(int ebnum) | |||
| 212 | return -1; | 249 | return -1; |
| 213 | } | 250 | } |
| 214 | } else if (bitflips) { | 251 | } else if (bitflips) { |
| 215 | pr_info("ignoring error as within bitflip_limit\n"); | 252 | pr_info("ignoring errors as within bitflip limit\n"); |
| 216 | } | 253 | } |
| 217 | |||
| 218 | for (k = 0; k < use_offset; ++k) | ||
| 219 | if (readbuf[k] != 0xff) { | ||
| 220 | pr_err("error: verify 0xff " | ||
| 221 | "failed at %#llx\n", | ||
| 222 | (long long)addr); | ||
| 223 | errcnt += 1; | ||
| 224 | if (errcnt > 1000) { | ||
| 225 | pr_err("error: too " | ||
| 226 | "many errors\n"); | ||
| 227 | return -1; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | for (k = use_offset + use_len; | ||
| 231 | k < mtd->ecclayout->oobavail; ++k) | ||
| 232 | if (readbuf[k] != 0xff) { | ||
| 233 | pr_err("error: verify 0xff " | ||
| 234 | "failed at %#llx\n", | ||
| 235 | (long long)addr); | ||
| 236 | errcnt += 1; | ||
| 237 | if (errcnt > 1000) { | ||
| 238 | pr_err("error: too " | ||
| 239 | "many errors\n"); | ||
| 240 | return -1; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | } | 254 | } |
| 244 | if (vary_offset) | 255 | if (vary_offset) |
| 245 | do_vary_offset(); | 256 | do_vary_offset(); |
| @@ -310,7 +321,10 @@ static int verify_all_eraseblocks(void) | |||
| 310 | return err; | 321 | return err; |
| 311 | if (i % 256 == 0) | 322 | if (i % 256 == 0) |
| 312 | pr_info("verified up to eraseblock %u\n", i); | 323 | pr_info("verified up to eraseblock %u\n", i); |
| 313 | cond_resched(); | 324 | |
| 325 | err = mtdtest_relax(); | ||
| 326 | if (err) | ||
| 327 | return err; | ||
| 314 | } | 328 | } |
| 315 | pr_info("verified %u eraseblocks\n", i); | 329 | pr_info("verified %u eraseblocks\n", i); |
| 316 | return 0; | 330 | return 0; |
| @@ -421,7 +435,10 @@ static int __init mtd_oobtest_init(void) | |||
| 421 | goto out; | 435 | goto out; |
| 422 | if (i % 256 == 0) | 436 | if (i % 256 == 0) |
| 423 | pr_info("verified up to eraseblock %u\n", i); | 437 | pr_info("verified up to eraseblock %u\n", i); |
| 424 | cond_resched(); | 438 | |
| 439 | err = mtdtest_relax(); | ||
| 440 | if (err) | ||
| 441 | goto out; | ||
| 425 | } | 442 | } |
| 426 | pr_info("verified %u eraseblocks\n", i); | 443 | pr_info("verified %u eraseblocks\n", i); |
| 427 | 444 | ||
| @@ -634,7 +651,11 @@ static int __init mtd_oobtest_init(void) | |||
| 634 | goto out; | 651 | goto out; |
| 635 | if (i % 256 == 0) | 652 | if (i % 256 == 0) |
| 636 | pr_info("written up to eraseblock %u\n", i); | 653 | pr_info("written up to eraseblock %u\n", i); |
| 637 | cond_resched(); | 654 | |
| 655 | err = mtdtest_relax(); | ||
| 656 | if (err) | ||
| 657 | goto out; | ||
| 658 | |||
| 638 | addr += mtd->writesize; | 659 | addr += mtd->writesize; |
| 639 | } | 660 | } |
| 640 | } | 661 | } |
| @@ -672,7 +693,10 @@ static int __init mtd_oobtest_init(void) | |||
| 672 | } | 693 | } |
| 673 | if (i % 256 == 0) | 694 | if (i % 256 == 0) |
| 674 | pr_info("verified up to eraseblock %u\n", i); | 695 | pr_info("verified up to eraseblock %u\n", i); |
| 675 | cond_resched(); | 696 | |
| 697 | err = mtdtest_relax(); | ||
| 698 | if (err) | ||
| 699 | goto out; | ||
| 676 | } | 700 | } |
| 677 | pr_info("verified %u eraseblocks\n", i); | 701 | pr_info("verified %u eraseblocks\n", i); |
| 678 | 702 | ||
diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c index 88296e888e9d..ba1890d5632c 100644 --- a/drivers/mtd/tests/pagetest.c +++ b/drivers/mtd/tests/pagetest.c | |||
| @@ -407,7 +407,10 @@ static int __init mtd_pagetest_init(void) | |||
| 407 | goto out; | 407 | goto out; |
| 408 | if (i % 256 == 0) | 408 | if (i % 256 == 0) |
| 409 | pr_info("written up to eraseblock %u\n", i); | 409 | pr_info("written up to eraseblock %u\n", i); |
| 410 | cond_resched(); | 410 | |
| 411 | err = mtdtest_relax(); | ||
| 412 | if (err) | ||
| 413 | goto out; | ||
| 411 | } | 414 | } |
| 412 | pr_info("written %u eraseblocks\n", i); | 415 | pr_info("written %u eraseblocks\n", i); |
| 413 | 416 | ||
| @@ -422,7 +425,10 @@ static int __init mtd_pagetest_init(void) | |||
| 422 | goto out; | 425 | goto out; |
| 423 | if (i % 256 == 0) | 426 | if (i % 256 == 0) |
| 424 | pr_info("verified up to eraseblock %u\n", i); | 427 | pr_info("verified up to eraseblock %u\n", i); |
| 425 | cond_resched(); | 428 | |
| 429 | err = mtdtest_relax(); | ||
| 430 | if (err) | ||
| 431 | goto out; | ||
| 426 | } | 432 | } |
| 427 | pr_info("verified %u eraseblocks\n", i); | 433 | pr_info("verified %u eraseblocks\n", i); |
| 428 | 434 | ||
diff --git a/drivers/mtd/tests/readtest.c b/drivers/mtd/tests/readtest.c index a54cf1511114..a3196b750a22 100644 --- a/drivers/mtd/tests/readtest.c +++ b/drivers/mtd/tests/readtest.c | |||
| @@ -190,7 +190,10 @@ static int __init mtd_readtest_init(void) | |||
| 190 | if (!err) | 190 | if (!err) |
| 191 | err = ret; | 191 | err = ret; |
| 192 | } | 192 | } |
| 193 | cond_resched(); | 193 | |
| 194 | err = mtdtest_relax(); | ||
| 195 | if (err) | ||
| 196 | goto out; | ||
| 194 | } | 197 | } |
| 195 | 198 | ||
| 196 | if (err) | 199 | if (err) |
diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c index 5ee9f7021020..5a6f31af06f9 100644 --- a/drivers/mtd/tests/speedtest.c +++ b/drivers/mtd/tests/speedtest.c | |||
| @@ -185,7 +185,7 @@ static long calc_speed(void) | |||
| 185 | (finish.tv_usec - start.tv_usec) / 1000; | 185 | (finish.tv_usec - start.tv_usec) / 1000; |
| 186 | if (ms == 0) | 186 | if (ms == 0) |
| 187 | return 0; | 187 | return 0; |
| 188 | k = goodebcnt * (mtd->erasesize / 1024) * 1000; | 188 | k = (uint64_t)goodebcnt * (mtd->erasesize / 1024) * 1000; |
| 189 | do_div(k, ms); | 189 | do_div(k, ms); |
| 190 | return k; | 190 | return k; |
| 191 | } | 191 | } |
| @@ -269,7 +269,10 @@ static int __init mtd_speedtest_init(void) | |||
| 269 | err = write_eraseblock(i); | 269 | err = write_eraseblock(i); |
| 270 | if (err) | 270 | if (err) |
| 271 | goto out; | 271 | goto out; |
| 272 | cond_resched(); | 272 | |
| 273 | err = mtdtest_relax(); | ||
| 274 | if (err) | ||
| 275 | goto out; | ||
| 273 | } | 276 | } |
| 274 | stop_timing(); | 277 | stop_timing(); |
| 275 | speed = calc_speed(); | 278 | speed = calc_speed(); |
| @@ -284,7 +287,10 @@ static int __init mtd_speedtest_init(void) | |||
| 284 | err = read_eraseblock(i); | 287 | err = read_eraseblock(i); |
| 285 | if (err) | 288 | if (err) |
| 286 | goto out; | 289 | goto out; |
| 287 | cond_resched(); | 290 | |
| 291 | err = mtdtest_relax(); | ||
| 292 | if (err) | ||
| 293 | goto out; | ||
| 288 | } | 294 | } |
| 289 | stop_timing(); | 295 | stop_timing(); |
| 290 | speed = calc_speed(); | 296 | speed = calc_speed(); |
| @@ -303,7 +309,10 @@ static int __init mtd_speedtest_init(void) | |||
| 303 | err = write_eraseblock_by_page(i); | 309 | err = write_eraseblock_by_page(i); |
| 304 | if (err) | 310 | if (err) |
| 305 | goto out; | 311 | goto out; |
| 306 | cond_resched(); | 312 | |
| 313 | err = mtdtest_relax(); | ||
| 314 | if (err) | ||
| 315 | goto out; | ||
| 307 | } | 316 | } |
| 308 | stop_timing(); | 317 | stop_timing(); |
| 309 | speed = calc_speed(); | 318 | speed = calc_speed(); |
| @@ -318,7 +327,10 @@ static int __init mtd_speedtest_init(void) | |||
| 318 | err = read_eraseblock_by_page(i); | 327 | err = read_eraseblock_by_page(i); |
| 319 | if (err) | 328 | if (err) |
| 320 | goto out; | 329 | goto out; |
| 321 | cond_resched(); | 330 | |
| 331 | err = mtdtest_relax(); | ||
| 332 | if (err) | ||
| 333 | goto out; | ||
| 322 | } | 334 | } |
| 323 | stop_timing(); | 335 | stop_timing(); |
| 324 | speed = calc_speed(); | 336 | speed = calc_speed(); |
| @@ -337,7 +349,10 @@ static int __init mtd_speedtest_init(void) | |||
| 337 | err = write_eraseblock_by_2pages(i); | 349 | err = write_eraseblock_by_2pages(i); |
| 338 | if (err) | 350 | if (err) |
| 339 | goto out; | 351 | goto out; |
| 340 | cond_resched(); | 352 | |
| 353 | err = mtdtest_relax(); | ||
| 354 | if (err) | ||
| 355 | goto out; | ||
| 341 | } | 356 | } |
| 342 | stop_timing(); | 357 | stop_timing(); |
| 343 | speed = calc_speed(); | 358 | speed = calc_speed(); |
| @@ -352,7 +367,10 @@ static int __init mtd_speedtest_init(void) | |||
| 352 | err = read_eraseblock_by_2pages(i); | 367 | err = read_eraseblock_by_2pages(i); |
| 353 | if (err) | 368 | if (err) |
| 354 | goto out; | 369 | goto out; |
| 355 | cond_resched(); | 370 | |
| 371 | err = mtdtest_relax(); | ||
| 372 | if (err) | ||
| 373 | goto out; | ||
| 356 | } | 374 | } |
| 357 | stop_timing(); | 375 | stop_timing(); |
| 358 | speed = calc_speed(); | 376 | speed = calc_speed(); |
| @@ -385,7 +403,11 @@ static int __init mtd_speedtest_init(void) | |||
| 385 | err = multiblock_erase(i, j); | 403 | err = multiblock_erase(i, j); |
| 386 | if (err) | 404 | if (err) |
| 387 | goto out; | 405 | goto out; |
| 388 | cond_resched(); | 406 | |
| 407 | err = mtdtest_relax(); | ||
| 408 | if (err) | ||
| 409 | goto out; | ||
| 410 | |||
| 389 | i += j; | 411 | i += j; |
| 390 | } | 412 | } |
| 391 | stop_timing(); | 413 | stop_timing(); |
diff --git a/drivers/mtd/tests/stresstest.c b/drivers/mtd/tests/stresstest.c index c9d42cc2df1b..e509f8aa9a7e 100644 --- a/drivers/mtd/tests/stresstest.c +++ b/drivers/mtd/tests/stresstest.c | |||
| @@ -96,7 +96,7 @@ static int do_read(void) | |||
| 96 | if (offs + len > mtd->erasesize) | 96 | if (offs + len > mtd->erasesize) |
| 97 | len = mtd->erasesize - offs; | 97 | len = mtd->erasesize - offs; |
| 98 | } | 98 | } |
| 99 | addr = eb * mtd->erasesize + offs; | 99 | addr = (loff_t)eb * mtd->erasesize + offs; |
| 100 | return mtdtest_read(mtd, addr, len, readbuf); | 100 | return mtdtest_read(mtd, addr, len, readbuf); |
| 101 | } | 101 | } |
| 102 | 102 | ||
| @@ -124,7 +124,7 @@ static int do_write(void) | |||
| 124 | offsets[eb + 1] = 0; | 124 | offsets[eb + 1] = 0; |
| 125 | } | 125 | } |
| 126 | } | 126 | } |
| 127 | addr = eb * mtd->erasesize + offs; | 127 | addr = (loff_t)eb * mtd->erasesize + offs; |
| 128 | err = mtdtest_write(mtd, addr, len, writebuf); | 128 | err = mtdtest_write(mtd, addr, len, writebuf); |
| 129 | if (unlikely(err)) | 129 | if (unlikely(err)) |
| 130 | return err; | 130 | return err; |
| @@ -221,7 +221,10 @@ static int __init mtd_stresstest_init(void) | |||
| 221 | err = do_operation(); | 221 | err = do_operation(); |
| 222 | if (err) | 222 | if (err) |
| 223 | goto out; | 223 | goto out; |
| 224 | cond_resched(); | 224 | |
| 225 | err = mtdtest_relax(); | ||
| 226 | if (err) | ||
| 227 | goto out; | ||
| 225 | } | 228 | } |
| 226 | pr_info("finished, %d operations done\n", op); | 229 | pr_info("finished, %d operations done\n", op); |
| 227 | 230 | ||
diff --git a/drivers/mtd/tests/subpagetest.c b/drivers/mtd/tests/subpagetest.c index 7b59ef522d5e..aecc6ce5a9e1 100644 --- a/drivers/mtd/tests/subpagetest.c +++ b/drivers/mtd/tests/subpagetest.c | |||
| @@ -95,7 +95,7 @@ static int write_eraseblock2(int ebnum) | |||
| 95 | loff_t addr = (loff_t)ebnum * mtd->erasesize; | 95 | loff_t addr = (loff_t)ebnum * mtd->erasesize; |
| 96 | 96 | ||
| 97 | for (k = 1; k < 33; ++k) { | 97 | for (k = 1; k < 33; ++k) { |
| 98 | if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) | 98 | if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize) |
| 99 | break; | 99 | break; |
| 100 | prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); | 100 | prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); |
| 101 | err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf); | 101 | err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf); |
| @@ -195,7 +195,7 @@ static int verify_eraseblock2(int ebnum) | |||
| 195 | loff_t addr = (loff_t)ebnum * mtd->erasesize; | 195 | loff_t addr = (loff_t)ebnum * mtd->erasesize; |
| 196 | 196 | ||
| 197 | for (k = 1; k < 33; ++k) { | 197 | for (k = 1; k < 33; ++k) { |
| 198 | if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) | 198 | if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize) |
| 199 | break; | 199 | break; |
| 200 | prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); | 200 | prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); |
| 201 | clear_data(readbuf, subpgsize * k); | 201 | clear_data(readbuf, subpgsize * k); |
| @@ -269,7 +269,10 @@ static int verify_all_eraseblocks_ff(void) | |||
| 269 | return err; | 269 | return err; |
| 270 | if (i % 256 == 0) | 270 | if (i % 256 == 0) |
| 271 | pr_info("verified up to eraseblock %u\n", i); | 271 | pr_info("verified up to eraseblock %u\n", i); |
| 272 | cond_resched(); | 272 | |
| 273 | err = mtdtest_relax(); | ||
| 274 | if (err) | ||
| 275 | return err; | ||
| 273 | } | 276 | } |
| 274 | pr_info("verified %u eraseblocks\n", i); | 277 | pr_info("verified %u eraseblocks\n", i); |
| 275 | return 0; | 278 | return 0; |
| @@ -346,7 +349,10 @@ static int __init mtd_subpagetest_init(void) | |||
| 346 | goto out; | 349 | goto out; |
| 347 | if (i % 256 == 0) | 350 | if (i % 256 == 0) |
| 348 | pr_info("written up to eraseblock %u\n", i); | 351 | pr_info("written up to eraseblock %u\n", i); |
| 349 | cond_resched(); | 352 | |
| 353 | err = mtdtest_relax(); | ||
| 354 | if (err) | ||
| 355 | goto out; | ||
| 350 | } | 356 | } |
| 351 | pr_info("written %u eraseblocks\n", i); | 357 | pr_info("written %u eraseblocks\n", i); |
| 352 | 358 | ||
| @@ -360,7 +366,10 @@ static int __init mtd_subpagetest_init(void) | |||
| 360 | goto out; | 366 | goto out; |
| 361 | if (i % 256 == 0) | 367 | if (i % 256 == 0) |
| 362 | pr_info("verified up to eraseblock %u\n", i); | 368 | pr_info("verified up to eraseblock %u\n", i); |
| 363 | cond_resched(); | 369 | |
| 370 | err = mtdtest_relax(); | ||
| 371 | if (err) | ||
| 372 | goto out; | ||
| 364 | } | 373 | } |
| 365 | pr_info("verified %u eraseblocks\n", i); | 374 | pr_info("verified %u eraseblocks\n", i); |
| 366 | 375 | ||
| @@ -383,7 +392,10 @@ static int __init mtd_subpagetest_init(void) | |||
| 383 | goto out; | 392 | goto out; |
| 384 | if (i % 256 == 0) | 393 | if (i % 256 == 0) |
| 385 | pr_info("written up to eraseblock %u\n", i); | 394 | pr_info("written up to eraseblock %u\n", i); |
| 386 | cond_resched(); | 395 | |
| 396 | err = mtdtest_relax(); | ||
| 397 | if (err) | ||
| 398 | goto out; | ||
| 387 | } | 399 | } |
| 388 | pr_info("written %u eraseblocks\n", i); | 400 | pr_info("written %u eraseblocks\n", i); |
| 389 | 401 | ||
| @@ -398,7 +410,10 @@ static int __init mtd_subpagetest_init(void) | |||
| 398 | goto out; | 410 | goto out; |
| 399 | if (i % 256 == 0) | 411 | if (i % 256 == 0) |
| 400 | pr_info("verified up to eraseblock %u\n", i); | 412 | pr_info("verified up to eraseblock %u\n", i); |
| 401 | cond_resched(); | 413 | |
| 414 | err = mtdtest_relax(); | ||
| 415 | if (err) | ||
| 416 | goto out; | ||
| 402 | } | 417 | } |
| 403 | pr_info("verified %u eraseblocks\n", i); | 418 | pr_info("verified %u eraseblocks\n", i); |
| 404 | 419 | ||
diff --git a/drivers/mtd/tests/torturetest.c b/drivers/mtd/tests/torturetest.c index b55bc52a1340..e5d6e6d9532f 100644 --- a/drivers/mtd/tests/torturetest.c +++ b/drivers/mtd/tests/torturetest.c | |||
| @@ -101,11 +101,11 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf) | |||
| 101 | { | 101 | { |
| 102 | int err, retries = 0; | 102 | int err, retries = 0; |
| 103 | size_t read; | 103 | size_t read; |
| 104 | loff_t addr = ebnum * mtd->erasesize; | 104 | loff_t addr = (loff_t)ebnum * mtd->erasesize; |
| 105 | size_t len = mtd->erasesize; | 105 | size_t len = mtd->erasesize; |
| 106 | 106 | ||
| 107 | if (pgcnt) { | 107 | if (pgcnt) { |
| 108 | addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; | 108 | addr = (loff_t)(ebnum + 1) * mtd->erasesize - pgcnt * pgsize; |
| 109 | len = pgcnt * pgsize; | 109 | len = pgcnt * pgsize; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| @@ -155,11 +155,11 @@ static inline int write_pattern(int ebnum, void *buf) | |||
| 155 | { | 155 | { |
| 156 | int err; | 156 | int err; |
| 157 | size_t written; | 157 | size_t written; |
| 158 | loff_t addr = ebnum * mtd->erasesize; | 158 | loff_t addr = (loff_t)ebnum * mtd->erasesize; |
| 159 | size_t len = mtd->erasesize; | 159 | size_t len = mtd->erasesize; |
| 160 | 160 | ||
| 161 | if (pgcnt) { | 161 | if (pgcnt) { |
| 162 | addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; | 162 | addr = (loff_t)(ebnum + 1) * mtd->erasesize - pgcnt * pgsize; |
| 163 | len = pgcnt * pgsize; | 163 | len = pgcnt * pgsize; |
| 164 | } | 164 | } |
| 165 | err = mtd_write(mtd, addr, len, &written, buf); | 165 | err = mtd_write(mtd, addr, len, &written, buf); |
| @@ -279,7 +279,10 @@ static int __init tort_init(void) | |||
| 279 | " for 0xFF... pattern\n"); | 279 | " for 0xFF... pattern\n"); |
| 280 | goto out; | 280 | goto out; |
| 281 | } | 281 | } |
| 282 | cond_resched(); | 282 | |
| 283 | err = mtdtest_relax(); | ||
| 284 | if (err) | ||
| 285 | goto out; | ||
| 283 | } | 286 | } |
| 284 | } | 287 | } |
| 285 | 288 | ||
| @@ -294,7 +297,10 @@ static int __init tort_init(void) | |||
| 294 | err = write_pattern(i, patt); | 297 | err = write_pattern(i, patt); |
| 295 | if (err) | 298 | if (err) |
| 296 | goto out; | 299 | goto out; |
| 297 | cond_resched(); | 300 | |
| 301 | err = mtdtest_relax(); | ||
| 302 | if (err) | ||
| 303 | goto out; | ||
| 298 | } | 304 | } |
| 299 | 305 | ||
| 300 | /* Verify what we wrote */ | 306 | /* Verify what we wrote */ |
| @@ -314,7 +320,10 @@ static int __init tort_init(void) | |||
| 314 | "0x55AA55..." : "0xAA55AA..."); | 320 | "0x55AA55..." : "0xAA55AA..."); |
| 315 | goto out; | 321 | goto out; |
| 316 | } | 322 | } |
| 317 | cond_resched(); | 323 | |
| 324 | err = mtdtest_relax(); | ||
| 325 | if (err) | ||
| 326 | goto out; | ||
| 318 | } | 327 | } |
| 319 | } | 328 | } |
| 320 | 329 | ||
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 762c7a3cf43d..2eac55379239 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c | |||
| @@ -1266,7 +1266,6 @@ int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ | |||
| 1266 | if (rc) { | 1266 | if (rc) { |
| 1267 | JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n", | 1267 | JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n", |
| 1268 | __func__, rc, totlen); | 1268 | __func__, rc, totlen); |
| 1269 | rc = rc ? rc : -EBADFD; | ||
| 1270 | goto out; | 1269 | goto out; |
| 1271 | } | 1270 | } |
| 1272 | rc = save_xattr_ref(c, ref); | 1271 | rc = save_xattr_ref(c, ref); |
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 5f487d776411..29975c73a953 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h | |||
| @@ -77,7 +77,7 @@ | |||
| 77 | /* ensure we never evaluate anything shorted than an unsigned long | 77 | /* ensure we never evaluate anything shorted than an unsigned long |
| 78 | * to zero, and ensure we'll never miss the end of an comparison (bjd) */ | 78 | * to zero, and ensure we'll never miss the end of an comparison (bjd) */ |
| 79 | 79 | ||
| 80 | #define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1))/ sizeof(unsigned long)) | 80 | #define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1)) / sizeof(unsigned long)) |
| 81 | 81 | ||
| 82 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 | 82 | #ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 |
| 83 | # ifdef map_bankwidth | 83 | # ifdef map_bankwidth |
| @@ -181,7 +181,7 @@ static inline int map_bankwidth_supported(int w) | |||
| 181 | } | 181 | } |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | #define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG ) | 184 | #define MAX_MAP_LONGS (((MAX_MAP_BANKWIDTH * 8) + BITS_PER_LONG - 1) / BITS_PER_LONG) |
| 185 | 185 | ||
| 186 | typedef union { | 186 | typedef union { |
| 187 | unsigned long x[MAX_MAP_LONGS]; | 187 | unsigned long x[MAX_MAP_LONGS]; |
| @@ -264,20 +264,22 @@ void unregister_mtd_chip_driver(struct mtd_chip_driver *); | |||
| 264 | struct mtd_info *do_map_probe(const char *name, struct map_info *map); | 264 | struct mtd_info *do_map_probe(const char *name, struct map_info *map); |
| 265 | void map_destroy(struct mtd_info *mtd); | 265 | void map_destroy(struct mtd_info *mtd); |
| 266 | 266 | ||
| 267 | #define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) | 267 | #define ENABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 1); } while (0) |
| 268 | #define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) | 268 | #define DISABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 0); } while (0) |
| 269 | 269 | ||
| 270 | #define INVALIDATE_CACHED_RANGE(map, from, size) \ | 270 | #define INVALIDATE_CACHED_RANGE(map, from, size) \ |
| 271 | do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0) | 271 | do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0) |
| 272 | 272 | ||
| 273 | 273 | ||
| 274 | static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2) | 274 | static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2) |
| 275 | { | 275 | { |
| 276 | int i; | 276 | int i; |
| 277 | for (i=0; i<map_words(map); i++) { | 277 | |
| 278 | for (i = 0; i < map_words(map); i++) { | ||
| 278 | if (val1.x[i] != val2.x[i]) | 279 | if (val1.x[i] != val2.x[i]) |
| 279 | return 0; | 280 | return 0; |
| 280 | } | 281 | } |
| 282 | |||
| 281 | return 1; | 283 | return 1; |
| 282 | } | 284 | } |
| 283 | 285 | ||
| @@ -286,9 +288,9 @@ static inline map_word map_word_and(struct map_info *map, map_word val1, map_wor | |||
| 286 | map_word r; | 288 | map_word r; |
| 287 | int i; | 289 | int i; |
| 288 | 290 | ||
| 289 | for (i=0; i<map_words(map); i++) { | 291 | for (i = 0; i < map_words(map); i++) |
| 290 | r.x[i] = val1.x[i] & val2.x[i]; | 292 | r.x[i] = val1.x[i] & val2.x[i]; |
| 291 | } | 293 | |
| 292 | return r; | 294 | return r; |
| 293 | } | 295 | } |
| 294 | 296 | ||
| @@ -297,9 +299,9 @@ static inline map_word map_word_clr(struct map_info *map, map_word val1, map_wor | |||
| 297 | map_word r; | 299 | map_word r; |
| 298 | int i; | 300 | int i; |
| 299 | 301 | ||
| 300 | for (i=0; i<map_words(map); i++) { | 302 | for (i = 0; i < map_words(map); i++) |
| 301 | r.x[i] = val1.x[i] & ~val2.x[i]; | 303 | r.x[i] = val1.x[i] & ~val2.x[i]; |
| 302 | } | 304 | |
| 303 | return r; | 305 | return r; |
| 304 | } | 306 | } |
| 305 | 307 | ||
| @@ -308,22 +310,33 @@ static inline map_word map_word_or(struct map_info *map, map_word val1, map_word | |||
| 308 | map_word r; | 310 | map_word r; |
| 309 | int i; | 311 | int i; |
| 310 | 312 | ||
| 311 | for (i=0; i<map_words(map); i++) { | 313 | for (i = 0; i < map_words(map); i++) |
| 312 | r.x[i] = val1.x[i] | val2.x[i]; | 314 | r.x[i] = val1.x[i] | val2.x[i]; |
| 313 | } | 315 | |
| 314 | return r; | 316 | return r; |
| 315 | } | 317 | } |
| 316 | 318 | ||
| 317 | #define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b)) | 319 | static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3) |
| 320 | { | ||
| 321 | int i; | ||
| 322 | |||
| 323 | for (i = 0; i < map_words(map); i++) { | ||
| 324 | if ((val1.x[i] & val2.x[i]) != val3.x[i]) | ||
| 325 | return 0; | ||
| 326 | } | ||
| 327 | |||
| 328 | return 1; | ||
| 329 | } | ||
| 318 | 330 | ||
| 319 | static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) | 331 | static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2) |
| 320 | { | 332 | { |
| 321 | int i; | 333 | int i; |
| 322 | 334 | ||
| 323 | for (i=0; i<map_words(map); i++) { | 335 | for (i = 0; i < map_words(map); i++) { |
| 324 | if (val1.x[i] & val2.x[i]) | 336 | if (val1.x[i] & val2.x[i]) |
| 325 | return 1; | 337 | return 1; |
| 326 | } | 338 | } |
| 339 | |||
| 327 | return 0; | 340 | return 0; |
| 328 | } | 341 | } |
| 329 | 342 | ||
| @@ -355,14 +368,16 @@ static inline map_word map_word_load_partial(struct map_info *map, map_word orig | |||
| 355 | 368 | ||
| 356 | if (map_bankwidth_is_large(map)) { | 369 | if (map_bankwidth_is_large(map)) { |
| 357 | char *dest = (char *)&orig; | 370 | char *dest = (char *)&orig; |
| 371 | |||
| 358 | memcpy(dest+start, buf, len); | 372 | memcpy(dest+start, buf, len); |
| 359 | } else { | 373 | } else { |
| 360 | for (i=start; i < start+len; i++) { | 374 | for (i = start; i < start+len; i++) { |
| 361 | int bitpos; | 375 | int bitpos; |
| 376 | |||
| 362 | #ifdef __LITTLE_ENDIAN | 377 | #ifdef __LITTLE_ENDIAN |
| 363 | bitpos = i*8; | 378 | bitpos = i * 8; |
| 364 | #else /* __BIG_ENDIAN */ | 379 | #else /* __BIG_ENDIAN */ |
| 365 | bitpos = (map_bankwidth(map)-1-i)*8; | 380 | bitpos = (map_bankwidth(map) - 1 - i) * 8; |
| 366 | #endif | 381 | #endif |
| 367 | orig.x[0] &= ~(0xff << bitpos); | 382 | orig.x[0] &= ~(0xff << bitpos); |
| 368 | orig.x[0] |= (unsigned long)buf[i-start] << bitpos; | 383 | orig.x[0] |= (unsigned long)buf[i-start] << bitpos; |
| @@ -384,9 +399,10 @@ static inline map_word map_word_ff(struct map_info *map) | |||
| 384 | 399 | ||
| 385 | if (map_bankwidth(map) < MAP_FF_LIMIT) { | 400 | if (map_bankwidth(map) < MAP_FF_LIMIT) { |
| 386 | int bw = 8 * map_bankwidth(map); | 401 | int bw = 8 * map_bankwidth(map); |
| 402 | |||
| 387 | r.x[0] = (1UL << bw) - 1; | 403 | r.x[0] = (1UL << bw) - 1; |
| 388 | } else { | 404 | } else { |
| 389 | for (i=0; i<map_words(map); i++) | 405 | for (i = 0; i < map_words(map); i++) |
| 390 | r.x[i] = ~0UL; | 406 | r.x[i] = ~0UL; |
| 391 | } | 407 | } |
| 392 | return r; | 408 | return r; |
| @@ -407,7 +423,7 @@ static inline map_word inline_map_read(struct map_info *map, unsigned long ofs) | |||
| 407 | r.x[0] = __raw_readq(map->virt + ofs); | 423 | r.x[0] = __raw_readq(map->virt + ofs); |
| 408 | #endif | 424 | #endif |
| 409 | else if (map_bankwidth_is_large(map)) | 425 | else if (map_bankwidth_is_large(map)) |
| 410 | memcpy_fromio(r.x, map->virt+ofs, map->bankwidth); | 426 | memcpy_fromio(r.x, map->virt + ofs, map->bankwidth); |
| 411 | else | 427 | else |
| 412 | BUG(); | 428 | BUG(); |
| 413 | 429 | ||
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 4720b86ee73d..e5409524bb0a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h | |||
| @@ -155,6 +155,8 @@ enum spi_nor_option_flags { | |||
| 155 | * @write: [DRIVER-SPECIFIC] write data to the SPI NOR | 155 | * @write: [DRIVER-SPECIFIC] write data to the SPI NOR |
| 156 | * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR | 156 | * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR |
| 157 | * at the offset @offs | 157 | * at the offset @offs |
| 158 | * @lock: [FLASH-SPECIFIC] lock a region of the SPI NOR | ||
| 159 | * @unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR | ||
| 158 | * @priv: the private data | 160 | * @priv: the private data |
| 159 | */ | 161 | */ |
| 160 | struct spi_nor { | 162 | struct spi_nor { |
| @@ -189,6 +191,9 @@ struct spi_nor { | |||
| 189 | size_t len, size_t *retlen, const u_char *write_buf); | 191 | size_t len, size_t *retlen, const u_char *write_buf); |
| 190 | int (*erase)(struct spi_nor *nor, loff_t offs); | 192 | int (*erase)(struct spi_nor *nor, loff_t offs); |
| 191 | 193 | ||
| 194 | int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len); | ||
| 195 | int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); | ||
| 196 | |||
| 192 | void *priv; | 197 | void *priv; |
| 193 | }; | 198 | }; |
| 194 | 199 | ||
