aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-01-09 15:36:45 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-09 15:37:15 -0500
commit7c51d57e9d7fbce89f79c41dc8da383101dbe9c6 (patch)
tree9f45a5ac5ce627b4c6138595b23ae7f02e1ee7fb /drivers/mtd
parenta3a798c88a14b35e5d4ca30716dbc9eb9a1ddfe2 (diff)
parent85795dac740e63e81aeec8d49aada54ab07656b5 (diff)
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (67 commits) [MTD] [MAPS] Fix printk format warning in nettel.c [MTD] [NAND] add cmdline parsing (mtdparts=) support to cafe_nand [MTD] CFI: remove major/minor version check for command set 0x0002 [MTD] [NAND] ndfc driver [MTD] [TESTS] Fix some size_t printk format warnings [MTD] LPDDR Makefile and KConfig [MTD] LPDDR extended physmap driver to support LPDDR flash [MTD] LPDDR added new pfow_base parameter [MTD] LPDDR Command set driver [MTD] LPDDR PFOW definition [MTD] LPDDR QINFO records definitions [MTD] LPDDR qinfo probing. [MTD] [NAND] pxa3xx: convert from ns to clock ticks more accurately [MTD] [NAND] pxa3xx: fix non-page-aligned reads [MTD] [NAND] fix nandsim sched.h references [MTD] [NAND] alauda: use USB API functions rather than constants [MTD] struct device - replace bus_id with dev_name(), dev_set_name() [MTD] fix m25p80 64-bit divisions [MTD] fix dataflash 64-bit divisions [MTD] [NAND] Set the fsl elbc ECCM according the settings in bootloader. ... Fixed up trivial debug conflicts in drivers/mtd/devices/{m25p80.c,mtd_dataflash.c}
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/Kconfig10
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c12
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c18
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0020.c14
-rw-r--r--drivers/mtd/chips/fwh_lock.h4
-rw-r--r--drivers/mtd/devices/lart.c6
-rw-r--r--drivers/mtd/devices/m25p80.c41
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c24
-rw-r--r--drivers/mtd/ftl.c100
-rw-r--r--drivers/mtd/inftlcore.c2
-rw-r--r--drivers/mtd/inftlmount.c4
-rw-r--r--drivers/mtd/lpddr/Kconfig22
-rw-r--r--drivers/mtd/lpddr/Makefile6
-rw-r--r--drivers/mtd/lpddr/lpddr_cmds.c796
-rw-r--r--drivers/mtd/lpddr/qinfo_probe.c255
-rw-r--r--drivers/mtd/maps/Kconfig21
-rw-r--r--drivers/mtd/maps/alchemy-flash.c2
-rw-r--r--drivers/mtd/maps/amd76xrom.c4
-rw-r--r--drivers/mtd/maps/cfi_flagadm.c2
-rw-r--r--drivers/mtd/maps/ck804xrom.c4
-rw-r--r--drivers/mtd/maps/dbox2-flash.c2
-rw-r--r--drivers/mtd/maps/edb7312.c2
-rw-r--r--drivers/mtd/maps/esb2rom.c4
-rw-r--r--drivers/mtd/maps/fortunet.c2
-rw-r--r--drivers/mtd/maps/h720x-flash.c2
-rw-r--r--drivers/mtd/maps/ichxrom.c4
-rw-r--r--drivers/mtd/maps/impa7.c2
-rw-r--r--drivers/mtd/maps/ipaq-flash.c2
-rw-r--r--drivers/mtd/maps/mbx860.c2
-rw-r--r--drivers/mtd/maps/nettel.c9
-rw-r--r--drivers/mtd/maps/octagon-5066.c2
-rw-r--r--drivers/mtd/maps/physmap.c41
-rw-r--r--drivers/mtd/maps/pmcmsp-flash.c2
-rw-r--r--drivers/mtd/maps/redwood.c2
-rw-r--r--drivers/mtd/maps/rpxlite.c2
-rw-r--r--drivers/mtd/maps/sbc8240.c2
-rw-r--r--drivers/mtd/maps/scb2_flash.c8
-rw-r--r--drivers/mtd/maps/sharpsl-flash.c2
-rw-r--r--drivers/mtd/maps/tqm8xxl.c2
-rw-r--r--drivers/mtd/maps/uclinux.c4
-rw-r--r--drivers/mtd/maps/vmax301.c2
-rw-r--r--drivers/mtd/maps/wr_sbc82xx_flash.c2
-rw-r--r--drivers/mtd/mtdchar.c6
-rw-r--r--drivers/mtd/mtdconcat.c35
-rw-r--r--drivers/mtd/mtdcore.c16
-rw-r--r--drivers/mtd/mtdoops.c9
-rw-r--r--drivers/mtd/mtdpart.c34
-rw-r--r--drivers/mtd/nand/Kconfig7
-rw-r--r--drivers/mtd/nand/alauda.c6
-rw-r--r--drivers/mtd/nand/cafe_nand.c7
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c4
-rw-r--r--drivers/mtd/nand/nand_base.c25
-rw-r--r--drivers/mtd/nand/nand_bbt.c31
-rw-r--r--drivers/mtd/nand/nandsim.c339
-rw-r--r--drivers/mtd/nand/ndfc.c269
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c6
-rw-r--r--drivers/mtd/nand/sharpsl.c247
-rw-r--r--drivers/mtd/nftlcore.c2
-rw-r--r--drivers/mtd/nftlmount.c4
-rw-r--r--drivers/mtd/onenand/onenand_base.c8
-rw-r--r--drivers/mtd/rfd_ftl.c29
-rw-r--r--drivers/mtd/ssfdc.c7
-rw-r--r--drivers/mtd/tests/Makefile7
-rw-r--r--drivers/mtd/tests/mtd_oobtest.c742
-rw-r--r--drivers/mtd/tests/mtd_pagetest.c632
-rw-r--r--drivers/mtd/tests/mtd_readtest.c253
-rw-r--r--drivers/mtd/tests/mtd_speedtest.c502
-rw-r--r--drivers/mtd/tests/mtd_stresstest.c330
-rw-r--r--drivers/mtd/tests/mtd_subpagetest.c525
-rw-r--r--drivers/mtd/tests/mtd_torturetest.c530
-rw-r--r--drivers/mtd/ubi/build.c2
-rw-r--r--drivers/mtd/ubi/gluebi.c17
73 files changed, 5503 insertions, 579 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index a90d50c2c3e5..7d04fb9ddcaa 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -45,6 +45,14 @@ config MTD_PARTITIONS
45 devices. Partitioning on NFTL 'devices' is a different - that's the 45 devices. Partitioning on NFTL 'devices' is a different - that's the
46 'normal' form of partitioning used on a block device. 46 'normal' form of partitioning used on a block device.
47 47
48config MTD_TESTS
49 tristate "MTD tests support"
50 depends on m
51 help
52 This option includes various MTD tests into compilation. The tests
53 should normally be compiled as kernel modules. The modules perform
54 various checks and verifications when loaded.
55
48config MTD_REDBOOT_PARTS 56config MTD_REDBOOT_PARTS
49 tristate "RedBoot partition table parsing" 57 tristate "RedBoot partition table parsing"
50 depends on MTD_PARTITIONS 58 depends on MTD_PARTITIONS
@@ -316,6 +324,8 @@ source "drivers/mtd/nand/Kconfig"
316 324
317source "drivers/mtd/onenand/Kconfig" 325source "drivers/mtd/onenand/Kconfig"
318 326
327source "drivers/mtd/lpddr/Kconfig"
328
319source "drivers/mtd/ubi/Kconfig" 329source "drivers/mtd/ubi/Kconfig"
320 330
321endif # MTD 331endif # MTD
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 4b77335715f0..4521b1ecce45 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -29,6 +29,6 @@ obj-$(CONFIG_MTD_OOPS) += mtdoops.o
29nftl-objs := nftlcore.o nftlmount.o 29nftl-objs := nftlcore.o nftlmount.o
30inftl-objs := inftlcore.o inftlmount.o 30inftl-objs := inftlcore.o inftlmount.o
31 31
32obj-y += chips/ maps/ devices/ nand/ onenand/ 32obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
33 33
34obj-$(CONFIG_MTD_UBI) += ubi/ 34obj-$(CONFIG_MTD_UBI) += ubi/
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index c93a8be5d5f1..f5ab6fa1057b 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -58,8 +58,8 @@ static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t
58static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *); 58static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *);
59static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); 59static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
60static void cfi_intelext_sync (struct mtd_info *); 60static void cfi_intelext_sync (struct mtd_info *);
61static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); 61static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
62static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); 62static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
63#ifdef CONFIG_MTD_OTP 63#ifdef CONFIG_MTD_OTP
64static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 64static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
65static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 65static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
@@ -558,8 +558,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
558 } 558 }
559 559
560 for (i=0; i<mtd->numeraseregions;i++){ 560 for (i=0; i<mtd->numeraseregions;i++){
561 printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n", 561 printk(KERN_DEBUG "erase region %d: offset=0x%llx,size=0x%x,blocks=%d\n",
562 i,mtd->eraseregions[i].offset, 562 i,(unsigned long long)mtd->eraseregions[i].offset,
563 mtd->eraseregions[i].erasesize, 563 mtd->eraseregions[i].erasesize,
564 mtd->eraseregions[i].numblocks); 564 mtd->eraseregions[i].numblocks);
565 } 565 }
@@ -2058,7 +2058,7 @@ out: put_chip(map, chip, adr);
2058 return ret; 2058 return ret;
2059} 2059}
2060 2060
2061static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) 2061static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
2062{ 2062{
2063 int ret; 2063 int ret;
2064 2064
@@ -2082,7 +2082,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
2082 return ret; 2082 return ret;
2083} 2083}
2084 2084
2085static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 2085static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
2086{ 2086{
2087 int ret; 2087 int ret;
2088 2088
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index d74ec46aa032..94bb61e19047 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -71,8 +71,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
71static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); 71static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
72#include "fwh_lock.h" 72#include "fwh_lock.h"
73 73
74static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len); 74static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
75static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); 75static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
76 76
77static struct mtd_chip_driver cfi_amdstd_chipdrv = { 77static struct mtd_chip_driver cfi_amdstd_chipdrv = {
78 .probe = NULL, /* Not usable directly */ 78 .probe = NULL, /* Not usable directly */
@@ -322,6 +322,14 @@ static struct cfi_fixup fixup_table[] = {
322}; 322};
323 323
324 324
325static void cfi_fixup_major_minor(struct cfi_private *cfi,
326 struct cfi_pri_amdstd *extp)
327{
328 if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e &&
329 extp->MajorVersion == '0')
330 extp->MajorVersion = '1';
331}
332
325struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) 333struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
326{ 334{
327 struct cfi_private *cfi = map->fldrv_priv; 335 struct cfi_private *cfi = map->fldrv_priv;
@@ -363,6 +371,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
363 return NULL; 371 return NULL;
364 } 372 }
365 373
374 cfi_fixup_major_minor(cfi, extp);
375
366 if (extp->MajorVersion != '1' || 376 if (extp->MajorVersion != '1' ||
367 (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { 377 (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
368 printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " 378 printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query "
@@ -1774,12 +1784,12 @@ out_unlock:
1774 return ret; 1784 return ret;
1775} 1785}
1776 1786
1777static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len) 1787static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1778{ 1788{
1779 return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL); 1789 return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL);
1780} 1790}
1781 1791
1782static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 1792static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1783{ 1793{
1784 return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL); 1794 return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL);
1785} 1795}
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index d4714dd9f7ab..6c740f346f91 100644
--- a/drivers/mtd/chips/cfi_cmdset_0020.c
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c
@@ -42,8 +42,8 @@ static int cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,
42 unsigned long count, loff_t to, size_t *retlen); 42 unsigned long count, loff_t to, size_t *retlen);
43static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *); 43static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *);
44static void cfi_staa_sync (struct mtd_info *); 44static void cfi_staa_sync (struct mtd_info *);
45static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len); 45static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
46static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); 46static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
47static int cfi_staa_suspend (struct mtd_info *); 47static int cfi_staa_suspend (struct mtd_info *);
48static void cfi_staa_resume (struct mtd_info *); 48static void cfi_staa_resume (struct mtd_info *);
49 49
@@ -221,8 +221,8 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
221 } 221 }
222 222
223 for (i=0; i<mtd->numeraseregions;i++){ 223 for (i=0; i<mtd->numeraseregions;i++){
224 printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", 224 printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n",
225 i,mtd->eraseregions[i].offset, 225 i, (unsigned long long)mtd->eraseregions[i].offset,
226 mtd->eraseregions[i].erasesize, 226 mtd->eraseregions[i].erasesize,
227 mtd->eraseregions[i].numblocks); 227 mtd->eraseregions[i].numblocks);
228 } 228 }
@@ -964,7 +964,7 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd,
964 adr += regions[i].erasesize; 964 adr += regions[i].erasesize;
965 len -= regions[i].erasesize; 965 len -= regions[i].erasesize;
966 966
967 if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) 967 if (adr % (1<< cfi->chipshift) == (((unsigned long)regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
968 i++; 968 i++;
969 969
970 if (adr >> cfi->chipshift) { 970 if (adr >> cfi->chipshift) {
@@ -1135,7 +1135,7 @@ retry:
1135 spin_unlock_bh(chip->mutex); 1135 spin_unlock_bh(chip->mutex);
1136 return 0; 1136 return 0;
1137} 1137}
1138static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) 1138static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1139{ 1139{
1140 struct map_info *map = mtd->priv; 1140 struct map_info *map = mtd->priv;
1141 struct cfi_private *cfi = map->fldrv_priv; 1141 struct cfi_private *cfi = map->fldrv_priv;
@@ -1284,7 +1284,7 @@ retry:
1284 spin_unlock_bh(chip->mutex); 1284 spin_unlock_bh(chip->mutex);
1285 return 0; 1285 return 0;
1286} 1286}
1287static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 1287static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
1288{ 1288{
1289 struct map_info *map = mtd->priv; 1289 struct map_info *map = mtd->priv;
1290 struct cfi_private *cfi = map->fldrv_priv; 1290 struct cfi_private *cfi = map->fldrv_priv;
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h
index ab44f2b996f8..57e0e4e921f9 100644
--- a/drivers/mtd/chips/fwh_lock.h
+++ b/drivers/mtd/chips/fwh_lock.h
@@ -77,7 +77,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
77} 77}
78 78
79 79
80static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) 80static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
81{ 81{
82 int ret; 82 int ret;
83 83
@@ -88,7 +88,7 @@ static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
88} 88}
89 89
90 90
91static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) 91static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len)
92{ 92{
93 int ret; 93 int ret;
94 94
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index f4bda4cee495..578de1c67bfe 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -619,7 +619,7 @@ static struct mtd_partition lart_partitions[] = {
619}; 619};
620#endif 620#endif
621 621
622int __init lart_flash_init (void) 622static int __init lart_flash_init (void)
623{ 623{
624 int result; 624 int result;
625 memset (&mtd,0,sizeof (mtd)); 625 memset (&mtd,0,sizeof (mtd));
@@ -690,7 +690,7 @@ int __init lart_flash_init (void)
690 return (result); 690 return (result);
691} 691}
692 692
693void __exit lart_flash_exit (void) 693static void __exit lart_flash_exit (void)
694{ 694{
695#ifndef HAVE_PARTITIONS 695#ifndef HAVE_PARTITIONS
696 del_mtd_device (&mtd); 696 del_mtd_device (&mtd);
@@ -705,5 +705,3 @@ module_exit (lart_flash_exit);
705MODULE_LICENSE("GPL"); 705MODULE_LICENSE("GPL");
706MODULE_AUTHOR("Abraham vd Merwe <abraham@2d3d.co.za>"); 706MODULE_AUTHOR("Abraham vd Merwe <abraham@2d3d.co.za>");
707MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board"); 707MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board");
708
709
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 5733f0643843..7c3fc766dcf1 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -20,6 +20,7 @@
20#include <linux/device.h> 20#include <linux/device.h>
21#include <linux/interrupt.h> 21#include <linux/interrupt.h>
22#include <linux/mutex.h> 22#include <linux/mutex.h>
23#include <linux/math64.h>
23 24
24#include <linux/mtd/mtd.h> 25#include <linux/mtd/mtd.h>
25#include <linux/mtd/partitions.h> 26#include <linux/mtd/partitions.h>
@@ -169,9 +170,9 @@ static int wait_till_ready(struct m25p *flash)
169 */ 170 */
170static int erase_chip(struct m25p *flash) 171static int erase_chip(struct m25p *flash)
171{ 172{
172 DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB\n", 173 DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n",
173 dev_name(&flash->spi->dev), __func__, 174 dev_name(&flash->spi->dev), __func__,
174 flash->mtd.size / 1024); 175 (long long)(flash->mtd.size >> 10));
175 176
176 /* Wait until finished previous write command. */ 177 /* Wait until finished previous write command. */
177 if (wait_till_ready(flash)) 178 if (wait_till_ready(flash))
@@ -232,18 +233,18 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
232{ 233{
233 struct m25p *flash = mtd_to_m25p(mtd); 234 struct m25p *flash = mtd_to_m25p(mtd);
234 u32 addr,len; 235 u32 addr,len;
236 uint32_t rem;
235 237
236 DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", 238 DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n",
237 dev_name(&flash->spi->dev), __func__, "at", 239 dev_name(&flash->spi->dev), __func__, "at",
238 (u32)instr->addr, instr->len); 240 (long long)instr->addr, (long long)instr->len);
239 241
240 /* sanity checks */ 242 /* sanity checks */
241 if (instr->addr + instr->len > flash->mtd.size) 243 if (instr->addr + instr->len > flash->mtd.size)
242 return -EINVAL; 244 return -EINVAL;
243 if ((instr->addr % mtd->erasesize) != 0 245 div_u64_rem(instr->len, mtd->erasesize, &rem);
244 || (instr->len % mtd->erasesize) != 0) { 246 if (rem)
245 return -EINVAL; 247 return -EINVAL;
246 }
247 248
248 addr = instr->addr; 249 addr = instr->addr;
249 len = instr->len; 250 len = instr->len;
@@ -677,24 +678,24 @@ static int __devinit m25p_probe(struct spi_device *spi)
677 flash->mtd.erasesize = info->sector_size; 678 flash->mtd.erasesize = info->sector_size;
678 } 679 }
679 680
680 dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name, 681 dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name,
681 flash->mtd.size / 1024); 682 (long long)flash->mtd.size >> 10);
682 683
683 DEBUG(MTD_DEBUG_LEVEL2, 684 DEBUG(MTD_DEBUG_LEVEL2,
684 "mtd .name = %s, .size = 0x%.8x (%uMiB) " 685 "mtd .name = %s, .size = 0x%llx (%lldMiB) "
685 ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", 686 ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
686 flash->mtd.name, 687 flash->mtd.name,
687 flash->mtd.size, flash->mtd.size / (1024*1024), 688 (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
688 flash->mtd.erasesize, flash->mtd.erasesize / 1024, 689 flash->mtd.erasesize, flash->mtd.erasesize / 1024,
689 flash->mtd.numeraseregions); 690 flash->mtd.numeraseregions);
690 691
691 if (flash->mtd.numeraseregions) 692 if (flash->mtd.numeraseregions)
692 for (i = 0; i < flash->mtd.numeraseregions; i++) 693 for (i = 0; i < flash->mtd.numeraseregions; i++)
693 DEBUG(MTD_DEBUG_LEVEL2, 694 DEBUG(MTD_DEBUG_LEVEL2,
694 "mtd.eraseregions[%d] = { .offset = 0x%.8x, " 695 "mtd.eraseregions[%d] = { .offset = 0x%llx, "
695 ".erasesize = 0x%.8x (%uKiB), " 696 ".erasesize = 0x%.8x (%uKiB), "
696 ".numblocks = %d }\n", 697 ".numblocks = %d }\n",
697 i, flash->mtd.eraseregions[i].offset, 698 i, (long long)flash->mtd.eraseregions[i].offset,
698 flash->mtd.eraseregions[i].erasesize, 699 flash->mtd.eraseregions[i].erasesize,
699 flash->mtd.eraseregions[i].erasesize / 1024, 700 flash->mtd.eraseregions[i].erasesize / 1024,
700 flash->mtd.eraseregions[i].numblocks); 701 flash->mtd.eraseregions[i].numblocks);
@@ -722,12 +723,12 @@ static int __devinit m25p_probe(struct spi_device *spi)
722 if (nr_parts > 0) { 723 if (nr_parts > 0) {
723 for (i = 0; i < nr_parts; i++) { 724 for (i = 0; i < nr_parts; i++) {
724 DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " 725 DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
725 "{.name = %s, .offset = 0x%.8x, " 726 "{.name = %s, .offset = 0x%llx, "
726 ".size = 0x%.8x (%uKiB) }\n", 727 ".size = 0x%llx (%lldKiB) }\n",
727 i, parts[i].name, 728 i, parts[i].name,
728 parts[i].offset, 729 (long long)parts[i].offset,
729 parts[i].size, 730 (long long)parts[i].size,
730 parts[i].size / 1024); 731 (long long)(parts[i].size >> 10));
731 } 732 }
732 flash->partitioned = 1; 733 flash->partitioned = 1;
733 return add_mtd_partitions(&flash->mtd, parts, nr_parts); 734 return add_mtd_partitions(&flash->mtd, parts, nr_parts);
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 65126cd668ff..d44f741ae229 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -16,6 +16,7 @@
16#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/mutex.h> 17#include <linux/mutex.h>
18#include <linux/err.h> 18#include <linux/err.h>
19#include <linux/math64.h>
19 20
20#include <linux/spi/spi.h> 21#include <linux/spi/spi.h>
21#include <linux/spi/flash.h> 22#include <linux/spi/flash.h>
@@ -152,15 +153,20 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
152 struct spi_message msg; 153 struct spi_message msg;
153 unsigned blocksize = priv->page_size << 3; 154 unsigned blocksize = priv->page_size << 3;
154 uint8_t *command; 155 uint8_t *command;
156 uint32_t rem;
155 157
156 DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n", 158 DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%llx len 0x%llx\n",
157 dev_name(&spi->dev), 159 dev_name(&spi->dev), (long long)instr->addr,
158 instr->addr, instr->len); 160 (long long)instr->len);
159 161
160 /* Sanity checks */ 162 /* Sanity checks */
161 if ((instr->addr + instr->len) > mtd->size 163 if (instr->addr + instr->len > mtd->size)
162 || (instr->len % priv->page_size) != 0 164 return -EINVAL;
163 || (instr->addr % priv->page_size) != 0) 165 div_u64_rem(instr->len, priv->page_size, &rem);
166 if (rem)
167 return -EINVAL;
168 div_u64_rem(instr->addr, priv->page_size, &rem);
169 if (rem)
164 return -EINVAL; 170 return -EINVAL;
165 171
166 spi_message_init(&msg); 172 spi_message_init(&msg);
@@ -178,7 +184,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
178 /* Calculate flash page address; use block erase (for speed) if 184 /* Calculate flash page address; use block erase (for speed) if
179 * we're at a block boundary and need to erase the whole block. 185 * we're at a block boundary and need to erase the whole block.
180 */ 186 */
181 pageaddr = instr->addr / priv->page_size; 187 pageaddr = div_u64(instr->len, priv->page_size);
182 do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize; 188 do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize;
183 pageaddr = pageaddr << priv->page_offset; 189 pageaddr = pageaddr << priv->page_offset;
184 190
@@ -667,8 +673,8 @@ add_dataflash_otp(struct spi_device *spi, char *name,
667 if (revision >= 'c') 673 if (revision >= 'c')
668 otp_tag = otp_setup(device, revision); 674 otp_tag = otp_setup(device, revision);
669 675
670 dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n", 676 dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n",
671 name, DIV_ROUND_UP(device->size, 1024), 677 name, (long long)((device->size + 1023) >> 10),
672 pagesize, otp_tag); 678 pagesize, otp_tag);
673 dev_set_drvdata(&spi->dev, priv); 679 dev_set_drvdata(&spi->dev, priv);
674 680
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 9bf581c4f740..a790c062af1f 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -109,25 +109,25 @@ module_param(shuffle_freq, int, 0);
109/* Each memory region corresponds to a minor device */ 109/* Each memory region corresponds to a minor device */
110typedef struct partition_t { 110typedef struct partition_t {
111 struct mtd_blktrans_dev mbd; 111 struct mtd_blktrans_dev mbd;
112 u_int32_t state; 112 uint32_t state;
113 u_int32_t *VirtualBlockMap; 113 uint32_t *VirtualBlockMap;
114 u_int32_t *VirtualPageMap; 114 uint32_t *VirtualPageMap;
115 u_int32_t FreeTotal; 115 uint32_t FreeTotal;
116 struct eun_info_t { 116 struct eun_info_t {
117 u_int32_t Offset; 117 uint32_t Offset;
118 u_int32_t EraseCount; 118 uint32_t EraseCount;
119 u_int32_t Free; 119 uint32_t Free;
120 u_int32_t Deleted; 120 uint32_t Deleted;
121 } *EUNInfo; 121 } *EUNInfo;
122 struct xfer_info_t { 122 struct xfer_info_t {
123 u_int32_t Offset; 123 uint32_t Offset;
124 u_int32_t EraseCount; 124 uint32_t EraseCount;
125 u_int16_t state; 125 uint16_t state;
126 } *XferInfo; 126 } *XferInfo;
127 u_int16_t bam_index; 127 uint16_t bam_index;
128 u_int32_t *bam_cache; 128 uint32_t *bam_cache;
129 u_int16_t DataUnits; 129 uint16_t DataUnits;
130 u_int32_t BlocksPerUnit; 130 uint32_t BlocksPerUnit;
131 erase_unit_header_t header; 131 erase_unit_header_t header;
132} partition_t; 132} partition_t;
133 133
@@ -199,8 +199,8 @@ static int scan_header(partition_t *part)
199static int build_maps(partition_t *part) 199static int build_maps(partition_t *part)
200{ 200{
201 erase_unit_header_t header; 201 erase_unit_header_t header;
202 u_int16_t xvalid, xtrans, i; 202 uint16_t xvalid, xtrans, i;
203 u_int blocks, j; 203 unsigned blocks, j;
204 int hdr_ok, ret = -1; 204 int hdr_ok, ret = -1;
205 ssize_t retval; 205 ssize_t retval;
206 loff_t offset; 206 loff_t offset;
@@ -269,14 +269,14 @@ static int build_maps(partition_t *part)
269 269
270 /* Set up virtual page map */ 270 /* Set up virtual page map */
271 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; 271 blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
272 part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t)); 272 part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t));
273 if (!part->VirtualBlockMap) 273 if (!part->VirtualBlockMap)
274 goto out_XferInfo; 274 goto out_XferInfo;
275 275
276 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t)); 276 memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t));
277 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize; 277 part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
278 278
279 part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t), 279 part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t),
280 GFP_KERNEL); 280 GFP_KERNEL);
281 if (!part->bam_cache) 281 if (!part->bam_cache)
282 goto out_VirtualBlockMap; 282 goto out_VirtualBlockMap;
@@ -290,7 +290,7 @@ static int build_maps(partition_t *part)
290 offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); 290 offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
291 291
292 ret = part->mbd.mtd->read(part->mbd.mtd, offset, 292 ret = part->mbd.mtd->read(part->mbd.mtd, offset,
293 part->BlocksPerUnit * sizeof(u_int32_t), &retval, 293 part->BlocksPerUnit * sizeof(uint32_t), &retval,
294 (unsigned char *)part->bam_cache); 294 (unsigned char *)part->bam_cache);
295 295
296 if (ret) 296 if (ret)
@@ -332,7 +332,7 @@ out:
332======================================================================*/ 332======================================================================*/
333 333
334static int erase_xfer(partition_t *part, 334static int erase_xfer(partition_t *part,
335 u_int16_t xfernum) 335 uint16_t xfernum)
336{ 336{
337 int ret; 337 int ret;
338 struct xfer_info_t *xfer; 338 struct xfer_info_t *xfer;
@@ -408,7 +408,7 @@ static int prepare_xfer(partition_t *part, int i)
408 erase_unit_header_t header; 408 erase_unit_header_t header;
409 struct xfer_info_t *xfer; 409 struct xfer_info_t *xfer;
410 int nbam, ret; 410 int nbam, ret;
411 u_int32_t ctl; 411 uint32_t ctl;
412 ssize_t retlen; 412 ssize_t retlen;
413 loff_t offset; 413 loff_t offset;
414 414
@@ -430,15 +430,15 @@ static int prepare_xfer(partition_t *part, int i)
430 } 430 }
431 431
432 /* Write the BAM stub */ 432 /* Write the BAM stub */
433 nbam = (part->BlocksPerUnit * sizeof(u_int32_t) + 433 nbam = (part->BlocksPerUnit * sizeof(uint32_t) +
434 le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE; 434 le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE;
435 435
436 offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset); 436 offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset);
437 ctl = cpu_to_le32(BLOCK_CONTROL); 437 ctl = cpu_to_le32(BLOCK_CONTROL);
438 438
439 for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { 439 for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) {
440 440
441 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), 441 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t),
442 &retlen, (u_char *)&ctl); 442 &retlen, (u_char *)&ctl);
443 443
444 if (ret) 444 if (ret)
@@ -461,18 +461,18 @@ static int prepare_xfer(partition_t *part, int i)
461 461
462======================================================================*/ 462======================================================================*/
463 463
464static int copy_erase_unit(partition_t *part, u_int16_t srcunit, 464static int copy_erase_unit(partition_t *part, uint16_t srcunit,
465 u_int16_t xferunit) 465 uint16_t xferunit)
466{ 466{
467 u_char buf[SECTOR_SIZE]; 467 u_char buf[SECTOR_SIZE];
468 struct eun_info_t *eun; 468 struct eun_info_t *eun;
469 struct xfer_info_t *xfer; 469 struct xfer_info_t *xfer;
470 u_int32_t src, dest, free, i; 470 uint32_t src, dest, free, i;
471 u_int16_t unit; 471 uint16_t unit;
472 int ret; 472 int ret;
473 ssize_t retlen; 473 ssize_t retlen;
474 loff_t offset; 474 loff_t offset;
475 u_int16_t srcunitswap = cpu_to_le16(srcunit); 475 uint16_t srcunitswap = cpu_to_le16(srcunit);
476 476
477 eun = &part->EUNInfo[srcunit]; 477 eun = &part->EUNInfo[srcunit];
478 xfer = &part->XferInfo[xferunit]; 478 xfer = &part->XferInfo[xferunit];
@@ -486,7 +486,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
486 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); 486 offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
487 487
488 ret = part->mbd.mtd->read(part->mbd.mtd, offset, 488 ret = part->mbd.mtd->read(part->mbd.mtd, offset,
489 part->BlocksPerUnit * sizeof(u_int32_t), 489 part->BlocksPerUnit * sizeof(uint32_t),
490 &retlen, (u_char *) (part->bam_cache)); 490 &retlen, (u_char *) (part->bam_cache));
491 491
492 /* mark the cache bad, in case we get an error later */ 492 /* mark the cache bad, in case we get an error later */
@@ -503,7 +503,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
503 offset = xfer->Offset + 20; /* Bad! */ 503 offset = xfer->Offset + 20; /* Bad! */
504 unit = cpu_to_le16(0x7fff); 504 unit = cpu_to_le16(0x7fff);
505 505
506 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), 506 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint16_t),
507 &retlen, (u_char *) &unit); 507 &retlen, (u_char *) &unit);
508 508
509 if (ret) { 509 if (ret) {
@@ -560,7 +560,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
560 560
561 561
562 /* All clear? Then update the LogicalEUN again */ 562 /* All clear? Then update the LogicalEUN again */
563 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), 563 ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t),
564 &retlen, (u_char *)&srcunitswap); 564 &retlen, (u_char *)&srcunitswap);
565 565
566 if (ret) { 566 if (ret) {
@@ -605,8 +605,8 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
605 605
606static int reclaim_block(partition_t *part) 606static int reclaim_block(partition_t *part)
607{ 607{
608 u_int16_t i, eun, xfer; 608 uint16_t i, eun, xfer;
609 u_int32_t best; 609 uint32_t best;
610 int queued, ret; 610 int queued, ret;
611 611
612 DEBUG(0, "ftl_cs: reclaiming space...\n"); 612 DEBUG(0, "ftl_cs: reclaiming space...\n");
@@ -723,10 +723,10 @@ static void dump_lists(partition_t *part)
723} 723}
724#endif 724#endif
725 725
726static u_int32_t find_free(partition_t *part) 726static uint32_t find_free(partition_t *part)
727{ 727{
728 u_int16_t stop, eun; 728 uint16_t stop, eun;
729 u_int32_t blk; 729 uint32_t blk;
730 size_t retlen; 730 size_t retlen;
731 int ret; 731 int ret;
732 732
@@ -749,7 +749,7 @@ static u_int32_t find_free(partition_t *part)
749 749
750 ret = part->mbd.mtd->read(part->mbd.mtd, 750 ret = part->mbd.mtd->read(part->mbd.mtd,
751 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), 751 part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
752 part->BlocksPerUnit * sizeof(u_int32_t), 752 part->BlocksPerUnit * sizeof(uint32_t),
753 &retlen, (u_char *) (part->bam_cache)); 753 &retlen, (u_char *) (part->bam_cache));
754 754
755 if (ret) { 755 if (ret) {
@@ -786,7 +786,7 @@ static u_int32_t find_free(partition_t *part)
786static int ftl_read(partition_t *part, caddr_t buffer, 786static int ftl_read(partition_t *part, caddr_t buffer,
787 u_long sector, u_long nblocks) 787 u_long sector, u_long nblocks)
788{ 788{
789 u_int32_t log_addr, bsize; 789 uint32_t log_addr, bsize;
790 u_long i; 790 u_long i;
791 int ret; 791 int ret;
792 size_t offset, retlen; 792 size_t offset, retlen;
@@ -829,14 +829,14 @@ static int ftl_read(partition_t *part, caddr_t buffer,
829 829
830======================================================================*/ 830======================================================================*/
831 831
832static int set_bam_entry(partition_t *part, u_int32_t log_addr, 832static int set_bam_entry(partition_t *part, uint32_t log_addr,
833 u_int32_t virt_addr) 833 uint32_t virt_addr)
834{ 834{
835 u_int32_t bsize, blk, le_virt_addr; 835 uint32_t bsize, blk, le_virt_addr;
836#ifdef PSYCHO_DEBUG 836#ifdef PSYCHO_DEBUG
837 u_int32_t old_addr; 837 uint32_t old_addr;
838#endif 838#endif
839 u_int16_t eun; 839 uint16_t eun;
840 int ret; 840 int ret;
841 size_t retlen, offset; 841 size_t retlen, offset;
842 842
@@ -845,11 +845,11 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
845 bsize = 1 << part->header.EraseUnitSize; 845 bsize = 1 << part->header.EraseUnitSize;
846 eun = log_addr / bsize; 846 eun = log_addr / bsize;
847 blk = (log_addr % bsize) / SECTOR_SIZE; 847 blk = (log_addr % bsize) / SECTOR_SIZE;
848 offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) + 848 offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) +
849 le32_to_cpu(part->header.BAMOffset)); 849 le32_to_cpu(part->header.BAMOffset));
850 850
851#ifdef PSYCHO_DEBUG 851#ifdef PSYCHO_DEBUG
852 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), 852 ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(uint32_t),
853 &retlen, (u_char *)&old_addr); 853 &retlen, (u_char *)&old_addr);
854 if (ret) { 854 if (ret) {
855 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret); 855 printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret);
@@ -886,7 +886,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
886#endif 886#endif
887 part->bam_cache[blk] = le_virt_addr; 887 part->bam_cache[blk] = le_virt_addr;
888 } 888 }
889 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), 889 ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t),
890 &retlen, (u_char *)&le_virt_addr); 890 &retlen, (u_char *)&le_virt_addr);
891 891
892 if (ret) { 892 if (ret) {
@@ -900,7 +900,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
900static int ftl_write(partition_t *part, caddr_t buffer, 900static int ftl_write(partition_t *part, caddr_t buffer,
901 u_long sector, u_long nblocks) 901 u_long sector, u_long nblocks)
902{ 902{
903 u_int32_t bsize, log_addr, virt_addr, old_addr, blk; 903 uint32_t bsize, log_addr, virt_addr, old_addr, blk;
904 u_long i; 904 u_long i;
905 int ret; 905 int ret;
906 size_t retlen, offset; 906 size_t retlen, offset;
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 50ce13887f63..73f05227dc8c 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -50,7 +50,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
50 struct INFTLrecord *inftl; 50 struct INFTLrecord *inftl;
51 unsigned long temp; 51 unsigned long temp;
52 52
53 if (mtd->type != MTD_NANDFLASH) 53 if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX)
54 return; 54 return;
55 /* OK, this is moderately ugly. But probably safe. Alternatives? */ 55 /* OK, this is moderately ugly. But probably safe. Alternatives? */
56 if (memcmp(mtd->name, "DiskOnChip", 10)) 56 if (memcmp(mtd->name, "DiskOnChip", 10))
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index 9113628ed1ef..f751dd97c549 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -63,7 +63,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
63 * otherwise. 63 * otherwise.
64 */ 64 */
65 inftl->EraseSize = inftl->mbd.mtd->erasesize; 65 inftl->EraseSize = inftl->mbd.mtd->erasesize;
66 inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; 66 inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;
67 67
68 inftl->MediaUnit = BLOCK_NIL; 68 inftl->MediaUnit = BLOCK_NIL;
69 69
@@ -187,7 +187,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
187 mh->BlockMultiplierBits); 187 mh->BlockMultiplierBits);
188 inftl->EraseSize = inftl->mbd.mtd->erasesize << 188 inftl->EraseSize = inftl->mbd.mtd->erasesize <<
189 mh->BlockMultiplierBits; 189 mh->BlockMultiplierBits;
190 inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; 190 inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize;
191 block >>= mh->BlockMultiplierBits; 191 block >>= mh->BlockMultiplierBits;
192 } 192 }
193 193
diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig
new file mode 100644
index 000000000000..acd4ea9b2278
--- /dev/null
+++ b/drivers/mtd/lpddr/Kconfig
@@ -0,0 +1,22 @@
1# drivers/mtd/chips/Kconfig
2
3menu "LPDDR flash memory drivers"
4 depends on MTD!=n
5
6config MTD_LPDDR
7 tristate "Support for LPDDR flash chips"
8 select MTD_QINFO_PROBE
9 help
10 This option enables support of LPDDR (Low power double data rate)
11 flash chips. Synonymous with Mobile-DDR. It is a new standard for
12 DDR memories, intended for battery-operated systems.
13
14config MTD_QINFO_PROBE
15 tristate "Detect flash chips by QINFO probe"
16 help
17 Device Information for LPDDR chips is offered through the Overlay
18 Window QINFO interface, permits software to be used for entire
19 families of devices. This serves similar purpose of CFI on legacy
20 Flash products
21endmenu
22
diff --git a/drivers/mtd/lpddr/Makefile b/drivers/mtd/lpddr/Makefile
new file mode 100644
index 000000000000..da48e46b5812
--- /dev/null
+++ b/drivers/mtd/lpddr/Makefile
@@ -0,0 +1,6 @@
1#
2# linux/drivers/mtd/lpddr/Makefile
3#
4
5obj-$(CONFIG_MTD_QINFO_PROBE) += qinfo_probe.o
6obj-$(CONFIG_MTD_LPDDR) += lpddr_cmds.o
diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c
new file mode 100644
index 000000000000..e22ca49583e7
--- /dev/null
+++ b/drivers/mtd/lpddr/lpddr_cmds.c
@@ -0,0 +1,796 @@
1/*
2 * LPDDR flash memory device operations. This module provides read, write,
3 * erase, lock/unlock support for LPDDR flash memories
4 * (C) 2008 Korolev Alexey <akorolev@infradead.org>
5 * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com>
6 * Many thanks to Roman Borisov for intial enabling
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 * TODO:
23 * Implement VPP management
24 * Implement XIP support
25 * Implement OTP support
26 */
27#include <linux/mtd/pfow.h>
28#include <linux/mtd/qinfo.h>
29
30static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
31 size_t *retlen, u_char *buf);
32static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to,
33 size_t len, size_t *retlen, const u_char *buf);
34static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
35 unsigned long count, loff_t to, size_t *retlen);
36static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr);
37static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
38static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
39static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
40 size_t *retlen, void **mtdbuf, resource_size_t *phys);
41static void lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len);
42static int get_chip(struct map_info *map, struct flchip *chip, int mode);
43static int chip_ready(struct map_info *map, struct flchip *chip, int mode);
44static void put_chip(struct map_info *map, struct flchip *chip);
45
46struct mtd_info *lpddr_cmdset(struct map_info *map)
47{
48 struct lpddr_private *lpddr = map->fldrv_priv;
49 struct flchip_shared *shared;
50 struct flchip *chip;
51 struct mtd_info *mtd;
52 int numchips;
53 int i, j;
54
55 mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
56 if (!mtd) {
57 printk(KERN_ERR "Failed to allocate memory for MTD device\n");
58 return NULL;
59 }
60 mtd->priv = map;
61 mtd->type = MTD_NORFLASH;
62
63 /* Fill in the default mtd operations */
64 mtd->read = lpddr_read;
65 mtd->type = MTD_NORFLASH;
66 mtd->flags = MTD_CAP_NORFLASH;
67 mtd->flags &= ~MTD_BIT_WRITEABLE;
68 mtd->erase = lpddr_erase;
69 mtd->write = lpddr_write_buffers;
70 mtd->writev = lpddr_writev;
71 mtd->read_oob = NULL;
72 mtd->write_oob = NULL;
73 mtd->sync = NULL;
74 mtd->lock = lpddr_lock;
75 mtd->unlock = lpddr_unlock;
76 mtd->suspend = NULL;
77 mtd->resume = NULL;
78 if (map_is_linear(map)) {
79 mtd->point = lpddr_point;
80 mtd->unpoint = lpddr_unpoint;
81 }
82 mtd->block_isbad = NULL;
83 mtd->block_markbad = NULL;
84 mtd->size = 1 << lpddr->qinfo->DevSizeShift;
85 mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift;
86 mtd->writesize = 1 << lpddr->qinfo->BufSizeShift;
87
88 shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips,
89 GFP_KERNEL);
90 if (!shared) {
91 kfree(lpddr);
92 kfree(mtd);
93 return NULL;
94 }
95
96 chip = &lpddr->chips[0];
97 numchips = lpddr->numchips / lpddr->qinfo->HWPartsNum;
98 for (i = 0; i < numchips; i++) {
99 shared[i].writing = shared[i].erasing = NULL;
100 spin_lock_init(&shared[i].lock);
101 for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) {
102 *chip = lpddr->chips[i];
103 chip->start += j << lpddr->chipshift;
104 chip->oldstate = chip->state = FL_READY;
105 chip->priv = &shared[i];
106 /* those should be reset too since
107 they create memory references. */
108 init_waitqueue_head(&chip->wq);
109 spin_lock_init(&chip->_spinlock);
110 chip->mutex = &chip->_spinlock;
111 chip++;
112 }
113 }
114
115 return mtd;
116}
117EXPORT_SYMBOL(lpddr_cmdset);
118
119static int wait_for_ready(struct map_info *map, struct flchip *chip,
120 unsigned int chip_op_time)
121{
122 unsigned int timeo, reset_timeo, sleep_time;
123 unsigned int dsr;
124 flstate_t chip_state = chip->state;
125 int ret = 0;
126
127 /* set our timeout to 8 times the expected delay */
128 timeo = chip_op_time * 8;
129 if (!timeo)
130 timeo = 500000;
131 reset_timeo = timeo;
132 sleep_time = chip_op_time / 2;
133
134 for (;;) {
135 dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR));
136 if (dsr & DSR_READY_STATUS)
137 break;
138 if (!timeo) {
139 printk(KERN_ERR "%s: Flash timeout error state %d \n",
140 map->name, chip_state);
141 ret = -ETIME;
142 break;
143 }
144
145 /* OK Still waiting. Drop the lock, wait a while and retry. */
146 spin_unlock(chip->mutex);
147 if (sleep_time >= 1000000/HZ) {
148 /*
149 * Half of the normal delay still remaining
150 * can be performed with a sleeping delay instead
151 * of busy waiting.
152 */
153 msleep(sleep_time/1000);
154 timeo -= sleep_time;
155 sleep_time = 1000000/HZ;
156 } else {
157 udelay(1);
158 cond_resched();
159 timeo--;
160 }
161 spin_lock(chip->mutex);
162
163 while (chip->state != chip_state) {
164 /* Someone's suspended the operation: sleep */
165 DECLARE_WAITQUEUE(wait, current);
166 set_current_state(TASK_UNINTERRUPTIBLE);
167 add_wait_queue(&chip->wq, &wait);
168 spin_unlock(chip->mutex);
169 schedule();
170 remove_wait_queue(&chip->wq, &wait);
171 spin_lock(chip->mutex);
172 }
173 if (chip->erase_suspended || chip->write_suspended) {
174 /* Suspend has occured while sleep: reset timeout */
175 timeo = reset_timeo;
176 chip->erase_suspended = chip->write_suspended = 0;
177 }
178 }
179 /* check status for errors */
180 if (dsr & DSR_ERR) {
181 /* Clear DSR*/
182 map_write(map, CMD(~(DSR_ERR)), map->pfow_base + PFOW_DSR);
183 printk(KERN_WARNING"%s: Bad status on wait: 0x%x \n",
184 map->name, dsr);
185 print_drs_error(dsr);
186 ret = -EIO;
187 }
188 chip->state = FL_READY;
189 return ret;
190}
191
192static int get_chip(struct map_info *map, struct flchip *chip, int mode)
193{
194 int ret;
195 DECLARE_WAITQUEUE(wait, current);
196
197 retry:
198 if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)
199 && chip->state != FL_SYNCING) {
200 /*
201 * OK. We have possibility for contension on the write/erase
202 * operations which are global to the real chip and not per
203 * partition. So let's fight it over in the partition which
204 * currently has authority on the operation.
205 *
206 * The rules are as follows:
207 *
208 * - any write operation must own shared->writing.
209 *
210 * - any erase operation must own _both_ shared->writing and
211 * shared->erasing.
212 *
213 * - contension arbitration is handled in the owner's context.
214 *
215 * The 'shared' struct can be read and/or written only when
216 * its lock is taken.
217 */
218 struct flchip_shared *shared = chip->priv;
219 struct flchip *contender;
220 spin_lock(&shared->lock);
221 contender = shared->writing;
222 if (contender && contender != chip) {
223 /*
224 * The engine to perform desired operation on this
225 * partition is already in use by someone else.
226 * Let's fight over it in the context of the chip
227 * currently using it. If it is possible to suspend,
228 * that other partition will do just that, otherwise
229 * it'll happily send us to sleep. In any case, when
230 * get_chip returns success we're clear to go ahead.
231 */
232 ret = spin_trylock(contender->mutex);
233 spin_unlock(&shared->lock);
234 if (!ret)
235 goto retry;
236 spin_unlock(chip->mutex);
237 ret = chip_ready(map, contender, mode);
238 spin_lock(chip->mutex);
239
240 if (ret == -EAGAIN) {
241 spin_unlock(contender->mutex);
242 goto retry;
243 }
244 if (ret) {
245 spin_unlock(contender->mutex);
246 return ret;
247 }
248 spin_lock(&shared->lock);
249
250 /* We should not own chip if it is already in FL_SYNCING
251 * state. Put contender and retry. */
252 if (chip->state == FL_SYNCING) {
253 put_chip(map, contender);
254 spin_unlock(contender->mutex);
255 goto retry;
256 }
257 spin_unlock(contender->mutex);
258 }
259
260 /* Check if we have suspended erase on this chip.
261 Must sleep in such a case. */
262 if (mode == FL_ERASING && shared->erasing
263 && shared->erasing->oldstate == FL_ERASING) {
264 spin_unlock(&shared->lock);
265 set_current_state(TASK_UNINTERRUPTIBLE);
266 add_wait_queue(&chip->wq, &wait);
267 spin_unlock(chip->mutex);
268 schedule();
269 remove_wait_queue(&chip->wq, &wait);
270 spin_lock(chip->mutex);
271 goto retry;
272 }
273
274 /* We now own it */
275 shared->writing = chip;
276 if (mode == FL_ERASING)
277 shared->erasing = chip;
278 spin_unlock(&shared->lock);
279 }
280
281 ret = chip_ready(map, chip, mode);
282 if (ret == -EAGAIN)
283 goto retry;
284
285 return ret;
286}
287
288static int chip_ready(struct map_info *map, struct flchip *chip, int mode)
289{
290 struct lpddr_private *lpddr = map->fldrv_priv;
291 int ret = 0;
292 DECLARE_WAITQUEUE(wait, current);
293
294 /* Prevent setting state FL_SYNCING for chip in suspended state. */
295 if (FL_SYNCING == mode && FL_READY != chip->oldstate)
296 goto sleep;
297
298 switch (chip->state) {
299 case FL_READY:
300 case FL_JEDEC_QUERY:
301 return 0;
302
303 case FL_ERASING:
304 if (!lpddr->qinfo->SuspEraseSupp ||
305 !(mode == FL_READY || mode == FL_POINT))
306 goto sleep;
307
308 map_write(map, CMD(LPDDR_SUSPEND),
309 map->pfow_base + PFOW_PROGRAM_ERASE_SUSPEND);
310 chip->oldstate = FL_ERASING;
311 chip->state = FL_ERASE_SUSPENDING;
312 ret = wait_for_ready(map, chip, 0);
313 if (ret) {
314 /* Oops. something got wrong. */
315 /* Resume and pretend we weren't here. */
316 map_write(map, CMD(LPDDR_RESUME),
317 map->pfow_base + PFOW_COMMAND_CODE);
318 map_write(map, CMD(LPDDR_START_EXECUTION),
319 map->pfow_base + PFOW_COMMAND_EXECUTE);
320 chip->state = FL_ERASING;
321 chip->oldstate = FL_READY;
322 printk(KERN_ERR "%s: suspend operation failed."
323 "State may be wrong \n", map->name);
324 return -EIO;
325 }
326 chip->erase_suspended = 1;
327 chip->state = FL_READY;
328 return 0;
329 /* Erase suspend */
330 case FL_POINT:
331 /* Only if there's no operation suspended... */
332 if (mode == FL_READY && chip->oldstate == FL_READY)
333 return 0;
334
335 default:
336sleep:
337 set_current_state(TASK_UNINTERRUPTIBLE);
338 add_wait_queue(&chip->wq, &wait);
339 spin_unlock(chip->mutex);
340 schedule();
341 remove_wait_queue(&chip->wq, &wait);
342 spin_lock(chip->mutex);
343 return -EAGAIN;
344 }
345}
346
347static void put_chip(struct map_info *map, struct flchip *chip)
348{
349 if (chip->priv) {
350 struct flchip_shared *shared = chip->priv;
351 spin_lock(&shared->lock);
352 if (shared->writing == chip && chip->oldstate == FL_READY) {
353 /* We own the ability to write, but we're done */
354 shared->writing = shared->erasing;
355 if (shared->writing && shared->writing != chip) {
356 /* give back the ownership */
357 struct flchip *loaner = shared->writing;
358 spin_lock(loaner->mutex);
359 spin_unlock(&shared->lock);
360 spin_unlock(chip->mutex);
361 put_chip(map, loaner);
362 spin_lock(chip->mutex);
363 spin_unlock(loaner->mutex);
364 wake_up(&chip->wq);
365 return;
366 }
367 shared->erasing = NULL;
368 shared->writing = NULL;
369 } else if (shared->erasing == chip && shared->writing != chip) {
370 /*
371 * We own the ability to erase without the ability
372 * to write, which means the erase was suspended
373 * and some other partition is currently writing.
374 * Don't let the switch below mess things up since
375 * we don't have ownership to resume anything.
376 */
377 spin_unlock(&shared->lock);
378 wake_up(&chip->wq);
379 return;
380 }
381 spin_unlock(&shared->lock);
382 }
383
384 switch (chip->oldstate) {
385 case FL_ERASING:
386 chip->state = chip->oldstate;
387 map_write(map, CMD(LPDDR_RESUME),
388 map->pfow_base + PFOW_COMMAND_CODE);
389 map_write(map, CMD(LPDDR_START_EXECUTION),
390 map->pfow_base + PFOW_COMMAND_EXECUTE);
391 chip->oldstate = FL_READY;
392 chip->state = FL_ERASING;
393 break;
394 case FL_READY:
395 break;
396 default:
397 printk(KERN_ERR "%s: put_chip() called with oldstate %d!\n",
398 map->name, chip->oldstate);
399 }
400 wake_up(&chip->wq);
401}
402
403int do_write_buffer(struct map_info *map, struct flchip *chip,
404 unsigned long adr, const struct kvec **pvec,
405 unsigned long *pvec_seek, int len)
406{
407 struct lpddr_private *lpddr = map->fldrv_priv;
408 map_word datum;
409 int ret, wbufsize, word_gap, words;
410 const struct kvec *vec;
411 unsigned long vec_seek;
412 unsigned long prog_buf_ofs;
413
414 wbufsize = 1 << lpddr->qinfo->BufSizeShift;
415
416 spin_lock(chip->mutex);
417 ret = get_chip(map, chip, FL_WRITING);
418 if (ret) {
419 spin_unlock(chip->mutex);
420 return ret;
421 }
422 /* Figure out the number of words to write */
423 word_gap = (-adr & (map_bankwidth(map)-1));
424 words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
425 if (!word_gap) {
426 words--;
427 } else {
428 word_gap = map_bankwidth(map) - word_gap;
429 adr -= word_gap;
430 datum = map_word_ff(map);
431 }
432 /* Write data */
433 /* Get the program buffer offset from PFOW register data first*/
434 prog_buf_ofs = map->pfow_base + CMDVAL(map_read(map,
435 map->pfow_base + PFOW_PROGRAM_BUFFER_OFFSET));
436 vec = *pvec;
437 vec_seek = *pvec_seek;
438 do {
439 int n = map_bankwidth(map) - word_gap;
440
441 if (n > vec->iov_len - vec_seek)
442 n = vec->iov_len - vec_seek;
443 if (n > len)
444 n = len;
445
446 if (!word_gap && (len < map_bankwidth(map)))
447 datum = map_word_ff(map);
448
449 datum = map_word_load_partial(map, datum,
450 vec->iov_base + vec_seek, word_gap, n);
451
452 len -= n;
453 word_gap += n;
454 if (!len || word_gap == map_bankwidth(map)) {
455 map_write(map, datum, prog_buf_ofs);
456 prog_buf_ofs += map_bankwidth(map);
457 word_gap = 0;
458 }
459
460 vec_seek += n;
461 if (vec_seek == vec->iov_len) {
462 vec++;
463 vec_seek = 0;
464 }
465 } while (len);
466 *pvec = vec;
467 *pvec_seek = vec_seek;
468
469 /* GO GO GO */
470 send_pfow_command(map, LPDDR_BUFF_PROGRAM, adr, wbufsize, NULL);
471 chip->state = FL_WRITING;
472 ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->ProgBufferTime));
473 if (ret) {
474 printk(KERN_WARNING"%s Buffer program error: %d at %lx; \n",
475 map->name, ret, adr);
476 goto out;
477 }
478
479 out: put_chip(map, chip);
480 spin_unlock(chip->mutex);
481 return ret;
482}
483
484int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
485{
486 struct map_info *map = mtd->priv;
487 struct lpddr_private *lpddr = map->fldrv_priv;
488 int chipnum = adr >> lpddr->chipshift;
489 struct flchip *chip = &lpddr->chips[chipnum];
490 int ret;
491
492 spin_lock(chip->mutex);
493 ret = get_chip(map, chip, FL_ERASING);
494 if (ret) {
495 spin_unlock(chip->mutex);
496 return ret;
497 }
498 send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL);
499 chip->state = FL_ERASING;
500 ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->BlockEraseTime)*1000);
501 if (ret) {
502 printk(KERN_WARNING"%s Erase block error %d at : %llx\n",
503 map->name, ret, adr);
504 goto out;
505 }
506 out: put_chip(map, chip);
507 spin_unlock(chip->mutex);
508 return ret;
509}
510
511static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len,
512 size_t *retlen, u_char *buf)
513{
514 struct map_info *map = mtd->priv;
515 struct lpddr_private *lpddr = map->fldrv_priv;
516 int chipnum = adr >> lpddr->chipshift;
517 struct flchip *chip = &lpddr->chips[chipnum];
518 int ret = 0;
519
520 spin_lock(chip->mutex);
521 ret = get_chip(map, chip, FL_READY);
522 if (ret) {
523 spin_unlock(chip->mutex);
524 return ret;
525 }
526
527 map_copy_from(map, buf, adr, len);
528 *retlen = len;
529
530 put_chip(map, chip);
531 spin_unlock(chip->mutex);
532 return ret;
533}
534
535static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len,
536 size_t *retlen, void **mtdbuf, resource_size_t *phys)
537{
538 struct map_info *map = mtd->priv;
539 struct lpddr_private *lpddr = map->fldrv_priv;
540 int chipnum = adr >> lpddr->chipshift;
541 unsigned long ofs, last_end = 0;
542 struct flchip *chip = &lpddr->chips[chipnum];
543 int ret = 0;
544
545 if (!map->virt || (adr + len > mtd->size))
546 return -EINVAL;
547
548 /* ofs: offset within the first chip that the first read should start */
549 ofs = adr - (chipnum << lpddr->chipshift);
550
551 *mtdbuf = (void *)map->virt + chip->start + ofs;
552 *retlen = 0;
553
554 while (len) {
555 unsigned long thislen;
556
557 if (chipnum >= lpddr->numchips)
558 break;
559
560 /* We cannot point across chips that are virtually disjoint */
561 if (!last_end)
562 last_end = chip->start;
563 else if (chip->start != last_end)
564 break;
565
566 if ((len + ofs - 1) >> lpddr->chipshift)
567 thislen = (1<<lpddr->chipshift) - ofs;
568 else
569 thislen = len;
570 /* get the chip */
571 spin_lock(chip->mutex);
572 ret = get_chip(map, chip, FL_POINT);
573 spin_unlock(chip->mutex);
574 if (ret)
575 break;
576
577 chip->state = FL_POINT;
578 chip->ref_point_counter++;
579 *retlen += thislen;
580 len -= thislen;
581
582 ofs = 0;
583 last_end += 1 << lpddr->chipshift;
584 chipnum++;
585 chip = &lpddr->chips[chipnum];
586 }
587 return 0;
588}
589
590static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len)
591{
592 struct map_info *map = mtd->priv;
593 struct lpddr_private *lpddr = map->fldrv_priv;
594 int chipnum = adr >> lpddr->chipshift;
595 unsigned long ofs;
596
597 /* ofs: offset within the first chip that the first read should start */
598 ofs = adr - (chipnum << lpddr->chipshift);
599
600 while (len) {
601 unsigned long thislen;
602 struct flchip *chip;
603
604 chip = &lpddr->chips[chipnum];
605 if (chipnum >= lpddr->numchips)
606 break;
607
608 if ((len + ofs - 1) >> lpddr->chipshift)
609 thislen = (1<<lpddr->chipshift) - ofs;
610 else
611 thislen = len;
612
613 spin_lock(chip->mutex);
614 if (chip->state == FL_POINT) {
615 chip->ref_point_counter--;
616 if (chip->ref_point_counter == 0)
617 chip->state = FL_READY;
618 } else
619 printk(KERN_WARNING "%s: Warning: unpoint called on non"
620 "pointed region\n", map->name);
621
622 put_chip(map, chip);
623 spin_unlock(chip->mutex);
624
625 len -= thislen;
626 ofs = 0;
627 chipnum++;
628 }
629}
630
631static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
632 size_t *retlen, const u_char *buf)
633{
634 struct kvec vec;
635
636 vec.iov_base = (void *) buf;
637 vec.iov_len = len;
638
639 return lpddr_writev(mtd, &vec, 1, to, retlen);
640}
641
642
643static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs,
644 unsigned long count, loff_t to, size_t *retlen)
645{
646 struct map_info *map = mtd->priv;
647 struct lpddr_private *lpddr = map->fldrv_priv;
648 int ret = 0;
649 int chipnum;
650 unsigned long ofs, vec_seek, i;
651 int wbufsize = 1 << lpddr->qinfo->BufSizeShift;
652
653 size_t len = 0;
654
655 for (i = 0; i < count; i++)
656 len += vecs[i].iov_len;
657
658 *retlen = 0;
659 if (!len)
660 return 0;
661
662 chipnum = to >> lpddr->chipshift;
663
664 ofs = to;
665 vec_seek = 0;
666
667 do {
668 /* We must not cross write block boundaries */
669 int size = wbufsize - (ofs & (wbufsize-1));
670
671 if (size > len)
672 size = len;
673
674 ret = do_write_buffer(map, &lpddr->chips[chipnum],
675 ofs, &vecs, &vec_seek, size);
676 if (ret)
677 return ret;
678
679 ofs += size;
680 (*retlen) += size;
681 len -= size;
682
683 /* Be nice and reschedule with the chip in a usable
684 * state for other processes */
685 cond_resched();
686
687 } while (len);
688
689 return 0;
690}
691
692static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr)
693{
694 unsigned long ofs, len;
695 int ret;
696 struct map_info *map = mtd->priv;
697 struct lpddr_private *lpddr = map->fldrv_priv;
698 int size = 1 << lpddr->qinfo->UniformBlockSizeShift;
699
700 ofs = instr->addr;
701 len = instr->len;
702
703 if (ofs > mtd->size || (len + ofs) > mtd->size)
704 return -EINVAL;
705
706 while (len > 0) {
707 ret = do_erase_oneblock(mtd, ofs);
708 if (ret)
709 return ret;
710 ofs += size;
711 len -= size;
712 }
713 instr->state = MTD_ERASE_DONE;
714 mtd_erase_callback(instr);
715
716 return 0;
717}
718
719#define DO_XXLOCK_LOCK 1
720#define DO_XXLOCK_UNLOCK 2
721int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk)
722{
723 int ret = 0;
724 struct map_info *map = mtd->priv;
725 struct lpddr_private *lpddr = map->fldrv_priv;
726 int chipnum = adr >> lpddr->chipshift;
727 struct flchip *chip = &lpddr->chips[chipnum];
728
729 spin_lock(chip->mutex);
730 ret = get_chip(map, chip, FL_LOCKING);
731 if (ret) {
732 spin_unlock(chip->mutex);
733 return ret;
734 }
735
736 if (thunk == DO_XXLOCK_LOCK) {
737 send_pfow_command(map, LPDDR_LOCK_BLOCK, adr, adr + len, NULL);
738 chip->state = FL_LOCKING;
739 } else if (thunk == DO_XXLOCK_UNLOCK) {
740 send_pfow_command(map, LPDDR_UNLOCK_BLOCK, adr, adr + len, NULL);
741 chip->state = FL_UNLOCKING;
742 } else
743 BUG();
744
745 ret = wait_for_ready(map, chip, 1);
746 if (ret) {
747 printk(KERN_ERR "%s: block unlock error status %d \n",
748 map->name, ret);
749 goto out;
750 }
751out: put_chip(map, chip);
752 spin_unlock(chip->mutex);
753 return ret;
754}
755
756static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
757{
758 return do_xxlock(mtd, ofs, len, DO_XXLOCK_LOCK);
759}
760
761static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
762{
763 return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK);
764}
765
766int word_program(struct map_info *map, loff_t adr, uint32_t curval)
767{
768 int ret;
769 struct lpddr_private *lpddr = map->fldrv_priv;
770 int chipnum = adr >> lpddr->chipshift;
771 struct flchip *chip = &lpddr->chips[chipnum];
772
773 spin_lock(chip->mutex);
774 ret = get_chip(map, chip, FL_WRITING);
775 if (ret) {
776 spin_unlock(chip->mutex);
777 return ret;
778 }
779
780 send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval);
781
782 ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime));
783 if (ret) {
784 printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n",
785 map->name, adr, curval);
786 goto out;
787 }
788
789out: put_chip(map, chip);
790 spin_unlock(chip->mutex);
791 return ret;
792}
793
794MODULE_LICENSE("GPL");
795MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>");
796MODULE_DESCRIPTION("MTD driver for LPDDR flash chips");
diff --git a/drivers/mtd/lpddr/qinfo_probe.c b/drivers/mtd/lpddr/qinfo_probe.c
new file mode 100644
index 000000000000..79bf40f48b75
--- /dev/null
+++ b/drivers/mtd/lpddr/qinfo_probe.c
@@ -0,0 +1,255 @@
1/*
2 * Probing flash chips with QINFO records.
3 * (C) 2008 Korolev Alexey <akorolev@infradead.org>
4 * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 */
21#include <linux/module.h>
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/init.h>
25#include <linux/errno.h>
26#include <linux/slab.h>
27#include <linux/interrupt.h>
28
29#include <linux/mtd/xip.h>
30#include <linux/mtd/map.h>
31#include <linux/mtd/pfow.h>
32#include <linux/mtd/qinfo.h>
33
34static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr);
35struct mtd_info *lpddr_probe(struct map_info *map);
36static struct lpddr_private *lpddr_probe_chip(struct map_info *map);
37static int lpddr_pfow_present(struct map_info *map,
38 struct lpddr_private *lpddr);
39
40static struct qinfo_query_info qinfo_array[] = {
41 /* General device info */
42 {0, 0, "DevSizeShift", "Device size 2^n bytes"},
43 {0, 3, "BufSizeShift", "Program buffer size 2^n bytes"},
44 /* Erase block information */
45 {1, 1, "TotalBlocksNum", "Total number of blocks"},
46 {1, 2, "UniformBlockSizeShift", "Uniform block size 2^n bytes"},
47 /* Partition information */
48 {2, 1, "HWPartsNum", "Number of hardware partitions"},
49 /* Optional features */
50 {5, 1, "SuspEraseSupp", "Suspend erase supported"},
51 /* Operation typical time */
52 {10, 0, "SingleWordProgTime", "Single word program 2^n u-sec"},
53 {10, 1, "ProgBufferTime", "Program buffer write 2^n u-sec"},
54 {10, 2, "BlockEraseTime", "Block erase 2^n m-sec"},
55 {10, 3, "FullChipEraseTime", "Full chip erase 2^n m-sec"},
56};
57
58static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str)
59{
60 int qinfo_lines = sizeof(qinfo_array)/sizeof(struct qinfo_query_info);
61 int i;
62 int bankwidth = map_bankwidth(map) * 8;
63 int major, minor;
64
65 for (i = 0; i < qinfo_lines; i++) {
66 if (strcmp(id_str, qinfo_array[i].id_str) == 0) {
67 major = qinfo_array[i].major & ((1 << bankwidth) - 1);
68 minor = qinfo_array[i].minor & ((1 << bankwidth) - 1);
69 return minor | (major << bankwidth);
70 }
71 }
72 printk(KERN_ERR"%s qinfo id string is wrong! \n", map->name);
73 BUG();
74 return -1;
75}
76
77static uint16_t lpddr_info_query(struct map_info *map, char *id_str)
78{
79 unsigned int dsr, val;
80 int bits_per_chip = map_bankwidth(map) * 8;
81 unsigned long adr = lpddr_get_qinforec_pos(map, id_str);
82 int attempts = 20;
83
84 /* Write a request for the PFOW record */
85 map_write(map, CMD(LPDDR_INFO_QUERY),
86 map->pfow_base + PFOW_COMMAND_CODE);
87 map_write(map, CMD(adr & ((1 << bits_per_chip) - 1)),
88 map->pfow_base + PFOW_COMMAND_ADDRESS_L);
89 map_write(map, CMD(adr >> bits_per_chip),
90 map->pfow_base + PFOW_COMMAND_ADDRESS_H);
91 map_write(map, CMD(LPDDR_START_EXECUTION),
92 map->pfow_base + PFOW_COMMAND_EXECUTE);
93
94 while ((attempts--) > 0) {
95 dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR));
96 if (dsr & DSR_READY_STATUS)
97 break;
98 udelay(10);
99 }
100
101 val = CMDVAL(map_read(map, map->pfow_base + PFOW_COMMAND_DATA));
102 return val;
103}
104
105static int lpddr_pfow_present(struct map_info *map, struct lpddr_private *lpddr)
106{
107 map_word pfow_val[4];
108
109 /* Check identification string */
110 pfow_val[0] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_P);
111 pfow_val[1] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_F);
112 pfow_val[2] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_O);
113 pfow_val[3] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_W);
114
115 if (!map_word_equal(map, CMD('P'), pfow_val[0]))
116 goto out;
117
118 if (!map_word_equal(map, CMD('F'), pfow_val[1]))
119 goto out;
120
121 if (!map_word_equal(map, CMD('O'), pfow_val[2]))
122 goto out;
123
124 if (!map_word_equal(map, CMD('W'), pfow_val[3]))
125 goto out;
126
127 return 1; /* "PFOW" is found */
128out:
129 printk(KERN_WARNING"%s: PFOW string at 0x%lx is not found \n",
130 map->name, map->pfow_base);
131 return 0;
132}
133
134static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr)
135{
136
137 lpddr->qinfo = kmalloc(sizeof(struct qinfo_chip), GFP_KERNEL);
138 if (!lpddr->qinfo) {
139 printk(KERN_WARNING "%s: no memory for LPDDR qinfo structure\n",
140 map->name);
141 return 0;
142 }
143 memset(lpddr->qinfo, 0, sizeof(struct qinfo_chip));
144
145 /* Get the ManuID */
146 lpddr->ManufactId = CMDVAL(map_read(map, map->pfow_base + PFOW_MANUFACTURER_ID));
147 /* Get the DeviceID */
148 lpddr->DevId = CMDVAL(map_read(map, map->pfow_base + PFOW_DEVICE_ID));
149 /* read parameters from chip qinfo table */
150 lpddr->qinfo->DevSizeShift = lpddr_info_query(map, "DevSizeShift");
151 lpddr->qinfo->TotalBlocksNum = lpddr_info_query(map, "TotalBlocksNum");
152 lpddr->qinfo->BufSizeShift = lpddr_info_query(map, "BufSizeShift");
153 lpddr->qinfo->HWPartsNum = lpddr_info_query(map, "HWPartsNum");
154 lpddr->qinfo->UniformBlockSizeShift =
155 lpddr_info_query(map, "UniformBlockSizeShift");
156 lpddr->qinfo->SuspEraseSupp = lpddr_info_query(map, "SuspEraseSupp");
157 lpddr->qinfo->SingleWordProgTime =
158 lpddr_info_query(map, "SingleWordProgTime");
159 lpddr->qinfo->ProgBufferTime = lpddr_info_query(map, "ProgBufferTime");
160 lpddr->qinfo->BlockEraseTime = lpddr_info_query(map, "BlockEraseTime");
161 return 1;
162}
163static struct lpddr_private *lpddr_probe_chip(struct map_info *map)
164{
165 struct lpddr_private lpddr;
166 struct lpddr_private *retlpddr;
167 int numvirtchips;
168
169
170 if ((map->pfow_base + 0x1000) >= map->size) {
171 printk(KERN_NOTICE"%s Probe at base (0x%08lx) past the end of"
172 "the map(0x%08lx)\n", map->name,
173 (unsigned long)map->pfow_base, map->size - 1);
174 return NULL;
175 }
176 memset(&lpddr, 0, sizeof(struct lpddr_private));
177 if (!lpddr_pfow_present(map, &lpddr))
178 return NULL;
179
180 if (!lpddr_chip_setup(map, &lpddr))
181 return NULL;
182
183 /* Ok so we found a chip */
184 lpddr.chipshift = lpddr.qinfo->DevSizeShift;
185 lpddr.numchips = 1;
186
187 numvirtchips = lpddr.numchips * lpddr.qinfo->HWPartsNum;
188 retlpddr = kmalloc(sizeof(struct lpddr_private) +
189 numvirtchips * sizeof(struct flchip), GFP_KERNEL);
190 if (!retlpddr)
191 return NULL;
192
193 memset(retlpddr, 0, sizeof(struct lpddr_private) +
194 numvirtchips * sizeof(struct flchip));
195 memcpy(retlpddr, &lpddr, sizeof(struct lpddr_private));
196
197 retlpddr->numchips = numvirtchips;
198 retlpddr->chipshift = retlpddr->qinfo->DevSizeShift -
199 __ffs(retlpddr->qinfo->HWPartsNum);
200
201 return retlpddr;
202}
203
204struct mtd_info *lpddr_probe(struct map_info *map)
205{
206 struct mtd_info *mtd = NULL;
207 struct lpddr_private *lpddr;
208
209 /* First probe the map to see if we havecan open PFOW here */
210 lpddr = lpddr_probe_chip(map);
211 if (!lpddr)
212 return NULL;
213
214 map->fldrv_priv = lpddr;
215 mtd = lpddr_cmdset(map);
216 if (mtd) {
217 if (mtd->size > map->size) {
218 printk(KERN_WARNING "Reducing visibility of %ldKiB chip"
219 "to %ldKiB\n", (unsigned long)mtd->size >> 10,
220 (unsigned long)map->size >> 10);
221 mtd->size = map->size;
222 }
223 return mtd;
224 }
225
226 kfree(lpddr->qinfo);
227 kfree(lpddr);
228 map->fldrv_priv = NULL;
229 return NULL;
230}
231
232static struct mtd_chip_driver lpddr_chipdrv = {
233 .probe = lpddr_probe,
234 .name = "qinfo_probe",
235 .module = THIS_MODULE
236};
237
238static int __init lpddr_probe_init(void)
239{
240 register_mtd_chip_driver(&lpddr_chipdrv);
241 return 0;
242}
243
244static void __exit lpddr_probe_exit(void)
245{
246 unregister_mtd_chip_driver(&lpddr_chipdrv);
247}
248
249module_init(lpddr_probe_init);
250module_exit(lpddr_probe_exit);
251
252MODULE_LICENSE("GPL");
253MODULE_AUTHOR("Vasiliy Leonenko <vasiliy.leonenko@gmail.com>");
254MODULE_DESCRIPTION("Driver to probe qinfo flash chips");
255
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 5ea169362164..0225cbbf22de 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -10,8 +10,8 @@ config MTD_COMPLEX_MAPPINGS
10 paged mappings of flash chips. 10 paged mappings of flash chips.
11 11
12config MTD_PHYSMAP 12config MTD_PHYSMAP
13 tristate "CFI Flash device in physical memory map" 13 tristate "Flash device in physical memory map"
14 depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM 14 depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_LPDDR
15 help 15 help
16 This provides a 'mapping' driver which allows the NOR Flash and 16 This provides a 'mapping' driver which allows the NOR Flash and
17 ROM driver code to communicate with chips which are mapped 17 ROM driver code to communicate with chips which are mapped
@@ -23,9 +23,20 @@ config MTD_PHYSMAP
23 To compile this driver as a module, choose M here: the 23 To compile this driver as a module, choose M here: the
24 module will be called physmap. 24 module will be called physmap.
25 25
26config MTD_PHYSMAP_COMPAT
27 bool "Physmap compat support"
28 depends on MTD_PHYSMAP
29 default n
30 help
31 Setup a simple mapping via the Kconfig options. Normally the
32 physmap configuration options are done via your board's
33 resource file.
34
35 If unsure, say N here.
36
26config MTD_PHYSMAP_START 37config MTD_PHYSMAP_START
27 hex "Physical start address of flash mapping" 38 hex "Physical start address of flash mapping"
28 depends on MTD_PHYSMAP 39 depends on MTD_PHYSMAP_COMPAT
29 default "0x8000000" 40 default "0x8000000"
30 help 41 help
31 This is the physical memory location at which the flash chips 42 This is the physical memory location at which the flash chips
@@ -37,7 +48,7 @@ config MTD_PHYSMAP_START
37 48
38config MTD_PHYSMAP_LEN 49config MTD_PHYSMAP_LEN
39 hex "Physical length of flash mapping" 50 hex "Physical length of flash mapping"
40 depends on MTD_PHYSMAP 51 depends on MTD_PHYSMAP_COMPAT
41 default "0" 52 default "0"
42 help 53 help
43 This is the total length of the mapping of the flash chips on 54 This is the total length of the mapping of the flash chips on
@@ -51,7 +62,7 @@ config MTD_PHYSMAP_LEN
51 62
52config MTD_PHYSMAP_BANKWIDTH 63config MTD_PHYSMAP_BANKWIDTH
53 int "Bank width in octets" 64 int "Bank width in octets"
54 depends on MTD_PHYSMAP 65 depends on MTD_PHYSMAP_COMPAT
55 default "2" 66 default "2"
56 help 67 help
57 This is the total width of the data bus of the flash devices 68 This is the total width of the data bus of the flash devices
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
index 82811bcb0436..845ad4f2a542 100644
--- a/drivers/mtd/maps/alchemy-flash.c
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -111,7 +111,7 @@ static struct mtd_partition alchemy_partitions[] = {
111 111
112static struct mtd_info *mymtd; 112static struct mtd_info *mymtd;
113 113
114int __init alchemy_mtd_init(void) 114static int __init alchemy_mtd_init(void)
115{ 115{
116 struct mtd_partition *parts; 116 struct mtd_partition *parts;
117 int nb_parts = 0; 117 int nb_parts = 0;
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index d1eec7d3243f..237733d094c4 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -232,8 +232,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
232 /* Trim the size if we are larger than the map */ 232 /* Trim the size if we are larger than the map */
233 if (map->mtd->size > map->map.size) { 233 if (map->mtd->size > map->map.size) {
234 printk(KERN_WARNING MOD_NAME 234 printk(KERN_WARNING MOD_NAME
235 " rom(%u) larger than window(%lu). fixing...\n", 235 " rom(%llu) larger than window(%lu). fixing...\n",
236 map->mtd->size, map->map.size); 236 (unsigned long long)map->mtd->size, map->map.size);
237 map->mtd->size = map->map.size; 237 map->mtd->size = map->map.size;
238 } 238 }
239 if (window->rsrc.parent) { 239 if (window->rsrc.parent) {
diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c
index 0ecc3f6d735b..b4ed81611918 100644
--- a/drivers/mtd/maps/cfi_flagadm.c
+++ b/drivers/mtd/maps/cfi_flagadm.c
@@ -88,7 +88,7 @@ struct mtd_partition flagadm_parts[] = {
88 88
89static struct mtd_info *mymtd; 89static struct mtd_info *mymtd;
90 90
91int __init init_flagadm(void) 91static int __init init_flagadm(void)
92{ 92{
93 printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", 93 printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n",
94 FLASH_SIZE, FLASH_PHYS_ADDR); 94 FLASH_SIZE, FLASH_PHYS_ADDR);
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 1a6feb4474de..5f7a245ed132 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -263,8 +263,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
263 /* Trim the size if we are larger than the map */ 263 /* Trim the size if we are larger than the map */
264 if (map->mtd->size > map->map.size) { 264 if (map->mtd->size > map->map.size) {
265 printk(KERN_WARNING MOD_NAME 265 printk(KERN_WARNING MOD_NAME
266 " rom(%u) larger than window(%lu). fixing...\n", 266 " rom(%llu) larger than window(%lu). fixing...\n",
267 map->mtd->size, map->map.size); 267 (unsigned long long)map->mtd->size, map->map.size);
268 map->mtd->size = map->map.size; 268 map->mtd->size = map->map.size;
269 } 269 }
270 if (window->rsrc.parent) { 270 if (window->rsrc.parent) {
diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c
index e115667bf1d0..cfacfa6f45dd 100644
--- a/drivers/mtd/maps/dbox2-flash.c
+++ b/drivers/mtd/maps/dbox2-flash.c
@@ -69,7 +69,7 @@ struct map_info dbox2_flash_map = {
69 .phys = WINDOW_ADDR, 69 .phys = WINDOW_ADDR,
70}; 70};
71 71
72int __init init_dbox2_flash(void) 72static int __init init_dbox2_flash(void)
73{ 73{
74 printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR); 74 printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR);
75 dbox2_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); 75 dbox2_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
index 9433738c1664..be9e90b44587 100644
--- a/drivers/mtd/maps/edb7312.c
+++ b/drivers/mtd/maps/edb7312.c
@@ -71,7 +71,7 @@ static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
71static int mtd_parts_nb = 0; 71static int mtd_parts_nb = 0;
72static struct mtd_partition *mtd_parts = 0; 72static struct mtd_partition *mtd_parts = 0;
73 73
74int __init init_edb7312nor(void) 74static int __init init_edb7312nor(void)
75{ 75{
76 static const char *rom_probe_types[] = PROBETYPES; 76 static const char *rom_probe_types[] = PROBETYPES;
77 const char **type; 77 const char **type;
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
index bbbcdd4c8d13..11a2f57df9cf 100644
--- a/drivers/mtd/maps/esb2rom.c
+++ b/drivers/mtd/maps/esb2rom.c
@@ -324,8 +324,8 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev,
324 /* Trim the size if we are larger than the map */ 324 /* Trim the size if we are larger than the map */
325 if (map->mtd->size > map->map.size) { 325 if (map->mtd->size > map->map.size) {
326 printk(KERN_WARNING MOD_NAME 326 printk(KERN_WARNING MOD_NAME
327 " rom(%u) larger than window(%lu). fixing...\n", 327 " rom(%llu) larger than window(%lu). fixing...\n",
328 map->mtd->size, map->map.size); 328 (unsigned long long)map->mtd->size, map->map.size);
329 map->mtd->size = map->map.size; 329 map->mtd->size = map->map.size;
330 } 330 }
331 if (window->rsrc.parent) { 331 if (window->rsrc.parent) {
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
index a8e3fde4cbd5..1e43124d498b 100644
--- a/drivers/mtd/maps/fortunet.c
+++ b/drivers/mtd/maps/fortunet.c
@@ -181,7 +181,7 @@ __setup("MTD_Partition=", MTD_New_Partition);
181/* Backwards-spelling-compatibility */ 181/* Backwards-spelling-compatibility */
182__setup("MTD_Partion=", MTD_New_Partition); 182__setup("MTD_Partion=", MTD_New_Partition);
183 183
184int __init init_fortunet(void) 184static int __init init_fortunet(void)
185{ 185{
186 int ix,iy; 186 int ix,iy;
187 for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++) 187 for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c
index 3b959fad1c4e..72c724fa8c27 100644
--- a/drivers/mtd/maps/h720x-flash.c
+++ b/drivers/mtd/maps/h720x-flash.c
@@ -65,7 +65,7 @@ static const char *probes[] = { "cmdlinepart", NULL };
65/* 65/*
66 * Initialize FLASH support 66 * Initialize FLASH support
67 */ 67 */
68int __init h720x_mtd_init(void) 68static int __init h720x_mtd_init(void)
69{ 69{
70 70
71 char *part_type = NULL; 71 char *part_type = NULL;
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index aeb6c916e23f..c32bc28920b3 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -258,8 +258,8 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
258 /* Trim the size if we are larger than the map */ 258 /* Trim the size if we are larger than the map */
259 if (map->mtd->size > map->map.size) { 259 if (map->mtd->size > map->map.size) {
260 printk(KERN_WARNING MOD_NAME 260 printk(KERN_WARNING MOD_NAME
261 " rom(%u) larger than window(%lu). fixing...\n", 261 " rom(%llu) larger than window(%lu). fixing...\n",
262 map->mtd->size, map->map.size); 262 (unsigned long long)map->mtd->size, map->map.size);
263 map->mtd->size = map->map.size; 263 map->mtd->size = map->map.size;
264 } 264 }
265 if (window->rsrc.parent) { 265 if (window->rsrc.parent) {
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
index 2682ab51a367..998a27da97f3 100644
--- a/drivers/mtd/maps/impa7.c
+++ b/drivers/mtd/maps/impa7.c
@@ -70,7 +70,7 @@ static struct mtd_partition *mtd_parts[NUM_FLASHBANKS];
70 70
71static const char *probes[] = { "cmdlinepart", NULL }; 71static const char *probes[] = { "cmdlinepart", NULL };
72 72
73int __init init_impa7(void) 73static int __init init_impa7(void)
74{ 74{
75 static const char *rom_probe_types[] = PROBETYPES; 75 static const char *rom_probe_types[] = PROBETYPES;
76 const char **type; 76 const char **type;
diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c
index ed58f6a77bd9..748c85f635f1 100644
--- a/drivers/mtd/maps/ipaq-flash.c
+++ b/drivers/mtd/maps/ipaq-flash.c
@@ -202,7 +202,7 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
202 202
203static int __init h1900_special_case(void); 203static int __init h1900_special_case(void);
204 204
205int __init ipaq_mtd_init(void) 205static int __init ipaq_mtd_init(void)
206{ 206{
207 struct mtd_partition *parts = NULL; 207 struct mtd_partition *parts = NULL;
208 int nb_parts = 0; 208 int nb_parts = 0;
diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c
index 706f67394b07..0eb5a7c85380 100644
--- a/drivers/mtd/maps/mbx860.c
+++ b/drivers/mtd/maps/mbx860.c
@@ -55,7 +55,7 @@ struct map_info mbx_map = {
55 .bankwidth = 4, 55 .bankwidth = 4,
56}; 56};
57 57
58int __init init_mbx(void) 58static int __init init_mbx(void)
59{ 59{
60 printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR); 60 printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR);
61 mbx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); 61 mbx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 965e6c6d6ab0..a97133eb9d70 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -226,7 +226,7 @@ static int __init nettel_init(void)
226 226
227 if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) { 227 if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) {
228 printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n", 228 printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n",
229 amd_mtd->size>>10); 229 (int)(amd_mtd->size>>10));
230 230
231 amd_mtd->owner = THIS_MODULE; 231 amd_mtd->owner = THIS_MODULE;
232 232
@@ -357,13 +357,12 @@ static int __init nettel_init(void)
357 *intel1par = 0; 357 *intel1par = 0;
358 } 358 }
359 359
360 printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n", 360 printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %lldKiB\n",
361 (intel_mtd->size >> 10)); 361 (unsigned long long)(intel_mtd->size >> 10));
362 362
363 intel_mtd->owner = THIS_MODULE; 363 intel_mtd->owner = THIS_MODULE;
364 364
365 num_intel_partitions = sizeof(nettel_intel_partitions) / 365 num_intel_partitions = ARRAY_SIZE(nettel_intel_partitions);
366 sizeof(nettel_intel_partitions[0]);
367 366
368 if (intelboot) { 367 if (intelboot) {
369 /* 368 /*
diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c
index 43e04c1d22a9..2b2e45093218 100644
--- a/drivers/mtd/maps/octagon-5066.c
+++ b/drivers/mtd/maps/octagon-5066.c
@@ -184,7 +184,7 @@ void cleanup_oct5066(void)
184 release_region(PAGE_IO, 1); 184 release_region(PAGE_IO, 1);
185} 185}
186 186
187int __init init_oct5066(void) 187static int __init init_oct5066(void)
188{ 188{
189 int i; 189 int i;
190 int ret = 0; 190 int ret = 0;
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 1db16e549e38..87743661d48e 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -29,7 +29,6 @@ struct physmap_flash_info {
29 struct map_info map[MAX_RESOURCES]; 29 struct map_info map[MAX_RESOURCES];
30#ifdef CONFIG_MTD_PARTITIONS 30#ifdef CONFIG_MTD_PARTITIONS
31 int nr_parts; 31 int nr_parts;
32 struct mtd_partition *parts;
33#endif 32#endif
34}; 33};
35 34
@@ -56,14 +55,10 @@ static int physmap_flash_remove(struct platform_device *dev)
56 for (i = 0; i < MAX_RESOURCES; i++) { 55 for (i = 0; i < MAX_RESOURCES; i++) {
57 if (info->mtd[i] != NULL) { 56 if (info->mtd[i] != NULL) {
58#ifdef CONFIG_MTD_PARTITIONS 57#ifdef CONFIG_MTD_PARTITIONS
59 if (info->nr_parts) { 58 if (info->nr_parts || physmap_data->nr_parts)
60 del_mtd_partitions(info->mtd[i]); 59 del_mtd_partitions(info->mtd[i]);
61 kfree(info->parts); 60 else
62 } else if (physmap_data->nr_parts) {
63 del_mtd_partitions(info->mtd[i]);
64 } else {
65 del_mtd_device(info->mtd[i]); 61 del_mtd_device(info->mtd[i]);
66 }
67#else 62#else
68 del_mtd_device(info->mtd[i]); 63 del_mtd_device(info->mtd[i]);
69#endif 64#endif
@@ -73,7 +68,12 @@ static int physmap_flash_remove(struct platform_device *dev)
73 return 0; 68 return 0;
74} 69}
75 70
76static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL }; 71static const char *rom_probe_types[] = {
72 "cfi_probe",
73 "jedec_probe",
74 "qinfo_probe",
75 "map_rom",
76 NULL };
77#ifdef CONFIG_MTD_PARTITIONS 77#ifdef CONFIG_MTD_PARTITIONS
78static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; 78static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
79#endif 79#endif
@@ -86,6 +86,9 @@ static int physmap_flash_probe(struct platform_device *dev)
86 int err = 0; 86 int err = 0;
87 int i; 87 int i;
88 int devices_found = 0; 88 int devices_found = 0;
89#ifdef CONFIG_MTD_PARTITIONS
90 struct mtd_partition *parts;
91#endif
89 92
90 physmap_data = dev->dev.platform_data; 93 physmap_data = dev->dev.platform_data;
91 if (physmap_data == NULL) 94 if (physmap_data == NULL)
@@ -119,6 +122,7 @@ static int physmap_flash_probe(struct platform_device *dev)
119 info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1; 122 info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1;
120 info->map[i].bankwidth = physmap_data->width; 123 info->map[i].bankwidth = physmap_data->width;
121 info->map[i].set_vpp = physmap_data->set_vpp; 124 info->map[i].set_vpp = physmap_data->set_vpp;
125 info->map[i].pfow_base = physmap_data->pfow_base;
122 126
123 info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys, 127 info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys,
124 info->map[i].size); 128 info->map[i].size);
@@ -163,9 +167,10 @@ static int physmap_flash_probe(struct platform_device *dev)
163 goto err_out; 167 goto err_out;
164 168
165#ifdef CONFIG_MTD_PARTITIONS 169#ifdef CONFIG_MTD_PARTITIONS
166 err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0); 170 err = parse_mtd_partitions(info->cmtd, part_probe_types, &parts, 0);
167 if (err > 0) { 171 if (err > 0) {
168 add_mtd_partitions(info->cmtd, info->parts, err); 172 add_mtd_partitions(info->cmtd, parts, err);
173 kfree(parts);
169 return 0; 174 return 0;
170 } 175 }
171 176
@@ -251,14 +256,7 @@ static struct platform_driver physmap_flash_driver = {
251}; 256};
252 257
253 258
254#ifdef CONFIG_MTD_PHYSMAP_LEN 259#ifdef CONFIG_MTD_PHYSMAP_COMPAT
255#if CONFIG_MTD_PHYSMAP_LEN != 0
256#warning using PHYSMAP compat code
257#define PHYSMAP_COMPAT
258#endif
259#endif
260
261#ifdef PHYSMAP_COMPAT
262static struct physmap_flash_data physmap_flash_data = { 260static struct physmap_flash_data physmap_flash_data = {
263 .width = CONFIG_MTD_PHYSMAP_BANKWIDTH, 261 .width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
264}; 262};
@@ -302,7 +300,7 @@ static int __init physmap_init(void)
302 int err; 300 int err;
303 301
304 err = platform_driver_register(&physmap_flash_driver); 302 err = platform_driver_register(&physmap_flash_driver);
305#ifdef PHYSMAP_COMPAT 303#ifdef CONFIG_MTD_PHYSMAP_COMPAT
306 if (err == 0) 304 if (err == 0)
307 platform_device_register(&physmap_flash); 305 platform_device_register(&physmap_flash);
308#endif 306#endif
@@ -312,7 +310,7 @@ static int __init physmap_init(void)
312 310
313static void __exit physmap_exit(void) 311static void __exit physmap_exit(void)
314{ 312{
315#ifdef PHYSMAP_COMPAT 313#ifdef CONFIG_MTD_PHYSMAP_COMPAT
316 platform_device_unregister(&physmap_flash); 314 platform_device_unregister(&physmap_flash);
317#endif 315#endif
318 platform_driver_unregister(&physmap_flash_driver); 316 platform_driver_unregister(&physmap_flash_driver);
@@ -326,8 +324,7 @@ MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
326MODULE_DESCRIPTION("Generic configurable MTD map driver"); 324MODULE_DESCRIPTION("Generic configurable MTD map driver");
327 325
328/* legacy platform drivers can't hotplug or coldplg */ 326/* legacy platform drivers can't hotplug or coldplg */
329#ifndef PHYSMAP_COMPAT 327#ifndef CONFIG_MTD_PHYSMAP_COMPAT
330/* work with hotplug and coldplug */ 328/* work with hotplug and coldplug */
331MODULE_ALIAS("platform:physmap-flash"); 329MODULE_ALIAS("platform:physmap-flash");
332#endif 330#endif
333
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c
index f43ba2815cbb..4768bd5459d6 100644
--- a/drivers/mtd/maps/pmcmsp-flash.c
+++ b/drivers/mtd/maps/pmcmsp-flash.c
@@ -48,7 +48,7 @@ static int fcnt;
48 48
49#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n", __func__, __LINE__) 49#define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n", __func__, __LINE__)
50 50
51int __init init_msp_flash(void) 51static int __init init_msp_flash(void)
52{ 52{
53 int i, j; 53 int i, j;
54 int offset, coff; 54 int offset, coff;
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c
index de002eb1a7fe..933c0b63b016 100644
--- a/drivers/mtd/maps/redwood.c
+++ b/drivers/mtd/maps/redwood.c
@@ -122,7 +122,7 @@ struct map_info redwood_flash_map = {
122 122
123static struct mtd_info *redwood_mtd; 123static struct mtd_info *redwood_mtd;
124 124
125int __init init_redwood_flash(void) 125static int __init init_redwood_flash(void)
126{ 126{
127 int err; 127 int err;
128 128
diff --git a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c
index 14d90edb4430..3e3ef53d4fd4 100644
--- a/drivers/mtd/maps/rpxlite.c
+++ b/drivers/mtd/maps/rpxlite.c
@@ -23,7 +23,7 @@ static struct map_info rpxlite_map = {
23 .phys = WINDOW_ADDR, 23 .phys = WINDOW_ADDR,
24}; 24};
25 25
26int __init init_rpxlite(void) 26static int __init init_rpxlite(void)
27{ 27{
28 printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); 28 printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
29 rpxlite_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); 29 rpxlite_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c
index 6e1e99cd2b59..d5374cdcb163 100644
--- a/drivers/mtd/maps/sbc8240.c
+++ b/drivers/mtd/maps/sbc8240.c
@@ -136,7 +136,7 @@ static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS];
136#endif /* CONFIG_MTD_PARTITIONS */ 136#endif /* CONFIG_MTD_PARTITIONS */
137 137
138 138
139int __init init_sbc8240_mtd (void) 139static int __init init_sbc8240_mtd (void)
140{ 140{
141 static struct _cjs { 141 static struct _cjs {
142 u_long addr; 142 u_long addr;
diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c
index 21169e6d646c..7e329f09a548 100644
--- a/drivers/mtd/maps/scb2_flash.c
+++ b/drivers/mtd/maps/scb2_flash.c
@@ -118,7 +118,8 @@ scb2_fixup_mtd(struct mtd_info *mtd)
118 struct mtd_erase_region_info *region = &mtd->eraseregions[i]; 118 struct mtd_erase_region_info *region = &mtd->eraseregions[i];
119 119
120 if (region->numblocks * region->erasesize > mtd->size) { 120 if (region->numblocks * region->erasesize > mtd->size) {
121 region->numblocks = (mtd->size / region->erasesize); 121 region->numblocks = ((unsigned long)mtd->size /
122 region->erasesize);
122 done = 1; 123 done = 1;
123 } else { 124 } else {
124 region->numblocks = 0; 125 region->numblocks = 0;
@@ -187,8 +188,9 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent)
187 return -ENODEV; 188 return -ENODEV;
188 } 189 }
189 190
190 printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n", 191 printk(KERN_NOTICE MODNAME ": chip size 0x%llx at offset 0x%llx\n",
191 scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size); 192 (unsigned long long)scb2_mtd->size,
193 (unsigned long long)(SCB2_WINDOW - scb2_mtd->size));
192 194
193 add_mtd_device(scb2_mtd); 195 add_mtd_device(scb2_mtd);
194 196
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c
index 026eab028189..b392f096c706 100644
--- a/drivers/mtd/maps/sharpsl-flash.c
+++ b/drivers/mtd/maps/sharpsl-flash.c
@@ -47,7 +47,7 @@ static struct mtd_partition sharpsl_partitions[1] = {
47 } 47 }
48}; 48};
49 49
50int __init init_sharpsl(void) 50static int __init init_sharpsl(void)
51{ 51{
52 struct mtd_partition *parts; 52 struct mtd_partition *parts;
53 int nb_parts = 0; 53 int nb_parts = 0;
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c
index a5d3d8531faa..60146984f4be 100644
--- a/drivers/mtd/maps/tqm8xxl.c
+++ b/drivers/mtd/maps/tqm8xxl.c
@@ -109,7 +109,7 @@ static struct mtd_partition tqm8xxl_fs_partitions[] = {
109}; 109};
110#endif 110#endif
111 111
112int __init init_tqm_mtd(void) 112static int __init init_tqm_mtd(void)
113{ 113{
114 int idx = 0, ret = 0; 114 int idx = 0, ret = 0;
115 unsigned long flash_addr, flash_size, mtd_size = 0; 115 unsigned long flash_addr, flash_size, mtd_size = 0;
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index 0dc645f8152f..81756e397711 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -51,7 +51,7 @@ int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
51 51
52/****************************************************************************/ 52/****************************************************************************/
53 53
54int __init uclinux_mtd_init(void) 54static int __init uclinux_mtd_init(void)
55{ 55{
56 struct mtd_info *mtd; 56 struct mtd_info *mtd;
57 struct map_info *mapp; 57 struct map_info *mapp;
@@ -94,7 +94,7 @@ int __init uclinux_mtd_init(void)
94 94
95/****************************************************************************/ 95/****************************************************************************/
96 96
97void __exit uclinux_mtd_cleanup(void) 97static void __exit uclinux_mtd_cleanup(void)
98{ 98{
99 if (uclinux_ram_mtdinfo) { 99 if (uclinux_ram_mtdinfo) {
100 del_mtd_partitions(uclinux_ram_mtdinfo); 100 del_mtd_partitions(uclinux_ram_mtdinfo);
diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c
index 5a0c9a353b0f..6d452dcdfe34 100644
--- a/drivers/mtd/maps/vmax301.c
+++ b/drivers/mtd/maps/vmax301.c
@@ -146,7 +146,7 @@ static void __exit cleanup_vmax301(void)
146 iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START); 146 iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
147} 147}
148 148
149int __init init_vmax301(void) 149static int __init init_vmax301(void)
150{ 150{
151 int i; 151 int i;
152 unsigned long iomapadr; 152 unsigned long iomapadr;
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c
index 413b0cf9bbd2..933a2b6598b4 100644
--- a/drivers/mtd/maps/wr_sbc82xx_flash.c
+++ b/drivers/mtd/maps/wr_sbc82xx_flash.c
@@ -74,7 +74,7 @@ do { \
74 } \ 74 } \
75} while (0); 75} while (0);
76 76
77int __init init_sbc82xx_flash(void) 77static int __init init_sbc82xx_flash(void)
78{ 78{
79 volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl; 79 volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
80 int bigflash; 80 int bigflash;
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index bcffeda2df3d..e9ec59e9a566 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -450,16 +450,20 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
450 if (!erase) 450 if (!erase)
451 ret = -ENOMEM; 451 ret = -ENOMEM;
452 else { 452 else {
453 struct erase_info_user einfo;
454
453 wait_queue_head_t waitq; 455 wait_queue_head_t waitq;
454 DECLARE_WAITQUEUE(wait, current); 456 DECLARE_WAITQUEUE(wait, current);
455 457
456 init_waitqueue_head(&waitq); 458 init_waitqueue_head(&waitq);
457 459
458 if (copy_from_user(&erase->addr, argp, 460 if (copy_from_user(&einfo, argp,
459 sizeof(struct erase_info_user))) { 461 sizeof(struct erase_info_user))) {
460 kfree(erase); 462 kfree(erase);
461 return -EFAULT; 463 return -EFAULT;
462 } 464 }
465 erase->addr = einfo.start;
466 erase->len = einfo.length;
463 erase->mtd = mtd; 467 erase->mtd = mtd;
464 erase->callback = mtdchar_erase_callback; 468 erase->callback = mtdchar_erase_callback;
465 erase->priv = (unsigned long)&waitq; 469 erase->priv = (unsigned long)&waitq;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 1a05cf37851e..3dbb1b38db66 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -197,7 +197,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
197 continue; 197 continue;
198 } 198 }
199 199
200 size = min(total_len, (size_t)(subdev->size - to)); 200 size = min_t(uint64_t, total_len, subdev->size - to);
201 wsize = size; /* store for future use */ 201 wsize = size; /* store for future use */
202 202
203 entry_high = entry_low; 203 entry_high = entry_low;
@@ -385,7 +385,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
385 struct mtd_concat *concat = CONCAT(mtd); 385 struct mtd_concat *concat = CONCAT(mtd);
386 struct mtd_info *subdev; 386 struct mtd_info *subdev;
387 int i, err; 387 int i, err;
388 u_int32_t length, offset = 0; 388 uint64_t length, offset = 0;
389 struct erase_info *erase; 389 struct erase_info *erase;
390 390
391 if (!(mtd->flags & MTD_WRITEABLE)) 391 if (!(mtd->flags & MTD_WRITEABLE))
@@ -518,7 +518,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
518 return 0; 518 return 0;
519} 519}
520 520
521static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) 521static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
522{ 522{
523 struct mtd_concat *concat = CONCAT(mtd); 523 struct mtd_concat *concat = CONCAT(mtd);
524 int i, err = -EINVAL; 524 int i, err = -EINVAL;
@@ -528,7 +528,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
528 528
529 for (i = 0; i < concat->num_subdev; i++) { 529 for (i = 0; i < concat->num_subdev; i++) {
530 struct mtd_info *subdev = concat->subdev[i]; 530 struct mtd_info *subdev = concat->subdev[i];
531 size_t size; 531 uint64_t size;
532 532
533 if (ofs >= subdev->size) { 533 if (ofs >= subdev->size) {
534 size = 0; 534 size = 0;
@@ -556,7 +556,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
556 return err; 556 return err;
557} 557}
558 558
559static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 559static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
560{ 560{
561 struct mtd_concat *concat = CONCAT(mtd); 561 struct mtd_concat *concat = CONCAT(mtd);
562 int i, err = 0; 562 int i, err = 0;
@@ -566,7 +566,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
566 566
567 for (i = 0; i < concat->num_subdev; i++) { 567 for (i = 0; i < concat->num_subdev; i++) {
568 struct mtd_info *subdev = concat->subdev[i]; 568 struct mtd_info *subdev = concat->subdev[i];
569 size_t size; 569 uint64_t size;
570 570
571 if (ofs >= subdev->size) { 571 if (ofs >= subdev->size) {
572 size = 0; 572 size = 0;
@@ -696,7 +696,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
696 int i; 696 int i;
697 size_t size; 697 size_t size;
698 struct mtd_concat *concat; 698 struct mtd_concat *concat;
699 u_int32_t max_erasesize, curr_erasesize; 699 uint32_t max_erasesize, curr_erasesize;
700 int num_erase_region; 700 int num_erase_region;
701 701
702 printk(KERN_NOTICE "Concatenating MTD devices:\n"); 702 printk(KERN_NOTICE "Concatenating MTD devices:\n");
@@ -842,12 +842,14 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
842 concat->mtd.erasesize = curr_erasesize; 842 concat->mtd.erasesize = curr_erasesize;
843 concat->mtd.numeraseregions = 0; 843 concat->mtd.numeraseregions = 0;
844 } else { 844 } else {
845 uint64_t tmp64;
846
845 /* 847 /*
846 * erase block size varies across the subdevices: allocate 848 * erase block size varies across the subdevices: allocate
847 * space to store the data describing the variable erase regions 849 * space to store the data describing the variable erase regions
848 */ 850 */
849 struct mtd_erase_region_info *erase_region_p; 851 struct mtd_erase_region_info *erase_region_p;
850 u_int32_t begin, position; 852 uint64_t begin, position;
851 853
852 concat->mtd.erasesize = max_erasesize; 854 concat->mtd.erasesize = max_erasesize;
853 concat->mtd.numeraseregions = num_erase_region; 855 concat->mtd.numeraseregions = num_erase_region;
@@ -879,8 +881,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
879 erase_region_p->offset = begin; 881 erase_region_p->offset = begin;
880 erase_region_p->erasesize = 882 erase_region_p->erasesize =
881 curr_erasesize; 883 curr_erasesize;
882 erase_region_p->numblocks = 884 tmp64 = position - begin;
883 (position - begin) / curr_erasesize; 885 do_div(tmp64, curr_erasesize);
886 erase_region_p->numblocks = tmp64;
884 begin = position; 887 begin = position;
885 888
886 curr_erasesize = subdev[i]->erasesize; 889 curr_erasesize = subdev[i]->erasesize;
@@ -897,9 +900,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
897 erase_region_p->offset = begin; 900 erase_region_p->offset = begin;
898 erase_region_p->erasesize = 901 erase_region_p->erasesize =
899 curr_erasesize; 902 curr_erasesize;
900 erase_region_p->numblocks = 903 tmp64 = position - begin;
901 (position - 904 do_div(tmp64, curr_erasesize);
902 begin) / curr_erasesize; 905 erase_region_p->numblocks = tmp64;
903 begin = position; 906 begin = position;
904 907
905 curr_erasesize = 908 curr_erasesize =
@@ -909,14 +912,16 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
909 } 912 }
910 position += 913 position +=
911 subdev[i]->eraseregions[j]. 914 subdev[i]->eraseregions[j].
912 numblocks * curr_erasesize; 915 numblocks * (uint64_t)curr_erasesize;
913 } 916 }
914 } 917 }
915 } 918 }
916 /* Now write the final entry */ 919 /* Now write the final entry */
917 erase_region_p->offset = begin; 920 erase_region_p->offset = begin;
918 erase_region_p->erasesize = curr_erasesize; 921 erase_region_p->erasesize = curr_erasesize;
919 erase_region_p->numblocks = (position - begin) / curr_erasesize; 922 tmp64 = position - begin;
923 do_div(tmp64, curr_erasesize);
924 erase_region_p->numblocks = tmp64;
920 } 925 }
921 926
922 return &concat->mtd; 927 return &concat->mtd;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index a9d246949820..76fe0a1e7a5e 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -57,6 +57,19 @@ int add_mtd_device(struct mtd_info *mtd)
57 mtd->index = i; 57 mtd->index = i;
58 mtd->usecount = 0; 58 mtd->usecount = 0;
59 59
60 if (is_power_of_2(mtd->erasesize))
61 mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
62 else
63 mtd->erasesize_shift = 0;
64
65 if (is_power_of_2(mtd->writesize))
66 mtd->writesize_shift = ffs(mtd->writesize) - 1;
67 else
68 mtd->writesize_shift = 0;
69
70 mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
71 mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
72
60 /* Some chips always power up locked. Unlock them now */ 73 /* Some chips always power up locked. Unlock them now */
61 if ((mtd->flags & MTD_WRITEABLE) 74 if ((mtd->flags & MTD_WRITEABLE)
62 && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) { 75 && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
@@ -344,7 +357,8 @@ static inline int mtd_proc_info (char *buf, int i)
344 if (!this) 357 if (!this)
345 return 0; 358 return 0;
346 359
347 return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size, 360 return sprintf(buf, "mtd%d: %8.8llx %8.8x \"%s\"\n", i,
361 (unsigned long long)this->size,
348 this->erasesize, this->name); 362 this->erasesize, this->name);
349} 363}
350 364
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index aebb3b27edbd..1a6b3beabe8d 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -80,9 +80,9 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
80 if (ret) { 80 if (ret) {
81 set_current_state(TASK_RUNNING); 81 set_current_state(TASK_RUNNING);
82 remove_wait_queue(&wait_q, &wait); 82 remove_wait_queue(&wait_q, &wait);
83 printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] " 83 printk (KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] "
84 "on \"%s\" failed\n", 84 "on \"%s\" failed\n",
85 erase.addr, erase.len, mtd->name); 85 (unsigned long long)erase.addr, (unsigned long long)erase.len, mtd->name);
86 return ret; 86 return ret;
87 } 87 }
88 88
@@ -289,7 +289,10 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
289 } 289 }
290 290
291 cxt->mtd = mtd; 291 cxt->mtd = mtd;
292 cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE; 292 if (mtd->size > INT_MAX)
293 cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE;
294 else
295 cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE;
293 296
294 find_next_position(cxt); 297 find_next_position(cxt);
295 298
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 3728913fa5fa..144e6b613a77 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -26,7 +26,7 @@ static LIST_HEAD(mtd_partitions);
26struct mtd_part { 26struct mtd_part {
27 struct mtd_info mtd; 27 struct mtd_info mtd;
28 struct mtd_info *master; 28 struct mtd_info *master;
29 u_int32_t offset; 29 uint64_t offset;
30 int index; 30 int index;
31 struct list_head list; 31 struct list_head list;
32 int registered; 32 int registered;
@@ -235,7 +235,7 @@ void mtd_erase_callback(struct erase_info *instr)
235} 235}
236EXPORT_SYMBOL_GPL(mtd_erase_callback); 236EXPORT_SYMBOL_GPL(mtd_erase_callback);
237 237
238static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) 238static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
239{ 239{
240 struct mtd_part *part = PART(mtd); 240 struct mtd_part *part = PART(mtd);
241 if ((len + ofs) > mtd->size) 241 if ((len + ofs) > mtd->size)
@@ -243,7 +243,7 @@ static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
243 return part->master->lock(part->master, ofs + part->offset, len); 243 return part->master->lock(part->master, ofs + part->offset, len);
244} 244}
245 245
246static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 246static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
247{ 247{
248 struct mtd_part *part = PART(mtd); 248 struct mtd_part *part = PART(mtd);
249 if ((len + ofs) > mtd->size) 249 if ((len + ofs) > mtd->size)
@@ -317,7 +317,7 @@ EXPORT_SYMBOL(del_mtd_partitions);
317 317
318static struct mtd_part *add_one_partition(struct mtd_info *master, 318static struct mtd_part *add_one_partition(struct mtd_info *master,
319 const struct mtd_partition *part, int partno, 319 const struct mtd_partition *part, int partno,
320 u_int32_t cur_offset) 320 uint64_t cur_offset)
321{ 321{
322 struct mtd_part *slave; 322 struct mtd_part *slave;
323 323
@@ -395,19 +395,19 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
395 slave->offset = cur_offset; 395 slave->offset = cur_offset;
396 if (slave->offset == MTDPART_OFS_NXTBLK) { 396 if (slave->offset == MTDPART_OFS_NXTBLK) {
397 slave->offset = cur_offset; 397 slave->offset = cur_offset;
398 if ((cur_offset % master->erasesize) != 0) { 398 if (mtd_mod_by_eb(cur_offset, master) != 0) {
399 /* Round up to next erasesize */ 399 /* Round up to next erasesize */
400 slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; 400 slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
401 printk(KERN_NOTICE "Moving partition %d: " 401 printk(KERN_NOTICE "Moving partition %d: "
402 "0x%08x -> 0x%08x\n", partno, 402 "0x%012llx -> 0x%012llx\n", partno,
403 cur_offset, slave->offset); 403 (unsigned long long)cur_offset, (unsigned long long)slave->offset);
404 } 404 }
405 } 405 }
406 if (slave->mtd.size == MTDPART_SIZ_FULL) 406 if (slave->mtd.size == MTDPART_SIZ_FULL)
407 slave->mtd.size = master->size - slave->offset; 407 slave->mtd.size = master->size - slave->offset;
408 408
409 printk(KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, 409 printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
410 slave->offset + slave->mtd.size, slave->mtd.name); 410 (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name);
411 411
412 /* let's do some sanity checks */ 412 /* let's do some sanity checks */
413 if (slave->offset >= master->size) { 413 if (slave->offset >= master->size) {
@@ -420,13 +420,13 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
420 } 420 }
421 if (slave->offset + slave->mtd.size > master->size) { 421 if (slave->offset + slave->mtd.size > master->size) {
422 slave->mtd.size = master->size - slave->offset; 422 slave->mtd.size = master->size - slave->offset;
423 printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", 423 printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
424 part->name, master->name, slave->mtd.size); 424 part->name, master->name, (unsigned long long)slave->mtd.size);
425 } 425 }
426 if (master->numeraseregions > 1) { 426 if (master->numeraseregions > 1) {
427 /* Deal with variable erase size stuff */ 427 /* Deal with variable erase size stuff */
428 int i, max = master->numeraseregions; 428 int i, max = master->numeraseregions;
429 u32 end = slave->offset + slave->mtd.size; 429 u64 end = slave->offset + slave->mtd.size;
430 struct mtd_erase_region_info *regions = master->eraseregions; 430 struct mtd_erase_region_info *regions = master->eraseregions;
431 431
432 /* Find the first erase regions which is part of this 432 /* Find the first erase regions which is part of this
@@ -449,7 +449,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
449 } 449 }
450 450
451 if ((slave->mtd.flags & MTD_WRITEABLE) && 451 if ((slave->mtd.flags & MTD_WRITEABLE) &&
452 (slave->offset % slave->mtd.erasesize)) { 452 mtd_mod_by_eb(slave->offset, &slave->mtd)) {
453 /* Doesn't start on a boundary of major erase size */ 453 /* Doesn't start on a boundary of major erase size */
454 /* FIXME: Let it be writable if it is on a boundary of 454 /* FIXME: Let it be writable if it is on a boundary of
455 * _minor_ erase size though */ 455 * _minor_ erase size though */
@@ -458,7 +458,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
458 part->name); 458 part->name);
459 } 459 }
460 if ((slave->mtd.flags & MTD_WRITEABLE) && 460 if ((slave->mtd.flags & MTD_WRITEABLE) &&
461 (slave->mtd.size % slave->mtd.erasesize)) { 461 mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
462 slave->mtd.flags &= ~MTD_WRITEABLE; 462 slave->mtd.flags &= ~MTD_WRITEABLE;
463 printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", 463 printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
464 part->name); 464 part->name);
@@ -466,7 +466,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master,
466 466
467 slave->mtd.ecclayout = master->ecclayout; 467 slave->mtd.ecclayout = master->ecclayout;
468 if (master->block_isbad) { 468 if (master->block_isbad) {
469 uint32_t offs = 0; 469 uint64_t offs = 0;
470 470
471 while (offs < slave->mtd.size) { 471 while (offs < slave->mtd.size) {
472 if (master->block_isbad(master, 472 if (master->block_isbad(master,
@@ -501,7 +501,7 @@ int add_mtd_partitions(struct mtd_info *master,
501 int nbparts) 501 int nbparts)
502{ 502{
503 struct mtd_part *slave; 503 struct mtd_part *slave;
504 u_int32_t cur_offset = 0; 504 uint64_t cur_offset = 0;
505 int i; 505 int i;
506 506
507 printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); 507 printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f8ae0400c49c..8b12e6e109d3 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -163,6 +163,13 @@ config MTD_NAND_S3C2410_HWECC
163 incorrect ECC generation, and if using these, the default of 163 incorrect ECC generation, and if using these, the default of
164 software ECC is preferable. 164 software ECC is preferable.
165 165
166config MTD_NAND_NDFC
167 tristate "NDFC NanD Flash Controller"
168 depends on 4xx
169 select MTD_NAND_ECC_SMC
170 help
171 NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
172
166config MTD_NAND_S3C2410_CLKSTOP 173config MTD_NAND_S3C2410_CLKSTOP
167 bool "S3C2410 NAND IDLE clock stop" 174 bool "S3C2410 NAND IDLE clock stop"
168 depends on MTD_NAND_S3C2410 175 depends on MTD_NAND_S3C2410
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
index 962380394855..6d9649159a18 100644
--- a/drivers/mtd/nand/alauda.c
+++ b/drivers/mtd/nand/alauda.c
@@ -676,11 +676,11 @@ static int alauda_probe(struct usb_interface *interface,
676 goto error; 676 goto error;
677 677
678 al->write_out = usb_sndbulkpipe(al->dev, 678 al->write_out = usb_sndbulkpipe(al->dev,
679 ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 679 usb_endpoint_num(ep_wr));
680 al->bulk_in = usb_rcvbulkpipe(al->dev, 680 al->bulk_in = usb_rcvbulkpipe(al->dev,
681 ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 681 usb_endpoint_num(ep_in));
682 al->bulk_out = usb_sndbulkpipe(al->dev, 682 al->bulk_out = usb_sndbulkpipe(al->dev,
683 ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); 683 usb_endpoint_num(ep_out));
684 684
685 /* second device is identical up to now */ 685 /* second device is identical up to now */
686 memcpy(al+1, al, sizeof(*al)); 686 memcpy(al+1, al, sizeof(*al));
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index b8064bf3aee4..22a6b2e50e91 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -90,7 +90,7 @@ static int timing[3];
90module_param_array(timing, int, &numtimings, 0644); 90module_param_array(timing, int, &numtimings, 0644);
91 91
92#ifdef CONFIG_MTD_PARTITIONS 92#ifdef CONFIG_MTD_PARTITIONS
93static const char *part_probes[] = { "RedBoot", NULL }; 93static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
94#endif 94#endif
95 95
96/* Hrm. Why isn't this already conditional on something in the struct device? */ 96/* Hrm. Why isn't this already conditional on something in the struct device? */
@@ -805,10 +805,13 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
805 add_mtd_device(mtd); 805 add_mtd_device(mtd);
806 806
807#ifdef CONFIG_MTD_PARTITIONS 807#ifdef CONFIG_MTD_PARTITIONS
808#ifdef CONFIG_MTD_CMDLINE_PARTS
809 mtd->name = "cafe_nand";
810#endif
808 nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); 811 nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
809 if (nr_parts > 0) { 812 if (nr_parts > 0) {
810 cafe->parts = parts; 813 cafe->parts = parts;
811 dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts); 814 dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts);
812 add_mtd_partitions(mtd, parts, nr_parts); 815 add_mtd_partitions(mtd, parts, nr_parts);
813 } 816 }
814#endif 817#endif
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 4aa5bd6158da..65929db29446 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -777,7 +777,9 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
777 /* Fill in fsl_elbc_mtd structure */ 777 /* Fill in fsl_elbc_mtd structure */
778 priv->mtd.priv = chip; 778 priv->mtd.priv = chip;
779 priv->mtd.owner = THIS_MODULE; 779 priv->mtd.owner = THIS_MODULE;
780 priv->fmr = 0; /* rest filled in later */ 780
781 /* Set the ECCM according to the settings in bootloader.*/
782 priv->fmr = in_be32(&lbc->fmr) & FMR_ECCM;
781 783
782 /* fill in nand_chip structure */ 784 /* fill in nand_chip structure */
783 /* set up function call table */ 785 /* set up function call table */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 0a9c9cd33f96..0c3afccde8a2 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2014,13 +2014,14 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
2014int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, 2014int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
2015 int allowbbt) 2015 int allowbbt)
2016{ 2016{
2017 int page, len, status, pages_per_block, ret, chipnr; 2017 int page, status, pages_per_block, ret, chipnr;
2018 struct nand_chip *chip = mtd->priv; 2018 struct nand_chip *chip = mtd->priv;
2019 int rewrite_bbt[NAND_MAX_CHIPS]={0}; 2019 loff_t rewrite_bbt[NAND_MAX_CHIPS]={0};
2020 unsigned int bbt_masked_page = 0xffffffff; 2020 unsigned int bbt_masked_page = 0xffffffff;
2021 loff_t len;
2021 2022
2022 DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", 2023 DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, len = %llu\n",
2023 (unsigned int)instr->addr, (unsigned int)instr->len); 2024 (unsigned long long)instr->addr, (unsigned long long)instr->len);
2024 2025
2025 /* Start address must align on block boundary */ 2026 /* Start address must align on block boundary */
2026 if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { 2027 if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
@@ -2116,7 +2117,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
2116 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " 2117 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
2117 "Failed erase, page 0x%08x\n", page); 2118 "Failed erase, page 0x%08x\n", page);
2118 instr->state = MTD_ERASE_FAILED; 2119 instr->state = MTD_ERASE_FAILED;
2119 instr->fail_addr = (page << chip->page_shift); 2120 instr->fail_addr =
2121 ((loff_t)page << chip->page_shift);
2120 goto erase_exit; 2122 goto erase_exit;
2121 } 2123 }
2122 2124
@@ -2126,7 +2128,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
2126 */ 2128 */
2127 if (bbt_masked_page != 0xffffffff && 2129 if (bbt_masked_page != 0xffffffff &&
2128 (page & BBT_PAGE_MASK) == bbt_masked_page) 2130 (page & BBT_PAGE_MASK) == bbt_masked_page)
2129 rewrite_bbt[chipnr] = (page << chip->page_shift); 2131 rewrite_bbt[chipnr] =
2132 ((loff_t)page << chip->page_shift);
2130 2133
2131 /* Increment page address and decrement length */ 2134 /* Increment page address and decrement length */
2132 len -= (1 << chip->phys_erase_shift); 2135 len -= (1 << chip->phys_erase_shift);
@@ -2173,7 +2176,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
2173 continue; 2176 continue;
2174 /* update the BBT for chip */ 2177 /* update the BBT for chip */
2175 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " 2178 DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
2176 "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr], 2179 "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
2177 chip->bbt_td->pages[chipnr]); 2180 chip->bbt_td->pages[chipnr]);
2178 nand_update_bbt(mtd, rewrite_bbt[chipnr]); 2181 nand_update_bbt(mtd, rewrite_bbt[chipnr]);
2179 } 2182 }
@@ -2365,7 +2368,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2365 if (!mtd->name) 2368 if (!mtd->name)
2366 mtd->name = type->name; 2369 mtd->name = type->name;
2367 2370
2368 chip->chipsize = type->chipsize << 20; 2371 chip->chipsize = (uint64_t)type->chipsize << 20;
2369 2372
2370 /* Newer devices have all the information in additional id bytes */ 2373 /* Newer devices have all the information in additional id bytes */
2371 if (!type->pagesize) { 2374 if (!type->pagesize) {
@@ -2423,7 +2426,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
2423 2426
2424 chip->bbt_erase_shift = chip->phys_erase_shift = 2427 chip->bbt_erase_shift = chip->phys_erase_shift =
2425 ffs(mtd->erasesize) - 1; 2428 ffs(mtd->erasesize) - 1;
2426 chip->chip_shift = ffs(chip->chipsize) - 1; 2429 if (chip->chipsize & 0xffffffff)
2430 chip->chip_shift = ffs((unsigned)chip->chipsize) - 1;
2431 else
2432 chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1;
2427 2433
2428 /* Set the bad block position */ 2434 /* Set the bad block position */
2429 chip->badblockpos = mtd->writesize > 512 ? 2435 chip->badblockpos = mtd->writesize > 512 ?
@@ -2517,7 +2523,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
2517/** 2523/**
2518 * nand_scan_tail - [NAND Interface] Scan for the NAND device 2524 * nand_scan_tail - [NAND Interface] Scan for the NAND device
2519 * @mtd: MTD device structure 2525 * @mtd: MTD device structure
2520 * @maxchips: Number of chips to scan for
2521 * 2526 *
2522 * This is the second phase of the normal nand_scan() function. It 2527 * This is the second phase of the normal nand_scan() function. It
2523 * fills out all the uninitialized function pointers with the defaults 2528 * fills out all the uninitialized function pointers with the defaults
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 0b1c48595f12..55c23e5cd210 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -171,16 +171,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
171 if (tmp == msk) 171 if (tmp == msk)
172 continue; 172 continue;
173 if (reserved_block_code && (tmp == reserved_block_code)) { 173 if (reserved_block_code && (tmp == reserved_block_code)) {
174 printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", 174 printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n",
175 ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); 175 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
176 this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); 176 this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
177 mtd->ecc_stats.bbtblocks++; 177 mtd->ecc_stats.bbtblocks++;
178 continue; 178 continue;
179 } 179 }
180 /* Leave it for now, if its matured we can move this 180 /* Leave it for now, if its matured we can move this
181 * message to MTD_DEBUG_LEVEL0 */ 181 * message to MTD_DEBUG_LEVEL0 */
182 printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", 182 printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n",
183 ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); 183 (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
184 /* Factory marked bad or worn out ? */ 184 /* Factory marked bad or worn out ? */
185 if (tmp == 0) 185 if (tmp == 0)
186 this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); 186 this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
@@ -284,7 +284,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
284 284
285 /* Read the primary version, if available */ 285 /* Read the primary version, if available */
286 if (td->options & NAND_BBT_VERSION) { 286 if (td->options & NAND_BBT_VERSION) {
287 scan_read_raw(mtd, buf, td->pages[0] << this->page_shift, 287 scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
288 mtd->writesize); 288 mtd->writesize);
289 td->version[0] = buf[mtd->writesize + td->veroffs]; 289 td->version[0] = buf[mtd->writesize + td->veroffs];
290 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", 290 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
@@ -293,7 +293,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
293 293
294 /* Read the mirror version, if available */ 294 /* Read the mirror version, if available */
295 if (md && (md->options & NAND_BBT_VERSION)) { 295 if (md && (md->options & NAND_BBT_VERSION)) {
296 scan_read_raw(mtd, buf, md->pages[0] << this->page_shift, 296 scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
297 mtd->writesize); 297 mtd->writesize);
298 md->version[0] = buf[mtd->writesize + md->veroffs]; 298 md->version[0] = buf[mtd->writesize + md->veroffs];
299 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", 299 printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",
@@ -411,7 +411,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
411 numblocks = this->chipsize >> (this->bbt_erase_shift - 1); 411 numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
412 startblock = chip * numblocks; 412 startblock = chip * numblocks;
413 numblocks += startblock; 413 numblocks += startblock;
414 from = startblock << (this->bbt_erase_shift - 1); 414 from = (loff_t)startblock << (this->bbt_erase_shift - 1);
415 } 415 }
416 416
417 for (i = startblock; i < numblocks;) { 417 for (i = startblock; i < numblocks;) {
@@ -428,8 +428,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
428 428
429 if (ret) { 429 if (ret) {
430 this->bbt[i >> 3] |= 0x03 << (i & 0x6); 430 this->bbt[i >> 3] |= 0x03 << (i & 0x6);
431 printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 431 printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n",
432 i >> 1, (unsigned int)from); 432 i >> 1, (unsigned long long)from);
433 mtd->ecc_stats.badblocks++; 433 mtd->ecc_stats.badblocks++;
434 } 434 }
435 435
@@ -495,7 +495,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
495 for (block = 0; block < td->maxblocks; block++) { 495 for (block = 0; block < td->maxblocks; block++) {
496 496
497 int actblock = startblock + dir * block; 497 int actblock = startblock + dir * block;
498 loff_t offs = actblock << this->bbt_erase_shift; 498 loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
499 499
500 /* Read first page */ 500 /* Read first page */
501 scan_read_raw(mtd, buf, offs, mtd->writesize); 501 scan_read_raw(mtd, buf, offs, mtd->writesize);
@@ -719,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
719 719
720 memset(&einfo, 0, sizeof(einfo)); 720 memset(&einfo, 0, sizeof(einfo));
721 einfo.mtd = mtd; 721 einfo.mtd = mtd;
722 einfo.addr = (unsigned long)to; 722 einfo.addr = to;
723 einfo.len = 1 << this->bbt_erase_shift; 723 einfo.len = 1 << this->bbt_erase_shift;
724 res = nand_erase_nand(mtd, &einfo, 1); 724 res = nand_erase_nand(mtd, &einfo, 1);
725 if (res < 0) 725 if (res < 0)
@@ -729,8 +729,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
729 if (res < 0) 729 if (res < 0)
730 goto outerr; 730 goto outerr;
731 731
732 printk(KERN_DEBUG "Bad block table written to 0x%08x, version " 732 printk(KERN_DEBUG "Bad block table written to 0x%012llx, version "
733 "0x%02X\n", (unsigned int)to, td->version[chip]); 733 "0x%02X\n", (unsigned long long)to, td->version[chip]);
734 734
735 /* Mark it as used */ 735 /* Mark it as used */
736 td->pages[chip] = page; 736 td->pages[chip] = page;
@@ -910,7 +910,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
910 newval = oldval | (0x2 << (block & 0x06)); 910 newval = oldval | (0x2 << (block & 0x06));
911 this->bbt[(block >> 3)] = newval; 911 this->bbt[(block >> 3)] = newval;
912 if ((oldval != newval) && td->reserved_block_code) 912 if ((oldval != newval) && td->reserved_block_code)
913 nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1)); 913 nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
914 continue; 914 continue;
915 } 915 }
916 update = 0; 916 update = 0;
@@ -931,7 +931,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
931 new ones have been marked, then we need to update the stored 931 new ones have been marked, then we need to update the stored
932 bbts. This should only happen once. */ 932 bbts. This should only happen once. */
933 if (update && td->reserved_block_code) 933 if (update && td->reserved_block_code)
934 nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1)); 934 nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
935 } 935 }
936} 936}
937 937
@@ -1027,7 +1027,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
1027 if (!this->bbt || !td) 1027 if (!this->bbt || !td)
1028 return -EINVAL; 1028 return -EINVAL;
1029 1029
1030 len = mtd->size >> (this->bbt_erase_shift + 2);
1031 /* Allocate a temporary buffer for one eraseblock incl. oob */ 1030 /* Allocate a temporary buffer for one eraseblock incl. oob */
1032 len = (1 << this->bbt_erase_shift); 1031 len = (1 << this->bbt_erase_shift);
1033 len += (len >> this->page_shift) * mtd->oobsize; 1032 len += (len >> this->page_shift) * mtd->oobsize;
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index ae7c57781a68..cd0711b83ac4 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -38,6 +38,9 @@
38#include <linux/delay.h> 38#include <linux/delay.h>
39#include <linux/list.h> 39#include <linux/list.h>
40#include <linux/random.h> 40#include <linux/random.h>
41#include <linux/sched.h>
42#include <linux/fs.h>
43#include <linux/pagemap.h>
41 44
42/* Default simulator parameters values */ 45/* Default simulator parameters values */
43#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ 46#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
@@ -100,6 +103,7 @@ static unsigned int bitflips = 0;
100static char *gravepages = NULL; 103static char *gravepages = NULL;
101static unsigned int rptwear = 0; 104static unsigned int rptwear = 0;
102static unsigned int overridesize = 0; 105static unsigned int overridesize = 0;
106static char *cache_file = NULL;
103 107
104module_param(first_id_byte, uint, 0400); 108module_param(first_id_byte, uint, 0400);
105module_param(second_id_byte, uint, 0400); 109module_param(second_id_byte, uint, 0400);
@@ -122,12 +126,13 @@ module_param(bitflips, uint, 0400);
122module_param(gravepages, charp, 0400); 126module_param(gravepages, charp, 0400);
123module_param(rptwear, uint, 0400); 127module_param(rptwear, uint, 0400);
124module_param(overridesize, uint, 0400); 128module_param(overridesize, uint, 0400);
129module_param(cache_file, charp, 0400);
125 130
126MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); 131MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
127MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); 132MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
128MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); 133MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command");
129MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); 134MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
130MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); 135MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)");
131MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); 136MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
132MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); 137MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)");
133MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); 138MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)");
@@ -153,6 +158,7 @@ MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if
153MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " 158MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. "
154 "The size is specified in erase blocks and as the exponent of a power of two" 159 "The size is specified in erase blocks and as the exponent of a power of two"
155 " e.g. 5 means a size of 32 erase blocks"); 160 " e.g. 5 means a size of 32 erase blocks");
161MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
156 162
157/* The largest possible page size */ 163/* The largest possible page size */
158#define NS_LARGEST_PAGE_SIZE 2048 164#define NS_LARGEST_PAGE_SIZE 2048
@@ -266,6 +272,9 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I
266 */ 272 */
267#define NS_MAX_PREVSTATES 1 273#define NS_MAX_PREVSTATES 1
268 274
275/* Maximum page cache pages needed to read or write a NAND page to the cache_file */
276#define NS_MAX_HELD_PAGES 16
277
269/* 278/*
270 * A union to represent flash memory contents and flash buffer. 279 * A union to represent flash memory contents and flash buffer.
271 */ 280 */
@@ -295,6 +304,9 @@ struct nandsim {
295 /* The simulated NAND flash pages array */ 304 /* The simulated NAND flash pages array */
296 union ns_mem *pages; 305 union ns_mem *pages;
297 306
307 /* Slab allocator for nand pages */
308 struct kmem_cache *nand_pages_slab;
309
298 /* Internal buffer of page + OOB size bytes */ 310 /* Internal buffer of page + OOB size bytes */
299 union ns_mem buf; 311 union ns_mem buf;
300 312
@@ -335,6 +347,13 @@ struct nandsim {
335 int ale; /* address Latch Enable */ 347 int ale; /* address Latch Enable */
336 int wp; /* write Protect */ 348 int wp; /* write Protect */
337 } lines; 349 } lines;
350
351 /* Fields needed when using a cache file */
352 struct file *cfile; /* Open file */
353 unsigned char *pages_written; /* Which pages have been written */
354 void *file_buf;
355 struct page *held_pages[NS_MAX_HELD_PAGES];
356 int held_cnt;
338}; 357};
339 358
340/* 359/*
@@ -420,25 +439,69 @@ static struct mtd_info *nsmtd;
420static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; 439static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
421 440
422/* 441/*
423 * Allocate array of page pointers and initialize the array to NULL 442 * Allocate array of page pointers, create slab allocation for an array
424 * pointers. 443 * and initialize the array by NULL pointers.
425 * 444 *
426 * RETURNS: 0 if success, -ENOMEM if memory alloc fails. 445 * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
427 */ 446 */
428static int alloc_device(struct nandsim *ns) 447static int alloc_device(struct nandsim *ns)
429{ 448{
430 int i; 449 struct file *cfile;
450 int i, err;
451
452 if (cache_file) {
453 cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
454 if (IS_ERR(cfile))
455 return PTR_ERR(cfile);
456 if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) {
457 NS_ERR("alloc_device: cache file not readable\n");
458 err = -EINVAL;
459 goto err_close;
460 }
461 if (!cfile->f_op->write && !cfile->f_op->aio_write) {
462 NS_ERR("alloc_device: cache file not writeable\n");
463 err = -EINVAL;
464 goto err_close;
465 }
466 ns->pages_written = vmalloc(ns->geom.pgnum);
467 if (!ns->pages_written) {
468 NS_ERR("alloc_device: unable to allocate pages written array\n");
469 err = -ENOMEM;
470 goto err_close;
471 }
472 ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
473 if (!ns->file_buf) {
474 NS_ERR("alloc_device: unable to allocate file buf\n");
475 err = -ENOMEM;
476 goto err_free;
477 }
478 ns->cfile = cfile;
479 memset(ns->pages_written, 0, ns->geom.pgnum);
480 return 0;
481 }
431 482
432 ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); 483 ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
433 if (!ns->pages) { 484 if (!ns->pages) {
434 NS_ERR("alloc_map: unable to allocate page array\n"); 485 NS_ERR("alloc_device: unable to allocate page array\n");
435 return -ENOMEM; 486 return -ENOMEM;
436 } 487 }
437 for (i = 0; i < ns->geom.pgnum; i++) { 488 for (i = 0; i < ns->geom.pgnum; i++) {
438 ns->pages[i].byte = NULL; 489 ns->pages[i].byte = NULL;
439 } 490 }
491 ns->nand_pages_slab = kmem_cache_create("nandsim",
492 ns->geom.pgszoob, 0, 0, NULL);
493 if (!ns->nand_pages_slab) {
494 NS_ERR("cache_create: unable to create kmem_cache\n");
495 return -ENOMEM;
496 }
440 497
441 return 0; 498 return 0;
499
500err_free:
501 vfree(ns->pages_written);
502err_close:
503 filp_close(cfile, NULL);
504 return err;
442} 505}
443 506
444/* 507/*
@@ -448,11 +511,20 @@ static void free_device(struct nandsim *ns)
448{ 511{
449 int i; 512 int i;
450 513
514 if (ns->cfile) {
515 kfree(ns->file_buf);
516 vfree(ns->pages_written);
517 filp_close(ns->cfile, NULL);
518 return;
519 }
520
451 if (ns->pages) { 521 if (ns->pages) {
452 for (i = 0; i < ns->geom.pgnum; i++) { 522 for (i = 0; i < ns->geom.pgnum; i++) {
453 if (ns->pages[i].byte) 523 if (ns->pages[i].byte)
454 kfree(ns->pages[i].byte); 524 kmem_cache_free(ns->nand_pages_slab,
525 ns->pages[i].byte);
455 } 526 }
527 kmem_cache_destroy(ns->nand_pages_slab);
456 vfree(ns->pages); 528 vfree(ns->pages);
457 } 529 }
458} 530}
@@ -464,7 +536,7 @@ static char *get_partition_name(int i)
464 return kstrdup(buf, GFP_KERNEL); 536 return kstrdup(buf, GFP_KERNEL);
465} 537}
466 538
467static u_int64_t divide(u_int64_t n, u_int32_t d) 539static uint64_t divide(uint64_t n, uint32_t d)
468{ 540{
469 do_div(n, d); 541 do_div(n, d);
470 return n; 542 return n;
@@ -480,8 +552,8 @@ static int init_nandsim(struct mtd_info *mtd)
480 struct nand_chip *chip = (struct nand_chip *)mtd->priv; 552 struct nand_chip *chip = (struct nand_chip *)mtd->priv;
481 struct nandsim *ns = (struct nandsim *)(chip->priv); 553 struct nandsim *ns = (struct nandsim *)(chip->priv);
482 int i, ret = 0; 554 int i, ret = 0;
483 u_int64_t remains; 555 uint64_t remains;
484 u_int64_t next_offset; 556 uint64_t next_offset;
485 557
486 if (NS_IS_INITIALIZED(ns)) { 558 if (NS_IS_INITIALIZED(ns)) {
487 NS_ERR("init_nandsim: nandsim is already initialized\n"); 559 NS_ERR("init_nandsim: nandsim is already initialized\n");
@@ -548,7 +620,7 @@ static int init_nandsim(struct mtd_info *mtd)
548 remains = ns->geom.totsz; 620 remains = ns->geom.totsz;
549 next_offset = 0; 621 next_offset = 0;
550 for (i = 0; i < parts_num; ++i) { 622 for (i = 0; i < parts_num; ++i) {
551 u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; 623 uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz;
552 624
553 if (!part_sz || part_sz > remains) { 625 if (!part_sz || part_sz > remains) {
554 NS_ERR("bad partition size.\n"); 626 NS_ERR("bad partition size.\n");
@@ -1211,6 +1283,97 @@ static int find_operation(struct nandsim *ns, uint32_t flag)
1211 return -1; 1283 return -1;
1212} 1284}
1213 1285
1286static void put_pages(struct nandsim *ns)
1287{
1288 int i;
1289
1290 for (i = 0; i < ns->held_cnt; i++)
1291 page_cache_release(ns->held_pages[i]);
1292}
1293
1294/* Get page cache pages in advance to provide NOFS memory allocation */
1295static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos)
1296{
1297 pgoff_t index, start_index, end_index;
1298 struct page *page;
1299 struct address_space *mapping = file->f_mapping;
1300
1301 start_index = pos >> PAGE_CACHE_SHIFT;
1302 end_index = (pos + count - 1) >> PAGE_CACHE_SHIFT;
1303 if (end_index - start_index + 1 > NS_MAX_HELD_PAGES)
1304 return -EINVAL;
1305 ns->held_cnt = 0;
1306 for (index = start_index; index <= end_index; index++) {
1307 page = find_get_page(mapping, index);
1308 if (page == NULL) {
1309 page = find_or_create_page(mapping, index, GFP_NOFS);
1310 if (page == NULL) {
1311 write_inode_now(mapping->host, 1);
1312 page = find_or_create_page(mapping, index, GFP_NOFS);
1313 }
1314 if (page == NULL) {
1315 put_pages(ns);
1316 return -ENOMEM;
1317 }
1318 unlock_page(page);
1319 }
1320 ns->held_pages[ns->held_cnt++] = page;
1321 }
1322 return 0;
1323}
1324
1325static int set_memalloc(void)
1326{
1327 if (current->flags & PF_MEMALLOC)
1328 return 0;
1329 current->flags |= PF_MEMALLOC;
1330 return 1;
1331}
1332
1333static void clear_memalloc(int memalloc)
1334{
1335 if (memalloc)
1336 current->flags &= ~PF_MEMALLOC;
1337}
1338
1339static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos)
1340{
1341 mm_segment_t old_fs;
1342 ssize_t tx;
1343 int err, memalloc;
1344
1345 err = get_pages(ns, file, count, *pos);
1346 if (err)
1347 return err;
1348 old_fs = get_fs();
1349 set_fs(get_ds());
1350 memalloc = set_memalloc();
1351 tx = vfs_read(file, (char __user *)buf, count, pos);
1352 clear_memalloc(memalloc);
1353 set_fs(old_fs);
1354 put_pages(ns);
1355 return tx;
1356}
1357
1358static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos)
1359{
1360 mm_segment_t old_fs;
1361 ssize_t tx;
1362 int err, memalloc;
1363
1364 err = get_pages(ns, file, count, *pos);
1365 if (err)
1366 return err;
1367 old_fs = get_fs();
1368 set_fs(get_ds());
1369 memalloc = set_memalloc();
1370 tx = vfs_write(file, (char __user *)buf, count, pos);
1371 clear_memalloc(memalloc);
1372 set_fs(old_fs);
1373 put_pages(ns);
1374 return tx;
1375}
1376
1214/* 1377/*
1215 * Returns a pointer to the current page. 1378 * Returns a pointer to the current page.
1216 */ 1379 */
@@ -1227,6 +1390,38 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
1227 return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; 1390 return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
1228} 1391}
1229 1392
1393int do_read_error(struct nandsim *ns, int num)
1394{
1395 unsigned int page_no = ns->regs.row;
1396
1397 if (read_error(page_no)) {
1398 int i;
1399 memset(ns->buf.byte, 0xFF, num);
1400 for (i = 0; i < num; ++i)
1401 ns->buf.byte[i] = random32();
1402 NS_WARN("simulating read error in page %u\n", page_no);
1403 return 1;
1404 }
1405 return 0;
1406}
1407
1408void do_bit_flips(struct nandsim *ns, int num)
1409{
1410 if (bitflips && random32() < (1 << 22)) {
1411 int flips = 1;
1412 if (bitflips > 1)
1413 flips = (random32() % (int) bitflips) + 1;
1414 while (flips--) {
1415 int pos = random32() % (num * 8);
1416 ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
1417 NS_WARN("read_page: flipping bit %d in page %d "
1418 "reading from %d ecc: corrected=%u failed=%u\n",
1419 pos, ns->regs.row, ns->regs.column + ns->regs.off,
1420 nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
1421 }
1422 }
1423}
1424
1230/* 1425/*
1231 * Fill the NAND buffer with data read from the specified page. 1426 * Fill the NAND buffer with data read from the specified page.
1232 */ 1427 */
@@ -1234,36 +1429,40 @@ static void read_page(struct nandsim *ns, int num)
1234{ 1429{
1235 union ns_mem *mypage; 1430 union ns_mem *mypage;
1236 1431
1432 if (ns->cfile) {
1433 if (!ns->pages_written[ns->regs.row]) {
1434 NS_DBG("read_page: page %d not written\n", ns->regs.row);
1435 memset(ns->buf.byte, 0xFF, num);
1436 } else {
1437 loff_t pos;
1438 ssize_t tx;
1439
1440 NS_DBG("read_page: page %d written, reading from %d\n",
1441 ns->regs.row, ns->regs.column + ns->regs.off);
1442 if (do_read_error(ns, num))
1443 return;
1444 pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
1445 tx = read_file(ns, ns->cfile, ns->buf.byte, num, &pos);
1446 if (tx != num) {
1447 NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
1448 return;
1449 }
1450 do_bit_flips(ns, num);
1451 }
1452 return;
1453 }
1454
1237 mypage = NS_GET_PAGE(ns); 1455 mypage = NS_GET_PAGE(ns);
1238 if (mypage->byte == NULL) { 1456 if (mypage->byte == NULL) {
1239 NS_DBG("read_page: page %d not allocated\n", ns->regs.row); 1457 NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
1240 memset(ns->buf.byte, 0xFF, num); 1458 memset(ns->buf.byte, 0xFF, num);
1241 } else { 1459 } else {
1242 unsigned int page_no = ns->regs.row;
1243 NS_DBG("read_page: page %d allocated, reading from %d\n", 1460 NS_DBG("read_page: page %d allocated, reading from %d\n",
1244 ns->regs.row, ns->regs.column + ns->regs.off); 1461 ns->regs.row, ns->regs.column + ns->regs.off);
1245 if (read_error(page_no)) { 1462 if (do_read_error(ns, num))
1246 int i;
1247 memset(ns->buf.byte, 0xFF, num);
1248 for (i = 0; i < num; ++i)
1249 ns->buf.byte[i] = random32();
1250 NS_WARN("simulating read error in page %u\n", page_no);
1251 return; 1463 return;
1252 }
1253 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); 1464 memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
1254 if (bitflips && random32() < (1 << 22)) { 1465 do_bit_flips(ns, num);
1255 int flips = 1;
1256 if (bitflips > 1)
1257 flips = (random32() % (int) bitflips) + 1;
1258 while (flips--) {
1259 int pos = random32() % (num * 8);
1260 ns->buf.byte[pos / 8] ^= (1 << (pos % 8));
1261 NS_WARN("read_page: flipping bit %d in page %d "
1262 "reading from %d ecc: corrected=%u failed=%u\n",
1263 pos, ns->regs.row, ns->regs.column + ns->regs.off,
1264 nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed);
1265 }
1266 }
1267 } 1466 }
1268} 1467}
1269 1468
@@ -1275,11 +1474,20 @@ static void erase_sector(struct nandsim *ns)
1275 union ns_mem *mypage; 1474 union ns_mem *mypage;
1276 int i; 1475 int i;
1277 1476
1477 if (ns->cfile) {
1478 for (i = 0; i < ns->geom.pgsec; i++)
1479 if (ns->pages_written[ns->regs.row + i]) {
1480 NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
1481 ns->pages_written[ns->regs.row + i] = 0;
1482 }
1483 return;
1484 }
1485
1278 mypage = NS_GET_PAGE(ns); 1486 mypage = NS_GET_PAGE(ns);
1279 for (i = 0; i < ns->geom.pgsec; i++) { 1487 for (i = 0; i < ns->geom.pgsec; i++) {
1280 if (mypage->byte != NULL) { 1488 if (mypage->byte != NULL) {
1281 NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i); 1489 NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
1282 kfree(mypage->byte); 1490 kmem_cache_free(ns->nand_pages_slab, mypage->byte);
1283 mypage->byte = NULL; 1491 mypage->byte = NULL;
1284 } 1492 }
1285 mypage++; 1493 mypage++;
@@ -1295,16 +1503,57 @@ static int prog_page(struct nandsim *ns, int num)
1295 union ns_mem *mypage; 1503 union ns_mem *mypage;
1296 u_char *pg_off; 1504 u_char *pg_off;
1297 1505
1506 if (ns->cfile) {
1507 loff_t off, pos;
1508 ssize_t tx;
1509 int all;
1510
1511 NS_DBG("prog_page: writing page %d\n", ns->regs.row);
1512 pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
1513 off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
1514 if (!ns->pages_written[ns->regs.row]) {
1515 all = 1;
1516 memset(ns->file_buf, 0xff, ns->geom.pgszoob);
1517 } else {
1518 all = 0;
1519 pos = off;
1520 tx = read_file(ns, ns->cfile, pg_off, num, &pos);
1521 if (tx != num) {
1522 NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
1523 return -1;
1524 }
1525 }
1526 for (i = 0; i < num; i++)
1527 pg_off[i] &= ns->buf.byte[i];
1528 if (all) {
1529 pos = (loff_t)ns->regs.row * ns->geom.pgszoob;
1530 tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos);
1531 if (tx != ns->geom.pgszoob) {
1532 NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
1533 return -1;
1534 }
1535 ns->pages_written[ns->regs.row] = 1;
1536 } else {
1537 pos = off;
1538 tx = write_file(ns, ns->cfile, pg_off, num, &pos);
1539 if (tx != num) {
1540 NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
1541 return -1;
1542 }
1543 }
1544 return 0;
1545 }
1546
1298 mypage = NS_GET_PAGE(ns); 1547 mypage = NS_GET_PAGE(ns);
1299 if (mypage->byte == NULL) { 1548 if (mypage->byte == NULL) {
1300 NS_DBG("prog_page: allocating page %d\n", ns->regs.row); 1549 NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
1301 /* 1550 /*
1302 * We allocate memory with GFP_NOFS because a flash FS may 1551 * We allocate memory with GFP_NOFS because a flash FS may
1303 * utilize this. If it is holding an FS lock, then gets here, 1552 * utilize this. If it is holding an FS lock, then gets here,
1304 * then kmalloc runs writeback which goes to the FS again 1553 * then kernel memory alloc runs writeback which goes to the FS
1305 * and deadlocks. This was seen in practice. 1554 * again and deadlocks. This was seen in practice.
1306 */ 1555 */
1307 mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS); 1556 mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS);
1308 if (mypage->byte == NULL) { 1557 if (mypage->byte == NULL) {
1309 NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); 1558 NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
1310 return -1; 1559 return -1;
@@ -1736,13 +1985,17 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
1736 1985
1737 /* Check if chip is expecting command */ 1986 /* Check if chip is expecting command */
1738 if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { 1987 if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
1739 /* 1988 /* Do not warn if only 2 id bytes are read */
1740 * We are in situation when something else (not command) 1989 if (!(ns->regs.command == NAND_CMD_READID &&
1741 * was expected but command was input. In this case ignore 1990 NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) {
1742 * previous command(s)/state(s) and accept the last one. 1991 /*
1743 */ 1992 * We are in situation when something else (not command)
1744 NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " 1993 * was expected but command was input. In this case ignore
1745 "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); 1994 * previous command(s)/state(s) and accept the last one.
1995 */
1996 NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
1997 "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
1998 }
1746 switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); 1999 switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
1747 } 2000 }
1748 2001
@@ -2044,7 +2297,7 @@ static int __init ns_init_module(void)
2044 } 2297 }
2045 2298
2046 if (overridesize) { 2299 if (overridesize) {
2047 u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; 2300 uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
2048 if (new_size >> overridesize != nsmtd->erasesize) { 2301 if (new_size >> overridesize != nsmtd->erasesize) {
2049 NS_ERR("overridesize is too big\n"); 2302 NS_ERR("overridesize is too big\n");
2050 goto err_exit; 2303 goto err_exit;
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 955959eb02d4..582cf80f555a 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -2,12 +2,20 @@
2 * drivers/mtd/ndfc.c 2 * drivers/mtd/ndfc.c
3 * 3 *
4 * Overview: 4 * Overview:
5 * Platform independend driver for NDFC (NanD Flash Controller) 5 * Platform independent driver for NDFC (NanD Flash Controller)
6 * integrated into EP440 cores 6 * integrated into EP440 cores
7 * 7 *
8 * Ported to an OF platform driver by Sean MacLennan
9 *
10 * The NDFC supports multiple chips, but this driver only supports a
11 * single chip since I do not have access to any boards with
12 * multiple chips.
13 *
8 * Author: Thomas Gleixner 14 * Author: Thomas Gleixner
9 * 15 *
10 * Copyright 2006 IBM 16 * Copyright 2006 IBM
17 * Copyright 2008 PIKA Technologies
18 * Sean MacLennan <smaclennan@pikatech.com>
11 * 19 *
12 * This program is free software; you can redistribute it and/or modify it 20 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the 21 * under the terms of the GNU General Public License as published by the
@@ -21,27 +29,20 @@
21#include <linux/mtd/partitions.h> 29#include <linux/mtd/partitions.h>
22#include <linux/mtd/ndfc.h> 30#include <linux/mtd/ndfc.h>
23#include <linux/mtd/mtd.h> 31#include <linux/mtd/mtd.h>
24#include <linux/platform_device.h> 32#include <linux/of_platform.h>
25
26#include <asm/io.h> 33#include <asm/io.h>
27#ifdef CONFIG_40x
28#include <asm/ibm405.h>
29#else
30#include <asm/ibm44x.h>
31#endif
32
33struct ndfc_nand_mtd {
34 struct mtd_info mtd;
35 struct nand_chip chip;
36 struct platform_nand_chip *pl_chip;
37};
38 34
39static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS];
40 35
41struct ndfc_controller { 36struct ndfc_controller {
42 void __iomem *ndfcbase; 37 struct of_device *ofdev;
43 struct nand_hw_control ndfc_control; 38 void __iomem *ndfcbase;
44 atomic_t childs_active; 39 struct mtd_info mtd;
40 struct nand_chip chip;
41 int chip_select;
42 struct nand_hw_control ndfc_control;
43#ifdef CONFIG_MTD_PARTITIONS
44 struct mtd_partition *parts;
45#endif
45}; 46};
46 47
47static struct ndfc_controller ndfc_ctrl; 48static struct ndfc_controller ndfc_ctrl;
@@ -50,17 +51,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
50{ 51{
51 uint32_t ccr; 52 uint32_t ccr;
52 struct ndfc_controller *ndfc = &ndfc_ctrl; 53 struct ndfc_controller *ndfc = &ndfc_ctrl;
53 struct nand_chip *nandchip = mtd->priv;
54 struct ndfc_nand_mtd *nandmtd = nandchip->priv;
55 struct platform_nand_chip *pchip = nandmtd->pl_chip;
56 54
57 ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); 55 ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
58 if (chip >= 0) { 56 if (chip >= 0) {
59 ccr &= ~NDFC_CCR_BS_MASK; 57 ccr &= ~NDFC_CCR_BS_MASK;
60 ccr |= NDFC_CCR_BS(chip + pchip->chip_offset); 58 ccr |= NDFC_CCR_BS(chip + ndfc->chip_select);
61 } else 59 } else
62 ccr |= NDFC_CCR_RESET_CE; 60 ccr |= NDFC_CCR_RESET_CE;
63 __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); 61 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
64} 62}
65 63
66static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) 64static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -80,7 +78,7 @@ static int ndfc_ready(struct mtd_info *mtd)
80{ 78{
81 struct ndfc_controller *ndfc = &ndfc_ctrl; 79 struct ndfc_controller *ndfc = &ndfc_ctrl;
82 80
83 return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; 81 return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY;
84} 82}
85 83
86static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) 84static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -88,9 +86,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode)
88 uint32_t ccr; 86 uint32_t ccr;
89 struct ndfc_controller *ndfc = &ndfc_ctrl; 87 struct ndfc_controller *ndfc = &ndfc_ctrl;
90 88
91 ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); 89 ccr = in_be32(ndfc->ndfcbase + NDFC_CCR);
92 ccr |= NDFC_CCR_RESET_ECC; 90 ccr |= NDFC_CCR_RESET_ECC;
93 __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); 91 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
94 wmb(); 92 wmb();
95} 93}
96 94
@@ -102,9 +100,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd,
102 uint8_t *p = (uint8_t *)&ecc; 100 uint8_t *p = (uint8_t *)&ecc;
103 101
104 wmb(); 102 wmb();
105 ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC); 103 ecc = in_be32(ndfc->ndfcbase + NDFC_ECC);
106 ecc_code[0] = p[1]; 104 /* The NDFC uses Smart Media (SMC) bytes order */
107 ecc_code[1] = p[2]; 105 ecc_code[0] = p[2];
106 ecc_code[1] = p[1];
108 ecc_code[2] = p[3]; 107 ecc_code[2] = p[3];
109 108
110 return 0; 109 return 0;
@@ -123,7 +122,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
123 uint32_t *p = (uint32_t *) buf; 122 uint32_t *p = (uint32_t *) buf;
124 123
125 for(;len > 0; len -= 4) 124 for(;len > 0; len -= 4)
126 *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA); 125 *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA);
127} 126}
128 127
129static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) 128static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -132,7 +131,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
132 uint32_t *p = (uint32_t *) buf; 131 uint32_t *p = (uint32_t *) buf;
133 132
134 for(;len > 0; len -= 4) 133 for(;len > 0; len -= 4)
135 __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA); 134 out_be32(ndfc->ndfcbase + NDFC_DATA, *p++);
136} 135}
137 136
138static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) 137static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
@@ -141,7 +140,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
141 uint32_t *p = (uint32_t *) buf; 140 uint32_t *p = (uint32_t *) buf;
142 141
143 for(;len > 0; len -= 4) 142 for(;len > 0; len -= 4)
144 if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA)) 143 if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA))
145 return -EFAULT; 144 return -EFAULT;
146 return 0; 145 return 0;
147} 146}
@@ -149,10 +148,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
149/* 148/*
150 * Initialize chip structure 149 * Initialize chip structure
151 */ 150 */
152static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) 151static int ndfc_chip_init(struct ndfc_controller *ndfc,
152 struct device_node *node)
153{ 153{
154 struct ndfc_controller *ndfc = &ndfc_ctrl; 154#ifdef CONFIG_MTD_PARTITIONS
155 struct nand_chip *chip = &mtd->chip; 155#ifdef CONFIG_MTD_CMDLINE_PARTS
156 static const char *part_types[] = { "cmdlinepart", NULL };
157#else
158 static const char *part_types[] = { NULL };
159#endif
160#endif
161 struct device_node *flash_np;
162 struct nand_chip *chip = &ndfc->chip;
163 int ret;
156 164
157 chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; 165 chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA;
158 chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; 166 chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA;
@@ -160,8 +168,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
160 chip->dev_ready = ndfc_ready; 168 chip->dev_ready = ndfc_ready;
161 chip->select_chip = ndfc_select_chip; 169 chip->select_chip = ndfc_select_chip;
162 chip->chip_delay = 50; 170 chip->chip_delay = 50;
163 chip->priv = mtd;
164 chip->options = mtd->pl_chip->options;
165 chip->controller = &ndfc->ndfc_control; 171 chip->controller = &ndfc->ndfc_control;
166 chip->read_buf = ndfc_read_buf; 172 chip->read_buf = ndfc_read_buf;
167 chip->write_buf = ndfc_write_buf; 173 chip->write_buf = ndfc_write_buf;
@@ -172,143 +178,136 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
172 chip->ecc.mode = NAND_ECC_HW; 178 chip->ecc.mode = NAND_ECC_HW;
173 chip->ecc.size = 256; 179 chip->ecc.size = 256;
174 chip->ecc.bytes = 3; 180 chip->ecc.bytes = 3;
175 chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
176 mtd->mtd.priv = chip;
177 mtd->mtd.owner = THIS_MODULE;
178}
179
180static int ndfc_chip_probe(struct platform_device *pdev)
181{
182 struct platform_nand_chip *nc = pdev->dev.platform_data;
183 struct ndfc_chip_settings *settings = nc->priv;
184 struct ndfc_controller *ndfc = &ndfc_ctrl;
185 struct ndfc_nand_mtd *nandmtd;
186
187 if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS)
188 return -EINVAL;
189
190 /* Set the bank settings */
191 __raw_writel(settings->bank_settings,
192 ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2));
193 181
194 nandmtd = &ndfc_mtd[pdev->id]; 182 ndfc->mtd.priv = chip;
195 if (nandmtd->pl_chip) 183 ndfc->mtd.owner = THIS_MODULE;
196 return -EBUSY;
197 184
198 nandmtd->pl_chip = nc; 185 flash_np = of_get_next_child(node, NULL);
199 ndfc_chip_init(nandmtd); 186 if (!flash_np)
200
201 /* Scan for chips */
202 if (nand_scan(&nandmtd->mtd, nc->nr_chips)) {
203 nandmtd->pl_chip = NULL;
204 return -ENODEV; 187 return -ENODEV;
188
189 ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s",
190 ndfc->ofdev->dev.bus_id, flash_np->name);
191 if (!ndfc->mtd.name) {
192 ret = -ENOMEM;
193 goto err;
205 } 194 }
206 195
207#ifdef CONFIG_MTD_PARTITIONS 196 ret = nand_scan(&ndfc->mtd, 1);
208 printk("Number of partitions %d\n", nc->nr_partitions); 197 if (ret)
209 if (nc->nr_partitions) { 198 goto err;
210 /* Add the full device, so complete dumps can be made */
211 add_mtd_device(&nandmtd->mtd);
212 add_mtd_partitions(&nandmtd->mtd, nc->partitions,
213 nc->nr_partitions);
214 199
215 } else 200#ifdef CONFIG_MTD_PARTITIONS
216#else 201 ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0);
217 add_mtd_device(&nandmtd->mtd); 202 if (ret < 0)
203 goto err;
204
205#ifdef CONFIG_MTD_OF_PARTS
206 if (ret == 0) {
207 ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np,
208 &ndfc->parts);
209 if (ret < 0)
210 goto err;
211 }
218#endif 212#endif
219 213
220 atomic_inc(&ndfc->childs_active); 214 if (ret > 0)
221 return 0; 215 ret = add_mtd_partitions(&ndfc->mtd, ndfc->parts, ret);
222} 216 else
217#endif
218 ret = add_mtd_device(&ndfc->mtd);
223 219
224static int ndfc_chip_remove(struct platform_device *pdev) 220err:
225{ 221 of_node_put(flash_np);
226 return 0; 222 if (ret)
223 kfree(ndfc->mtd.name);
224 return ret;
227} 225}
228 226
229static int ndfc_nand_probe(struct platform_device *pdev) 227static int __devinit ndfc_probe(struct of_device *ofdev,
228 const struct of_device_id *match)
230{ 229{
231 struct platform_nand_ctrl *nc = pdev->dev.platform_data;
232 struct ndfc_controller_settings *settings = nc->priv;
233 struct resource *res = pdev->resource;
234 struct ndfc_controller *ndfc = &ndfc_ctrl; 230 struct ndfc_controller *ndfc = &ndfc_ctrl;
235 unsigned long long phys = settings->ndfc_erpn | res->start; 231 const u32 *reg;
232 u32 ccr;
233 int err, len;
236 234
237#ifndef CONFIG_PHYS_64BIT 235 spin_lock_init(&ndfc->ndfc_control.lock);
238 ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1); 236 init_waitqueue_head(&ndfc->ndfc_control.wq);
239#else 237 ndfc->ofdev = ofdev;
240 ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1); 238 dev_set_drvdata(&ofdev->dev, ndfc);
241#endif 239
240 /* Read the reg property to get the chip select */
241 reg = of_get_property(ofdev->node, "reg", &len);
242 if (reg == NULL || len != 12) {
243 dev_err(&ofdev->dev, "unable read reg property (%d)\n", len);
244 return -ENOENT;
245 }
246 ndfc->chip_select = reg[0];
247
248 ndfc->ndfcbase = of_iomap(ofdev->node, 0);
242 if (!ndfc->ndfcbase) { 249 if (!ndfc->ndfcbase) {
243 printk(KERN_ERR "NDFC: ioremap failed\n"); 250 dev_err(&ofdev->dev, "failed to get memory\n");
244 return -EIO; 251 return -EIO;
245 } 252 }
246 253
247 __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR); 254 ccr = NDFC_CCR_BS(ndfc->chip_select);
248 255
249 spin_lock_init(&ndfc->ndfc_control.lock); 256 /* It is ok if ccr does not exist - just default to 0 */
250 init_waitqueue_head(&ndfc->ndfc_control.wq); 257 reg = of_get_property(ofdev->node, "ccr", NULL);
258 if (reg)
259 ccr |= *reg;
251 260
252 platform_set_drvdata(pdev, ndfc); 261 out_be32(ndfc->ndfcbase + NDFC_CCR, ccr);
253 262
254 printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n", 263 /* Set the bank settings if given */
255 __raw_readl(ndfc->ndfcbase + NDFC_REVID)); 264 reg = of_get_property(ofdev->node, "bank-settings", NULL);
265 if (reg) {
266 int offset = NDFC_BCFG0 + (ndfc->chip_select << 2);
267 out_be32(ndfc->ndfcbase + offset, *reg);
268 }
269
270 err = ndfc_chip_init(ndfc, ofdev->node);
271 if (err) {
272 iounmap(ndfc->ndfcbase);
273 return err;
274 }
256 275
257 return 0; 276 return 0;
258} 277}
259 278
260static int ndfc_nand_remove(struct platform_device *pdev) 279static int __devexit ndfc_remove(struct of_device *ofdev)
261{ 280{
262 struct ndfc_controller *ndfc = platform_get_drvdata(pdev); 281 struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev);
263 282
264 if (atomic_read(&ndfc->childs_active)) 283 nand_release(&ndfc->mtd);
265 return -EBUSY;
266 284
267 if (ndfc) {
268 platform_set_drvdata(pdev, NULL);
269 iounmap(ndfc_ctrl.ndfcbase);
270 ndfc_ctrl.ndfcbase = NULL;
271 }
272 return 0; 285 return 0;
273} 286}
274 287
275/* driver device registration */ 288static const struct of_device_id ndfc_match[] = {
276 289 { .compatible = "ibm,ndfc", },
277static struct platform_driver ndfc_chip_driver = { 290 {}
278 .probe = ndfc_chip_probe,
279 .remove = ndfc_chip_remove,
280 .driver = {
281 .name = "ndfc-chip",
282 .owner = THIS_MODULE,
283 },
284}; 291};
292MODULE_DEVICE_TABLE(of, ndfc_match);
285 293
286static struct platform_driver ndfc_nand_driver = { 294static struct of_platform_driver ndfc_driver = {
287 .probe = ndfc_nand_probe, 295 .driver = {
288 .remove = ndfc_nand_remove, 296 .name = "ndfc",
289 .driver = {
290 .name = "ndfc-nand",
291 .owner = THIS_MODULE,
292 }, 297 },
298 .match_table = ndfc_match,
299 .probe = ndfc_probe,
300 .remove = __devexit_p(ndfc_remove),
293}; 301};
294 302
295static int __init ndfc_nand_init(void) 303static int __init ndfc_nand_init(void)
296{ 304{
297 int ret; 305 return of_register_platform_driver(&ndfc_driver);
298
299 spin_lock_init(&ndfc_ctrl.ndfc_control.lock);
300 init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq);
301
302 ret = platform_driver_register(&ndfc_nand_driver);
303 if (!ret)
304 ret = platform_driver_register(&ndfc_chip_driver);
305 return ret;
306} 306}
307 307
308static void __exit ndfc_nand_exit(void) 308static void __exit ndfc_nand_exit(void)
309{ 309{
310 platform_driver_unregister(&ndfc_chip_driver); 310 of_unregister_platform_driver(&ndfc_driver);
311 platform_driver_unregister(&ndfc_nand_driver);
312} 311}
313 312
314module_init(ndfc_nand_init); 313module_init(ndfc_nand_init);
@@ -316,6 +315,4 @@ module_exit(ndfc_nand_exit);
316 315
317MODULE_LICENSE("GPL"); 316MODULE_LICENSE("GPL");
318MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); 317MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
319MODULE_DESCRIPTION("Platform driver for NDFC"); 318MODULE_DESCRIPTION("OF Platform driver for NDFC");
320MODULE_ALIAS("platform:ndfc-chip");
321MODULE_ALIAS("platform:ndfc-nand");
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index fc4144495610..cc55cbc2b308 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -298,7 +298,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = {
298#define NDTR1_tAR(c) (min((c), 15) << 0) 298#define NDTR1_tAR(c) (min((c), 15) << 0)
299 299
300/* convert nano-seconds to nand flash controller clock cycles */ 300/* convert nano-seconds to nand flash controller clock cycles */
301#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1) 301#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1)
302 302
303static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, 303static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info,
304 const struct pxa3xx_nand_timing *t) 304 const struct pxa3xx_nand_timing *t)
@@ -368,14 +368,14 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info,
368 /* large block, 2 cycles for column address 368 /* large block, 2 cycles for column address
369 * row address starts from 3rd cycle 369 * row address starts from 3rd cycle
370 */ 370 */
371 info->ndcb1 |= (page_addr << 16) | (column & 0xffff); 371 info->ndcb1 |= page_addr << 16;
372 if (info->row_addr_cycles == 3) 372 if (info->row_addr_cycles == 3)
373 info->ndcb2 = (page_addr >> 16) & 0xff; 373 info->ndcb2 = (page_addr >> 16) & 0xff;
374 } else 374 } else
375 /* small block, 1 cycles for column address 375 /* small block, 1 cycles for column address
376 * row address starts from 2nd cycle 376 * row address starts from 2nd cycle
377 */ 377 */
378 info->ndcb1 = (page_addr << 8) | (column & 0xff); 378 info->ndcb1 = page_addr << 8;
379 379
380 if (cmd == cmdset->program) 380 if (cmd == cmdset->program)
381 info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; 381 info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 30a518e211bd..54ec7542a7b7 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -2,6 +2,7 @@
2 * drivers/mtd/nand/sharpsl.c 2 * drivers/mtd/nand/sharpsl.c
3 * 3 *
4 * Copyright (C) 2004 Richard Purdie 4 * Copyright (C) 2004 Richard Purdie
5 * Copyright (C) 2008 Dmitry Baryshkov
5 * 6 *
6 * Based on Sharp's NAND driver sharp_sl.c 7 * Based on Sharp's NAND driver sharp_sl.c
7 * 8 *
@@ -19,22 +20,31 @@
19#include <linux/mtd/nand.h> 20#include <linux/mtd/nand.h>
20#include <linux/mtd/nand_ecc.h> 21#include <linux/mtd/nand_ecc.h>
21#include <linux/mtd/partitions.h> 22#include <linux/mtd/partitions.h>
23#include <linux/mtd/sharpsl.h>
22#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/platform_device.h>
26
23#include <asm/io.h> 27#include <asm/io.h>
24#include <mach/hardware.h> 28#include <mach/hardware.h>
25#include <asm/mach-types.h> 29#include <asm/mach-types.h>
26 30
27static void __iomem *sharpsl_io_base; 31struct sharpsl_nand {
28static int sharpsl_phys_base = 0x0C000000; 32 struct mtd_info mtd;
33 struct nand_chip chip;
34
35 void __iomem *io;
36};
37
38#define mtd_to_sharpsl(_mtd) container_of(_mtd, struct sharpsl_nand, mtd)
29 39
30/* register offset */ 40/* register offset */
31#define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */ 41#define ECCLPLB 0x00 /* line parity 7 - 0 bit */
32#define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */ 42#define ECCLPUB 0x04 /* line parity 15 - 8 bit */
33#define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */ 43#define ECCCP 0x08 /* column parity 5 - 0 bit */
34#define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */ 44#define ECCCNTR 0x0C /* ECC byte counter */
35#define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */ 45#define ECCCLRR 0x10 /* cleare ECC */
36#define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */ 46#define FLASHIO 0x14 /* Flash I/O */
37#define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */ 47#define FLASHCTL 0x18 /* Flash Control */
38 48
39/* Flash control bit */ 49/* Flash control bit */
40#define FLRYBY (1 << 5) 50#define FLRYBY (1 << 5)
@@ -45,35 +55,6 @@ static int sharpsl_phys_base = 0x0C000000;
45#define FLCE0 (1 << 0) 55#define FLCE0 (1 << 0)
46 56
47/* 57/*
48 * MTD structure for SharpSL
49 */
50static struct mtd_info *sharpsl_mtd = NULL;
51
52/*
53 * Define partitions for flash device
54 */
55#define DEFAULT_NUM_PARTITIONS 3
56
57static int nr_partitions;
58static struct mtd_partition sharpsl_nand_default_partition_info[] = {
59 {
60 .name = "System Area",
61 .offset = 0,
62 .size = 7 * 1024 * 1024,
63 },
64 {
65 .name = "Root Filesystem",
66 .offset = 7 * 1024 * 1024,
67 .size = 30 * 1024 * 1024,
68 },
69 {
70 .name = "Home Filesystem",
71 .offset = MTDPART_OFS_APPEND,
72 .size = MTDPART_SIZ_FULL,
73 },
74};
75
76/*
77 * hardware specific access to control-lines 58 * hardware specific access to control-lines
78 * ctrl: 59 * ctrl:
79 * NAND_CNE: bit 0 -> ! bit 0 & 4 60 * NAND_CNE: bit 0 -> ! bit 0 & 4
@@ -84,6 +65,7 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = {
84static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, 65static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
85 unsigned int ctrl) 66 unsigned int ctrl)
86{ 67{
68 struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
87 struct nand_chip *chip = mtd->priv; 69 struct nand_chip *chip = mtd->priv;
88 70
89 if (ctrl & NAND_CTRL_CHANGE) { 71 if (ctrl & NAND_CTRL_CHANGE) {
@@ -93,103 +75,97 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
93 75
94 bits ^= 0x11; 76 bits ^= 0x11;
95 77
96 writeb((readb(FLASHCTL) & ~0x17) | bits, FLASHCTL); 78 writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL);
97 } 79 }
98 80
99 if (cmd != NAND_CMD_NONE) 81 if (cmd != NAND_CMD_NONE)
100 writeb(cmd, chip->IO_ADDR_W); 82 writeb(cmd, chip->IO_ADDR_W);
101} 83}
102 84
103static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
104
105static struct nand_bbt_descr sharpsl_bbt = {
106 .options = 0,
107 .offs = 4,
108 .len = 2,
109 .pattern = scan_ff_pattern
110};
111
112static struct nand_bbt_descr sharpsl_akita_bbt = {
113 .options = 0,
114 .offs = 4,
115 .len = 1,
116 .pattern = scan_ff_pattern
117};
118
119static struct nand_ecclayout akita_oobinfo = {
120 .eccbytes = 24,
121 .eccpos = {
122 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11,
123 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
124 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37},
125 .oobfree = {{0x08, 0x09}}
126};
127
128static int sharpsl_nand_dev_ready(struct mtd_info *mtd) 85static int sharpsl_nand_dev_ready(struct mtd_info *mtd)
129{ 86{
130 return !((readb(FLASHCTL) & FLRYBY) == 0); 87 struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
88 return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
131} 89}
132 90
133static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode) 91static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode)
134{ 92{
135 writeb(0, ECCCLRR); 93 struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
94 writeb(0, sharpsl->io + ECCCLRR);
136} 95}
137 96
138static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) 97static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code)
139{ 98{
140 ecc_code[0] = ~readb(ECCLPUB); 99 struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd);
141 ecc_code[1] = ~readb(ECCLPLB); 100 ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
142 ecc_code[2] = (~readb(ECCCP) << 2) | 0x03; 101 ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
143 return readb(ECCCNTR) != 0; 102 ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
103 return readb(sharpsl->io + ECCCNTR) != 0;
144} 104}
145 105
146#ifdef CONFIG_MTD_PARTITIONS 106#ifdef CONFIG_MTD_PARTITIONS
147const char *part_probes[] = { "cmdlinepart", NULL }; 107static const char *part_probes[] = { "cmdlinepart", NULL };
148#endif 108#endif
149 109
150/* 110/*
151 * Main initialization routine 111 * Main initialization routine
152 */ 112 */
153static int __init sharpsl_nand_init(void) 113static int __devinit sharpsl_nand_probe(struct platform_device *pdev)
154{ 114{
155 struct nand_chip *this; 115 struct nand_chip *this;
116#ifdef CONFIG_MTD_PARTITIONS
156 struct mtd_partition *sharpsl_partition_info; 117 struct mtd_partition *sharpsl_partition_info;
118 int nr_partitions;
119#endif
120 struct resource *r;
157 int err = 0; 121 int err = 0;
122 struct sharpsl_nand *sharpsl;
123 struct sharpsl_nand_platform_data *data = pdev->dev.platform_data;
124
125 if (!data) {
126 dev_err(&pdev->dev, "no platform data!\n");
127 return -EINVAL;
128 }
158 129
159 /* Allocate memory for MTD device structure and private data */ 130 /* Allocate memory for MTD device structure and private data */
160 sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); 131 sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
161 if (!sharpsl_mtd) { 132 if (!sharpsl) {
162 printk("Unable to allocate SharpSL NAND MTD device structure.\n"); 133 printk("Unable to allocate SharpSL NAND MTD device structure.\n");
163 return -ENOMEM; 134 return -ENOMEM;
164 } 135 }
165 136
137 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
138 if (!r) {
139 dev_err(&pdev->dev, "no io memory resource defined!\n");
140 err = -ENODEV;
141 goto err_get_res;
142 }
143
166 /* map physical address */ 144 /* map physical address */
167 sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); 145 sharpsl->io = ioremap(r->start, resource_size(r));
168 if (!sharpsl_io_base) { 146 if (!sharpsl->io) {
169 printk("ioremap to access Sharp SL NAND chip failed\n"); 147 printk("ioremap to access Sharp SL NAND chip failed\n");
170 kfree(sharpsl_mtd); 148 err = -EIO;
171 return -EIO; 149 goto err_ioremap;
172 } 150 }
173 151
174 /* Get pointer to private data */ 152 /* Get pointer to private data */
175 this = (struct nand_chip *)(&sharpsl_mtd[1]); 153 this = (struct nand_chip *)(&sharpsl->chip);
176
177 /* Initialize structures */
178 memset(sharpsl_mtd, 0, sizeof(struct mtd_info));
179 memset(this, 0, sizeof(struct nand_chip));
180 154
181 /* Link the private data with the MTD structure */ 155 /* Link the private data with the MTD structure */
182 sharpsl_mtd->priv = this; 156 sharpsl->mtd.priv = this;
183 sharpsl_mtd->owner = THIS_MODULE; 157 sharpsl->mtd.owner = THIS_MODULE;
158
159 platform_set_drvdata(pdev, sharpsl);
184 160
185 /* 161 /*
186 * PXA initialize 162 * PXA initialize
187 */ 163 */
188 writeb(readb(FLASHCTL) | FLWP, FLASHCTL); 164 writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
189 165
190 /* Set address of NAND IO lines */ 166 /* Set address of NAND IO lines */
191 this->IO_ADDR_R = FLASHIO; 167 this->IO_ADDR_R = sharpsl->io + FLASHIO;
192 this->IO_ADDR_W = FLASHIO; 168 this->IO_ADDR_W = sharpsl->io + FLASHIO;
193 /* Set address of hardware control function */ 169 /* Set address of hardware control function */
194 this->cmd_ctrl = sharpsl_nand_hwcontrol; 170 this->cmd_ctrl = sharpsl_nand_hwcontrol;
195 this->dev_ready = sharpsl_nand_dev_ready; 171 this->dev_ready = sharpsl_nand_dev_ready;
@@ -199,68 +175,89 @@ static int __init sharpsl_nand_init(void)
199 this->ecc.mode = NAND_ECC_HW; 175 this->ecc.mode = NAND_ECC_HW;
200 this->ecc.size = 256; 176 this->ecc.size = 256;
201 this->ecc.bytes = 3; 177 this->ecc.bytes = 3;
202 this->badblock_pattern = &sharpsl_bbt; 178 this->badblock_pattern = data->badblock_pattern;
203 if (machine_is_akita() || machine_is_borzoi()) { 179 this->ecc.layout = data->ecc_layout;
204 this->badblock_pattern = &sharpsl_akita_bbt;
205 this->ecc.layout = &akita_oobinfo;
206 }
207 this->ecc.hwctl = sharpsl_nand_enable_hwecc; 180 this->ecc.hwctl = sharpsl_nand_enable_hwecc;
208 this->ecc.calculate = sharpsl_nand_calculate_ecc; 181 this->ecc.calculate = sharpsl_nand_calculate_ecc;
209 this->ecc.correct = nand_correct_data; 182 this->ecc.correct = nand_correct_data;
210 183
211 /* Scan to find existence of the device */ 184 /* Scan to find existence of the device */
212 err = nand_scan(sharpsl_mtd, 1); 185 err = nand_scan(&sharpsl->mtd, 1);
213 if (err) { 186 if (err)
214 iounmap(sharpsl_io_base); 187 goto err_scan;
215 kfree(sharpsl_mtd);
216 return err;
217 }
218 188
219 /* Register the partitions */ 189 /* Register the partitions */
220 sharpsl_mtd->name = "sharpsl-nand"; 190 sharpsl->mtd.name = "sharpsl-nand";
221 nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0); 191#ifdef CONFIG_MTD_PARTITIONS
222 192 nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0);
223 if (nr_partitions <= 0) { 193 if (nr_partitions <= 0) {
224 nr_partitions = DEFAULT_NUM_PARTITIONS; 194 nr_partitions = data->nr_partitions;
225 sharpsl_partition_info = sharpsl_nand_default_partition_info; 195 sharpsl_partition_info = data->partitions;
226 if (machine_is_poodle()) {
227 sharpsl_partition_info[1].size = 22 * 1024 * 1024;
228 } else if (machine_is_corgi() || machine_is_shepherd()) {
229 sharpsl_partition_info[1].size = 25 * 1024 * 1024;
230 } else if (machine_is_husky()) {
231 sharpsl_partition_info[1].size = 53 * 1024 * 1024;
232 } else if (machine_is_spitz()) {
233 sharpsl_partition_info[1].size = 5 * 1024 * 1024;
234 } else if (machine_is_akita()) {
235 sharpsl_partition_info[1].size = 58 * 1024 * 1024;
236 } else if (machine_is_borzoi()) {
237 sharpsl_partition_info[1].size = 32 * 1024 * 1024;
238 }
239 } 196 }
240 197
241 add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions); 198 if (nr_partitions > 0)
199 err = add_mtd_partitions(&sharpsl->mtd, sharpsl_partition_info, nr_partitions);
200 else
201#endif
202 err = add_mtd_device(&sharpsl->mtd);
203 if (err)
204 goto err_add;
242 205
243 /* Return happy */ 206 /* Return happy */
244 return 0; 207 return 0;
245}
246 208
247module_init(sharpsl_nand_init); 209err_add:
210 nand_release(&sharpsl->mtd);
211
212err_scan:
213 platform_set_drvdata(pdev, NULL);
214 iounmap(sharpsl->io);
215err_ioremap:
216err_get_res:
217 kfree(sharpsl);
218 return err;
219}
248 220
249/* 221/*
250 * Clean up routine 222 * Clean up routine
251 */ 223 */
252static void __exit sharpsl_nand_cleanup(void) 224static int __devexit sharpsl_nand_remove(struct platform_device *pdev)
253{ 225{
226 struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
227
254 /* Release resources, unregister device */ 228 /* Release resources, unregister device */
255 nand_release(sharpsl_mtd); 229 nand_release(&sharpsl->mtd);
256 230
257 iounmap(sharpsl_io_base); 231 platform_set_drvdata(pdev, NULL);
232
233 iounmap(sharpsl->io);
258 234
259 /* Free the MTD device structure */ 235 /* Free the MTD device structure */
260 kfree(sharpsl_mtd); 236 kfree(sharpsl);
237
238 return 0;
239}
240
241static struct platform_driver sharpsl_nand_driver = {
242 .driver = {
243 .name = "sharpsl-nand",
244 .owner = THIS_MODULE,
245 },
246 .probe = sharpsl_nand_probe,
247 .remove = __devexit_p(sharpsl_nand_remove),
248};
249
250static int __init sharpsl_nand_init(void)
251{
252 return platform_driver_register(&sharpsl_nand_driver);
261} 253}
254module_init(sharpsl_nand_init);
262 255
263module_exit(sharpsl_nand_cleanup); 256static void __exit sharpsl_nand_exit(void)
257{
258 platform_driver_unregister(&sharpsl_nand_driver);
259}
260module_exit(sharpsl_nand_exit);
264 261
265MODULE_LICENSE("GPL"); 262MODULE_LICENSE("GPL");
266MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); 263MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 320b929abe79..d1c4546513f7 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -39,7 +39,7 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
39 struct NFTLrecord *nftl; 39 struct NFTLrecord *nftl;
40 unsigned long temp; 40 unsigned long temp;
41 41
42 if (mtd->type != MTD_NANDFLASH) 42 if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX)
43 return; 43 return;
44 /* OK, this is moderately ugly. But probably safe. Alternatives? */ 44 /* OK, this is moderately ugly. But probably safe. Alternatives? */
45 if (memcmp(mtd->name, "DiskOnChip", 10)) 45 if (memcmp(mtd->name, "DiskOnChip", 10))
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index ccc4f209fbb5..8b22b1836e9f 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -51,7 +51,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
51 the mtd device accordingly. We could even get rid of 51 the mtd device accordingly. We could even get rid of
52 nftl->EraseSize if there were any point in doing so. */ 52 nftl->EraseSize if there were any point in doing so. */
53 nftl->EraseSize = nftl->mbd.mtd->erasesize; 53 nftl->EraseSize = nftl->mbd.mtd->erasesize;
54 nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; 54 nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
55 55
56 nftl->MediaUnit = BLOCK_NIL; 56 nftl->MediaUnit = BLOCK_NIL;
57 nftl->SpareMediaUnit = BLOCK_NIL; 57 nftl->SpareMediaUnit = BLOCK_NIL;
@@ -168,7 +168,7 @@ device is already correct.
168 printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n", 168 printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n",
169 mh->UnitSizeFactor); 169 mh->UnitSizeFactor);
170 nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor); 170 nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
171 nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; 171 nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize;
172 } 172 }
173#endif 173#endif
174 nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); 174 nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 90ed319f26e6..529af271db17 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1772,7 +1772,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
1772 int len; 1772 int len;
1773 int ret = 0; 1773 int ret = 0;
1774 1774
1775 DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); 1775 DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%012llx, len = %llu\n", (unsigned long long) instr->addr, (unsigned long long) instr->len);
1776 1776
1777 block_size = (1 << this->erase_shift); 1777 block_size = (1 << this->erase_shift);
1778 1778
@@ -1810,7 +1810,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
1810 1810
1811 /* Check if we have a bad block, we do not erase bad blocks */ 1811 /* Check if we have a bad block, we do not erase bad blocks */
1812 if (onenand_block_isbad_nolock(mtd, addr, 0)) { 1812 if (onenand_block_isbad_nolock(mtd, addr, 0)) {
1813 printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); 1813 printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%012llx\n", (unsigned long long) addr);
1814 instr->state = MTD_ERASE_FAILED; 1814 instr->state = MTD_ERASE_FAILED;
1815 goto erase_exit; 1815 goto erase_exit;
1816 } 1816 }
@@ -2029,7 +2029,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int
2029 * 2029 *
2030 * Lock one or more blocks 2030 * Lock one or more blocks
2031 */ 2031 */
2032static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) 2032static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
2033{ 2033{
2034 int ret; 2034 int ret;
2035 2035
@@ -2047,7 +2047,7 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
2047 * 2047 *
2048 * Unlock one or more blocks 2048 * Unlock one or more blocks
2049 */ 2049 */
2050static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) 2050static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
2051{ 2051{
2052 int ret; 2052 int ret;
2053 2053
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index e538c0a72abb..d2aa9c46530f 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -21,8 +21,6 @@
21 21
22#include <asm/types.h> 22#include <asm/types.h>
23 23
24#define const_cpu_to_le16 __constant_cpu_to_le16
25
26static int block_size = 0; 24static int block_size = 0;
27module_param(block_size, int, 0); 25module_param(block_size, int, 0);
28MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size"); 26MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size");
@@ -156,7 +154,7 @@ static int scan_header(struct partition *part)
156 size_t retlen; 154 size_t retlen;
157 155
158 sectors_per_block = part->block_size / SECTOR_SIZE; 156 sectors_per_block = part->block_size / SECTOR_SIZE;
159 part->total_blocks = part->mbd.mtd->size / part->block_size; 157 part->total_blocks = (u32)part->mbd.mtd->size / part->block_size;
160 158
161 if (part->total_blocks < 2) 159 if (part->total_blocks < 2)
162 return -ENOENT; 160 return -ENOENT;
@@ -276,16 +274,17 @@ static void erase_callback(struct erase_info *erase)
276 274
277 part = (struct partition*)erase->priv; 275 part = (struct partition*)erase->priv;
278 276
279 i = erase->addr / part->block_size; 277 i = (u32)erase->addr / part->block_size;
280 if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) { 278 if (i >= part->total_blocks || part->blocks[i].offset != erase->addr ||
281 printk(KERN_ERR PREFIX "erase callback for unknown offset %x " 279 erase->addr > UINT_MAX) {
282 "on '%s'\n", erase->addr, part->mbd.mtd->name); 280 printk(KERN_ERR PREFIX "erase callback for unknown offset %llx "
281 "on '%s'\n", (unsigned long long)erase->addr, part->mbd.mtd->name);
283 return; 282 return;
284 } 283 }
285 284
286 if (erase->state != MTD_ERASE_DONE) { 285 if (erase->state != MTD_ERASE_DONE) {
287 printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', " 286 printk(KERN_WARNING PREFIX "erase failed at 0x%llx on '%s', "
288 "state %d\n", erase->addr, 287 "state %d\n", (unsigned long long)erase->addr,
289 part->mbd.mtd->name, erase->state); 288 part->mbd.mtd->name, erase->state);
290 289
291 part->blocks[i].state = BLOCK_FAILED; 290 part->blocks[i].state = BLOCK_FAILED;
@@ -297,7 +296,7 @@ static void erase_callback(struct erase_info *erase)
297 return; 296 return;
298 } 297 }
299 298
300 magic = const_cpu_to_le16(RFD_MAGIC); 299 magic = cpu_to_le16(RFD_MAGIC);
301 300
302 part->blocks[i].state = BLOCK_ERASED; 301 part->blocks[i].state = BLOCK_ERASED;
303 part->blocks[i].free_sectors = part->data_sectors_per_block; 302 part->blocks[i].free_sectors = part->data_sectors_per_block;
@@ -345,9 +344,9 @@ static int erase_block(struct partition *part, int block)
345 rc = part->mbd.mtd->erase(part->mbd.mtd, erase); 344 rc = part->mbd.mtd->erase(part->mbd.mtd, erase);
346 345
347 if (rc) { 346 if (rc) {
348 printk(KERN_ERR PREFIX "erase of region %x,%x on '%s' " 347 printk(KERN_ERR PREFIX "erase of region %llx,%llx on '%s' "
349 "failed\n", erase->addr, erase->len, 348 "failed\n", (unsigned long long)erase->addr,
350 part->mbd.mtd->name); 349 (unsigned long long)erase->len, part->mbd.mtd->name);
351 kfree(erase); 350 kfree(erase);
352 } 351 }
353 352
@@ -587,7 +586,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr)
587 int block, offset, rc; 586 int block, offset, rc;
588 u_long addr; 587 u_long addr;
589 size_t retlen; 588 size_t retlen;
590 u16 del = const_cpu_to_le16(SECTOR_DELETED); 589 u16 del = cpu_to_le16(SECTOR_DELETED);
591 590
592 block = old_addr / part->block_size; 591 block = old_addr / part->block_size;
593 offset = (old_addr % part->block_size) / SECTOR_SIZE - 592 offset = (old_addr % part->block_size) / SECTOR_SIZE -
@@ -763,7 +762,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
763{ 762{
764 struct partition *part; 763 struct partition *part;
765 764
766 if (mtd->type != MTD_NORFLASH) 765 if (mtd->type != MTD_NORFLASH || mtd->size > UINT_MAX)
767 return; 766 return;
768 767
769 part = kzalloc(sizeof(struct partition), GFP_KERNEL); 768 part = kzalloc(sizeof(struct partition), GFP_KERNEL);
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c
index 33a5d6ed6f18..3f67e00d98e0 100644
--- a/drivers/mtd/ssfdc.c
+++ b/drivers/mtd/ssfdc.c
@@ -294,7 +294,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
294 int cis_sector; 294 int cis_sector;
295 295
296 /* Check for small page NAND flash */ 296 /* Check for small page NAND flash */
297 if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE) 297 if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE ||
298 mtd->size > UINT_MAX)
298 return; 299 return;
299 300
300 /* Check for SSDFC format by reading CIS/IDI sector */ 301 /* Check for SSDFC format by reading CIS/IDI sector */
@@ -316,7 +317,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
316 317
317 ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT); 318 ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT);
318 ssfdc->erase_size = mtd->erasesize; 319 ssfdc->erase_size = mtd->erasesize;
319 ssfdc->map_len = mtd->size / mtd->erasesize; 320 ssfdc->map_len = (u32)mtd->size / mtd->erasesize;
320 321
321 DEBUG(MTD_DEBUG_LEVEL1, 322 DEBUG(MTD_DEBUG_LEVEL1,
322 "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", 323 "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
@@ -327,7 +328,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
327 ssfdc->heads = 16; 328 ssfdc->heads = 16;
328 ssfdc->sectors = 32; 329 ssfdc->sectors = 32;
329 get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors); 330 get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors);
330 ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) / 331 ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) /
331 ((long)ssfdc->sectors * (long)ssfdc->heads)); 332 ((long)ssfdc->sectors * (long)ssfdc->heads));
332 333
333 DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", 334 DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",
diff --git a/drivers/mtd/tests/Makefile b/drivers/mtd/tests/Makefile
new file mode 100644
index 000000000000..c1d501335006
--- /dev/null
+++ b/drivers/mtd/tests/Makefile
@@ -0,0 +1,7 @@
1obj-$(CONFIG_MTD_TESTS) += mtd_oobtest.o
2obj-$(CONFIG_MTD_TESTS) += mtd_pagetest.o
3obj-$(CONFIG_MTD_TESTS) += mtd_readtest.o
4obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o
5obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o
6obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o
7obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c
new file mode 100644
index 000000000000..afbc3f8126db
--- /dev/null
+++ b/drivers/mtd/tests/mtd_oobtest.c
@@ -0,0 +1,742 @@
1/*
2 * Copyright (C) 2006-2008 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; see the file COPYING. If not, write to the Free Software
15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 * Test OOB read and write on MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
22#include <asm/div64.h>
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/err.h>
27#include <linux/mtd/mtd.h>
28#include <linux/sched.h>
29
30#define PRINT_PREF KERN_INFO "mtd_oobtest: "
31
32static int dev;
33module_param(dev, int, S_IRUGO);
34MODULE_PARM_DESC(dev, "MTD device number to use");
35
36static struct mtd_info *mtd;
37static unsigned char *readbuf;
38static unsigned char *writebuf;
39static unsigned char *bbt;
40
41static int ebcnt;
42static int pgcnt;
43static int errcnt;
44static int use_offset;
45static int use_len;
46static int use_len_max;
47static int vary_offset;
48static unsigned long next = 1;
49
50static inline unsigned int simple_rand(void)
51{
52 next = next * 1103515245 + 12345;
53 return (unsigned int)((next / 65536) % 32768);
54}
55
56static inline void simple_srand(unsigned long seed)
57{
58 next = seed;
59}
60
61static void set_random_data(unsigned char *buf, size_t len)
62{
63 size_t i;
64
65 for (i = 0; i < len; ++i)
66 buf[i] = simple_rand();
67}
68
69static int erase_eraseblock(int ebnum)
70{
71 int err;
72 struct erase_info ei;
73 loff_t addr = ebnum * mtd->erasesize;
74
75 memset(&ei, 0, sizeof(struct erase_info));
76 ei.mtd = mtd;
77 ei.addr = addr;
78 ei.len = mtd->erasesize;
79
80 err = mtd->erase(mtd, &ei);
81 if (err) {
82 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
83 return err;
84 }
85
86 if (ei.state == MTD_ERASE_FAILED) {
87 printk(PRINT_PREF "some erase error occurred at EB %d\n",
88 ebnum);
89 return -EIO;
90 }
91
92 return 0;
93}
94
95static int erase_whole_device(void)
96{
97 int err;
98 unsigned int i;
99
100 printk(PRINT_PREF "erasing whole device\n");
101 for (i = 0; i < ebcnt; ++i) {
102 if (bbt[i])
103 continue;
104 err = erase_eraseblock(i);
105 if (err)
106 return err;
107 cond_resched();
108 }
109 printk(PRINT_PREF "erased %u eraseblocks\n", i);
110 return 0;
111}
112
113static void do_vary_offset(void)
114{
115 use_len -= 1;
116 if (use_len < 1) {
117 use_offset += 1;
118 if (use_offset >= use_len_max)
119 use_offset = 0;
120 use_len = use_len_max - use_offset;
121 }
122}
123
124static int write_eraseblock(int ebnum)
125{
126 int i;
127 struct mtd_oob_ops ops;
128 int err = 0;
129 loff_t addr = ebnum * mtd->erasesize;
130
131 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
132 set_random_data(writebuf, use_len);
133 ops.mode = MTD_OOB_AUTO;
134 ops.len = 0;
135 ops.retlen = 0;
136 ops.ooblen = use_len;
137 ops.oobretlen = 0;
138 ops.ooboffs = use_offset;
139 ops.datbuf = 0;
140 ops.oobbuf = writebuf;
141 err = mtd->write_oob(mtd, addr, &ops);
142 if (err || ops.oobretlen != use_len) {
143 printk(PRINT_PREF "error: writeoob failed at %#llx\n",
144 (long long)addr);
145 printk(PRINT_PREF "error: use_len %d, use_offset %d\n",
146 use_len, use_offset);
147 errcnt += 1;
148 return err ? err : -1;
149 }
150 if (vary_offset)
151 do_vary_offset();
152 }
153
154 return err;
155}
156
157static int write_whole_device(void)
158{
159 int err;
160 unsigned int i;
161
162 printk(PRINT_PREF "writing OOBs of whole device\n");
163 for (i = 0; i < ebcnt; ++i) {
164 if (bbt[i])
165 continue;
166 err = write_eraseblock(i);
167 if (err)
168 return err;
169 if (i % 256 == 0)
170 printk(PRINT_PREF "written up to eraseblock %u\n", i);
171 cond_resched();
172 }
173 printk(PRINT_PREF "written %u eraseblocks\n", i);
174 return 0;
175}
176
177static int verify_eraseblock(int ebnum)
178{
179 int i;
180 struct mtd_oob_ops ops;
181 int err = 0;
182 loff_t addr = ebnum * mtd->erasesize;
183
184 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
185 set_random_data(writebuf, use_len);
186 ops.mode = MTD_OOB_AUTO;
187 ops.len = 0;
188 ops.retlen = 0;
189 ops.ooblen = use_len;
190 ops.oobretlen = 0;
191 ops.ooboffs = use_offset;
192 ops.datbuf = 0;
193 ops.oobbuf = readbuf;
194 err = mtd->read_oob(mtd, addr, &ops);
195 if (err || ops.oobretlen != use_len) {
196 printk(PRINT_PREF "error: readoob failed at %#llx\n",
197 (long long)addr);
198 errcnt += 1;
199 return err ? err : -1;
200 }
201 if (memcmp(readbuf, writebuf, use_len)) {
202 printk(PRINT_PREF "error: verify failed at %#llx\n",
203 (long long)addr);
204 errcnt += 1;
205 if (errcnt > 1000) {
206 printk(PRINT_PREF "error: too many errors\n");
207 return -1;
208 }
209 }
210 if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
211 int k;
212
213 ops.mode = MTD_OOB_AUTO;
214 ops.len = 0;
215 ops.retlen = 0;
216 ops.ooblen = mtd->ecclayout->oobavail;
217 ops.oobretlen = 0;
218 ops.ooboffs = 0;
219 ops.datbuf = 0;
220 ops.oobbuf = readbuf;
221 err = mtd->read_oob(mtd, addr, &ops);
222 if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
223 printk(PRINT_PREF "error: readoob failed at "
224 "%#llx\n", (long long)addr);
225 errcnt += 1;
226 return err ? err : -1;
227 }
228 if (memcmp(readbuf + use_offset, writebuf, use_len)) {
229 printk(PRINT_PREF "error: verify failed at "
230 "%#llx\n", (long long)addr);
231 errcnt += 1;
232 if (errcnt > 1000) {
233 printk(PRINT_PREF "error: too many "
234 "errors\n");
235 return -1;
236 }
237 }
238 for (k = 0; k < use_offset; ++k)
239 if (readbuf[k] != 0xff) {
240 printk(PRINT_PREF "error: verify 0xff "
241 "failed at %#llx\n",
242 (long long)addr);
243 errcnt += 1;
244 if (errcnt > 1000) {
245 printk(PRINT_PREF "error: too "
246 "many errors\n");
247 return -1;
248 }
249 }
250 for (k = use_offset + use_len;
251 k < mtd->ecclayout->oobavail; ++k)
252 if (readbuf[k] != 0xff) {
253 printk(PRINT_PREF "error: verify 0xff "
254 "failed at %#llx\n",
255 (long long)addr);
256 errcnt += 1;
257 if (errcnt > 1000) {
258 printk(PRINT_PREF "error: too "
259 "many errors\n");
260 return -1;
261 }
262 }
263 }
264 if (vary_offset)
265 do_vary_offset();
266 }
267 return err;
268}
269
270static int verify_eraseblock_in_one_go(int ebnum)
271{
272 struct mtd_oob_ops ops;
273 int err = 0;
274 loff_t addr = ebnum * mtd->erasesize;
275 size_t len = mtd->ecclayout->oobavail * pgcnt;
276
277 set_random_data(writebuf, len);
278 ops.mode = MTD_OOB_AUTO;
279 ops.len = 0;
280 ops.retlen = 0;
281 ops.ooblen = len;
282 ops.oobretlen = 0;
283 ops.ooboffs = 0;
284 ops.datbuf = 0;
285 ops.oobbuf = readbuf;
286 err = mtd->read_oob(mtd, addr, &ops);
287 if (err || ops.oobretlen != len) {
288 printk(PRINT_PREF "error: readoob failed at %#llx\n",
289 (long long)addr);
290 errcnt += 1;
291 return err ? err : -1;
292 }
293 if (memcmp(readbuf, writebuf, len)) {
294 printk(PRINT_PREF "error: verify failed at %#llx\n",
295 (long long)addr);
296 errcnt += 1;
297 if (errcnt > 1000) {
298 printk(PRINT_PREF "error: too many errors\n");
299 return -1;
300 }
301 }
302
303 return err;
304}
305
306static int verify_all_eraseblocks(void)
307{
308 int err;
309 unsigned int i;
310
311 printk(PRINT_PREF "verifying all eraseblocks\n");
312 for (i = 0; i < ebcnt; ++i) {
313 if (bbt[i])
314 continue;
315 err = verify_eraseblock(i);
316 if (err)
317 return err;
318 if (i % 256 == 0)
319 printk(PRINT_PREF "verified up to eraseblock %u\n", i);
320 cond_resched();
321 }
322 printk(PRINT_PREF "verified %u eraseblocks\n", i);
323 return 0;
324}
325
326static int is_block_bad(int ebnum)
327{
328 int ret;
329 loff_t addr = ebnum * mtd->erasesize;
330
331 ret = mtd->block_isbad(mtd, addr);
332 if (ret)
333 printk(PRINT_PREF "block %d is bad\n", ebnum);
334 return ret;
335}
336
337static int scan_for_bad_eraseblocks(void)
338{
339 int i, bad = 0;
340
341 bbt = kmalloc(ebcnt, GFP_KERNEL);
342 if (!bbt) {
343 printk(PRINT_PREF "error: cannot allocate memory\n");
344 return -ENOMEM;
345 }
346 memset(bbt, 0 , ebcnt);
347
348 printk(PRINT_PREF "scanning for bad eraseblocks\n");
349 for (i = 0; i < ebcnt; ++i) {
350 bbt[i] = is_block_bad(i) ? 1 : 0;
351 if (bbt[i])
352 bad += 1;
353 cond_resched();
354 }
355 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
356 return 0;
357}
358
359static int __init mtd_oobtest_init(void)
360{
361 int err = 0;
362 unsigned int i;
363 uint64_t tmp;
364 struct mtd_oob_ops ops;
365 loff_t addr = 0, addr0;
366
367 printk(KERN_INFO "\n");
368 printk(KERN_INFO "=================================================\n");
369 printk(PRINT_PREF "MTD device: %d\n", dev);
370
371 mtd = get_mtd_device(NULL, dev);
372 if (IS_ERR(mtd)) {
373 err = PTR_ERR(mtd);
374 printk(PRINT_PREF "error: cannot get MTD device\n");
375 return err;
376 }
377
378 if (mtd->type != MTD_NANDFLASH) {
379 printk(PRINT_PREF "this test requires NAND flash\n");
380 goto out;
381 }
382
383 tmp = mtd->size;
384 do_div(tmp, mtd->erasesize);
385 ebcnt = tmp;
386 pgcnt = mtd->erasesize / mtd->writesize;
387
388 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
389 "page size %u, count of eraseblocks %u, pages per "
390 "eraseblock %u, OOB size %u\n",
391 (unsigned long long)mtd->size, mtd->erasesize,
392 mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
393
394 err = -ENOMEM;
395 mtd->erasesize = mtd->erasesize;
396 readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
397 if (!readbuf) {
398 printk(PRINT_PREF "error: cannot allocate memory\n");
399 goto out;
400 }
401 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
402 if (!writebuf) {
403 printk(PRINT_PREF "error: cannot allocate memory\n");
404 goto out;
405 }
406
407 err = scan_for_bad_eraseblocks();
408 if (err)
409 goto out;
410
411 use_offset = 0;
412 use_len = mtd->ecclayout->oobavail;
413 use_len_max = mtd->ecclayout->oobavail;
414 vary_offset = 0;
415
416 /* First test: write all OOB, read it back and verify */
417 printk(PRINT_PREF "test 1 of 5\n");
418
419 err = erase_whole_device();
420 if (err)
421 goto out;
422
423 simple_srand(1);
424 err = write_whole_device();
425 if (err)
426 goto out;
427
428 simple_srand(1);
429 err = verify_all_eraseblocks();
430 if (err)
431 goto out;
432
433 /*
434 * Second test: write all OOB, a block at a time, read it back and
435 * verify.
436 */
437 printk(PRINT_PREF "test 2 of 5\n");
438
439 err = erase_whole_device();
440 if (err)
441 goto out;
442
443 simple_srand(3);
444 err = write_whole_device();
445 if (err)
446 goto out;
447
448 /* Check all eraseblocks */
449 simple_srand(3);
450 printk(PRINT_PREF "verifying all eraseblocks\n");
451 for (i = 0; i < ebcnt; ++i) {
452 if (bbt[i])
453 continue;
454 err = verify_eraseblock_in_one_go(i);
455 if (err)
456 goto out;
457 if (i % 256 == 0)
458 printk(PRINT_PREF "verified up to eraseblock %u\n", i);
459 cond_resched();
460 }
461 printk(PRINT_PREF "verified %u eraseblocks\n", i);
462
463 /*
464 * Third test: write OOB at varying offsets and lengths, read it back
465 * and verify.
466 */
467 printk(PRINT_PREF "test 3 of 5\n");
468
469 err = erase_whole_device();
470 if (err)
471 goto out;
472
473 /* Write all eraseblocks */
474 use_offset = 0;
475 use_len = mtd->ecclayout->oobavail;
476 use_len_max = mtd->ecclayout->oobavail;
477 vary_offset = 1;
478 simple_srand(5);
479 printk(PRINT_PREF "writing OOBs of whole device\n");
480 for (i = 0; i < ebcnt; ++i) {
481 if (bbt[i])
482 continue;
483 err = write_eraseblock(i);
484 if (err)
485 goto out;
486 if (i % 256 == 0)
487 printk(PRINT_PREF "written up to eraseblock %u\n", i);
488 cond_resched();
489 }
490 printk(PRINT_PREF "written %u eraseblocks\n", i);
491
492 /* Check all eraseblocks */
493 use_offset = 0;
494 use_len = mtd->ecclayout->oobavail;
495 use_len_max = mtd->ecclayout->oobavail;
496 vary_offset = 1;
497 simple_srand(5);
498 err = verify_all_eraseblocks();
499 if (err)
500 goto out;
501
502 use_offset = 0;
503 use_len = mtd->ecclayout->oobavail;
504 use_len_max = mtd->ecclayout->oobavail;
505 vary_offset = 0;
506
507 /* Fourth test: try to write off end of device */
508 printk(PRINT_PREF "test 4 of 5\n");
509
510 err = erase_whole_device();
511 if (err)
512 goto out;
513
514 addr0 = 0;
515 for (i = 0; bbt[i] && i < ebcnt; ++i)
516 addr0 += mtd->erasesize;
517
518 /* Attempt to write off end of OOB */
519 ops.mode = MTD_OOB_AUTO;
520 ops.len = 0;
521 ops.retlen = 0;
522 ops.ooblen = 1;
523 ops.oobretlen = 0;
524 ops.ooboffs = mtd->ecclayout->oobavail;
525 ops.datbuf = 0;
526 ops.oobbuf = writebuf;
527 printk(PRINT_PREF "attempting to start write past end of OOB\n");
528 printk(PRINT_PREF "an error is expected...\n");
529 err = mtd->write_oob(mtd, addr0, &ops);
530 if (err) {
531 printk(PRINT_PREF "error occurred as expected\n");
532 err = 0;
533 } else {
534 printk(PRINT_PREF "error: can write past end of OOB\n");
535 errcnt += 1;
536 }
537
538 /* Attempt to read off end of OOB */
539 ops.mode = MTD_OOB_AUTO;
540 ops.len = 0;
541 ops.retlen = 0;
542 ops.ooblen = 1;
543 ops.oobretlen = 0;
544 ops.ooboffs = mtd->ecclayout->oobavail;
545 ops.datbuf = 0;
546 ops.oobbuf = readbuf;
547 printk(PRINT_PREF "attempting to start read past end of OOB\n");
548 printk(PRINT_PREF "an error is expected...\n");
549 err = mtd->read_oob(mtd, addr0, &ops);
550 if (err) {
551 printk(PRINT_PREF "error occurred as expected\n");
552 err = 0;
553 } else {
554 printk(PRINT_PREF "error: can read past end of OOB\n");
555 errcnt += 1;
556 }
557
558 if (bbt[ebcnt - 1])
559 printk(PRINT_PREF "skipping end of device tests because last "
560 "block is bad\n");
561 else {
562 /* Attempt to write off end of device */
563 ops.mode = MTD_OOB_AUTO;
564 ops.len = 0;
565 ops.retlen = 0;
566 ops.ooblen = mtd->ecclayout->oobavail + 1;
567 ops.oobretlen = 0;
568 ops.ooboffs = 0;
569 ops.datbuf = 0;
570 ops.oobbuf = writebuf;
571 printk(PRINT_PREF "attempting to write past end of device\n");
572 printk(PRINT_PREF "an error is expected...\n");
573 err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops);
574 if (err) {
575 printk(PRINT_PREF "error occurred as expected\n");
576 err = 0;
577 } else {
578 printk(PRINT_PREF "error: wrote past end of device\n");
579 errcnt += 1;
580 }
581
582 /* Attempt to read off end of device */
583 ops.mode = MTD_OOB_AUTO;
584 ops.len = 0;
585 ops.retlen = 0;
586 ops.ooblen = mtd->ecclayout->oobavail + 1;
587 ops.oobretlen = 0;
588 ops.ooboffs = 0;
589 ops.datbuf = 0;
590 ops.oobbuf = readbuf;
591 printk(PRINT_PREF "attempting to read past end of device\n");
592 printk(PRINT_PREF "an error is expected...\n");
593 err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops);
594 if (err) {
595 printk(PRINT_PREF "error occurred as expected\n");
596 err = 0;
597 } else {
598 printk(PRINT_PREF "error: read past end of device\n");
599 errcnt += 1;
600 }
601
602 err = erase_eraseblock(ebcnt - 1);
603 if (err)
604 goto out;
605
606 /* Attempt to write off end of device */
607 ops.mode = MTD_OOB_AUTO;
608 ops.len = 0;
609 ops.retlen = 0;
610 ops.ooblen = mtd->ecclayout->oobavail;
611 ops.oobretlen = 0;
612 ops.ooboffs = 1;
613 ops.datbuf = 0;
614 ops.oobbuf = writebuf;
615 printk(PRINT_PREF "attempting to write past end of device\n");
616 printk(PRINT_PREF "an error is expected...\n");
617 err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops);
618 if (err) {
619 printk(PRINT_PREF "error occurred as expected\n");
620 err = 0;
621 } else {
622 printk(PRINT_PREF "error: wrote past end of device\n");
623 errcnt += 1;
624 }
625
626 /* Attempt to read off end of device */
627 ops.mode = MTD_OOB_AUTO;
628 ops.len = 0;
629 ops.retlen = 0;
630 ops.ooblen = mtd->ecclayout->oobavail;
631 ops.oobretlen = 0;
632 ops.ooboffs = 1;
633 ops.datbuf = 0;
634 ops.oobbuf = readbuf;
635 printk(PRINT_PREF "attempting to read past end of device\n");
636 printk(PRINT_PREF "an error is expected...\n");
637 err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops);
638 if (err) {
639 printk(PRINT_PREF "error occurred as expected\n");
640 err = 0;
641 } else {
642 printk(PRINT_PREF "error: read past end of device\n");
643 errcnt += 1;
644 }
645 }
646
647 /* Fifth test: write / read across block boundaries */
648 printk(PRINT_PREF "test 5 of 5\n");
649
650 /* Erase all eraseblocks */
651 err = erase_whole_device();
652 if (err)
653 goto out;
654
655 /* Write all eraseblocks */
656 simple_srand(11);
657 printk(PRINT_PREF "writing OOBs of whole device\n");
658 for (i = 0; i < ebcnt - 1; ++i) {
659 int cnt = 2;
660 int pg;
661 size_t sz = mtd->ecclayout->oobavail;
662 if (bbt[i] || bbt[i + 1])
663 continue;
664 addr = (i + 1) * mtd->erasesize - mtd->writesize;
665 for (pg = 0; pg < cnt; ++pg) {
666 set_random_data(writebuf, sz);
667 ops.mode = MTD_OOB_AUTO;
668 ops.len = 0;
669 ops.retlen = 0;
670 ops.ooblen = sz;
671 ops.oobretlen = 0;
672 ops.ooboffs = 0;
673 ops.datbuf = 0;
674 ops.oobbuf = writebuf;
675 err = mtd->write_oob(mtd, addr, &ops);
676 if (err)
677 goto out;
678 if (i % 256 == 0)
679 printk(PRINT_PREF "written up to eraseblock "
680 "%u\n", i);
681 cond_resched();
682 addr += mtd->writesize;
683 }
684 }
685 printk(PRINT_PREF "written %u eraseblocks\n", i);
686
687 /* Check all eraseblocks */
688 simple_srand(11);
689 printk(PRINT_PREF "verifying all eraseblocks\n");
690 for (i = 0; i < ebcnt - 1; ++i) {
691 if (bbt[i] || bbt[i + 1])
692 continue;
693 set_random_data(writebuf, mtd->ecclayout->oobavail * 2);
694 addr = (i + 1) * mtd->erasesize - mtd->writesize;
695 ops.mode = MTD_OOB_AUTO;
696 ops.len = 0;
697 ops.retlen = 0;
698 ops.ooblen = mtd->ecclayout->oobavail * 2;
699 ops.oobretlen = 0;
700 ops.ooboffs = 0;
701 ops.datbuf = 0;
702 ops.oobbuf = readbuf;
703 err = mtd->read_oob(mtd, addr, &ops);
704 if (err)
705 goto out;
706 if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
707 printk(PRINT_PREF "error: verify failed at %#llx\n",
708 (long long)addr);
709 errcnt += 1;
710 if (errcnt > 1000) {
711 printk(PRINT_PREF "error: too many errors\n");
712 goto out;
713 }
714 }
715 if (i % 256 == 0)
716 printk(PRINT_PREF "verified up to eraseblock %u\n", i);
717 cond_resched();
718 }
719 printk(PRINT_PREF "verified %u eraseblocks\n", i);
720
721 printk(PRINT_PREF "finished with %d errors\n", errcnt);
722out:
723 kfree(bbt);
724 kfree(writebuf);
725 kfree(readbuf);
726 put_mtd_device(mtd);
727 if (err)
728 printk(PRINT_PREF "error %d occurred\n", err);
729 printk(KERN_INFO "=================================================\n");
730 return err;
731}
732module_init(mtd_oobtest_init);
733
734static void __exit mtd_oobtest_exit(void)
735{
736 return;
737}
738module_exit(mtd_oobtest_exit);
739
740MODULE_DESCRIPTION("Out-of-band test module");
741MODULE_AUTHOR("Adrian Hunter");
742MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c
new file mode 100644
index 000000000000..9648818b9e2c
--- /dev/null
+++ b/drivers/mtd/tests/mtd_pagetest.c
@@ -0,0 +1,632 @@
1/*
2 * Copyright (C) 2006-2008 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; see the file COPYING. If not, write to the Free Software
15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 * Test page read and write on MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
22#include <asm/div64.h>
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/err.h>
27#include <linux/mtd/mtd.h>
28#include <linux/sched.h>
29
30#define PRINT_PREF KERN_INFO "mtd_pagetest: "
31
32static int dev;
33module_param(dev, int, S_IRUGO);
34MODULE_PARM_DESC(dev, "MTD device number to use");
35
36static struct mtd_info *mtd;
37static unsigned char *twopages;
38static unsigned char *writebuf;
39static unsigned char *boundary;
40static unsigned char *bbt;
41
42static int pgsize;
43static int bufsize;
44static int ebcnt;
45static int pgcnt;
46static int errcnt;
47static unsigned long next = 1;
48
49static inline unsigned int simple_rand(void)
50{
51 next = next * 1103515245 + 12345;
52 return (unsigned int)((next / 65536) % 32768);
53}
54
55static inline void simple_srand(unsigned long seed)
56{
57 next = seed;
58}
59
60static void set_random_data(unsigned char *buf, size_t len)
61{
62 size_t i;
63
64 for (i = 0; i < len; ++i)
65 buf[i] = simple_rand();
66}
67
68static int erase_eraseblock(int ebnum)
69{
70 int err;
71 struct erase_info ei;
72 loff_t addr = ebnum * mtd->erasesize;
73
74 memset(&ei, 0, sizeof(struct erase_info));
75 ei.mtd = mtd;
76 ei.addr = addr;
77 ei.len = mtd->erasesize;
78
79 err = mtd->erase(mtd, &ei);
80 if (err) {
81 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
82 return err;
83 }
84
85 if (ei.state == MTD_ERASE_FAILED) {
86 printk(PRINT_PREF "some erase error occurred at EB %d\n",
87 ebnum);
88 return -EIO;
89 }
90
91 return 0;
92}
93
94static int write_eraseblock(int ebnum)
95{
96 int err = 0;
97 size_t written = 0;
98 loff_t addr = ebnum * mtd->erasesize;
99
100 set_random_data(writebuf, mtd->erasesize);
101 cond_resched();
102 err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf);
103 if (err || written != mtd->erasesize)
104 printk(PRINT_PREF "error: write failed at %#llx\n",
105 (long long)addr);
106
107 return err;
108}
109
110static int verify_eraseblock(int ebnum)
111{
112 uint32_t j;
113 size_t read = 0;
114 int err = 0, i;
115 loff_t addr0, addrn;
116 loff_t addr = ebnum * mtd->erasesize;
117
118 addr0 = 0;
119 for (i = 0; bbt[i] && i < ebcnt; ++i)
120 addr0 += mtd->erasesize;
121
122 addrn = mtd->size;
123 for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i)
124 addrn -= mtd->erasesize;
125
126 set_random_data(writebuf, mtd->erasesize);
127 for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
128 /* Do a read to set the internal dataRAMs to different data */
129 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
130 if (err == -EUCLEAN)
131 err = 0;
132 if (err || read != bufsize) {
133 printk(PRINT_PREF "error: read failed at %#llx\n",
134 (long long)addr0);
135 return err;
136 }
137 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
138 if (err == -EUCLEAN)
139 err = 0;
140 if (err || read != bufsize) {
141 printk(PRINT_PREF "error: read failed at %#llx\n",
142 (long long)(addrn - bufsize));
143 return err;
144 }
145 memset(twopages, 0, bufsize);
146 read = 0;
147 err = mtd->read(mtd, addr, bufsize, &read, twopages);
148 if (err == -EUCLEAN)
149 err = 0;
150 if (err || read != bufsize) {
151 printk(PRINT_PREF "error: read failed at %#llx\n",
152 (long long)addr);
153 break;
154 }
155 if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
156 printk(PRINT_PREF "error: verify failed at %#llx\n",
157 (long long)addr);
158 errcnt += 1;
159 }
160 }
161 /* Check boundary between eraseblocks */
162 if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
163 unsigned long oldnext = next;
164 /* Do a read to set the internal dataRAMs to different data */
165 err = mtd->read(mtd, addr0, bufsize, &read, twopages);
166 if (err == -EUCLEAN)
167 err = 0;
168 if (err || read != bufsize) {
169 printk(PRINT_PREF "error: read failed at %#llx\n",
170 (long long)addr0);
171 return err;
172 }
173 err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages);
174 if (err == -EUCLEAN)
175 err = 0;
176 if (err || read != bufsize) {
177 printk(PRINT_PREF "error: read failed at %#llx\n",
178 (long long)(addrn - bufsize));
179 return err;
180 }
181 memset(twopages, 0, bufsize);
182 read = 0;
183 err = mtd->read(mtd, addr, bufsize, &read, twopages);
184 if (err == -EUCLEAN)
185 err = 0;
186 if (err || read != bufsize) {
187 printk(PRINT_PREF "error: read failed at %#llx\n",
188 (long long)addr);
189 return err;
190 }
191 memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
192 set_random_data(boundary + pgsize, pgsize);
193 if (memcmp(twopages, boundary, bufsize)) {
194 printk(PRINT_PREF "error: verify failed at %#llx\n",
195 (long long)addr);
196 errcnt += 1;
197 }
198 next = oldnext;
199 }
200 return err;
201}
202
203static int crosstest(void)
204{
205 size_t read = 0;
206 int err = 0, i;
207 loff_t addr, addr0, addrn;
208 unsigned char *pp1, *pp2, *pp3, *pp4;
209
210 printk(PRINT_PREF "crosstest\n");
211 pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
212 if (!pp1) {
213 printk(PRINT_PREF "error: cannot allocate memory\n");
214 return -ENOMEM;
215 }
216 pp2 = pp1 + pgsize;
217 pp3 = pp2 + pgsize;
218 pp4 = pp3 + pgsize;
219 memset(pp1, 0, pgsize * 4);
220
221 addr0 = 0;
222 for (i = 0; bbt[i] && i < ebcnt; ++i)
223 addr0 += mtd->erasesize;
224
225 addrn = mtd->size;
226 for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i)
227 addrn -= mtd->erasesize;
228
229 /* Read 2nd-to-last page to pp1 */
230 read = 0;
231 addr = addrn - pgsize - pgsize;
232 err = mtd->read(mtd, addr, pgsize, &read, pp1);
233 if (err == -EUCLEAN)
234 err = 0;
235 if (err || read != pgsize) {
236 printk(PRINT_PREF "error: read failed at %#llx\n",
237 (long long)addr);
238 kfree(pp1);
239 return err;
240 }
241
242 /* Read 3rd-to-last page to pp1 */
243 read = 0;
244 addr = addrn - pgsize - pgsize - pgsize;
245 err = mtd->read(mtd, addr, pgsize, &read, pp1);
246 if (err == -EUCLEAN)
247 err = 0;
248 if (err || read != pgsize) {
249 printk(PRINT_PREF "error: read failed at %#llx\n",
250 (long long)addr);
251 kfree(pp1);
252 return err;
253 }
254
255 /* Read first page to pp2 */
256 read = 0;
257 addr = addr0;
258 printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
259 err = mtd->read(mtd, addr, pgsize, &read, pp2);
260 if (err == -EUCLEAN)
261 err = 0;
262 if (err || read != pgsize) {
263 printk(PRINT_PREF "error: read failed at %#llx\n",
264 (long long)addr);
265 kfree(pp1);
266 return err;
267 }
268
269 /* Read last page to pp3 */
270 read = 0;
271 addr = addrn - pgsize;
272 printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
273 err = mtd->read(mtd, addr, pgsize, &read, pp3);
274 if (err == -EUCLEAN)
275 err = 0;
276 if (err || read != pgsize) {
277 printk(PRINT_PREF "error: read failed at %#llx\n",
278 (long long)addr);
279 kfree(pp1);
280 return err;
281 }
282
283 /* Read first page again to pp4 */
284 read = 0;
285 addr = addr0;
286 printk(PRINT_PREF "reading page at %#llx\n", (long long)addr);
287 err = mtd->read(mtd, addr, pgsize, &read, pp4);
288 if (err == -EUCLEAN)
289 err = 0;
290 if (err || read != pgsize) {
291 printk(PRINT_PREF "error: read failed at %#llx\n",
292 (long long)addr);
293 kfree(pp1);
294 return err;
295 }
296
297 /* pp2 and pp4 should be the same */
298 printk(PRINT_PREF "verifying pages read at %#llx match\n",
299 (long long)addr0);
300 if (memcmp(pp2, pp4, pgsize)) {
301 printk(PRINT_PREF "verify failed!\n");
302 errcnt += 1;
303 } else if (!err)
304 printk(PRINT_PREF "crosstest ok\n");
305 kfree(pp1);
306 return err;
307}
308
309static int erasecrosstest(void)
310{
311 size_t read = 0, written = 0;
312 int err = 0, i, ebnum, ok = 1, ebnum2;
313 loff_t addr0;
314 char *readbuf = twopages;
315
316 printk(PRINT_PREF "erasecrosstest\n");
317
318 ebnum = 0;
319 addr0 = 0;
320 for (i = 0; bbt[i] && i < ebcnt; ++i) {
321 addr0 += mtd->erasesize;
322 ebnum += 1;
323 }
324
325 ebnum2 = ebcnt - 1;
326 while (ebnum2 && bbt[ebnum2])
327 ebnum2 -= 1;
328
329 printk(PRINT_PREF "erasing block %d\n", ebnum);
330 err = erase_eraseblock(ebnum);
331 if (err)
332 return err;
333
334 printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
335 set_random_data(writebuf, pgsize);
336 strcpy(writebuf, "There is no data like this!");
337 err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
338 if (err || written != pgsize) {
339 printk(PRINT_PREF "error: write failed at %#llx\n",
340 (long long)addr0);
341 return err ? err : -1;
342 }
343
344 printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
345 memset(readbuf, 0, pgsize);
346 err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
347 if (err == -EUCLEAN)
348 err = 0;
349 if (err || read != pgsize) {
350 printk(PRINT_PREF "error: read failed at %#llx\n",
351 (long long)addr0);
352 return err ? err : -1;
353 }
354
355 printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
356 if (memcmp(writebuf, readbuf, pgsize)) {
357 printk(PRINT_PREF "verify failed!\n");
358 errcnt += 1;
359 ok = 0;
360 return err;
361 }
362
363 printk(PRINT_PREF "erasing block %d\n", ebnum);
364 err = erase_eraseblock(ebnum);
365 if (err)
366 return err;
367
368 printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
369 set_random_data(writebuf, pgsize);
370 strcpy(writebuf, "There is no data like this!");
371 err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
372 if (err || written != pgsize) {
373 printk(PRINT_PREF "error: write failed at %#llx\n",
374 (long long)addr0);
375 return err ? err : -1;
376 }
377
378 printk(PRINT_PREF "erasing block %d\n", ebnum2);
379 err = erase_eraseblock(ebnum2);
380 if (err)
381 return err;
382
383 printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
384 memset(readbuf, 0, pgsize);
385 err = mtd->read(mtd, addr0, pgsize, &read, readbuf);
386 if (err == -EUCLEAN)
387 err = 0;
388 if (err || read != pgsize) {
389 printk(PRINT_PREF "error: read failed at %#llx\n",
390 (long long)addr0);
391 return err ? err : -1;
392 }
393
394 printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum);
395 if (memcmp(writebuf, readbuf, pgsize)) {
396 printk(PRINT_PREF "verify failed!\n");
397 errcnt += 1;
398 ok = 0;
399 }
400
401 if (ok && !err)
402 printk(PRINT_PREF "erasecrosstest ok\n");
403 return err;
404}
405
406static int erasetest(void)
407{
408 size_t read = 0, written = 0;
409 int err = 0, i, ebnum, ok = 1;
410 loff_t addr0;
411
412 printk(PRINT_PREF "erasetest\n");
413
414 ebnum = 0;
415 addr0 = 0;
416 for (i = 0; bbt[i] && i < ebcnt; ++i) {
417 addr0 += mtd->erasesize;
418 ebnum += 1;
419 }
420
421 printk(PRINT_PREF "erasing block %d\n", ebnum);
422 err = erase_eraseblock(ebnum);
423 if (err)
424 return err;
425
426 printk(PRINT_PREF "writing 1st page of block %d\n", ebnum);
427 set_random_data(writebuf, pgsize);
428 err = mtd->write(mtd, addr0, pgsize, &written, writebuf);
429 if (err || written != pgsize) {
430 printk(PRINT_PREF "error: write failed at %#llx\n",
431 (long long)addr0);
432 return err ? err : -1;
433 }
434
435 printk(PRINT_PREF "erasing block %d\n", ebnum);
436 err = erase_eraseblock(ebnum);
437 if (err)
438 return err;
439
440 printk(PRINT_PREF "reading 1st page of block %d\n", ebnum);
441 err = mtd->read(mtd, addr0, pgsize, &read, twopages);
442 if (err == -EUCLEAN)
443 err = 0;
444 if (err || read != pgsize) {
445 printk(PRINT_PREF "error: read failed at %#llx\n",
446 (long long)addr0);
447 return err ? err : -1;
448 }
449
450 printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n",
451 ebnum);
452 for (i = 0; i < pgsize; ++i)
453 if (twopages[i] != 0xff) {
454 printk(PRINT_PREF "verifying all 0xff failed at %d\n",
455 i);
456 errcnt += 1;
457 ok = 0;
458 break;
459 }
460
461 if (ok && !err)
462 printk(PRINT_PREF "erasetest ok\n");
463
464 return err;
465}
466
467static int is_block_bad(int ebnum)
468{
469 loff_t addr = ebnum * mtd->erasesize;
470 int ret;
471
472 ret = mtd->block_isbad(mtd, addr);
473 if (ret)
474 printk(PRINT_PREF "block %d is bad\n", ebnum);
475 return ret;
476}
477
478static int scan_for_bad_eraseblocks(void)
479{
480 int i, bad = 0;
481
482 bbt = kmalloc(ebcnt, GFP_KERNEL);
483 if (!bbt) {
484 printk(PRINT_PREF "error: cannot allocate memory\n");
485 return -ENOMEM;
486 }
487 memset(bbt, 0 , ebcnt);
488
489 printk(PRINT_PREF "scanning for bad eraseblocks\n");
490 for (i = 0; i < ebcnt; ++i) {
491 bbt[i] = is_block_bad(i) ? 1 : 0;
492 if (bbt[i])
493 bad += 1;
494 cond_resched();
495 }
496 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
497 return 0;
498}
499
500static int __init mtd_pagetest_init(void)
501{
502 int err = 0;
503 uint64_t tmp;
504 uint32_t i;
505
506 printk(KERN_INFO "\n");
507 printk(KERN_INFO "=================================================\n");
508 printk(PRINT_PREF "MTD device: %d\n", dev);
509
510 mtd = get_mtd_device(NULL, dev);
511 if (IS_ERR(mtd)) {
512 err = PTR_ERR(mtd);
513 printk(PRINT_PREF "error: cannot get MTD device\n");
514 return err;
515 }
516
517 if (mtd->type != MTD_NANDFLASH) {
518 printk(PRINT_PREF "this test requires NAND flash\n");
519 goto out;
520 }
521
522 tmp = mtd->size;
523 do_div(tmp, mtd->erasesize);
524 ebcnt = tmp;
525 pgcnt = mtd->erasesize / mtd->writesize;
526
527 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
528 "page size %u, count of eraseblocks %u, pages per "
529 "eraseblock %u, OOB size %u\n",
530 (unsigned long long)mtd->size, mtd->erasesize,
531 pgsize, ebcnt, pgcnt, mtd->oobsize);
532
533 err = -ENOMEM;
534 bufsize = pgsize * 2;
535 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
536 if (!writebuf) {
537 printk(PRINT_PREF "error: cannot allocate memory\n");
538 goto out;
539 }
540 twopages = kmalloc(bufsize, GFP_KERNEL);
541 if (!twopages) {
542 printk(PRINT_PREF "error: cannot allocate memory\n");
543 goto out;
544 }
545 boundary = kmalloc(bufsize, GFP_KERNEL);
546 if (!boundary) {
547 printk(PRINT_PREF "error: cannot allocate memory\n");
548 goto out;
549 }
550
551 err = scan_for_bad_eraseblocks();
552 if (err)
553 goto out;
554
555 /* Erase all eraseblocks */
556 printk(PRINT_PREF "erasing whole device\n");
557 for (i = 0; i < ebcnt; ++i) {
558 if (bbt[i])
559 continue;
560 err = erase_eraseblock(i);
561 if (err)
562 goto out;
563 cond_resched();
564 }
565 printk(PRINT_PREF "erased %u eraseblocks\n", i);
566
567 /* Write all eraseblocks */
568 simple_srand(1);
569 printk(PRINT_PREF "writing whole device\n");
570 for (i = 0; i < ebcnt; ++i) {
571 if (bbt[i])
572 continue;
573 err = write_eraseblock(i);
574 if (err)
575 goto out;
576 if (i % 256 == 0)
577 printk(PRINT_PREF "written up to eraseblock %u\n", i);
578 cond_resched();
579 }
580 printk(PRINT_PREF "written %u eraseblocks\n", i);
581
582 /* Check all eraseblocks */
583 simple_srand(1);
584 printk(PRINT_PREF "verifying all eraseblocks\n");
585 for (i = 0; i < ebcnt; ++i) {
586 if (bbt[i])
587 continue;
588 err = verify_eraseblock(i);
589 if (err)
590 goto out;
591 if (i % 256 == 0)
592 printk(PRINT_PREF "verified up to eraseblock %u\n", i);
593 cond_resched();
594 }
595 printk(PRINT_PREF "verified %u eraseblocks\n", i);
596
597 err = crosstest();
598 if (err)
599 goto out;
600
601 err = erasecrosstest();
602 if (err)
603 goto out;
604
605 err = erasetest();
606 if (err)
607 goto out;
608
609 printk(PRINT_PREF "finished with %d errors\n", errcnt);
610out:
611
612 kfree(bbt);
613 kfree(boundary);
614 kfree(twopages);
615 kfree(writebuf);
616 put_mtd_device(mtd);
617 if (err)
618 printk(PRINT_PREF "error %d occurred\n", err);
619 printk(KERN_INFO "=================================================\n");
620 return err;
621}
622module_init(mtd_pagetest_init);
623
624static void __exit mtd_pagetest_exit(void)
625{
626 return;
627}
628module_exit(mtd_pagetest_exit);
629
630MODULE_DESCRIPTION("NAND page test");
631MODULE_AUTHOR("Adrian Hunter");
632MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c
new file mode 100644
index 000000000000..645e77fdc63d
--- /dev/null
+++ b/drivers/mtd/tests/mtd_readtest.c
@@ -0,0 +1,253 @@
1/*
2 * Copyright (C) 2006-2008 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; see the file COPYING. If not, write to the Free Software
15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 * Check MTD device read.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/err.h>
26#include <linux/mtd/mtd.h>
27#include <linux/sched.h>
28
29#define PRINT_PREF KERN_INFO "mtd_readtest: "
30
31static int dev;
32module_param(dev, int, S_IRUGO);
33MODULE_PARM_DESC(dev, "MTD device number to use");
34
35static struct mtd_info *mtd;
36static unsigned char *iobuf;
37static unsigned char *iobuf1;
38static unsigned char *bbt;
39
40static int pgsize;
41static int ebcnt;
42static int pgcnt;
43
44static int read_eraseblock_by_page(int ebnum)
45{
46 size_t read = 0;
47 int i, ret, err = 0;
48 loff_t addr = ebnum * mtd->erasesize;
49 void *buf = iobuf;
50 void *oobbuf = iobuf1;
51
52 for (i = 0; i < pgcnt; i++) {
53 memset(buf, 0 , pgcnt);
54 ret = mtd->read(mtd, addr, pgsize, &read, buf);
55 if (ret == -EUCLEAN)
56 ret = 0;
57 if (ret || read != pgsize) {
58 printk(PRINT_PREF "error: read failed at %#llx\n",
59 (long long)addr);
60 if (!err)
61 err = ret;
62 if (!err)
63 err = -EINVAL;
64 }
65 if (mtd->oobsize) {
66 struct mtd_oob_ops ops;
67
68 ops.mode = MTD_OOB_PLACE;
69 ops.len = 0;
70 ops.retlen = 0;
71 ops.ooblen = mtd->oobsize;
72 ops.oobretlen = 0;
73 ops.ooboffs = 0;
74 ops.datbuf = 0;
75 ops.oobbuf = oobbuf;
76 ret = mtd->read_oob(mtd, addr, &ops);
77 if (ret || ops.oobretlen != mtd->oobsize) {
78 printk(PRINT_PREF "error: read oob failed at "
79 "%#llx\n", (long long)addr);
80 if (!err)
81 err = ret;
82 if (!err)
83 err = -EINVAL;
84 }
85 oobbuf += mtd->oobsize;
86 }
87 addr += pgsize;
88 buf += pgsize;
89 }
90
91 return err;
92}
93
94static void dump_eraseblock(int ebnum)
95{
96 int i, j, n;
97 char line[128];
98 int pg, oob;
99
100 printk(PRINT_PREF "dumping eraseblock %d\n", ebnum);
101 n = mtd->erasesize;
102 for (i = 0; i < n;) {
103 char *p = line;
104
105 p += sprintf(p, "%05x: ", i);
106 for (j = 0; j < 32 && i < n; j++, i++)
107 p += sprintf(p, "%02x", (unsigned int)iobuf[i]);
108 printk(KERN_CRIT "%s\n", line);
109 cond_resched();
110 }
111 if (!mtd->oobsize)
112 return;
113 printk(PRINT_PREF "dumping oob from eraseblock %d\n", ebnum);
114 n = mtd->oobsize;
115 for (pg = 0, i = 0; pg < pgcnt; pg++)
116 for (oob = 0; oob < n;) {
117 char *p = line;
118
119 p += sprintf(p, "%05x: ", i);
120 for (j = 0; j < 32 && oob < n; j++, oob++, i++)
121 p += sprintf(p, "%02x",
122 (unsigned int)iobuf1[i]);
123 printk(KERN_CRIT "%s\n", line);
124 cond_resched();
125 }
126}
127
128static int is_block_bad(int ebnum)
129{
130 loff_t addr = ebnum * mtd->erasesize;
131 int ret;
132
133 ret = mtd->block_isbad(mtd, addr);
134 if (ret)
135 printk(PRINT_PREF "block %d is bad\n", ebnum);
136 return ret;
137}
138
139static int scan_for_bad_eraseblocks(void)
140{
141 int i, bad = 0;
142
143 bbt = kmalloc(ebcnt, GFP_KERNEL);
144 if (!bbt) {
145 printk(PRINT_PREF "error: cannot allocate memory\n");
146 return -ENOMEM;
147 }
148 memset(bbt, 0 , ebcnt);
149
150 printk(PRINT_PREF "scanning for bad eraseblocks\n");
151 for (i = 0; i < ebcnt; ++i) {
152 bbt[i] = is_block_bad(i) ? 1 : 0;
153 if (bbt[i])
154 bad += 1;
155 cond_resched();
156 }
157 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
158 return 0;
159}
160
161static int __init mtd_readtest_init(void)
162{
163 uint64_t tmp;
164 int err, i;
165
166 printk(KERN_INFO "\n");
167 printk(KERN_INFO "=================================================\n");
168 printk(PRINT_PREF "MTD device: %d\n", dev);
169
170 mtd = get_mtd_device(NULL, dev);
171 if (IS_ERR(mtd)) {
172 err = PTR_ERR(mtd);
173 printk(PRINT_PREF "error: Cannot get MTD device\n");
174 return err;
175 }
176
177 if (mtd->writesize == 1) {
178 printk(PRINT_PREF "not NAND flash, assume page size is 512 "
179 "bytes.\n");
180 pgsize = 512;
181 } else
182 pgsize = mtd->writesize;
183
184 tmp = mtd->size;
185 do_div(tmp, mtd->erasesize);
186 ebcnt = tmp;
187 pgcnt = mtd->erasesize / mtd->writesize;
188
189 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
190 "page size %u, count of eraseblocks %u, pages per "
191 "eraseblock %u, OOB size %u\n",
192 (unsigned long long)mtd->size, mtd->erasesize,
193 pgsize, ebcnt, pgcnt, mtd->oobsize);
194
195 err = -ENOMEM;
196 iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
197 if (!iobuf) {
198 printk(PRINT_PREF "error: cannot allocate memory\n");
199 goto out;
200 }
201 iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
202 if (!iobuf1) {
203 printk(PRINT_PREF "error: cannot allocate memory\n");
204 goto out;
205 }
206
207 err = scan_for_bad_eraseblocks();
208 if (err)
209 goto out;
210
211 /* Read all eraseblocks 1 page at a time */
212 printk(PRINT_PREF "testing page read\n");
213 for (i = 0; i < ebcnt; ++i) {
214 int ret;
215
216 if (bbt[i])
217 continue;
218 ret = read_eraseblock_by_page(i);
219 if (ret) {
220 dump_eraseblock(i);
221 if (!err)
222 err = ret;
223 }
224 cond_resched();
225 }
226
227 if (err)
228 printk(PRINT_PREF "finished with errors\n");
229 else
230 printk(PRINT_PREF "finished\n");
231
232out:
233
234 kfree(iobuf);
235 kfree(iobuf1);
236 kfree(bbt);
237 put_mtd_device(mtd);
238 if (err)
239 printk(PRINT_PREF "error %d occurred\n", err);
240 printk(KERN_INFO "=================================================\n");
241 return err;
242}
243module_init(mtd_readtest_init);
244
245static void __exit mtd_readtest_exit(void)
246{
247 return;
248}
249module_exit(mtd_readtest_exit);
250
251MODULE_DESCRIPTION("Read test module");
252MODULE_AUTHOR("Adrian Hunter");
253MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c
new file mode 100644
index 000000000000..141363a7e805
--- /dev/null
+++ b/drivers/mtd/tests/mtd_speedtest.c
@@ -0,0 +1,502 @@
1/*
2 * Copyright (C) 2007 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; see the file COPYING. If not, write to the Free Software
15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 * Test read and write speed of a MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/err.h>
26#include <linux/mtd/mtd.h>
27#include <linux/sched.h>
28
29#define PRINT_PREF KERN_INFO "mtd_speedtest: "
30
31static int dev;
32module_param(dev, int, S_IRUGO);
33MODULE_PARM_DESC(dev, "MTD device number to use");
34
35static struct mtd_info *mtd;
36static unsigned char *iobuf;
37static unsigned char *bbt;
38
39static int pgsize;
40static int ebcnt;
41static int pgcnt;
42static int goodebcnt;
43static struct timeval start, finish;
44static unsigned long next = 1;
45
46static inline unsigned int simple_rand(void)
47{
48 next = next * 1103515245 + 12345;
49 return (unsigned int)((next / 65536) % 32768);
50}
51
52static inline void simple_srand(unsigned long seed)
53{
54 next = seed;
55}
56
57static void set_random_data(unsigned char *buf, size_t len)
58{
59 size_t i;
60
61 for (i = 0; i < len; ++i)
62 buf[i] = simple_rand();
63}
64
65static int erase_eraseblock(int ebnum)
66{
67 int err;
68 struct erase_info ei;
69 loff_t addr = ebnum * mtd->erasesize;
70
71 memset(&ei, 0, sizeof(struct erase_info));
72 ei.mtd = mtd;
73 ei.addr = addr;
74 ei.len = mtd->erasesize;
75
76 err = mtd->erase(mtd, &ei);
77 if (err) {
78 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
79 return err;
80 }
81
82 if (ei.state == MTD_ERASE_FAILED) {
83 printk(PRINT_PREF "some erase error occurred at EB %d\n",
84 ebnum);
85 return -EIO;
86 }
87
88 return 0;
89}
90
91static int erase_whole_device(void)
92{
93 int err;
94 unsigned int i;
95
96 for (i = 0; i < ebcnt; ++i) {
97 if (bbt[i])
98 continue;
99 err = erase_eraseblock(i);
100 if (err)
101 return err;
102 cond_resched();
103 }
104 return 0;
105}
106
107static int write_eraseblock(int ebnum)
108{
109 size_t written = 0;
110 int err = 0;
111 loff_t addr = ebnum * mtd->erasesize;
112
113 err = mtd->write(mtd, addr, mtd->erasesize, &written, iobuf);
114 if (err || written != mtd->erasesize) {
115 printk(PRINT_PREF "error: write failed at %#llx\n", addr);
116 if (!err)
117 err = -EINVAL;
118 }
119
120 return err;
121}
122
123static int write_eraseblock_by_page(int ebnum)
124{
125 size_t written = 0;
126 int i, err = 0;
127 loff_t addr = ebnum * mtd->erasesize;
128 void *buf = iobuf;
129
130 for (i = 0; i < pgcnt; i++) {
131 err = mtd->write(mtd, addr, pgsize, &written, buf);
132 if (err || written != pgsize) {
133 printk(PRINT_PREF "error: write failed at %#llx\n",
134 addr);
135 if (!err)
136 err = -EINVAL;
137 break;
138 }
139 addr += pgsize;
140 buf += pgsize;
141 }
142
143 return err;
144}
145
146static int write_eraseblock_by_2pages(int ebnum)
147{
148 size_t written = 0, sz = pgsize * 2;
149 int i, n = pgcnt / 2, err = 0;
150 loff_t addr = ebnum * mtd->erasesize;
151 void *buf = iobuf;
152
153 for (i = 0; i < n; i++) {
154 err = mtd->write(mtd, addr, sz, &written, buf);
155 if (err || written != sz) {
156 printk(PRINT_PREF "error: write failed at %#llx\n",
157 addr);
158 if (!err)
159 err = -EINVAL;
160 return err;
161 }
162 addr += sz;
163 buf += sz;
164 }
165 if (pgcnt % 2) {
166 err = mtd->write(mtd, addr, pgsize, &written, buf);
167 if (err || written != pgsize) {
168 printk(PRINT_PREF "error: write failed at %#llx\n",
169 addr);
170 if (!err)
171 err = -EINVAL;
172 }
173 }
174
175 return err;
176}
177
178static int read_eraseblock(int ebnum)
179{
180 size_t read = 0;
181 int err = 0;
182 loff_t addr = ebnum * mtd->erasesize;
183
184 err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf);
185 /* Ignore corrected ECC errors */
186 if (err == -EUCLEAN)
187 err = 0;
188 if (err || read != mtd->erasesize) {
189 printk(PRINT_PREF "error: read failed at %#llx\n", addr);
190 if (!err)
191 err = -EINVAL;
192 }
193
194 return err;
195}
196
197static int read_eraseblock_by_page(int ebnum)
198{
199 size_t read = 0;
200 int i, err = 0;
201 loff_t addr = ebnum * mtd->erasesize;
202 void *buf = iobuf;
203
204 for (i = 0; i < pgcnt; i++) {
205 err = mtd->read(mtd, addr, pgsize, &read, buf);
206 /* Ignore corrected ECC errors */
207 if (err == -EUCLEAN)
208 err = 0;
209 if (err || read != pgsize) {
210 printk(PRINT_PREF "error: read failed at %#llx\n",
211 addr);
212 if (!err)
213 err = -EINVAL;
214 break;
215 }
216 addr += pgsize;
217 buf += pgsize;
218 }
219
220 return err;
221}
222
223static int read_eraseblock_by_2pages(int ebnum)
224{
225 size_t read = 0, sz = pgsize * 2;
226 int i, n = pgcnt / 2, err = 0;
227 loff_t addr = ebnum * mtd->erasesize;
228 void *buf = iobuf;
229
230 for (i = 0; i < n; i++) {
231 err = mtd->read(mtd, addr, sz, &read, buf);
232 /* Ignore corrected ECC errors */
233 if (err == -EUCLEAN)
234 err = 0;
235 if (err || read != sz) {
236 printk(PRINT_PREF "error: read failed at %#llx\n",
237 addr);
238 if (!err)
239 err = -EINVAL;
240 return err;
241 }
242 addr += sz;
243 buf += sz;
244 }
245 if (pgcnt % 2) {
246 err = mtd->read(mtd, addr, pgsize, &read, buf);
247 /* Ignore corrected ECC errors */
248 if (err == -EUCLEAN)
249 err = 0;
250 if (err || read != pgsize) {
251 printk(PRINT_PREF "error: read failed at %#llx\n",
252 addr);
253 if (!err)
254 err = -EINVAL;
255 }
256 }
257
258 return err;
259}
260
261static int is_block_bad(int ebnum)
262{
263 loff_t addr = ebnum * mtd->erasesize;
264 int ret;
265
266 ret = mtd->block_isbad(mtd, addr);
267 if (ret)
268 printk(PRINT_PREF "block %d is bad\n", ebnum);
269 return ret;
270}
271
272static inline void start_timing(void)
273{
274 do_gettimeofday(&start);
275}
276
277static inline void stop_timing(void)
278{
279 do_gettimeofday(&finish);
280}
281
282static long calc_speed(void)
283{
284 long ms, k, speed;
285
286 ms = (finish.tv_sec - start.tv_sec) * 1000 +
287 (finish.tv_usec - start.tv_usec) / 1000;
288 k = goodebcnt * mtd->erasesize / 1024;
289 speed = (k * 1000) / ms;
290 return speed;
291}
292
293static int scan_for_bad_eraseblocks(void)
294{
295 int i, bad = 0;
296
297 bbt = kmalloc(ebcnt, GFP_KERNEL);
298 if (!bbt) {
299 printk(PRINT_PREF "error: cannot allocate memory\n");
300 return -ENOMEM;
301 }
302 memset(bbt, 0 , ebcnt);
303
304 printk(PRINT_PREF "scanning for bad eraseblocks\n");
305 for (i = 0; i < ebcnt; ++i) {
306 bbt[i] = is_block_bad(i) ? 1 : 0;
307 if (bbt[i])
308 bad += 1;
309 cond_resched();
310 }
311 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
312 goodebcnt = ebcnt - bad;
313 return 0;
314}
315
316static int __init mtd_speedtest_init(void)
317{
318 int err, i;
319 long speed;
320 uint64_t tmp;
321
322 printk(KERN_INFO "\n");
323 printk(KERN_INFO "=================================================\n");
324 printk(PRINT_PREF "MTD device: %d\n", dev);
325
326 mtd = get_mtd_device(NULL, dev);
327 if (IS_ERR(mtd)) {
328 err = PTR_ERR(mtd);
329 printk(PRINT_PREF "error: cannot get MTD device\n");
330 return err;
331 }
332
333 if (mtd->writesize == 1) {
334 printk(PRINT_PREF "not NAND flash, assume page size is 512 "
335 "bytes.\n");
336 pgsize = 512;
337 } else
338 pgsize = mtd->writesize;
339
340 tmp = mtd->size;
341 do_div(tmp, mtd->erasesize);
342 ebcnt = tmp;
343 pgcnt = mtd->erasesize / mtd->writesize;
344
345 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
346 "page size %u, count of eraseblocks %u, pages per "
347 "eraseblock %u, OOB size %u\n",
348 (unsigned long long)mtd->size, mtd->erasesize,
349 pgsize, ebcnt, pgcnt, mtd->oobsize);
350
351 err = -ENOMEM;
352 iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
353 if (!iobuf) {
354 printk(PRINT_PREF "error: cannot allocate memory\n");
355 goto out;
356 }
357
358 simple_srand(1);
359 set_random_data(iobuf, mtd->erasesize);
360
361 err = scan_for_bad_eraseblocks();
362 if (err)
363 goto out;
364
365 err = erase_whole_device();
366 if (err)
367 goto out;
368
369 /* Write all eraseblocks, 1 eraseblock at a time */
370 printk(PRINT_PREF "testing eraseblock write speed\n");
371 start_timing();
372 for (i = 0; i < ebcnt; ++i) {
373 if (bbt[i])
374 continue;
375 err = write_eraseblock(i);
376 if (err)
377 goto out;
378 cond_resched();
379 }
380 stop_timing();
381 speed = calc_speed();
382 printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed);
383
384 /* Read all eraseblocks, 1 eraseblock at a time */
385 printk(PRINT_PREF "testing eraseblock read speed\n");
386 start_timing();
387 for (i = 0; i < ebcnt; ++i) {
388 if (bbt[i])
389 continue;
390 err = read_eraseblock(i);
391 if (err)
392 goto out;
393 cond_resched();
394 }
395 stop_timing();
396 speed = calc_speed();
397 printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed);
398
399 err = erase_whole_device();
400 if (err)
401 goto out;
402
403 /* Write all eraseblocks, 1 page at a time */
404 printk(PRINT_PREF "testing page write speed\n");
405 start_timing();
406 for (i = 0; i < ebcnt; ++i) {
407 if (bbt[i])
408 continue;
409 err = write_eraseblock_by_page(i);
410 if (err)
411 goto out;
412 cond_resched();
413 }
414 stop_timing();
415 speed = calc_speed();
416 printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed);
417
418 /* Read all eraseblocks, 1 page at a time */
419 printk(PRINT_PREF "testing page read speed\n");
420 start_timing();
421 for (i = 0; i < ebcnt; ++i) {
422 if (bbt[i])
423 continue;
424 err = read_eraseblock_by_page(i);
425 if (err)
426 goto out;
427 cond_resched();
428 }
429 stop_timing();
430 speed = calc_speed();
431 printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed);
432
433 err = erase_whole_device();
434 if (err)
435 goto out;
436
437 /* Write all eraseblocks, 2 pages at a time */
438 printk(PRINT_PREF "testing 2 page write speed\n");
439 start_timing();
440 for (i = 0; i < ebcnt; ++i) {
441 if (bbt[i])
442 continue;
443 err = write_eraseblock_by_2pages(i);
444 if (err)
445 goto out;
446 cond_resched();
447 }
448 stop_timing();
449 speed = calc_speed();
450 printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed);
451
452 /* Read all eraseblocks, 2 pages at a time */
453 printk(PRINT_PREF "testing 2 page read speed\n");
454 start_timing();
455 for (i = 0; i < ebcnt; ++i) {
456 if (bbt[i])
457 continue;
458 err = read_eraseblock_by_2pages(i);
459 if (err)
460 goto out;
461 cond_resched();
462 }
463 stop_timing();
464 speed = calc_speed();
465 printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed);
466
467 /* Erase all eraseblocks */
468 printk(PRINT_PREF "Testing erase speed\n");
469 start_timing();
470 for (i = 0; i < ebcnt; ++i) {
471 if (bbt[i])
472 continue;
473 err = erase_eraseblock(i);
474 if (err)
475 goto out;
476 cond_resched();
477 }
478 stop_timing();
479 speed = calc_speed();
480 printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed);
481
482 printk(PRINT_PREF "finished\n");
483out:
484 kfree(iobuf);
485 kfree(bbt);
486 put_mtd_device(mtd);
487 if (err)
488 printk(PRINT_PREF "error %d occurred\n", err);
489 printk(KERN_INFO "=================================================\n");
490 return err;
491}
492module_init(mtd_speedtest_init);
493
494static void __exit mtd_speedtest_exit(void)
495{
496 return;
497}
498module_exit(mtd_speedtest_exit);
499
500MODULE_DESCRIPTION("Speed test module");
501MODULE_AUTHOR("Adrian Hunter");
502MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
new file mode 100644
index 000000000000..63920476b57a
--- /dev/null
+++ b/drivers/mtd/tests/mtd_stresstest.c
@@ -0,0 +1,330 @@
1/*
2 * Copyright (C) 2006-2008 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; see the file COPYING. If not, write to the Free Software
15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 * Test random reads, writes and erases on MTD device.
18 *
19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
20 */
21
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/err.h>
26#include <linux/mtd/mtd.h>
27#include <linux/sched.h>
28#include <linux/vmalloc.h>
29
30#define PRINT_PREF KERN_INFO "mtd_stresstest: "
31
32static int dev;
33module_param(dev, int, S_IRUGO);
34MODULE_PARM_DESC(dev, "MTD device number to use");
35
36static int count = 10000;
37module_param(count, int, S_IRUGO);
38MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)");
39
40static struct mtd_info *mtd;
41static unsigned char *writebuf;
42static unsigned char *readbuf;
43static unsigned char *bbt;
44static int *offsets;
45
46static int pgsize;
47static int bufsize;
48static int ebcnt;
49static int pgcnt;
50static unsigned long next = 1;
51
52static inline unsigned int simple_rand(void)
53{
54 next = next * 1103515245 + 12345;
55 return (unsigned int)((next / 65536) % 32768);
56}
57
58static inline void simple_srand(unsigned long seed)
59{
60 next = seed;
61}
62
63static int rand_eb(void)
64{
65 int eb;
66
67again:
68 if (ebcnt < 32768)
69 eb = simple_rand();
70 else
71 eb = (simple_rand() << 15) | simple_rand();
72 /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
73 eb %= (ebcnt - 1);
74 if (bbt[eb])
75 goto again;
76 return eb;
77}
78
79static int rand_offs(void)
80{
81 int offs;
82
83 if (bufsize < 32768)
84 offs = simple_rand();
85 else
86 offs = (simple_rand() << 15) | simple_rand();
87 offs %= bufsize;
88 return offs;
89}
90
91static int rand_len(int offs)
92{
93 int len;
94
95 if (bufsize < 32768)
96 len = simple_rand();
97 else
98 len = (simple_rand() << 15) | simple_rand();
99 len %= (bufsize - offs);
100 return len;
101}
102
103static int erase_eraseblock(int ebnum)
104{
105 int err;
106 struct erase_info ei;
107 loff_t addr = ebnum * mtd->erasesize;
108
109 memset(&ei, 0, sizeof(struct erase_info));
110 ei.mtd = mtd;
111 ei.addr = addr;
112 ei.len = mtd->erasesize;
113
114 err = mtd->erase(mtd, &ei);
115 if (unlikely(err)) {
116 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
117 return err;
118 }
119
120 if (unlikely(ei.state == MTD_ERASE_FAILED)) {
121 printk(PRINT_PREF "some erase error occurred at EB %d\n",
122 ebnum);
123 return -EIO;
124 }
125
126 return 0;
127}
128
129static int is_block_bad(int ebnum)
130{
131 loff_t addr = ebnum * mtd->erasesize;
132 int ret;
133
134 ret = mtd->block_isbad(mtd, addr);
135 if (ret)
136 printk(PRINT_PREF "block %d is bad\n", ebnum);
137 return ret;
138}
139
140static int do_read(void)
141{
142 size_t read = 0;
143 int eb = rand_eb();
144 int offs = rand_offs();
145 int len = rand_len(offs), err;
146 loff_t addr;
147
148 if (bbt[eb + 1]) {
149 if (offs >= mtd->erasesize)
150 offs -= mtd->erasesize;
151 if (offs + len > mtd->erasesize)
152 len = mtd->erasesize - offs;
153 }
154 addr = eb * mtd->erasesize + offs;
155 err = mtd->read(mtd, addr, len, &read, readbuf);
156 if (err == -EUCLEAN)
157 err = 0;
158 if (unlikely(err || read != len)) {
159 printk(PRINT_PREF "error: read failed at 0x%llx\n",
160 (long long)addr);
161 if (!err)
162 err = -EINVAL;
163 return err;
164 }
165 return 0;
166}
167
168static int do_write(void)
169{
170 int eb = rand_eb(), offs, err, len;
171 size_t written = 0;
172 loff_t addr;
173
174 offs = offsets[eb];
175 if (offs >= mtd->erasesize) {
176 err = erase_eraseblock(eb);
177 if (err)
178 return err;
179 offs = offsets[eb] = 0;
180 }
181 len = rand_len(offs);
182 len = ((len + pgsize - 1) / pgsize) * pgsize;
183 if (offs + len > mtd->erasesize) {
184 if (bbt[eb + 1])
185 len = mtd->erasesize - offs;
186 else {
187 err = erase_eraseblock(eb + 1);
188 if (err)
189 return err;
190 offsets[eb + 1] = 0;
191 }
192 }
193 addr = eb * mtd->erasesize + offs;
194 err = mtd->write(mtd, addr, len, &written, writebuf);
195 if (unlikely(err || written != len)) {
196 printk(PRINT_PREF "error: write failed at 0x%llx\n",
197 (long long)addr);
198 if (!err)
199 err = -EINVAL;
200 return err;
201 }
202 offs += len;
203 while (offs > mtd->erasesize) {
204 offsets[eb++] = mtd->erasesize;
205 offs -= mtd->erasesize;
206 }
207 offsets[eb] = offs;
208 return 0;
209}
210
211static int do_operation(void)
212{
213 if (simple_rand() & 1)
214 return do_read();
215 else
216 return do_write();
217}
218
219static int scan_for_bad_eraseblocks(void)
220{
221 int i, bad = 0;
222
223 bbt = kmalloc(ebcnt, GFP_KERNEL);
224 if (!bbt) {
225 printk(PRINT_PREF "error: cannot allocate memory\n");
226 return -ENOMEM;
227 }
228 memset(bbt, 0 , ebcnt);
229
230 printk(PRINT_PREF "scanning for bad eraseblocks\n");
231 for (i = 0; i < ebcnt; ++i) {
232 bbt[i] = is_block_bad(i) ? 1 : 0;
233 if (bbt[i])
234 bad += 1;
235 cond_resched();
236 }
237 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
238 return 0;
239}
240
241static int __init mtd_stresstest_init(void)
242{
243 int err;
244 int i, op;
245 uint64_t tmp;
246
247 printk(KERN_INFO "\n");
248 printk(KERN_INFO "=================================================\n");
249 printk(PRINT_PREF "MTD device: %d\n", dev);
250
251 mtd = get_mtd_device(NULL, dev);
252 if (IS_ERR(mtd)) {
253 err = PTR_ERR(mtd);
254 printk(PRINT_PREF "error: cannot get MTD device\n");
255 return err;
256 }
257
258 if (mtd->writesize == 1) {
259 printk(PRINT_PREF "not NAND flash, assume page size is 512 "
260 "bytes.\n");
261 pgsize = 512;
262 } else
263 pgsize = mtd->writesize;
264
265 tmp = mtd->size;
266 do_div(tmp, mtd->erasesize);
267 ebcnt = tmp;
268 pgcnt = mtd->erasesize / mtd->writesize;
269
270 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
271 "page size %u, count of eraseblocks %u, pages per "
272 "eraseblock %u, OOB size %u\n",
273 (unsigned long long)mtd->size, mtd->erasesize,
274 pgsize, ebcnt, pgcnt, mtd->oobsize);
275
276 /* Read or write up 2 eraseblocks at a time */
277 bufsize = mtd->erasesize * 2;
278
279 err = -ENOMEM;
280 readbuf = vmalloc(bufsize);
281 writebuf = vmalloc(bufsize);
282 offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
283 if (!readbuf || !writebuf || !offsets) {
284 printk(PRINT_PREF "error: cannot allocate memory\n");
285 goto out;
286 }
287 for (i = 0; i < ebcnt; i++)
288 offsets[i] = mtd->erasesize;
289 simple_srand(current->pid);
290 for (i = 0; i < bufsize; i++)
291 writebuf[i] = simple_rand();
292
293 err = scan_for_bad_eraseblocks();
294 if (err)
295 goto out;
296
297 /* Do operations */
298 printk(PRINT_PREF "doing operations\n");
299 for (op = 0; op < count; op++) {
300 if ((op & 1023) == 0)
301 printk(PRINT_PREF "%d operations done\n", op);
302 err = do_operation();
303 if (err)
304 goto out;
305 cond_resched();
306 }
307 printk(PRINT_PREF "finished, %d operations done\n", op);
308
309out:
310 kfree(offsets);
311 kfree(bbt);
312 vfree(writebuf);
313 vfree(readbuf);
314 put_mtd_device(mtd);
315 if (err)
316 printk(PRINT_PREF "error %d occurred\n", err);
317 printk(KERN_INFO "=================================================\n");
318 return err;
319}
320module_init(mtd_stresstest_init);
321
322static void __exit mtd_stresstest_exit(void)
323{
324 return;
325}
326module_exit(mtd_stresstest_exit);
327
328MODULE_DESCRIPTION("Stress test module");
329MODULE_AUTHOR("Adrian Hunter");
330MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c
new file mode 100644
index 000000000000..5b889724268e
--- /dev/null
+++ b/drivers/mtd/tests/mtd_subpagetest.c
@@ -0,0 +1,525 @@
1/*
2 * Copyright (C) 2006-2007 Nokia Corporation
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; see the file COPYING. If not, write to the Free Software
15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 *
17 * Test sub-page read and write on MTD device.
18 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
19 *
20 */
21
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/err.h>
26#include <linux/mtd/mtd.h>
27#include <linux/sched.h>
28
29#define PRINT_PREF KERN_INFO "mtd_subpagetest: "
30
31static int dev;
32module_param(dev, int, S_IRUGO);
33MODULE_PARM_DESC(dev, "MTD device number to use");
34
35static struct mtd_info *mtd;
36static unsigned char *writebuf;
37static unsigned char *readbuf;
38static unsigned char *bbt;
39
40static int subpgsize;
41static int bufsize;
42static int ebcnt;
43static int pgcnt;
44static int errcnt;
45static unsigned long next = 1;
46
47static inline unsigned int simple_rand(void)
48{
49 next = next * 1103515245 + 12345;
50 return (unsigned int)((next / 65536) % 32768);
51}
52
53static inline void simple_srand(unsigned long seed)
54{
55 next = seed;
56}
57
58static void set_random_data(unsigned char *buf, size_t len)
59{
60 size_t i;
61
62 for (i = 0; i < len; ++i)
63 buf[i] = simple_rand();
64}
65
66static inline void clear_data(unsigned char *buf, size_t len)
67{
68 memset(buf, 0, len);
69}
70
71static int erase_eraseblock(int ebnum)
72{
73 int err;
74 struct erase_info ei;
75 loff_t addr = ebnum * mtd->erasesize;
76
77 memset(&ei, 0, sizeof(struct erase_info));
78 ei.mtd = mtd;
79 ei.addr = addr;
80 ei.len = mtd->erasesize;
81
82 err = mtd->erase(mtd, &ei);
83 if (err) {
84 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
85 return err;
86 }
87
88 if (ei.state == MTD_ERASE_FAILED) {
89 printk(PRINT_PREF "some erase error occurred at EB %d\n",
90 ebnum);
91 return -EIO;
92 }
93
94 return 0;
95}
96
97static int erase_whole_device(void)
98{
99 int err;
100 unsigned int i;
101
102 printk(PRINT_PREF "erasing whole device\n");
103 for (i = 0; i < ebcnt; ++i) {
104 if (bbt[i])
105 continue;
106 err = erase_eraseblock(i);
107 if (err)
108 return err;
109 cond_resched();
110 }
111 printk(PRINT_PREF "erased %u eraseblocks\n", i);
112 return 0;
113}
114
115static int write_eraseblock(int ebnum)
116{
117 size_t written = 0;
118 int err = 0;
119 loff_t addr = ebnum * mtd->erasesize;
120
121 set_random_data(writebuf, subpgsize);
122 err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
123 if (unlikely(err || written != subpgsize)) {
124 printk(PRINT_PREF "error: write failed at %#llx\n",
125 (long long)addr);
126 if (written != subpgsize) {
127 printk(PRINT_PREF " write size: %#x\n", subpgsize);
128 printk(PRINT_PREF " written: %#zx\n", written);
129 }
130 return err ? err : -1;
131 }
132
133 addr += subpgsize;
134
135 set_random_data(writebuf, subpgsize);
136 err = mtd->write(mtd, addr, subpgsize, &written, writebuf);
137 if (unlikely(err || written != subpgsize)) {
138 printk(PRINT_PREF "error: write failed at %#llx\n",
139 (long long)addr);
140 if (written != subpgsize) {
141 printk(PRINT_PREF " write size: %#x\n", subpgsize);
142 printk(PRINT_PREF " written: %#zx\n", written);
143 }
144 return err ? err : -1;
145 }
146
147 return err;
148}
149
150static int write_eraseblock2(int ebnum)
151{
152 size_t written = 0;
153 int err = 0, k;
154 loff_t addr = ebnum * mtd->erasesize;
155
156 for (k = 1; k < 33; ++k) {
157 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
158 break;
159 set_random_data(writebuf, subpgsize * k);
160 err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf);
161 if (unlikely(err || written != subpgsize * k)) {
162 printk(PRINT_PREF "error: write failed at %#llx\n",
163 (long long)addr);
164 if (written != subpgsize) {
165 printk(PRINT_PREF " write size: %#x\n",
166 subpgsize * k);
167 printk(PRINT_PREF " written: %#08zx\n",
168 written);
169 }
170 return err ? err : -1;
171 }
172 addr += subpgsize * k;
173 }
174
175 return err;
176}
177
178static void print_subpage(unsigned char *p)
179{
180 int i, j;
181
182 for (i = 0; i < subpgsize; ) {
183 for (j = 0; i < subpgsize && j < 32; ++i, ++j)
184 printk("%02x", *p++);
185 printk("\n");
186 }
187}
188
189static int verify_eraseblock(int ebnum)
190{
191 size_t read = 0;
192 int err = 0;
193 loff_t addr = ebnum * mtd->erasesize;
194
195 set_random_data(writebuf, subpgsize);
196 clear_data(readbuf, subpgsize);
197 read = 0;
198 err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
199 if (unlikely(err || read != subpgsize)) {
200 if (err == -EUCLEAN && read == subpgsize) {
201 printk(PRINT_PREF "ECC correction at %#llx\n",
202 (long long)addr);
203 err = 0;
204 } else {
205 printk(PRINT_PREF "error: read failed at %#llx\n",
206 (long long)addr);
207 return err ? err : -1;
208 }
209 }
210 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
211 printk(PRINT_PREF "error: verify failed at %#llx\n",
212 (long long)addr);
213 printk(PRINT_PREF "------------- written----------------\n");
214 print_subpage(writebuf);
215 printk(PRINT_PREF "------------- read ------------------\n");
216 print_subpage(readbuf);
217 printk(PRINT_PREF "-------------------------------------\n");
218 errcnt += 1;
219 }
220
221 addr += subpgsize;
222
223 set_random_data(writebuf, subpgsize);
224 clear_data(readbuf, subpgsize);
225 read = 0;
226 err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
227 if (unlikely(err || read != subpgsize)) {
228 if (err == -EUCLEAN && read == subpgsize) {
229 printk(PRINT_PREF "ECC correction at %#llx\n",
230 (long long)addr);
231 err = 0;
232 } else {
233 printk(PRINT_PREF "error: read failed at %#llx\n",
234 (long long)addr);
235 return err ? err : -1;
236 }
237 }
238 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
239 printk(PRINT_PREF "error: verify failed at %#llx\n",
240 (long long)addr);
241 printk(PRINT_PREF "------------- written----------------\n");
242 print_subpage(writebuf);
243 printk(PRINT_PREF "------------- read ------------------\n");
244 print_subpage(readbuf);
245 printk(PRINT_PREF "-------------------------------------\n");
246 errcnt += 1;
247 }
248
249 return err;
250}
251
252static int verify_eraseblock2(int ebnum)
253{
254 size_t read = 0;
255 int err = 0, k;
256 loff_t addr = ebnum * mtd->erasesize;
257
258 for (k = 1; k < 33; ++k) {
259 if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
260 break;
261 set_random_data(writebuf, subpgsize * k);
262 clear_data(readbuf, subpgsize * k);
263 read = 0;
264 err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf);
265 if (unlikely(err || read != subpgsize * k)) {
266 if (err == -EUCLEAN && read == subpgsize * k) {
267 printk(PRINT_PREF "ECC correction at %#llx\n",
268 (long long)addr);
269 err = 0;
270 } else {
271 printk(PRINT_PREF "error: read failed at "
272 "%#llx\n", (long long)addr);
273 return err ? err : -1;
274 }
275 }
276 if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
277 printk(PRINT_PREF "error: verify failed at %#llx\n",
278 (long long)addr);
279 errcnt += 1;
280 }
281 addr += subpgsize * k;
282 }
283
284 return err;
285}
286
287static int verify_eraseblock_ff(int ebnum)
288{
289 uint32_t j;
290 size_t read = 0;
291 int err = 0;
292 loff_t addr = ebnum * mtd->erasesize;
293
294 memset(writebuf, 0xff, subpgsize);
295 for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
296 clear_data(readbuf, subpgsize);
297 read = 0;
298 err = mtd->read(mtd, addr, subpgsize, &read, readbuf);
299 if (unlikely(err || read != subpgsize)) {
300 if (err == -EUCLEAN && read == subpgsize) {
301 printk(PRINT_PREF "ECC correction at %#llx\n",
302 (long long)addr);
303 err = 0;
304 } else {
305 printk(PRINT_PREF "error: read failed at "
306 "%#llx\n", (long long)addr);
307 return err ? err : -1;
308 }
309 }
310 if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
311 printk(PRINT_PREF "error: verify 0xff failed at "
312 "%#llx\n", (long long)addr);
313 errcnt += 1;
314 }
315 addr += subpgsize;
316 }
317
318 return err;
319}
320
321static int verify_all_eraseblocks_ff(void)
322{
323 int err;
324 unsigned int i;
325
326 printk(PRINT_PREF "verifying all eraseblocks for 0xff\n");
327 for (i = 0; i < ebcnt; ++i) {
328 if (bbt[i])
329 continue;
330 err = verify_eraseblock_ff(i);
331 if (err)
332 return err;
333 if (i % 256 == 0)
334 printk(PRINT_PREF "verified up to eraseblock %u\n", i);
335 cond_resched();
336 }
337 printk(PRINT_PREF "verified %u eraseblocks\n", i);
338 return 0;
339}
340
341static int is_block_bad(int ebnum)
342{
343 loff_t addr = ebnum * mtd->erasesize;
344 int ret;
345
346 ret = mtd->block_isbad(mtd, addr);
347 if (ret)
348 printk(PRINT_PREF "block %d is bad\n", ebnum);
349 return ret;
350}
351
352static int scan_for_bad_eraseblocks(void)
353{
354 int i, bad = 0;
355
356 bbt = kmalloc(ebcnt, GFP_KERNEL);
357 if (!bbt) {
358 printk(PRINT_PREF "error: cannot allocate memory\n");
359 return -ENOMEM;
360 }
361 memset(bbt, 0 , ebcnt);
362
363 printk(PRINT_PREF "scanning for bad eraseblocks\n");
364 for (i = 0; i < ebcnt; ++i) {
365 bbt[i] = is_block_bad(i) ? 1 : 0;
366 if (bbt[i])
367 bad += 1;
368 cond_resched();
369 }
370 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad);
371 return 0;
372}
373
374static int __init mtd_subpagetest_init(void)
375{
376 int err = 0;
377 uint32_t i;
378 uint64_t tmp;
379
380 printk(KERN_INFO "\n");
381 printk(KERN_INFO "=================================================\n");
382 printk(PRINT_PREF "MTD device: %d\n", dev);
383
384 mtd = get_mtd_device(NULL, dev);
385 if (IS_ERR(mtd)) {
386 err = PTR_ERR(mtd);
387 printk(PRINT_PREF "error: cannot get MTD device\n");
388 return err;
389 }
390
391 if (mtd->type != MTD_NANDFLASH) {
392 printk(PRINT_PREF "this test requires NAND flash\n");
393 goto out;
394 }
395
396 subpgsize = mtd->writesize >> mtd->subpage_sft;
397 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
398 "page size %u, subpage size %u, count of eraseblocks %u, "
399 "pages per eraseblock %u, OOB size %u\n",
400 (unsigned long long)mtd->size, mtd->erasesize,
401 mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
402
403 err = -ENOMEM;
404 bufsize = subpgsize * 32;
405 writebuf = kmalloc(bufsize, GFP_KERNEL);
406 if (!writebuf) {
407 printk(PRINT_PREF "error: cannot allocate memory\n");
408 goto out;
409 }
410 readbuf = kmalloc(bufsize, GFP_KERNEL);
411 if (!readbuf) {
412 printk(PRINT_PREF "error: cannot allocate memory\n");
413 goto out;
414 }
415
416 tmp = mtd->size;
417 do_div(tmp, mtd->erasesize);
418 ebcnt = tmp;
419 pgcnt = mtd->erasesize / mtd->writesize;
420
421 err = scan_for_bad_eraseblocks();
422 if (err)
423 goto out;
424
425 err = erase_whole_device();
426 if (err)
427 goto out;
428
429 printk(PRINT_PREF "writing whole device\n");
430 simple_srand(1);
431 for (i = 0; i < ebcnt; ++i) {
432 if (bbt[i])
433 continue;
434 err = write_eraseblock(i);
435 if (unlikely(err))
436 goto out;
437 if (i % 256 == 0)
438 printk(PRINT_PREF "written up to eraseblock %u\n", i);
439 cond_resched();
440 }
441 printk(PRINT_PREF "written %u eraseblocks\n", i);
442
443 simple_srand(1);
444 printk(PRINT_PREF "verifying all eraseblocks\n");
445 for (i = 0; i < ebcnt; ++i) {
446 if (bbt[i])
447 continue;
448 err = verify_eraseblock(i);
449 if (unlikely(err))
450 goto out;
451 if (i % 256 == 0)
452 printk(PRINT_PREF "verified up to eraseblock %u\n", i);
453 cond_resched();
454 }
455 printk(PRINT_PREF "verified %u eraseblocks\n", i);
456
457 err = erase_whole_device();
458 if (err)
459 goto out;
460
461 err = verify_all_eraseblocks_ff();
462 if (err)
463 goto out;
464
465 /* Write all eraseblocks */
466 simple_srand(3);
467 printk(PRINT_PREF "writing whole device\n");
468 for (i = 0; i < ebcnt; ++i) {
469 if (bbt[i])
470 continue;
471 err = write_eraseblock2(i);
472 if (unlikely(err))
473 goto out;
474 if (i % 256 == 0)
475 printk(PRINT_PREF "written up to eraseblock %u\n", i);
476 cond_resched();
477 }
478 printk(PRINT_PREF "written %u eraseblocks\n", i);
479
480 /* Check all eraseblocks */
481 simple_srand(3);
482 printk(PRINT_PREF "verifying all eraseblocks\n");
483 for (i = 0; i < ebcnt; ++i) {
484 if (bbt[i])
485 continue;
486 err = verify_eraseblock2(i);
487 if (unlikely(err))
488 goto out;
489 if (i % 256 == 0)
490 printk(PRINT_PREF "verified up to eraseblock %u\n", i);
491 cond_resched();
492 }
493 printk(PRINT_PREF "verified %u eraseblocks\n", i);
494
495 err = erase_whole_device();
496 if (err)
497 goto out;
498
499 err = verify_all_eraseblocks_ff();
500 if (err)
501 goto out;
502
503 printk(PRINT_PREF "finished with %d errors\n", errcnt);
504
505out:
506 kfree(bbt);
507 kfree(readbuf);
508 kfree(writebuf);
509 put_mtd_device(mtd);
510 if (err)
511 printk(PRINT_PREF "error %d occurred\n", err);
512 printk(KERN_INFO "=================================================\n");
513 return err;
514}
515module_init(mtd_subpagetest_init);
516
517static void __exit mtd_subpagetest_exit(void)
518{
519 return;
520}
521module_exit(mtd_subpagetest_exit);
522
523MODULE_DESCRIPTION("Subpage test module");
524MODULE_AUTHOR("Adrian Hunter");
525MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c
new file mode 100644
index 000000000000..631a0ab3a33c
--- /dev/null
+++ b/drivers/mtd/tests/mtd_torturetest.c
@@ -0,0 +1,530 @@
1/*
2 * Copyright (C) 2006-2008 Artem Bityutskiy
3 * Copyright (C) 2006-2008 Jarkko Lavinen
4 * Copyright (C) 2006-2008 Adrian Hunter
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; see the file COPYING. If not, write to the Free Software
17 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter
20 *
21 * WARNING: this test program may kill your flash and your device. Do not
22 * use it unless you know what you do. Authors are not responsible for any
23 * damage caused by this program.
24 */
25
26#include <linux/init.h>
27#include <linux/module.h>
28#include <linux/moduleparam.h>
29#include <linux/err.h>
30#include <linux/mtd/mtd.h>
31#include <linux/sched.h>
32
33#define PRINT_PREF KERN_INFO "mtd_torturetest: "
34#define RETRIES 3
35
36static int eb = 8;
37module_param(eb, int, S_IRUGO);
38MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device");
39
40static int ebcnt = 32;
41module_param(ebcnt, int, S_IRUGO);
42MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture");
43
44static int pgcnt;
45module_param(pgcnt, int, S_IRUGO);
46MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)");
47
48static int dev;
49module_param(dev, int, S_IRUGO);
50MODULE_PARM_DESC(dev, "MTD device number to use");
51
52static int gran = 512;
53module_param(gran, int, S_IRUGO);
54MODULE_PARM_DESC(gran, "how often the status information should be printed");
55
56static int check = 1;
57module_param(check, int, S_IRUGO);
58MODULE_PARM_DESC(check, "if the written data should be checked");
59
60static unsigned int cycles_count;
61module_param(cycles_count, uint, S_IRUGO);
62MODULE_PARM_DESC(cycles_count, "how many erase cycles to do "
63 "(infinite by default)");
64
65static struct mtd_info *mtd;
66
67/* This buffer contains 0x555555...0xAAAAAA... pattern */
68static unsigned char *patt_5A5;
69/* This buffer contains 0xAAAAAA...0x555555... pattern */
70static unsigned char *patt_A5A;
71/* This buffer contains all 0xFF bytes */
72static unsigned char *patt_FF;
73/* This a temporary buffer is use when checking data */
74static unsigned char *check_buf;
75/* How many erase cycles were done */
76static unsigned int erase_cycles;
77
78static int pgsize;
79static struct timeval start, finish;
80
81static void report_corrupt(unsigned char *read, unsigned char *written);
82
83static inline void start_timing(void)
84{
85 do_gettimeofday(&start);
86}
87
88static inline void stop_timing(void)
89{
90 do_gettimeofday(&finish);
91}
92
93/*
94 * Erase eraseblock number @ebnum.
95 */
96static inline int erase_eraseblock(int ebnum)
97{
98 int err;
99 struct erase_info ei;
100 loff_t addr = ebnum * mtd->erasesize;
101
102 memset(&ei, 0, sizeof(struct erase_info));
103 ei.mtd = mtd;
104 ei.addr = addr;
105 ei.len = mtd->erasesize;
106
107 err = mtd->erase(mtd, &ei);
108 if (err) {
109 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum);
110 return err;
111 }
112
113 if (ei.state == MTD_ERASE_FAILED) {
114 printk(PRINT_PREF "some erase error occurred at EB %d\n",
115 ebnum);
116 return -EIO;
117 }
118
119 return 0;
120}
121
122/*
123 * Check that the contents of eraseblock number @enbum is equivalent to the
124 * @buf buffer.
125 */
126static inline int check_eraseblock(int ebnum, unsigned char *buf)
127{
128 int err, retries = 0;
129 size_t read = 0;
130 loff_t addr = ebnum * mtd->erasesize;
131 size_t len = mtd->erasesize;
132
133 if (pgcnt) {
134 addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
135 len = pgcnt * pgsize;
136 }
137
138retry:
139 err = mtd->read(mtd, addr, len, &read, check_buf);
140 if (err == -EUCLEAN)
141 printk(PRINT_PREF "single bit flip occurred at EB %d "
142 "MTD reported that it was fixed.\n", ebnum);
143 else if (err) {
144 printk(PRINT_PREF "error %d while reading EB %d, "
145 "read %zd\n", err, ebnum, read);
146 return err;
147 }
148
149 if (read != len) {
150 printk(PRINT_PREF "failed to read %zd bytes from EB %d, "
151 "read only %zd, but no error reported\n",
152 len, ebnum, read);
153 return -EIO;
154 }
155
156 if (memcmp(buf, check_buf, len)) {
157 printk(PRINT_PREF "read wrong data from EB %d\n", ebnum);
158 report_corrupt(check_buf, buf);
159
160 if (retries++ < RETRIES) {
161 /* Try read again */
162 yield();
163 printk(PRINT_PREF "re-try reading data from EB %d\n",
164 ebnum);
165 goto retry;
166 } else {
167 printk(PRINT_PREF "retried %d times, still errors, "
168 "give-up\n", RETRIES);
169 return -EINVAL;
170 }
171 }
172
173 if (retries != 0)
174 printk(PRINT_PREF "only attempt number %d was OK (!!!)\n",
175 retries);
176
177 return 0;
178}
179
180static inline int write_pattern(int ebnum, void *buf)
181{
182 int err;
183 size_t written = 0;
184 loff_t addr = ebnum * mtd->erasesize;
185 size_t len = mtd->erasesize;
186
187 if (pgcnt) {
188 addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
189 len = pgcnt * pgsize;
190 }
191 err = mtd->write(mtd, addr, len, &written, buf);
192 if (err) {
193 printk(PRINT_PREF "error %d while writing EB %d, written %zd"
194 " bytes\n", err, ebnum, written);
195 return err;
196 }
197 if (written != len) {
198 printk(PRINT_PREF "written only %zd bytes of %zd, but no error"
199 " reported\n", written, len);
200 return -EIO;
201 }
202
203 return 0;
204}
205
206static int __init tort_init(void)
207{
208 int err = 0, i, infinite = !cycles_count;
209 int bad_ebs[ebcnt];
210
211 printk(KERN_INFO "\n");
212 printk(KERN_INFO "=================================================\n");
213 printk(PRINT_PREF "Warning: this program is trying to wear out your "
214 "flash, stop it if this is not wanted.\n");
215 printk(PRINT_PREF "MTD device: %d\n", dev);
216 printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n",
217 ebcnt, eb, eb + ebcnt - 1, dev);
218 if (pgcnt)
219 printk(PRINT_PREF "torturing just %d pages per eraseblock\n",
220 pgcnt);
221 printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled");
222
223 mtd = get_mtd_device(NULL, dev);
224 if (IS_ERR(mtd)) {
225 err = PTR_ERR(mtd);
226 printk(PRINT_PREF "error: cannot get MTD device\n");
227 return err;
228 }
229
230 if (mtd->writesize == 1) {
231 printk(PRINT_PREF "not NAND flash, assume page size is 512 "
232 "bytes.\n");
233 pgsize = 512;
234 } else
235 pgsize = mtd->writesize;
236
237 if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {
238 printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt);
239 goto out_mtd;
240 }
241
242 err = -ENOMEM;
243 patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
244 if (!patt_5A5) {
245 printk(PRINT_PREF "error: cannot allocate memory\n");
246 goto out_mtd;
247 }
248
249 patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
250 if (!patt_A5A) {
251 printk(PRINT_PREF "error: cannot allocate memory\n");
252 goto out_patt_5A5;
253 }
254
255 patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
256 if (!patt_FF) {
257 printk(PRINT_PREF "error: cannot allocate memory\n");
258 goto out_patt_A5A;
259 }
260
261 check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
262 if (!check_buf) {
263 printk(PRINT_PREF "error: cannot allocate memory\n");
264 goto out_patt_FF;
265 }
266
267 err = 0;
268
269 /* Initialize patterns */
270 memset(patt_FF, 0xFF, mtd->erasesize);
271 for (i = 0; i < mtd->erasesize / pgsize; i++) {
272 if (!(i & 1)) {
273 memset(patt_5A5 + i * pgsize, 0x55, pgsize);
274 memset(patt_A5A + i * pgsize, 0xAA, pgsize);
275 } else {
276 memset(patt_5A5 + i * pgsize, 0xAA, pgsize);
277 memset(patt_A5A + i * pgsize, 0x55, pgsize);
278 }
279 }
280
281 /*
282 * Check if there is a bad eraseblock among those we are going to test.
283 */
284 memset(&bad_ebs[0], 0, sizeof(int) * ebcnt);
285 if (mtd->block_isbad) {
286 for (i = eb; i < eb + ebcnt; i++) {
287 err = mtd->block_isbad(mtd,
288 (loff_t)i * mtd->erasesize);
289
290 if (err < 0) {
291 printk(PRINT_PREF "block_isbad() returned %d "
292 "for EB %d\n", err, i);
293 goto out;
294 }
295
296 if (err) {
297 printk("EB %d is bad. Skip it.\n", i);
298 bad_ebs[i - eb] = 1;
299 }
300 }
301 }
302
303 start_timing();
304 while (1) {
305 int i;
306 void *patt;
307
308 /* Erase all eraseblocks */
309 for (i = eb; i < eb + ebcnt; i++) {
310 if (bad_ebs[i - eb])
311 continue;
312 err = erase_eraseblock(i);
313 if (err)
314 goto out;
315 cond_resched();
316 }
317
318 /* Check if the eraseblocks contain only 0xFF bytes */
319 if (check) {
320 for (i = eb; i < eb + ebcnt; i++) {
321 if (bad_ebs[i - eb])
322 continue;
323 err = check_eraseblock(i, patt_FF);
324 if (err) {
325 printk(PRINT_PREF "verify failed"
326 " for 0xFF... pattern\n");
327 goto out;
328 }
329 cond_resched();
330 }
331 }
332
333 /* Write the pattern */
334 for (i = eb; i < eb + ebcnt; i++) {
335 if (bad_ebs[i - eb])
336 continue;
337 if ((eb + erase_cycles) & 1)
338 patt = patt_5A5;
339 else
340 patt = patt_A5A;
341 err = write_pattern(i, patt);
342 if (err)
343 goto out;
344 cond_resched();
345 }
346
347 /* Verify what we wrote */
348 if (check) {
349 for (i = eb; i < eb + ebcnt; i++) {
350 if (bad_ebs[i - eb])
351 continue;
352 if ((eb + erase_cycles) & 1)
353 patt = patt_5A5;
354 else
355 patt = patt_A5A;
356 err = check_eraseblock(i, patt);
357 if (err) {
358 printk(PRINT_PREF "verify failed for %s"
359 " pattern\n",
360 ((eb + erase_cycles) & 1) ?
361 "0x55AA55..." : "0xAA55AA...");
362 goto out;
363 }
364 cond_resched();
365 }
366 }
367
368 erase_cycles += 1;
369
370 if (erase_cycles % gran == 0) {
371 long ms;
372
373 stop_timing();
374 ms = (finish.tv_sec - start.tv_sec) * 1000 +
375 (finish.tv_usec - start.tv_usec) / 1000;
376 printk(PRINT_PREF "%08u erase cycles done, took %lu "
377 "milliseconds (%lu seconds)\n",
378 erase_cycles, ms, ms / 1000);
379 start_timing();
380 }
381
382 if (!infinite && --cycles_count == 0)
383 break;
384 }
385out:
386
387 printk(PRINT_PREF "finished after %u erase cycles\n",
388 erase_cycles);
389 kfree(check_buf);
390out_patt_FF:
391 kfree(patt_FF);
392out_patt_A5A:
393 kfree(patt_A5A);
394out_patt_5A5:
395 kfree(patt_5A5);
396out_mtd:
397 put_mtd_device(mtd);
398 if (err)
399 printk(PRINT_PREF "error %d occurred during torturing\n", err);
400 printk(KERN_INFO "=================================================\n");
401 return err;
402}
403module_init(tort_init);
404
405static void __exit tort_exit(void)
406{
407 return;
408}
409module_exit(tort_exit);
410
411static int countdiffs(unsigned char *buf, unsigned char *check_buf,
412 unsigned offset, unsigned len, unsigned *bytesp,
413 unsigned *bitsp);
414static void print_bufs(unsigned char *read, unsigned char *written, int start,
415 int len);
416
417/*
418 * Report the detailed information about how the read EB differs from what was
419 * written.
420 */
421static void report_corrupt(unsigned char *read, unsigned char *written)
422{
423 int i;
424 int bytes, bits, pages, first;
425 int offset, len;
426 size_t check_len = mtd->erasesize;
427
428 if (pgcnt)
429 check_len = pgcnt * pgsize;
430
431 bytes = bits = pages = 0;
432 for (i = 0; i < check_len; i += pgsize)
433 if (countdiffs(written, read, i, pgsize, &bytes,
434 &bits) >= 0)
435 pages++;
436
437 printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n",
438 pages, bytes, bits);
439 printk(PRINT_PREF "The following is a list of all differences between"
440 " what was read from flash and what was expected\n");
441
442 for (i = 0; i < check_len; i += pgsize) {
443 cond_resched();
444 bytes = bits = 0;
445 first = countdiffs(written, read, i, pgsize, &bytes,
446 &bits);
447 if (first < 0)
448 continue;
449
450 printk("-------------------------------------------------------"
451 "----------------------------------\n");
452
453 printk(PRINT_PREF "Page %zd has %d bytes/%d bits failing verify,"
454 " starting at offset 0x%x\n",
455 (mtd->erasesize - check_len + i) / pgsize,
456 bytes, bits, first);
457
458 offset = first & ~0x7;
459 len = ((first + bytes) | 0x7) + 1 - offset;
460
461 print_bufs(read, written, offset, len);
462 }
463}
464
465static void print_bufs(unsigned char *read, unsigned char *written, int start,
466 int len)
467{
468 int i = 0, j1, j2;
469 char *diff;
470
471 printk("Offset Read Written\n");
472 while (i < len) {
473 printk("0x%08x: ", start + i);
474 diff = " ";
475 for (j1 = 0; j1 < 8 && i + j1 < len; j1++) {
476 printk(" %02x", read[start + i + j1]);
477 if (read[start + i + j1] != written[start + i + j1])
478 diff = "***";
479 }
480
481 while (j1 < 8) {
482 printk(" ");
483 j1 += 1;
484 }
485
486 printk(" %s ", diff);
487
488 for (j2 = 0; j2 < 8 && i + j2 < len; j2++)
489 printk(" %02x", written[start + i + j2]);
490 printk("\n");
491 i += 8;
492 }
493}
494
495/*
496 * Count the number of differing bytes and bits and return the first differing
497 * offset.
498 */
499static int countdiffs(unsigned char *buf, unsigned char *check_buf,
500 unsigned offset, unsigned len, unsigned *bytesp,
501 unsigned *bitsp)
502{
503 unsigned i, bit;
504 int first = -1;
505
506 for (i = offset; i < offset + len; i++)
507 if (buf[i] != check_buf[i]) {
508 first = i;
509 break;
510 }
511
512 while (i < offset + len) {
513 if (buf[i] != check_buf[i]) {
514 (*bytesp)++;
515 bit = 1;
516 while (bit < 256) {
517 if ((buf[i] & bit) != (check_buf[i] & bit))
518 (*bitsp)++;
519 bit <<= 1;
520 }
521 }
522 i++;
523 }
524
525 return first;
526}
527
528MODULE_DESCRIPTION("Eraseblock torturing module");
529MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter");
530MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 7caf22cd5ad0..9082768cc6c3 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -561,7 +561,7 @@ static int io_init(struct ubi_device *ubi)
561 */ 561 */
562 562
563 ubi->peb_size = ubi->mtd->erasesize; 563 ubi->peb_size = ubi->mtd->erasesize;
564 ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; 564 ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd);
565 ubi->flash_size = ubi->mtd->size; 565 ubi->flash_size = ubi->mtd->size;
566 566
567 if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) 567 if (ubi->mtd->block_isbad && ubi->mtd->block_markbad)
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 605812bb0b1a..6dd4f5e77f82 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -215,7 +215,8 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
215 struct ubi_volume *vol; 215 struct ubi_volume *vol;
216 struct ubi_device *ubi; 216 struct ubi_device *ubi;
217 217
218 dbg_gen("erase %u bytes at offset %u", instr->len, instr->addr); 218 dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len,
219 (unsigned long long)instr->addr);
219 220
220 if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) 221 if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize)
221 return -EINVAL; 222 return -EINVAL;
@@ -223,11 +224,11 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
223 if (instr->len < 0 || instr->addr + instr->len > mtd->size) 224 if (instr->len < 0 || instr->addr + instr->len > mtd->size)
224 return -EINVAL; 225 return -EINVAL;
225 226
226 if (instr->addr % mtd->writesize || instr->len % mtd->writesize) 227 if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd))
227 return -EINVAL; 228 return -EINVAL;
228 229
229 lnum = instr->addr / mtd->erasesize; 230 lnum = mtd_div_by_eb(instr->addr, mtd);
230 count = instr->len / mtd->erasesize; 231 count = mtd_div_by_eb(instr->len, mtd);
231 232
232 vol = container_of(mtd, struct ubi_volume, gluebi_mtd); 233 vol = container_of(mtd, struct ubi_volume, gluebi_mtd);
233 ubi = vol->ubi; 234 ubi = vol->ubi;
@@ -255,7 +256,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr)
255 256
256out_err: 257out_err:
257 instr->state = MTD_ERASE_FAILED; 258 instr->state = MTD_ERASE_FAILED;
258 instr->fail_addr = lnum * mtd->erasesize; 259 instr->fail_addr = (long long)lnum * mtd->erasesize;
259 return err; 260 return err;
260} 261}
261 262
@@ -294,7 +295,7 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
294 * bytes. 295 * bytes.
295 */ 296 */
296 if (vol->vol_type == UBI_DYNAMIC_VOLUME) 297 if (vol->vol_type == UBI_DYNAMIC_VOLUME)
297 mtd->size = vol->usable_leb_size * vol->reserved_pebs; 298 mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs;
298 else 299 else
299 mtd->size = vol->used_bytes; 300 mtd->size = vol->used_bytes;
300 301
@@ -304,8 +305,8 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
304 return -ENFILE; 305 return -ENFILE;
305 } 306 }
306 307
307 dbg_gen("added mtd%d (\"%s\"), size %u, EB size %u", 308 dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u",
308 mtd->index, mtd->name, mtd->size, mtd->erasesize); 309 mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize);
309 return 0; 310 return 0;
310} 311}
311 312