diff options
Diffstat (limited to 'drivers/mtd')
35 files changed, 582 insertions, 293 deletions
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 | ||