diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-27 18:34:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-27 18:34:57 -0400 |
commit | f00546363fff1576ceddc2690d47e5f9c1dd2e05 (patch) | |
tree | f6cb8965b6754fc6ce7570cf1471ebe9874e509a /drivers | |
parent | 50f732ee63b91eb08a29974b36bd63e1150bb642 (diff) | |
parent | 28b57cddb3ed4f7999e4b76ef36ebaaf6e2e0c37 (diff) |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (46 commits)
[MTD] [MAPS] drivers/mtd/maps/ck804xrom.c: convert pci_module_init()
[MTD] [NAND] CM-x270 MTD driver
[MTD] [NAND] Wrong calculation of page number in nand_block_bad()
[MTD] [MAPS] fix plat-ram printk format
[JFFS2] Fix compr_rubin.c build after include file elimination.
[JFFS2] Handle inodes with only a single metadata node with non-zero isize
[JFFS2] Tidy up licensing/copyright boilerplate.
[MTD] [OneNAND] Exit loop only when column start with 0
[MTD] [OneNAND] Fix access the past of the real oobfree array
[MTD] [OneNAND] Update Samsung OneNAND official URL
[JFFS2] Better fix for all-zero node headers
[JFFS2] Improve read_inode memory usage, v2.
[JFFS2] Improve failure mode if inode checking leaves unchecked space.
[JFFS2] Fix cross-endian build.
[MTD] Finish conversion mtd_blkdevs to use the kthread API
[JFFS2] Obsolete dirent nodes immediately on unlink, where possible.
Use menuconfig objects: MTD
[MTD] mtd_blkdevs: Convert to use the kthread API
[MTD] Fix fwh_lock locking
[JFFS2] Speed up mount for directly-mapped NOR flash
...
Diffstat (limited to 'drivers')
26 files changed, 1796 insertions, 240 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 6d1b91bf7ad5..c1b47db29bd2 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -1,8 +1,6 @@ | |||
1 | # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ | 1 | # $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $ |
2 | 2 | ||
3 | menu "Memory Technology Devices (MTD)" | 3 | menuconfig MTD |
4 | |||
5 | config MTD | ||
6 | tristate "Memory Technology Device (MTD) support" | 4 | tristate "Memory Technology Device (MTD) support" |
7 | help | 5 | help |
8 | Memory Technology Devices are flash, RAM and similar chips, often | 6 | Memory Technology Devices are flash, RAM and similar chips, often |
@@ -13,9 +11,10 @@ config MTD | |||
13 | them. It will also allow you to select individual drivers for | 11 | them. It will also allow you to select individual drivers for |
14 | particular hardware and users of MTD devices. If unsure, say N. | 12 | particular hardware and users of MTD devices. If unsure, say N. |
15 | 13 | ||
14 | if MTD | ||
15 | |||
16 | config MTD_DEBUG | 16 | config MTD_DEBUG |
17 | bool "Debugging" | 17 | bool "Debugging" |
18 | depends on MTD | ||
19 | help | 18 | help |
20 | This turns on low-level debugging for the entire MTD sub-system. | 19 | This turns on low-level debugging for the entire MTD sub-system. |
21 | Normally, you should say 'N'. | 20 | Normally, you should say 'N'. |
@@ -29,7 +28,6 @@ config MTD_DEBUG_VERBOSE | |||
29 | 28 | ||
30 | config MTD_CONCAT | 29 | config MTD_CONCAT |
31 | tristate "MTD concatenating support" | 30 | tristate "MTD concatenating support" |
32 | depends on MTD | ||
33 | help | 31 | help |
34 | Support for concatenating several MTD devices into a single | 32 | Support for concatenating several MTD devices into a single |
35 | (virtual) one. This allows you to have -for example- a JFFS(2) | 33 | (virtual) one. This allows you to have -for example- a JFFS(2) |
@@ -38,7 +36,6 @@ config MTD_CONCAT | |||
38 | 36 | ||
39 | config MTD_PARTITIONS | 37 | config MTD_PARTITIONS |
40 | bool "MTD partitioning support" | 38 | bool "MTD partitioning support" |
41 | depends on MTD | ||
42 | help | 39 | help |
43 | If you have a device which needs to divide its flash chip(s) up | 40 | If you have a device which needs to divide its flash chip(s) up |
44 | into multiple 'partitions', each of which appears to the user as | 41 | into multiple 'partitions', each of which appears to the user as |
@@ -153,11 +150,9 @@ config MTD_AFS_PARTS | |||
153 | 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. | 150 | 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. |
154 | 151 | ||
155 | comment "User Modules And Translation Layers" | 152 | comment "User Modules And Translation Layers" |
156 | depends on MTD | ||
157 | 153 | ||
158 | config MTD_CHAR | 154 | config MTD_CHAR |
159 | tristate "Direct char device access to MTD devices" | 155 | tristate "Direct char device access to MTD devices" |
160 | depends on MTD | ||
161 | help | 156 | help |
162 | This provides a character device for each MTD device present in | 157 | This provides a character device for each MTD device present in |
163 | the system, allowing the user to read and write directly to the | 158 | the system, allowing the user to read and write directly to the |
@@ -166,12 +161,12 @@ config MTD_CHAR | |||
166 | 161 | ||
167 | config MTD_BLKDEVS | 162 | config MTD_BLKDEVS |
168 | tristate "Common interface to block layer for MTD 'translation layers'" | 163 | tristate "Common interface to block layer for MTD 'translation layers'" |
169 | depends on MTD && BLOCK | 164 | depends on BLOCK |
170 | default n | 165 | default n |
171 | 166 | ||
172 | config MTD_BLOCK | 167 | config MTD_BLOCK |
173 | tristate "Caching block device access to MTD devices" | 168 | tristate "Caching block device access to MTD devices" |
174 | depends on MTD && BLOCK | 169 | depends on BLOCK |
175 | select MTD_BLKDEVS | 170 | select MTD_BLKDEVS |
176 | ---help--- | 171 | ---help--- |
177 | Although most flash chips have an erase size too large to be useful | 172 | Although most flash chips have an erase size too large to be useful |
@@ -194,7 +189,7 @@ config MTD_BLOCK | |||
194 | 189 | ||
195 | config MTD_BLOCK_RO | 190 | config MTD_BLOCK_RO |
196 | tristate "Readonly block device access to MTD devices" | 191 | tristate "Readonly block device access to MTD devices" |
197 | depends on MTD_BLOCK!=y && MTD && BLOCK | 192 | depends on MTD_BLOCK!=y && BLOCK |
198 | select MTD_BLKDEVS | 193 | select MTD_BLKDEVS |
199 | help | 194 | help |
200 | This allows you to mount read-only file systems (such as cramfs) | 195 | This allows you to mount read-only file systems (such as cramfs) |
@@ -206,7 +201,7 @@ config MTD_BLOCK_RO | |||
206 | 201 | ||
207 | config FTL | 202 | config FTL |
208 | tristate "FTL (Flash Translation Layer) support" | 203 | tristate "FTL (Flash Translation Layer) support" |
209 | depends on MTD && BLOCK | 204 | depends on BLOCK |
210 | select MTD_BLKDEVS | 205 | select MTD_BLKDEVS |
211 | ---help--- | 206 | ---help--- |
212 | This provides support for the original Flash Translation Layer which | 207 | This provides support for the original Flash Translation Layer which |
@@ -223,7 +218,7 @@ config FTL | |||
223 | 218 | ||
224 | config NFTL | 219 | config NFTL |
225 | tristate "NFTL (NAND Flash Translation Layer) support" | 220 | tristate "NFTL (NAND Flash Translation Layer) support" |
226 | depends on MTD && BLOCK | 221 | depends on BLOCK |
227 | select MTD_BLKDEVS | 222 | select MTD_BLKDEVS |
228 | ---help--- | 223 | ---help--- |
229 | This provides support for the NAND Flash Translation Layer which is | 224 | This provides support for the NAND Flash Translation Layer which is |
@@ -247,7 +242,7 @@ config NFTL_RW | |||
247 | 242 | ||
248 | config INFTL | 243 | config INFTL |
249 | tristate "INFTL (Inverse NAND Flash Translation Layer) support" | 244 | tristate "INFTL (Inverse NAND Flash Translation Layer) support" |
250 | depends on MTD && BLOCK | 245 | depends on BLOCK |
251 | select MTD_BLKDEVS | 246 | select MTD_BLKDEVS |
252 | ---help--- | 247 | ---help--- |
253 | This provides support for the Inverse NAND Flash Translation | 248 | This provides support for the Inverse NAND Flash Translation |
@@ -265,7 +260,7 @@ config INFTL | |||
265 | 260 | ||
266 | config RFD_FTL | 261 | config RFD_FTL |
267 | tristate "Resident Flash Disk (Flash Translation Layer) support" | 262 | tristate "Resident Flash Disk (Flash Translation Layer) support" |
268 | depends on MTD && BLOCK | 263 | depends on BLOCK |
269 | select MTD_BLKDEVS | 264 | select MTD_BLKDEVS |
270 | ---help--- | 265 | ---help--- |
271 | This provides support for the flash translation layer known | 266 | This provides support for the flash translation layer known |
@@ -276,7 +271,7 @@ config RFD_FTL | |||
276 | 271 | ||
277 | config SSFDC | 272 | config SSFDC |
278 | tristate "NAND SSFDC (SmartMedia) read only translation layer" | 273 | tristate "NAND SSFDC (SmartMedia) read only translation layer" |
279 | depends on MTD && BLOCK | 274 | depends on BLOCK |
280 | select MTD_BLKDEVS | 275 | select MTD_BLKDEVS |
281 | help | 276 | help |
282 | This enables read only access to SmartMedia formatted NAND | 277 | This enables read only access to SmartMedia formatted NAND |
@@ -294,5 +289,4 @@ source "drivers/mtd/onenand/Kconfig" | |||
294 | 289 | ||
295 | source "drivers/mtd/ubi/Kconfig" | 290 | source "drivers/mtd/ubi/Kconfig" |
296 | 291 | ||
297 | endmenu | 292 | endif # MTD |
298 | |||
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 72e6d73beb40..d28e0fc85e12 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig | |||
@@ -6,7 +6,6 @@ menu "RAM/ROM/Flash chip drivers" | |||
6 | 6 | ||
7 | config MTD_CFI | 7 | config MTD_CFI |
8 | tristate "Detect flash chips by Common Flash Interface (CFI) probe" | 8 | tristate "Detect flash chips by Common Flash Interface (CFI) probe" |
9 | depends on MTD | ||
10 | select MTD_GEN_PROBE | 9 | select MTD_GEN_PROBE |
11 | help | 10 | help |
12 | The Common Flash Interface specification was developed by Intel, | 11 | The Common Flash Interface specification was developed by Intel, |
@@ -18,7 +17,6 @@ config MTD_CFI | |||
18 | 17 | ||
19 | config MTD_JEDECPROBE | 18 | config MTD_JEDECPROBE |
20 | tristate "Detect non-CFI AMD/JEDEC-compatible flash chips" | 19 | tristate "Detect non-CFI AMD/JEDEC-compatible flash chips" |
21 | depends on MTD | ||
22 | select MTD_GEN_PROBE | 20 | select MTD_GEN_PROBE |
23 | help | 21 | help |
24 | This option enables JEDEC-style probing of flash chips which are not | 22 | This option enables JEDEC-style probing of flash chips which are not |
@@ -213,21 +211,18 @@ config MTD_CFI_UTIL | |||
213 | 211 | ||
214 | config MTD_RAM | 212 | config MTD_RAM |
215 | tristate "Support for RAM chips in bus mapping" | 213 | tristate "Support for RAM chips in bus mapping" |
216 | depends on MTD | ||
217 | help | 214 | help |
218 | This option enables basic support for RAM chips accessed through | 215 | This option enables basic support for RAM chips accessed through |
219 | a bus mapping driver. | 216 | a bus mapping driver. |
220 | 217 | ||
221 | config MTD_ROM | 218 | config MTD_ROM |
222 | tristate "Support for ROM chips in bus mapping" | 219 | tristate "Support for ROM chips in bus mapping" |
223 | depends on MTD | ||
224 | help | 220 | help |
225 | This option enables basic support for ROM chips accessed through | 221 | This option enables basic support for ROM chips accessed through |
226 | a bus mapping driver. | 222 | a bus mapping driver. |
227 | 223 | ||
228 | config MTD_ABSENT | 224 | config MTD_ABSENT |
229 | tristate "Support for absent chips in bus mapping" | 225 | tristate "Support for absent chips in bus mapping" |
230 | depends on MTD | ||
231 | help | 226 | help |
232 | This option enables support for a dummy probing driver used to | 227 | This option enables support for a dummy probing driver used to |
233 | allocated placeholder MTD devices on systems that have socketed | 228 | allocated placeholder MTD devices on systems that have socketed |
@@ -237,7 +232,6 @@ config MTD_ABSENT | |||
237 | with this driver will return -ENODEV upon access. | 232 | with this driver will return -ENODEV upon access. |
238 | 233 | ||
239 | config MTD_OBSOLETE_CHIPS | 234 | config MTD_OBSOLETE_CHIPS |
240 | depends on MTD | ||
241 | bool "Older (theoretically obsoleted now) drivers for non-CFI chips" | 235 | bool "Older (theoretically obsoleted now) drivers for non-CFI chips" |
242 | help | 236 | help |
243 | This option does not enable any code directly, but will allow you to | 237 | This option does not enable any code directly, but will allow you to |
@@ -250,7 +244,7 @@ config MTD_OBSOLETE_CHIPS | |||
250 | 244 | ||
251 | config MTD_AMDSTD | 245 | config MTD_AMDSTD |
252 | tristate "AMD compatible flash chip support (non-CFI)" | 246 | tristate "AMD compatible flash chip support (non-CFI)" |
253 | depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN | 247 | depends on MTD_OBSOLETE_CHIPS && BROKEN |
254 | help | 248 | help |
255 | This option enables support for flash chips using AMD-compatible | 249 | This option enables support for flash chips using AMD-compatible |
256 | commands, including some which are not CFI-compatible and hence | 250 | commands, including some which are not CFI-compatible and hence |
@@ -260,7 +254,7 @@ config MTD_AMDSTD | |||
260 | 254 | ||
261 | config MTD_SHARP | 255 | config MTD_SHARP |
262 | tristate "pre-CFI Sharp chip support" | 256 | tristate "pre-CFI Sharp chip support" |
263 | depends on MTD && MTD_OBSOLETE_CHIPS | 257 | depends on MTD_OBSOLETE_CHIPS |
264 | help | 258 | help |
265 | This option enables support for flash chips using Sharp-compatible | 259 | This option enables support for flash chips using Sharp-compatible |
266 | commands, including some which are not CFI-compatible and hence | 260 | commands, including some which are not CFI-compatible and hence |
@@ -268,7 +262,7 @@ config MTD_SHARP | |||
268 | 262 | ||
269 | config MTD_JEDEC | 263 | config MTD_JEDEC |
270 | tristate "JEDEC device support" | 264 | tristate "JEDEC device support" |
271 | depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN | 265 | depends on MTD_OBSOLETE_CHIPS && BROKEN |
272 | help | 266 | help |
273 | Enable older JEDEC flash interface devices for self | 267 | Enable older JEDEC flash interface devices for self |
274 | programming flash. It is commonly used in older AMD chips. It is | 268 | programming flash. It is commonly used in older AMD chips. It is |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index f334959a335b..2f19fa78d24a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -15,6 +15,8 @@ | |||
15 | * - optimized write buffer method | 15 | * - optimized write buffer method |
16 | * 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com> | 16 | * 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com> |
17 | * - reworked lock/unlock/erase support for var size flash | 17 | * - reworked lock/unlock/erase support for var size flash |
18 | * 21/03/2007 Rodolfo Giometti <giometti@linux.it> | ||
19 | * - auto unlock sectors on resume for auto locking flash on power up | ||
18 | */ | 20 | */ |
19 | 21 | ||
20 | #include <linux/module.h> | 22 | #include <linux/module.h> |
@@ -30,6 +32,7 @@ | |||
30 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
31 | #include <linux/interrupt.h> | 33 | #include <linux/interrupt.h> |
32 | #include <linux/reboot.h> | 34 | #include <linux/reboot.h> |
35 | #include <linux/bitmap.h> | ||
33 | #include <linux/mtd/xip.h> | 36 | #include <linux/mtd/xip.h> |
34 | #include <linux/mtd/map.h> | 37 | #include <linux/mtd/map.h> |
35 | #include <linux/mtd/mtd.h> | 38 | #include <linux/mtd/mtd.h> |
@@ -220,6 +223,15 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | |||
220 | } | 223 | } |
221 | } | 224 | } |
222 | 225 | ||
226 | /* | ||
227 | * Some chips power-up with all sectors locked by default. | ||
228 | */ | ||
229 | static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param) | ||
230 | { | ||
231 | printk(KERN_INFO "Using auto-unlock on power-up/resume\n" ); | ||
232 | mtd->flags |= MTD_STUPID_LOCK; | ||
233 | } | ||
234 | |||
223 | static struct cfi_fixup cfi_fixup_table[] = { | 235 | static struct cfi_fixup cfi_fixup_table[] = { |
224 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 236 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
225 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, | 237 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, |
@@ -232,6 +244,7 @@ static struct cfi_fixup cfi_fixup_table[] = { | |||
232 | #endif | 244 | #endif |
233 | { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, | 245 | { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, |
234 | { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, | 246 | { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, |
247 | { MANUFACTURER_INTEL, 0x891c, fixup_use_powerup_lock, NULL, }, | ||
235 | { 0, 0, NULL, NULL } | 248 | { 0, 0, NULL, NULL } |
236 | }; | 249 | }; |
237 | 250 | ||
@@ -460,6 +473,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) | |||
460 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; | 473 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset; |
461 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; | 474 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize; |
462 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; | 475 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; |
476 | mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].lockmap = kmalloc(ernum / 8 + 1, GFP_KERNEL); | ||
463 | } | 477 | } |
464 | offset += (ersize * ernum); | 478 | offset += (ersize * ernum); |
465 | } | 479 | } |
@@ -1825,8 +1839,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd) | |||
1825 | } | 1839 | } |
1826 | } | 1840 | } |
1827 | 1841 | ||
1828 | #ifdef DEBUG_LOCK_BITS | 1842 | static int __xipram do_getlockstatus_oneblock(struct map_info *map, |
1829 | static int __xipram do_printlockstatus_oneblock(struct map_info *map, | ||
1830 | struct flchip *chip, | 1843 | struct flchip *chip, |
1831 | unsigned long adr, | 1844 | unsigned long adr, |
1832 | int len, void *thunk) | 1845 | int len, void *thunk) |
@@ -1840,8 +1853,17 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map, | |||
1840 | chip->state = FL_JEDEC_QUERY; | 1853 | chip->state = FL_JEDEC_QUERY; |
1841 | status = cfi_read_query(map, adr+(2*ofs_factor)); | 1854 | status = cfi_read_query(map, adr+(2*ofs_factor)); |
1842 | xip_enable(map, chip, 0); | 1855 | xip_enable(map, chip, 0); |
1856 | return status; | ||
1857 | } | ||
1858 | |||
1859 | #ifdef DEBUG_LOCK_BITS | ||
1860 | static int __xipram do_printlockstatus_oneblock(struct map_info *map, | ||
1861 | struct flchip *chip, | ||
1862 | unsigned long adr, | ||
1863 | int len, void *thunk) | ||
1864 | { | ||
1843 | printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", | 1865 | printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", |
1844 | adr, status); | 1866 | adr, do_getlockstatus_oneblock(map, chip, adr, len, thunk)); |
1845 | return 0; | 1867 | return 0; |
1846 | } | 1868 | } |
1847 | #endif | 1869 | #endif |
@@ -2216,14 +2238,45 @@ static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, | |||
2216 | 2238 | ||
2217 | #endif | 2239 | #endif |
2218 | 2240 | ||
2241 | static void cfi_intelext_save_locks(struct mtd_info *mtd) | ||
2242 | { | ||
2243 | struct mtd_erase_region_info *region; | ||
2244 | int block, status, i; | ||
2245 | unsigned long adr; | ||
2246 | size_t len; | ||
2247 | |||
2248 | for (i = 0; i < mtd->numeraseregions; i++) { | ||
2249 | region = &mtd->eraseregions[i]; | ||
2250 | if (!region->lockmap) | ||
2251 | continue; | ||
2252 | |||
2253 | for (block = 0; block < region->numblocks; block++){ | ||
2254 | len = region->erasesize; | ||
2255 | adr = region->offset + block * len; | ||
2256 | |||
2257 | status = cfi_varsize_frob(mtd, | ||
2258 | do_getlockstatus_oneblock, adr, len, 0); | ||
2259 | if (status) | ||
2260 | set_bit(block, region->lockmap); | ||
2261 | else | ||
2262 | clear_bit(block, region->lockmap); | ||
2263 | } | ||
2264 | } | ||
2265 | } | ||
2266 | |||
2219 | static int cfi_intelext_suspend(struct mtd_info *mtd) | 2267 | static int cfi_intelext_suspend(struct mtd_info *mtd) |
2220 | { | 2268 | { |
2221 | struct map_info *map = mtd->priv; | 2269 | struct map_info *map = mtd->priv; |
2222 | struct cfi_private *cfi = map->fldrv_priv; | 2270 | struct cfi_private *cfi = map->fldrv_priv; |
2271 | struct cfi_pri_intelext *extp = cfi->cmdset_priv; | ||
2223 | int i; | 2272 | int i; |
2224 | struct flchip *chip; | 2273 | struct flchip *chip; |
2225 | int ret = 0; | 2274 | int ret = 0; |
2226 | 2275 | ||
2276 | if ((mtd->flags & MTD_STUPID_LOCK) | ||
2277 | && extp && (extp->FeatureSupport & (1 << 5))) | ||
2278 | cfi_intelext_save_locks(mtd); | ||
2279 | |||
2227 | for (i=0; !ret && i<cfi->numchips; i++) { | 2280 | for (i=0; !ret && i<cfi->numchips; i++) { |
2228 | chip = &cfi->chips[i]; | 2281 | chip = &cfi->chips[i]; |
2229 | 2282 | ||
@@ -2285,10 +2338,33 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) | |||
2285 | return ret; | 2338 | return ret; |
2286 | } | 2339 | } |
2287 | 2340 | ||
2341 | static void cfi_intelext_restore_locks(struct mtd_info *mtd) | ||
2342 | { | ||
2343 | struct mtd_erase_region_info *region; | ||
2344 | int block, i; | ||
2345 | unsigned long adr; | ||
2346 | size_t len; | ||
2347 | |||
2348 | for (i = 0; i < mtd->numeraseregions; i++) { | ||
2349 | region = &mtd->eraseregions[i]; | ||
2350 | if (!region->lockmap) | ||
2351 | continue; | ||
2352 | |||
2353 | for (block = 0; block < region->numblocks; block++) { | ||
2354 | len = region->erasesize; | ||
2355 | adr = region->offset + block * len; | ||
2356 | |||
2357 | if (!test_bit(block, region->lockmap)) | ||
2358 | cfi_intelext_unlock(mtd, adr, len); | ||
2359 | } | ||
2360 | } | ||
2361 | } | ||
2362 | |||
2288 | static void cfi_intelext_resume(struct mtd_info *mtd) | 2363 | static void cfi_intelext_resume(struct mtd_info *mtd) |
2289 | { | 2364 | { |
2290 | struct map_info *map = mtd->priv; | 2365 | struct map_info *map = mtd->priv; |
2291 | struct cfi_private *cfi = map->fldrv_priv; | 2366 | struct cfi_private *cfi = map->fldrv_priv; |
2367 | struct cfi_pri_intelext *extp = cfi->cmdset_priv; | ||
2292 | int i; | 2368 | int i; |
2293 | struct flchip *chip; | 2369 | struct flchip *chip; |
2294 | 2370 | ||
@@ -2307,6 +2383,10 @@ static void cfi_intelext_resume(struct mtd_info *mtd) | |||
2307 | 2383 | ||
2308 | spin_unlock(chip->mutex); | 2384 | spin_unlock(chip->mutex); |
2309 | } | 2385 | } |
2386 | |||
2387 | if ((mtd->flags & MTD_STUPID_LOCK) | ||
2388 | && extp && (extp->FeatureSupport & (1 << 5))) | ||
2389 | cfi_intelext_restore_locks(mtd); | ||
2310 | } | 2390 | } |
2311 | 2391 | ||
2312 | static int cfi_intelext_reset(struct mtd_info *mtd) | 2392 | static int cfi_intelext_reset(struct mtd_info *mtd) |
@@ -2347,12 +2427,19 @@ static void cfi_intelext_destroy(struct mtd_info *mtd) | |||
2347 | { | 2427 | { |
2348 | struct map_info *map = mtd->priv; | 2428 | struct map_info *map = mtd->priv; |
2349 | struct cfi_private *cfi = map->fldrv_priv; | 2429 | struct cfi_private *cfi = map->fldrv_priv; |
2430 | struct mtd_erase_region_info *region; | ||
2431 | int i; | ||
2350 | cfi_intelext_reset(mtd); | 2432 | cfi_intelext_reset(mtd); |
2351 | unregister_reboot_notifier(&mtd->reboot_notifier); | 2433 | unregister_reboot_notifier(&mtd->reboot_notifier); |
2352 | kfree(cfi->cmdset_priv); | 2434 | kfree(cfi->cmdset_priv); |
2353 | kfree(cfi->cfiq); | 2435 | kfree(cfi->cfiq); |
2354 | kfree(cfi->chips[0].priv); | 2436 | kfree(cfi->chips[0].priv); |
2355 | kfree(cfi); | 2437 | kfree(cfi); |
2438 | for (i = 0; i < mtd->numeraseregions; i++) { | ||
2439 | region = &mtd->eraseregions[i]; | ||
2440 | if (region->lockmap) | ||
2441 | kfree(region->lockmap); | ||
2442 | } | ||
2356 | kfree(mtd->eraseregions); | 2443 | kfree(mtd->eraseregions); |
2357 | } | 2444 | } |
2358 | 2445 | ||
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index 77303ce5dcf1..ab44f2b996f8 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h | |||
@@ -65,11 +65,12 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, | |||
65 | return ret; | 65 | return ret; |
66 | } | 66 | } |
67 | 67 | ||
68 | chip->oldstate = chip->state; | ||
68 | chip->state = xxlt->state; | 69 | chip->state = xxlt->state; |
69 | map_write(map, CMD(xxlt->val), adr); | 70 | map_write(map, CMD(xxlt->val), adr); |
70 | 71 | ||
71 | /* Done and happy. */ | 72 | /* Done and happy. */ |
72 | chip->state = FL_READY; | 73 | chip->state = chip->oldstate; |
73 | put_chip(map, chip, adr); | 74 | put_chip(map, chip, adr); |
74 | spin_unlock(chip->mutex); | 75 | spin_unlock(chip->mutex); |
75 | return 0; | 76 | return 0; |
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 440f6851da69..690c94236d7f 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig | |||
@@ -6,7 +6,7 @@ menu "Self-contained MTD device drivers" | |||
6 | 6 | ||
7 | config MTD_PMC551 | 7 | config MTD_PMC551 |
8 | tristate "Ramix PMC551 PCI Mezzanine RAM card support" | 8 | tristate "Ramix PMC551 PCI Mezzanine RAM card support" |
9 | depends on MTD && PCI | 9 | depends on PCI |
10 | ---help--- | 10 | ---help--- |
11 | This provides a MTD device driver for the Ramix PMC551 RAM PCI card | 11 | This provides a MTD device driver for the Ramix PMC551 RAM PCI card |
12 | from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>. | 12 | from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>. |
@@ -40,7 +40,7 @@ config MTD_PMC551_DEBUG | |||
40 | 40 | ||
41 | config MTD_MS02NV | 41 | config MTD_MS02NV |
42 | tristate "DEC MS02-NV NVRAM module support" | 42 | tristate "DEC MS02-NV NVRAM module support" |
43 | depends on MTD && MACH_DECSTATION | 43 | depends on MACH_DECSTATION |
44 | help | 44 | help |
45 | This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery | 45 | This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery |
46 | backed-up NVRAM module. The module was originally meant as an NFS | 46 | backed-up NVRAM module. The module was originally meant as an NFS |
@@ -54,15 +54,23 @@ config MTD_MS02NV | |||
54 | 54 | ||
55 | config MTD_DATAFLASH | 55 | config MTD_DATAFLASH |
56 | tristate "Support for AT45xxx DataFlash" | 56 | tristate "Support for AT45xxx DataFlash" |
57 | depends on MTD && SPI_MASTER && EXPERIMENTAL | 57 | depends on SPI_MASTER && EXPERIMENTAL |
58 | help | 58 | help |
59 | This enables access to AT45xxx DataFlash chips, using SPI. | 59 | This enables access to AT45xxx DataFlash chips, using SPI. |
60 | Sometimes DataFlash chips are packaged inside MMC-format | 60 | Sometimes DataFlash chips are packaged inside MMC-format |
61 | cards; at this writing, the MMC stack won't handle those. | 61 | cards; at this writing, the MMC stack won't handle those. |
62 | 62 | ||
63 | config MTD_DATAFLASH26 | ||
64 | tristate "AT91RM9200 DataFlash AT26xxx" | ||
65 | depends on MTD && ARCH_AT91RM9200 && AT91_SPI | ||
66 | help | ||
67 | This enables access to the DataFlash chip (AT26xxx) on an | ||
68 | AT91RM9200-based board. | ||
69 | If you have such a board and such a DataFlash, say 'Y'. | ||
70 | |||
63 | config MTD_M25P80 | 71 | config MTD_M25P80 |
64 | tristate "Support for M25 SPI Flash" | 72 | tristate "Support for M25 SPI Flash" |
65 | depends on MTD && SPI_MASTER && EXPERIMENTAL | 73 | depends on SPI_MASTER && EXPERIMENTAL |
66 | help | 74 | help |
67 | This enables access to ST M25P80 and similar SPI flash chips, | 75 | This enables access to ST M25P80 and similar SPI flash chips, |
68 | used for program and data storage. Set up your spi devices | 76 | used for program and data storage. Set up your spi devices |
@@ -70,7 +78,6 @@ config MTD_M25P80 | |||
70 | 78 | ||
71 | config MTD_SLRAM | 79 | config MTD_SLRAM |
72 | tristate "Uncached system RAM" | 80 | tristate "Uncached system RAM" |
73 | depends on MTD | ||
74 | help | 81 | help |
75 | If your CPU cannot cache all of the physical memory in your machine, | 82 | If your CPU cannot cache all of the physical memory in your machine, |
76 | you can still use it for storage or swap by using this driver to | 83 | you can still use it for storage or swap by using this driver to |
@@ -78,7 +85,6 @@ config MTD_SLRAM | |||
78 | 85 | ||
79 | config MTD_PHRAM | 86 | config MTD_PHRAM |
80 | tristate "Physical system RAM" | 87 | tristate "Physical system RAM" |
81 | depends on MTD | ||
82 | help | 88 | help |
83 | This is a re-implementation of the slram driver above. | 89 | This is a re-implementation of the slram driver above. |
84 | 90 | ||
@@ -88,7 +94,7 @@ config MTD_PHRAM | |||
88 | 94 | ||
89 | config MTD_LART | 95 | config MTD_LART |
90 | tristate "28F160xx flash driver for LART" | 96 | tristate "28F160xx flash driver for LART" |
91 | depends on SA1100_LART && MTD | 97 | depends on SA1100_LART |
92 | help | 98 | help |
93 | This enables the flash driver for LART. Please note that you do | 99 | This enables the flash driver for LART. Please note that you do |
94 | not need any mapping/chip driver for LART. This one does it all | 100 | not need any mapping/chip driver for LART. This one does it all |
@@ -96,7 +102,6 @@ config MTD_LART | |||
96 | 102 | ||
97 | config MTD_MTDRAM | 103 | config MTD_MTDRAM |
98 | tristate "Test driver using RAM" | 104 | tristate "Test driver using RAM" |
99 | depends on MTD | ||
100 | help | 105 | help |
101 | This enables a test MTD device driver which uses vmalloc() to | 106 | This enables a test MTD device driver which uses vmalloc() to |
102 | provide storage. You probably want to say 'N' unless you're | 107 | provide storage. You probably want to say 'N' unless you're |
@@ -136,7 +141,7 @@ config MTDRAM_ABS_POS | |||
136 | 141 | ||
137 | config MTD_BLOCK2MTD | 142 | config MTD_BLOCK2MTD |
138 | tristate "MTD using block device" | 143 | tristate "MTD using block device" |
139 | depends on MTD && BLOCK | 144 | depends on BLOCK |
140 | help | 145 | help |
141 | This driver allows a block device to appear as an MTD. It would | 146 | This driver allows a block device to appear as an MTD. It would |
142 | generally be used in the following cases: | 147 | generally be used in the following cases: |
@@ -150,7 +155,6 @@ comment "Disk-On-Chip Device Drivers" | |||
150 | 155 | ||
151 | config MTD_DOC2000 | 156 | config MTD_DOC2000 |
152 | tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)" | 157 | tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)" |
153 | depends on MTD | ||
154 | select MTD_DOCPROBE | 158 | select MTD_DOCPROBE |
155 | select MTD_NAND_IDS | 159 | select MTD_NAND_IDS |
156 | ---help--- | 160 | ---help--- |
@@ -173,7 +177,6 @@ config MTD_DOC2000 | |||
173 | 177 | ||
174 | config MTD_DOC2001 | 178 | config MTD_DOC2001 |
175 | tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)" | 179 | tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)" |
176 | depends on MTD | ||
177 | select MTD_DOCPROBE | 180 | select MTD_DOCPROBE |
178 | select MTD_NAND_IDS | 181 | select MTD_NAND_IDS |
179 | ---help--- | 182 | ---help--- |
@@ -195,7 +198,6 @@ config MTD_DOC2001 | |||
195 | 198 | ||
196 | config MTD_DOC2001PLUS | 199 | config MTD_DOC2001PLUS |
197 | tristate "M-Systems Disk-On-Chip Millennium Plus" | 200 | tristate "M-Systems Disk-On-Chip Millennium Plus" |
198 | depends on MTD | ||
199 | select MTD_DOCPROBE | 201 | select MTD_DOCPROBE |
200 | select MTD_NAND_IDS | 202 | select MTD_NAND_IDS |
201 | ---help--- | 203 | ---help--- |
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 0f788d5c4bf8..8ab568b3f533 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile | |||
@@ -16,4 +16,5 @@ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o | |||
16 | obj-$(CONFIG_MTD_LART) += lart.o | 16 | obj-$(CONFIG_MTD_LART) += lart.o |
17 | obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o | 17 | obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o |
18 | obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o | 18 | obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o |
19 | obj-$(CONFIG_MTD_DATAFLASH26) += at91_dataflash26.o | ||
19 | obj-$(CONFIG_MTD_M25P80) += m25p80.o | 20 | obj-$(CONFIG_MTD_M25P80) += m25p80.o |
diff --git a/drivers/mtd/devices/at91_dataflash26.c b/drivers/mtd/devices/at91_dataflash26.c new file mode 100644 index 000000000000..64ce37f986fc --- /dev/null +++ b/drivers/mtd/devices/at91_dataflash26.c | |||
@@ -0,0 +1,485 @@ | |||
1 | /* | ||
2 | * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder) | ||
3 | * This is a largely modified version of at91_dataflash.c that | ||
4 | * supports AT26xxx dataflash chips. The original driver supports | ||
5 | * AT45xxx chips. | ||
6 | * | ||
7 | * Note: This driver was only tested with an AT26F004. It should be | ||
8 | * easy to make it work with other AT26xxx dataflash devices, though. | ||
9 | * | ||
10 | * Copyright (C) 2007 Hans J. Koch <hjk@linutronix.de> | ||
11 | * original Copyright (C) SAN People (Pty) Ltd | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * version 2 as published by the Free Software Foundation. | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/mtd/mtd.h> | ||
22 | |||
23 | #include <asm/arch/at91_spi.h> | ||
24 | |||
25 | #define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */ | ||
26 | |||
27 | #define MANUFACTURER_ID_ATMEL 0x1F | ||
28 | |||
29 | /* command codes */ | ||
30 | |||
31 | #define AT26_OP_READ_STATUS 0x05 | ||
32 | #define AT26_OP_READ_DEV_ID 0x9F | ||
33 | #define AT26_OP_ERASE_PAGE_4K 0x20 | ||
34 | #define AT26_OP_READ_ARRAY_FAST 0x0B | ||
35 | #define AT26_OP_SEQUENTIAL_WRITE 0xAF | ||
36 | #define AT26_OP_WRITE_ENABLE 0x06 | ||
37 | #define AT26_OP_WRITE_DISABLE 0x04 | ||
38 | #define AT26_OP_SECTOR_PROTECT 0x36 | ||
39 | #define AT26_OP_SECTOR_UNPROTECT 0x39 | ||
40 | |||
41 | /* status register bits */ | ||
42 | |||
43 | #define AT26_STATUS_BUSY 0x01 | ||
44 | #define AT26_STATUS_WRITE_ENABLE 0x02 | ||
45 | |||
46 | struct dataflash_local | ||
47 | { | ||
48 | int spi; /* SPI chip-select number */ | ||
49 | unsigned int page_size; /* number of bytes per page */ | ||
50 | }; | ||
51 | |||
52 | |||
53 | /* Detected DataFlash devices */ | ||
54 | static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES]; | ||
55 | static int nr_devices = 0; | ||
56 | |||
57 | /* Allocate a single SPI transfer descriptor. We're assuming that if multiple | ||
58 | SPI transfers occur at the same time, spi_access_bus() will serialize them. | ||
59 | If this is not valid, then either (i) each dataflash 'priv' structure | ||
60 | needs it's own transfer descriptor, (ii) we lock this one, or (iii) use | ||
61 | another mechanism. */ | ||
62 | static struct spi_transfer_list* spi_transfer_desc; | ||
63 | |||
64 | /* | ||
65 | * Perform a SPI transfer to access the DataFlash device. | ||
66 | */ | ||
67 | static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len, | ||
68 | char* txnext, int txnext_len, char* rxnext, int rxnext_len) | ||
69 | { | ||
70 | struct spi_transfer_list* list = spi_transfer_desc; | ||
71 | |||
72 | list->tx[0] = tx; list->txlen[0] = tx_len; | ||
73 | list->rx[0] = rx; list->rxlen[0] = rx_len; | ||
74 | |||
75 | list->tx[1] = txnext; list->txlen[1] = txnext_len; | ||
76 | list->rx[1] = rxnext; list->rxlen[1] = rxnext_len; | ||
77 | |||
78 | list->nr_transfers = nr; | ||
79 | /* Note: spi_transfer() always returns 0, there are no error checks */ | ||
80 | return spi_transfer(list); | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Return the status of the DataFlash device. | ||
85 | */ | ||
86 | static unsigned char at91_dataflash26_status(void) | ||
87 | { | ||
88 | unsigned char command[2]; | ||
89 | |||
90 | command[0] = AT26_OP_READ_STATUS; | ||
91 | command[1] = 0; | ||
92 | |||
93 | do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0); | ||
94 | |||
95 | return command[1]; | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * Poll the DataFlash device until it is READY. | ||
100 | */ | ||
101 | static unsigned char at91_dataflash26_waitready(void) | ||
102 | { | ||
103 | unsigned char status; | ||
104 | |||
105 | while (1) { | ||
106 | status = at91_dataflash26_status(); | ||
107 | if (!(status & AT26_STATUS_BUSY)) | ||
108 | return status; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Enable/disable write access | ||
114 | */ | ||
115 | static void at91_dataflash26_write_enable(int enable) | ||
116 | { | ||
117 | unsigned char cmd[2]; | ||
118 | |||
119 | DEBUG(MTD_DEBUG_LEVEL3, "write_enable: enable=%i\n", enable); | ||
120 | |||
121 | if (enable) | ||
122 | cmd[0] = AT26_OP_WRITE_ENABLE; | ||
123 | else | ||
124 | cmd[0] = AT26_OP_WRITE_DISABLE; | ||
125 | cmd[1] = 0; | ||
126 | |||
127 | do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * Protect/unprotect sector | ||
132 | */ | ||
133 | static void at91_dataflash26_sector_protect(loff_t addr, int protect) | ||
134 | { | ||
135 | unsigned char cmd[4]; | ||
136 | |||
137 | DEBUG(MTD_DEBUG_LEVEL3, "sector_protect: addr=0x%06x prot=%d\n", | ||
138 | addr, protect); | ||
139 | |||
140 | if (protect) | ||
141 | cmd[0] = AT26_OP_SECTOR_PROTECT; | ||
142 | else | ||
143 | cmd[0] = AT26_OP_SECTOR_UNPROTECT; | ||
144 | cmd[1] = (addr & 0x00FF0000) >> 16; | ||
145 | cmd[2] = (addr & 0x0000FF00) >> 8; | ||
146 | cmd[3] = (addr & 0x000000FF); | ||
147 | |||
148 | do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0); | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Erase blocks of flash. | ||
153 | */ | ||
154 | static int at91_dataflash26_erase(struct mtd_info *mtd, | ||
155 | struct erase_info *instr) | ||
156 | { | ||
157 | struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; | ||
158 | unsigned char cmd[4]; | ||
159 | |||
160 | DEBUG(MTD_DEBUG_LEVEL1, "dataflash_erase: addr=0x%06x len=%i\n", | ||
161 | instr->addr, instr->len); | ||
162 | |||
163 | /* Sanity checks */ | ||
164 | if (priv->page_size != 4096) | ||
165 | return -EINVAL; /* Can't handle other sizes at the moment */ | ||
166 | |||
167 | if ( ((instr->len % mtd->erasesize) != 0) | ||
168 | || ((instr->len % priv->page_size) != 0) | ||
169 | || ((instr->addr % priv->page_size) != 0) | ||
170 | || ((instr->addr + instr->len) > mtd->size)) | ||
171 | return -EINVAL; | ||
172 | |||
173 | spi_access_bus(priv->spi); | ||
174 | |||
175 | while (instr->len > 0) { | ||
176 | at91_dataflash26_write_enable(1); | ||
177 | at91_dataflash26_sector_protect(instr->addr, 0); | ||
178 | at91_dataflash26_write_enable(1); | ||
179 | cmd[0] = AT26_OP_ERASE_PAGE_4K; | ||
180 | cmd[1] = (instr->addr & 0x00FF0000) >> 16; | ||
181 | cmd[2] = (instr->addr & 0x0000FF00) >> 8; | ||
182 | cmd[3] = (instr->addr & 0x000000FF); | ||
183 | |||
184 | DEBUG(MTD_DEBUG_LEVEL3, "ERASE: (0x%02x) 0x%02x 0x%02x" | ||
185 | "0x%02x\n", | ||
186 | cmd[0], cmd[1], cmd[2], cmd[3]); | ||
187 | |||
188 | do_spi_transfer(1, cmd, 4, cmd, 4, NULL, 0, NULL, 0); | ||
189 | at91_dataflash26_waitready(); | ||
190 | |||
191 | instr->addr += priv->page_size; /* next page */ | ||
192 | instr->len -= priv->page_size; | ||
193 | } | ||
194 | |||
195 | at91_dataflash26_write_enable(0); | ||
196 | spi_release_bus(priv->spi); | ||
197 | |||
198 | /* Inform MTD subsystem that erase is complete */ | ||
199 | instr->state = MTD_ERASE_DONE; | ||
200 | if (instr->callback) | ||
201 | instr->callback(instr); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * Read from the DataFlash device. | ||
208 | * from : Start offset in flash device | ||
209 | * len : Number of bytes to read | ||
210 | * retlen : Number of bytes actually read | ||
211 | * buf : Buffer that will receive data | ||
212 | */ | ||
213 | static int at91_dataflash26_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
214 | size_t *retlen, u_char *buf) | ||
215 | { | ||
216 | struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; | ||
217 | unsigned char cmd[5]; | ||
218 | |||
219 | DEBUG(MTD_DEBUG_LEVEL1, "dataflash_read: %lli .. %lli\n", | ||
220 | from, from+len); | ||
221 | |||
222 | *retlen = 0; | ||
223 | |||
224 | /* Sanity checks */ | ||
225 | if (!len) | ||
226 | return 0; | ||
227 | if (from + len > mtd->size) | ||
228 | return -EINVAL; | ||
229 | |||
230 | cmd[0] = AT26_OP_READ_ARRAY_FAST; | ||
231 | cmd[1] = (from & 0x00FF0000) >> 16; | ||
232 | cmd[2] = (from & 0x0000FF00) >> 8; | ||
233 | cmd[3] = (from & 0x000000FF); | ||
234 | /* cmd[4] is a "Don't care" byte */ | ||
235 | |||
236 | DEBUG(MTD_DEBUG_LEVEL3, "READ: (0x%02x) 0x%02x 0x%02x 0x%02x\n", | ||
237 | cmd[0], cmd[1], cmd[2], cmd[3]); | ||
238 | |||
239 | spi_access_bus(priv->spi); | ||
240 | do_spi_transfer(2, cmd, 5, cmd, 5, buf, len, buf, len); | ||
241 | spi_release_bus(priv->spi); | ||
242 | |||
243 | *retlen = len; | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * Write to the DataFlash device. | ||
249 | * to : Start offset in flash device | ||
250 | * len : Number of bytes to write | ||
251 | * retlen : Number of bytes actually written | ||
252 | * buf : Buffer containing the data | ||
253 | */ | ||
254 | static int at91_dataflash26_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
255 | size_t *retlen, const u_char *buf) | ||
256 | { | ||
257 | struct dataflash_local *priv = (struct dataflash_local *) mtd->priv; | ||
258 | unsigned int addr, buf_index = 0; | ||
259 | int ret = -EIO, sector, last_sector; | ||
260 | unsigned char status, cmd[5]; | ||
261 | |||
262 | DEBUG(MTD_DEBUG_LEVEL1, "dataflash_write: %lli .. %lli\n", to, to+len); | ||
263 | |||
264 | *retlen = 0; | ||
265 | |||
266 | /* Sanity checks */ | ||
267 | if (!len) | ||
268 | return 0; | ||
269 | if (to + len > mtd->size) | ||
270 | return -EINVAL; | ||
271 | |||
272 | spi_access_bus(priv->spi); | ||
273 | |||
274 | addr = to; | ||
275 | last_sector = -1; | ||
276 | |||
277 | while (buf_index < len) { | ||
278 | sector = addr / priv->page_size; | ||
279 | /* Write first byte if a new sector begins */ | ||
280 | if (sector != last_sector) { | ||
281 | at91_dataflash26_write_enable(1); | ||
282 | at91_dataflash26_sector_protect(addr, 0); | ||
283 | at91_dataflash26_write_enable(1); | ||
284 | |||
285 | /* Program first byte of a new sector */ | ||
286 | cmd[0] = AT26_OP_SEQUENTIAL_WRITE; | ||
287 | cmd[1] = (addr & 0x00FF0000) >> 16; | ||
288 | cmd[2] = (addr & 0x0000FF00) >> 8; | ||
289 | cmd[3] = (addr & 0x000000FF); | ||
290 | cmd[4] = buf[buf_index++]; | ||
291 | do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0); | ||
292 | status = at91_dataflash26_waitready(); | ||
293 | addr++; | ||
294 | /* On write errors, the chip resets the write enable | ||
295 | flag. This also happens after the last byte of a | ||
296 | sector is successfully programmed. */ | ||
297 | if ( ( !(status & AT26_STATUS_WRITE_ENABLE)) | ||
298 | && ((addr % priv->page_size) != 0) ) { | ||
299 | DEBUG(MTD_DEBUG_LEVEL1, | ||
300 | "write error1: addr=0x%06x, " | ||
301 | "status=0x%02x\n", addr, status); | ||
302 | goto write_err; | ||
303 | } | ||
304 | (*retlen)++; | ||
305 | last_sector = sector; | ||
306 | } | ||
307 | |||
308 | /* Write subsequent bytes in the same sector */ | ||
309 | cmd[0] = AT26_OP_SEQUENTIAL_WRITE; | ||
310 | cmd[1] = buf[buf_index++]; | ||
311 | do_spi_transfer(1, cmd, 2, cmd, 2, NULL, 0, NULL, 0); | ||
312 | status = at91_dataflash26_waitready(); | ||
313 | addr++; | ||
314 | |||
315 | if ( ( !(status & AT26_STATUS_WRITE_ENABLE)) | ||
316 | && ((addr % priv->page_size) != 0) ) { | ||
317 | DEBUG(MTD_DEBUG_LEVEL1, "write error2: addr=0x%06x, " | ||
318 | "status=0x%02x\n", addr, status); | ||
319 | goto write_err; | ||
320 | } | ||
321 | |||
322 | (*retlen)++; | ||
323 | } | ||
324 | |||
325 | ret = 0; | ||
326 | at91_dataflash26_write_enable(0); | ||
327 | write_err: | ||
328 | spi_release_bus(priv->spi); | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Initialize and register DataFlash device with MTD subsystem. | ||
334 | */ | ||
335 | static int __init add_dataflash(int channel, char *name, int nr_pages, | ||
336 | int pagesize) | ||
337 | { | ||
338 | struct mtd_info *device; | ||
339 | struct dataflash_local *priv; | ||
340 | |||
341 | if (nr_devices >= DATAFLASH_MAX_DEVICES) { | ||
342 | printk(KERN_ERR "at91_dataflash26: Too many devices " | ||
343 | "detected\n"); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | device = kzalloc(sizeof(struct mtd_info) + strlen(name) + 8, | ||
348 | GFP_KERNEL); | ||
349 | if (!device) | ||
350 | return -ENOMEM; | ||
351 | |||
352 | device->name = (char *)&device[1]; | ||
353 | sprintf(device->name, "%s.spi%d", name, channel); | ||
354 | device->size = nr_pages * pagesize; | ||
355 | device->erasesize = pagesize; | ||
356 | device->owner = THIS_MODULE; | ||
357 | device->type = MTD_DATAFLASH; | ||
358 | device->flags = MTD_CAP_NORFLASH; | ||
359 | device->erase = at91_dataflash26_erase; | ||
360 | device->read = at91_dataflash26_read; | ||
361 | device->write = at91_dataflash26_write; | ||
362 | |||
363 | priv = (struct dataflash_local *)kzalloc(sizeof(struct dataflash_local), | ||
364 | GFP_KERNEL); | ||
365 | if (!priv) { | ||
366 | kfree(device); | ||
367 | return -ENOMEM; | ||
368 | } | ||
369 | |||
370 | priv->spi = channel; | ||
371 | priv->page_size = pagesize; | ||
372 | device->priv = priv; | ||
373 | |||
374 | mtd_devices[nr_devices] = device; | ||
375 | nr_devices++; | ||
376 | printk(KERN_INFO "at91_dataflash26: %s detected [spi%i] (%i bytes)\n", | ||
377 | name, channel, device->size); | ||
378 | |||
379 | return add_mtd_device(device); | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * Detect and initialize DataFlash device connected to specified SPI channel. | ||
384 | * | ||
385 | */ | ||
386 | |||
387 | struct dataflash26_types { | ||
388 | unsigned char id0; | ||
389 | unsigned char id1; | ||
390 | char *name; | ||
391 | int pagesize; | ||
392 | int nr_pages; | ||
393 | }; | ||
394 | |||
395 | struct dataflash26_types df26_types[] = { | ||
396 | { | ||
397 | .id0 = 0x04, | ||
398 | .id1 = 0x00, | ||
399 | .name = "AT26F004", | ||
400 | .pagesize = 4096, | ||
401 | .nr_pages = 128, | ||
402 | }, | ||
403 | { | ||
404 | .id0 = 0x45, | ||
405 | .id1 = 0x01, | ||
406 | .name = "AT26DF081A", /* Not tested ! */ | ||
407 | .pagesize = 4096, | ||
408 | .nr_pages = 256, | ||
409 | }, | ||
410 | }; | ||
411 | |||
412 | static int __init at91_dataflash26_detect(int channel) | ||
413 | { | ||
414 | unsigned char status, cmd[5]; | ||
415 | int i; | ||
416 | |||
417 | spi_access_bus(channel); | ||
418 | status = at91_dataflash26_status(); | ||
419 | |||
420 | if (status == 0 || status == 0xff) { | ||
421 | printk(KERN_ERR "at91_dataflash26_detect: status error %d\n", | ||
422 | status); | ||
423 | spi_release_bus(channel); | ||
424 | return -ENODEV; | ||
425 | } | ||
426 | |||
427 | cmd[0] = AT26_OP_READ_DEV_ID; | ||
428 | do_spi_transfer(1, cmd, 5, cmd, 5, NULL, 0, NULL, 0); | ||
429 | spi_release_bus(channel); | ||
430 | |||
431 | if (cmd[1] != MANUFACTURER_ID_ATMEL) | ||
432 | return -ENODEV; | ||
433 | |||
434 | for (i = 0; i < ARRAY_SIZE(df26_types); i++) { | ||
435 | if ( cmd[2] == df26_types[i].id0 | ||
436 | && cmd[3] == df26_types[i].id1) | ||
437 | return add_dataflash(channel, | ||
438 | df26_types[i].name, | ||
439 | df26_types[i].nr_pages, | ||
440 | df26_types[i].pagesize); | ||
441 | } | ||
442 | |||
443 | printk(KERN_ERR "at91_dataflash26_detect: Unsupported device " | ||
444 | "(0x%02x/0x%02x)\n", cmd[2], cmd[3]); | ||
445 | return -ENODEV; | ||
446 | } | ||
447 | |||
448 | static int __init at91_dataflash26_init(void) | ||
449 | { | ||
450 | spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), | ||
451 | GFP_KERNEL); | ||
452 | if (!spi_transfer_desc) | ||
453 | return -ENOMEM; | ||
454 | |||
455 | /* DataFlash (SPI chip select 0) */ | ||
456 | at91_dataflash26_detect(0); | ||
457 | |||
458 | #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD | ||
459 | /* DataFlash card (SPI chip select 3) */ | ||
460 | at91_dataflash26_detect(3); | ||
461 | #endif | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static void __exit at91_dataflash26_exit(void) | ||
466 | { | ||
467 | int i; | ||
468 | |||
469 | for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) { | ||
470 | if (mtd_devices[i]) { | ||
471 | del_mtd_device(mtd_devices[i]); | ||
472 | kfree(mtd_devices[i]->priv); | ||
473 | kfree(mtd_devices[i]); | ||
474 | } | ||
475 | } | ||
476 | nr_devices = 0; | ||
477 | kfree(spi_transfer_desc); | ||
478 | } | ||
479 | |||
480 | module_init(at91_dataflash26_init); | ||
481 | module_exit(at91_dataflash26_exit); | ||
482 | |||
483 | MODULE_LICENSE("GPL"); | ||
484 | MODULE_AUTHOR("Hans J. Koch"); | ||
485 | MODULE_DESCRIPTION("DataFlash AT26xxx driver for Atmel AT91RM9200"); | ||
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index f9f2ce7806b0..ce47544dc120 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c | |||
@@ -40,56 +40,9 @@ struct block2mtd_dev { | |||
40 | static LIST_HEAD(blkmtd_device_list); | 40 | static LIST_HEAD(blkmtd_device_list); |
41 | 41 | ||
42 | 42 | ||
43 | #define PAGE_READAHEAD 64 | 43 | static struct page* page_read(struct address_space *mapping, int index) |
44 | static void cache_readahead(struct address_space *mapping, int index) | ||
45 | { | 44 | { |
46 | filler_t *filler = (filler_t*)mapping->a_ops->readpage; | 45 | filler_t *filler = (filler_t*)mapping->a_ops->readpage; |
47 | int i, pagei; | ||
48 | unsigned ret = 0; | ||
49 | unsigned long end_index; | ||
50 | struct page *page; | ||
51 | LIST_HEAD(page_pool); | ||
52 | struct inode *inode = mapping->host; | ||
53 | loff_t isize = i_size_read(inode); | ||
54 | |||
55 | if (!isize) { | ||
56 | INFO("iSize=0 in cache_readahead\n"); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | end_index = ((isize - 1) >> PAGE_CACHE_SHIFT); | ||
61 | |||
62 | read_lock_irq(&mapping->tree_lock); | ||
63 | for (i = 0; i < PAGE_READAHEAD; i++) { | ||
64 | pagei = index + i; | ||
65 | if (pagei > end_index) { | ||
66 | INFO("Overrun end of disk in cache readahead\n"); | ||
67 | break; | ||
68 | } | ||
69 | page = radix_tree_lookup(&mapping->page_tree, pagei); | ||
70 | if (page && (!i)) | ||
71 | break; | ||
72 | if (page) | ||
73 | continue; | ||
74 | read_unlock_irq(&mapping->tree_lock); | ||
75 | page = page_cache_alloc_cold(mapping); | ||
76 | read_lock_irq(&mapping->tree_lock); | ||
77 | if (!page) | ||
78 | break; | ||
79 | page->index = pagei; | ||
80 | list_add(&page->lru, &page_pool); | ||
81 | ret++; | ||
82 | } | ||
83 | read_unlock_irq(&mapping->tree_lock); | ||
84 | if (ret) | ||
85 | read_cache_pages(mapping, &page_pool, filler, NULL); | ||
86 | } | ||
87 | |||
88 | |||
89 | static struct page* page_readahead(struct address_space *mapping, int index) | ||
90 | { | ||
91 | filler_t *filler = (filler_t*)mapping->a_ops->readpage; | ||
92 | cache_readahead(mapping, index); | ||
93 | return read_cache_page(mapping, index, filler, NULL); | 46 | return read_cache_page(mapping, index, filler, NULL); |
94 | } | 47 | } |
95 | 48 | ||
@@ -105,14 +58,14 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len) | |||
105 | u_long *max; | 58 | u_long *max; |
106 | 59 | ||
107 | while (pages) { | 60 | while (pages) { |
108 | page = page_readahead(mapping, index); | 61 | page = page_read(mapping, index); |
109 | if (!page) | 62 | if (!page) |
110 | return -ENOMEM; | 63 | return -ENOMEM; |
111 | if (IS_ERR(page)) | 64 | if (IS_ERR(page)) |
112 | return PTR_ERR(page); | 65 | return PTR_ERR(page); |
113 | 66 | ||
114 | max = (u_long*)page_address(page) + PAGE_SIZE; | 67 | max = page_address(page) + PAGE_SIZE; |
115 | for (p=(u_long*)page_address(page); p<max; p++) | 68 | for (p=page_address(page); p<max; p++) |
116 | if (*p != -1UL) { | 69 | if (*p != -1UL) { |
117 | lock_page(page); | 70 | lock_page(page); |
118 | memset(page_address(page), 0xff, PAGE_SIZE); | 71 | memset(page_address(page), 0xff, PAGE_SIZE); |
@@ -174,8 +127,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
174 | cpylen = len; // this page | 127 | cpylen = len; // this page |
175 | len = len - cpylen; | 128 | len = len - cpylen; |
176 | 129 | ||
177 | // Get page | 130 | page = page_read(dev->blkdev->bd_inode->i_mapping, index); |
178 | page = page_readahead(dev->blkdev->bd_inode->i_mapping, index); | ||
179 | if (!page) | 131 | if (!page) |
180 | return -ENOMEM; | 132 | return -ENOMEM; |
181 | if (IS_ERR(page)) | 133 | if (IS_ERR(page)) |
@@ -213,8 +165,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf, | |||
213 | cpylen = len; // this page | 165 | cpylen = len; // this page |
214 | len = len - cpylen; | 166 | len = len - cpylen; |
215 | 167 | ||
216 | // Get page | 168 | page = page_read(mapping, index); |
217 | page = page_readahead(mapping, index); | ||
218 | if (!page) | 169 | if (!page) |
219 | return -ENOMEM; | 170 | return -ENOMEM; |
220 | if (IS_ERR(page)) | 171 | if (IS_ERR(page)) |
@@ -308,9 +259,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) | |||
308 | /* We might not have rootfs mounted at this point. Try | 259 | /* We might not have rootfs mounted at this point. Try |
309 | to resolve the device name by other means. */ | 260 | to resolve the device name by other means. */ |
310 | 261 | ||
311 | dev_t dev = name_to_dev_t(devname); | 262 | dev_t devt = name_to_dev_t(devname); |
312 | if (dev != 0) { | 263 | if (devt) { |
313 | bdev = open_by_devnum(dev, FMODE_WRITE | FMODE_READ); | 264 | bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ); |
314 | } | 265 | } |
315 | } | 266 | } |
316 | #endif | 267 | #endif |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index bbf0553bdb2e..d990d8141ef5 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
@@ -6,7 +6,6 @@ menu "Mapping drivers for chip access" | |||
6 | 6 | ||
7 | config MTD_COMPLEX_MAPPINGS | 7 | config MTD_COMPLEX_MAPPINGS |
8 | bool "Support non-linear mappings of flash chips" | 8 | bool "Support non-linear mappings of flash chips" |
9 | depends on MTD | ||
10 | help | 9 | help |
11 | This causes the chip drivers to allow for complicated | 10 | This causes the chip drivers to allow for complicated |
12 | paged mappings of flash chips. | 11 | paged mappings of flash chips. |
@@ -69,6 +68,39 @@ config MTD_PHYSMAP_OF | |||
69 | physically into the CPU's memory. The mapping description here is | 68 | physically into the CPU's memory. The mapping description here is |
70 | taken from OF device tree. | 69 | taken from OF device tree. |
71 | 70 | ||
71 | config MTD_PMC_MSP_EVM | ||
72 | tristate "CFI Flash device mapped on PMC-Sierra MSP" | ||
73 | depends on PMC_MSP && MTD_CFI | ||
74 | select MTD_PARTITIONS | ||
75 | help | ||
76 | This provides a 'mapping' driver which support the way | ||
77 | in which user-programmable flash chips are connected on the | ||
78 | PMC-Sierra MSP eval/demo boards | ||
79 | |||
80 | choice | ||
81 | prompt "Maximum mappable memory avialable for flash IO" | ||
82 | depends on MTD_PMC_MSP_EVM | ||
83 | default MSP_FLASH_MAP_LIMIT_32M | ||
84 | |||
85 | config MSP_FLASH_MAP_LIMIT_32M | ||
86 | bool "32M" | ||
87 | |||
88 | endchoice | ||
89 | |||
90 | config MSP_FLASH_MAP_LIMIT | ||
91 | hex | ||
92 | default "0x02000000" | ||
93 | depends on MSP_FLASH_MAP_LIMIT_32M | ||
94 | |||
95 | config MTD_PMC_MSP_RAMROOT | ||
96 | tristate "Embedded RAM block device for root on PMC-Sierra MSP" | ||
97 | depends on PMC_MSP_EMBEDDED_ROOTFS && \ | ||
98 | (MTD_BLOCK || MTD_BLOCK_RO) && \ | ||
99 | MTD_RAM | ||
100 | help | ||
101 | This provides support for the embedded root file system | ||
102 | on PMC MSP devices. This memory is mapped as a MTD block device. | ||
103 | |||
72 | config MTD_SUN_UFLASH | 104 | config MTD_SUN_UFLASH |
73 | tristate "Sun Microsystems userflash support" | 105 | tristate "Sun Microsystems userflash support" |
74 | depends on SPARC && MTD_CFI | 106 | depends on SPARC && MTD_CFI |
@@ -240,13 +272,13 @@ config MTD_NETtel | |||
240 | 272 | ||
241 | config MTD_ALCHEMY | 273 | config MTD_ALCHEMY |
242 | tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support" | 274 | tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support" |
243 | depends on SOC_AU1X00 | 275 | depends on SOC_AU1X00 && MTD_PARTITIONS && MTD_CFI |
244 | help | 276 | help |
245 | Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards | 277 | Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards |
246 | 278 | ||
247 | config MTD_MTX1 | 279 | config MTD_MTX1 |
248 | tristate "4G Systems MTX-1 Flash device" | 280 | tristate "4G Systems MTX-1 Flash device" |
249 | depends on MIPS && MIPS_MTX1 | 281 | depends on MIPS_MTX1 && MTD_CFI |
250 | help | 282 | help |
251 | Flash memory access on 4G Systems MTX-1 Board. If you have one of | 283 | Flash memory access on 4G Systems MTX-1 Board. If you have one of |
252 | these boards and would like to use the flash chips on it, say 'Y'. | 284 | these boards and would like to use the flash chips on it, say 'Y'. |
@@ -384,7 +416,7 @@ config MTD_TQM834x | |||
384 | 416 | ||
385 | config MTD_OCELOT | 417 | config MTD_OCELOT |
386 | tristate "Momenco Ocelot boot flash device" | 418 | tristate "Momenco Ocelot boot flash device" |
387 | depends on MIPS && MOMENCO_OCELOT | 419 | depends on MOMENCO_OCELOT |
388 | help | 420 | help |
389 | This enables access routines for the boot flash device and for the | 421 | This enables access routines for the boot flash device and for the |
390 | NVRAM on the Momenco Ocelot board. If you have one of these boards | 422 | NVRAM on the Momenco Ocelot board. If you have one of these boards |
@@ -517,7 +549,7 @@ config MTD_OMAP_NOR | |||
517 | # This needs CFI or JEDEC, depending on the cards found. | 549 | # This needs CFI or JEDEC, depending on the cards found. |
518 | config MTD_PCI | 550 | config MTD_PCI |
519 | tristate "PCI MTD driver" | 551 | tristate "PCI MTD driver" |
520 | depends on MTD && PCI && MTD_COMPLEX_MAPPINGS | 552 | depends on PCI && MTD_COMPLEX_MAPPINGS |
521 | help | 553 | help |
522 | Mapping for accessing flash devices on add-in cards like the Intel XScale | 554 | Mapping for accessing flash devices on add-in cards like the Intel XScale |
523 | IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode | 555 | IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode |
@@ -527,7 +559,7 @@ config MTD_PCI | |||
527 | 559 | ||
528 | config MTD_PCMCIA | 560 | config MTD_PCMCIA |
529 | tristate "PCMCIA MTD driver" | 561 | tristate "PCMCIA MTD driver" |
530 | depends on MTD && PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN | 562 | depends on PCMCIA && MTD_COMPLEX_MAPPINGS && BROKEN |
531 | help | 563 | help |
532 | Map driver for accessing PCMCIA linear flash memory cards. These | 564 | Map driver for accessing PCMCIA linear flash memory cards. These |
533 | cards are usually around 4-16MiB in size. This does not include | 565 | cards are usually around 4-16MiB in size. This does not include |
@@ -591,13 +623,12 @@ config MTD_BAST_MAXSIZE | |||
591 | 623 | ||
592 | config MTD_SHARP_SL | 624 | config MTD_SHARP_SL |
593 | bool "ROM mapped on Sharp SL Series" | 625 | bool "ROM mapped on Sharp SL Series" |
594 | depends on MTD && ARCH_PXA | 626 | depends on ARCH_PXA |
595 | help | 627 | help |
596 | This enables access to the flash chip on the Sharp SL Series of PDAs. | 628 | This enables access to the flash chip on the Sharp SL Series of PDAs. |
597 | 629 | ||
598 | config MTD_PLATRAM | 630 | config MTD_PLATRAM |
599 | tristate "Map driver for platform device RAM (mtd-ram)" | 631 | tristate "Map driver for platform device RAM (mtd-ram)" |
600 | depends on MTD | ||
601 | select MTD_RAM | 632 | select MTD_RAM |
602 | help | 633 | help |
603 | Map driver for RAM areas described via the platform device | 634 | Map driver for RAM areas described via the platform device |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 071d0bf922b6..de036c5e6139 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
@@ -27,6 +27,8 @@ obj-$(CONFIG_MTD_CEIVA) += ceiva.o | |||
27 | obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o | 27 | obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o |
28 | obj-$(CONFIG_MTD_PHYSMAP) += physmap.o | 28 | obj-$(CONFIG_MTD_PHYSMAP) += physmap.o |
29 | obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o | 29 | obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o |
30 | obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o | ||
31 | obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o | ||
30 | obj-$(CONFIG_MTD_PNC2000) += pnc2000.o | 32 | obj-$(CONFIG_MTD_PNC2000) += pnc2000.o |
31 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o | 33 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o |
32 | obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o | 34 | obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o |
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index 7fc8097e41d2..84fbe0e8c47e 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c | |||
@@ -1,10 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Flash memory access on AMD Alchemy evaluation boards | 2 | * Flash memory access on AMD Alchemy evaluation boards |
3 | * | 3 | * |
4 | * $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $ | ||
5 | * | ||
6 | * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com> | 4 | * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com> |
7 | * | ||
8 | */ | 5 | */ |
9 | 6 | ||
10 | #include <linux/init.h> | 7 | #include <linux/init.h> |
@@ -18,12 +15,6 @@ | |||
18 | 15 | ||
19 | #include <asm/io.h> | 16 | #include <asm/io.h> |
20 | 17 | ||
21 | #ifdef DEBUG_RW | ||
22 | #define DBG(x...) printk(x) | ||
23 | #else | ||
24 | #define DBG(x...) | ||
25 | #endif | ||
26 | |||
27 | #ifdef CONFIG_MIPS_PB1000 | 18 | #ifdef CONFIG_MIPS_PB1000 |
28 | #define BOARD_MAP_NAME "Pb1000 Flash" | 19 | #define BOARD_MAP_NAME "Pb1000 Flash" |
29 | #define BOARD_FLASH_SIZE 0x00800000 /* 8MB */ | 20 | #define BOARD_FLASH_SIZE 0x00800000 /* 8MB */ |
diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 3d4a4d8ac789..688ef495888a 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c | |||
@@ -338,7 +338,7 @@ static int __init init_ck804xrom(void) | |||
338 | } | 338 | } |
339 | return -ENXIO; | 339 | return -ENXIO; |
340 | #if 0 | 340 | #if 0 |
341 | return pci_module_init(&ck804xrom_driver); | 341 | return pci_register_driver(&ck804xrom_driver); |
342 | #endif | 342 | #endif |
343 | } | 343 | } |
344 | 344 | ||
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 2b6504ecbbd1..894c0b271289 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c | |||
@@ -169,7 +169,8 @@ static int platram_probe(struct platform_device *pdev) | |||
169 | goto exit_free; | 169 | goto exit_free; |
170 | } | 170 | } |
171 | 171 | ||
172 | dev_dbg(&pdev->dev, "got platform resource %p (0x%lx)\n", res, res->start); | 172 | dev_dbg(&pdev->dev, "got platform resource %p (0x%llx)\n", res, |
173 | (unsigned long long)res->start); | ||
173 | 174 | ||
174 | /* setup map parameters */ | 175 | /* setup map parameters */ |
175 | 176 | ||
diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c new file mode 100644 index 000000000000..7e0377ec1c40 --- /dev/null +++ b/drivers/mtd/maps/pmcmsp-flash.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. | ||
3 | * Config with both CFI and JEDEC device support. | ||
4 | * | ||
5 | * Basically physmap.c with the addition of partitions and | ||
6 | * an array of mapping info to accomodate more than one flash type per board. | ||
7 | * | ||
8 | * Copyright 2005-2007 PMC-Sierra, Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
18 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
21 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
22 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License along | ||
27 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | #include <linux/types.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/mtd/mtd.h> | ||
35 | #include <linux/mtd/map.h> | ||
36 | #include <linux/mtd/partitions.h> | ||
37 | |||
38 | #include <asm/io.h> | ||
39 | |||
40 | #include <msp_prom.h> | ||
41 | #include <msp_regs.h> | ||
42 | |||
43 | |||
44 | static struct mtd_info **msp_flash; | ||
45 | static struct mtd_partition **msp_parts; | ||
46 | static struct map_info *msp_maps; | ||
47 | static int fcnt; | ||
48 | |||
49 | #define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n",__FUNCTION__,__LINE__) | ||
50 | |||
51 | int __init init_msp_flash(void) | ||
52 | { | ||
53 | int i, j; | ||
54 | int offset, coff; | ||
55 | char *env; | ||
56 | int pcnt; | ||
57 | char flash_name[] = "flash0"; | ||
58 | char part_name[] = "flash0_0"; | ||
59 | unsigned addr, size; | ||
60 | |||
61 | /* If ELB is disabled by "ful-mux" mode, we can't get at flash */ | ||
62 | if ((*DEV_ID_REG & DEV_ID_SINGLE_PC) && | ||
63 | (*ELB_1PC_EN_REG & SINGLE_PCCARD)) { | ||
64 | printk(KERN_NOTICE "Single PC Card mode: no flash access\n"); | ||
65 | return -ENXIO; | ||
66 | } | ||
67 | |||
68 | /* examine the prom environment for flash devices */ | ||
69 | for (fcnt = 0; (env = prom_getenv(flash_name)); fcnt++) | ||
70 | flash_name[5] = '0' + fcnt + 1; | ||
71 | |||
72 | if (fcnt < 1) | ||
73 | return -ENXIO; | ||
74 | |||
75 | printk(KERN_NOTICE "Found %d PMC flash devices\n", fcnt); | ||
76 | msp_flash = (struct mtd_info **)kmalloc( | ||
77 | fcnt * sizeof(struct map_info *), GFP_KERNEL); | ||
78 | msp_parts = (struct mtd_partition **)kmalloc( | ||
79 | fcnt * sizeof(struct mtd_partition *), GFP_KERNEL); | ||
80 | msp_maps = (struct map_info *)kmalloc( | ||
81 | fcnt * sizeof(struct mtd_info), GFP_KERNEL); | ||
82 | memset(msp_maps, 0, fcnt * sizeof(struct mtd_info)); | ||
83 | |||
84 | /* loop over the flash devices, initializing each */ | ||
85 | for (i = 0; i < fcnt; i++) { | ||
86 | /* examine the prom environment for flash partititions */ | ||
87 | part_name[5] = '0' + i; | ||
88 | part_name[7] = '0'; | ||
89 | for (pcnt = 0; (env = prom_getenv(part_name)); pcnt++) | ||
90 | part_name[7] = '0' + pcnt + 1; | ||
91 | |||
92 | if (pcnt == 0) { | ||
93 | printk(KERN_NOTICE "Skipping flash device %d " | ||
94 | "(no partitions defined)\n", i); | ||
95 | continue; | ||
96 | } | ||
97 | |||
98 | msp_parts[i] = (struct mtd_partition *)kmalloc( | ||
99 | pcnt * sizeof(struct mtd_partition), GFP_KERNEL); | ||
100 | memset(msp_parts[i], 0, pcnt * sizeof(struct mtd_partition)); | ||
101 | |||
102 | /* now initialize the devices proper */ | ||
103 | flash_name[5] = '0' + i; | ||
104 | env = prom_getenv(flash_name); | ||
105 | |||
106 | if (sscanf(env, "%x:%x", &addr, &size) < 2) | ||
107 | return -ENXIO; | ||
108 | addr = CPHYSADDR(addr); | ||
109 | |||
110 | printk(KERN_NOTICE | ||
111 | "MSP flash device \"%s\": 0x%08x at 0x%08x\n", | ||
112 | flash_name, size, addr); | ||
113 | /* This must matchs the actual size of the flash chip */ | ||
114 | msp_maps[i].size = size; | ||
115 | msp_maps[i].phys = addr; | ||
116 | |||
117 | /* | ||
118 | * Platforms have a specific limit of the size of memory | ||
119 | * which may be mapped for flash: | ||
120 | */ | ||
121 | if (size > CONFIG_MSP_FLASH_MAP_LIMIT) | ||
122 | size = CONFIG_MSP_FLASH_MAP_LIMIT; | ||
123 | msp_maps[i].virt = ioremap(addr, size); | ||
124 | msp_maps[i].bankwidth = 1; | ||
125 | msp_maps[i].name = strncpy(kmalloc(7, GFP_KERNEL), | ||
126 | flash_name, 7); | ||
127 | |||
128 | if (msp_maps[i].virt == NULL) | ||
129 | return -ENXIO; | ||
130 | |||
131 | for (j = 0; j < pcnt; j++) { | ||
132 | part_name[5] = '0' + i; | ||
133 | part_name[7] = '0' + j; | ||
134 | |||
135 | env = prom_getenv(part_name); | ||
136 | |||
137 | if (sscanf(env, "%x:%x:%n", &offset, &size, &coff) < 2) | ||
138 | return -ENXIO; | ||
139 | |||
140 | msp_parts[i][j].size = size; | ||
141 | msp_parts[i][j].offset = offset; | ||
142 | msp_parts[i][j].name = env + coff; | ||
143 | } | ||
144 | |||
145 | /* now probe and add the device */ | ||
146 | simple_map_init(&msp_maps[i]); | ||
147 | msp_flash[i] = do_map_probe("cfi_probe", &msp_maps[i]); | ||
148 | if (msp_flash[i]) { | ||
149 | msp_flash[i]->owner = THIS_MODULE; | ||
150 | add_mtd_partitions(msp_flash[i], msp_parts[i], pcnt); | ||
151 | } else { | ||
152 | printk(KERN_ERR "map probe failed for flash\n"); | ||
153 | return -ENXIO; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static void __exit cleanup_msp_flash(void) | ||
161 | { | ||
162 | int i; | ||
163 | |||
164 | for (i = 0; i < sizeof(msp_flash) / sizeof(struct mtd_info **); i++) { | ||
165 | del_mtd_partitions(msp_flash[i]); | ||
166 | map_destroy(msp_flash[i]); | ||
167 | iounmap((void *)msp_maps[i].virt); | ||
168 | |||
169 | /* free the memory */ | ||
170 | kfree(msp_maps[i].name); | ||
171 | kfree(msp_parts[i]); | ||
172 | } | ||
173 | |||
174 | kfree(msp_flash); | ||
175 | kfree(msp_parts); | ||
176 | kfree(msp_maps); | ||
177 | } | ||
178 | |||
179 | MODULE_AUTHOR("PMC-Sierra, Inc"); | ||
180 | MODULE_DESCRIPTION("MTD map driver for PMC-Sierra MSP boards"); | ||
181 | MODULE_LICENSE("GPL"); | ||
182 | |||
183 | module_init(init_msp_flash); | ||
184 | module_exit(cleanup_msp_flash); | ||
diff --git a/drivers/mtd/maps/pmcmsp-ramroot.c b/drivers/mtd/maps/pmcmsp-ramroot.c new file mode 100644 index 000000000000..18049bceba8d --- /dev/null +++ b/drivers/mtd/maps/pmcmsp-ramroot.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Mapping of the rootfs in a physical region of memory | ||
3 | * | ||
4 | * Copyright (C) 2005-2007 PMC-Sierra Inc. | ||
5 | * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
13 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
14 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||
15 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
16 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
17 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
18 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
21 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/fs.h> | ||
34 | #include <linux/root_dev.h> | ||
35 | #include <linux/mtd/mtd.h> | ||
36 | #include <linux/mtd/map.h> | ||
37 | |||
38 | #include <asm/io.h> | ||
39 | |||
40 | #include <msp_prom.h> | ||
41 | |||
42 | static struct mtd_info *rr_mtd; | ||
43 | |||
44 | struct map_info rr_map = { | ||
45 | .name = "ramroot", | ||
46 | .bankwidth = 4, | ||
47 | }; | ||
48 | |||
49 | static int __init init_rrmap(void) | ||
50 | { | ||
51 | void *ramroot_start; | ||
52 | unsigned long ramroot_size; | ||
53 | |||
54 | /* Check for supported rootfs types */ | ||
55 | if (get_ramroot(&ramroot_start, &ramroot_size)) { | ||
56 | rr_map.phys = CPHYSADDR(ramroot_start); | ||
57 | rr_map.size = ramroot_size; | ||
58 | |||
59 | printk(KERN_NOTICE | ||
60 | "PMC embedded root device: 0x%08lx @ 0x%08lx\n", | ||
61 | rr_map.size, (unsigned long)rr_map.phys); | ||
62 | } else { | ||
63 | printk(KERN_ERR | ||
64 | "init_rrmap: no supported embedded rootfs detected!\n"); | ||
65 | return -ENXIO; | ||
66 | } | ||
67 | |||
68 | /* Map rootfs to I/O space for block device driver */ | ||
69 | rr_map.virt = ioremap(rr_map.phys, rr_map.size); | ||
70 | if (!rr_map.virt) { | ||
71 | printk(KERN_ERR "Failed to ioremap\n"); | ||
72 | return -EIO; | ||
73 | } | ||
74 | |||
75 | simple_map_init(&rr_map); | ||
76 | |||
77 | rr_mtd = do_map_probe("map_ram", &rr_map); | ||
78 | if (rr_mtd) { | ||
79 | rr_mtd->owner = THIS_MODULE; | ||
80 | |||
81 | add_mtd_device(rr_mtd); | ||
82 | ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, rr_mtd->index); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | iounmap(rr_map.virt); | ||
88 | return -ENXIO; | ||
89 | } | ||
90 | |||
91 | static void __exit cleanup_rrmap(void) | ||
92 | { | ||
93 | del_mtd_device(rr_mtd); | ||
94 | map_destroy(rr_mtd); | ||
95 | |||
96 | iounmap(rr_map.virt); | ||
97 | rr_map.virt = NULL; | ||
98 | } | ||
99 | |||
100 | MODULE_AUTHOR("PMC-Sierra, Inc"); | ||
101 | MODULE_DESCRIPTION("MTD map driver for embedded PMC-Sierra MSP filesystem"); | ||
102 | MODULE_LICENSE("GPL"); | ||
103 | |||
104 | module_init(init_rrmap); | ||
105 | module_exit(cleanup_rrmap); | ||
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index b879a66daa9e..524b83b5ebf5 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/hdreg.h> | 20 | #include <linux/hdreg.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/kthread.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | 25 | ||
25 | static LIST_HEAD(blktrans_majors); | 26 | static LIST_HEAD(blktrans_majors); |
@@ -28,9 +29,7 @@ extern struct mutex mtd_table_mutex; | |||
28 | extern struct mtd_info *mtd_table[]; | 29 | extern struct mtd_info *mtd_table[]; |
29 | 30 | ||
30 | struct mtd_blkcore_priv { | 31 | struct mtd_blkcore_priv { |
31 | struct completion thread_dead; | 32 | struct task_struct *thread; |
32 | int exiting; | ||
33 | wait_queue_head_t thread_wq; | ||
34 | struct request_queue *rq; | 33 | struct request_queue *rq; |
35 | spinlock_t queue_lock; | 34 | spinlock_t queue_lock; |
36 | }; | 35 | }; |
@@ -83,38 +82,19 @@ static int mtd_blktrans_thread(void *arg) | |||
83 | /* we might get involved when memory gets low, so use PF_MEMALLOC */ | 82 | /* we might get involved when memory gets low, so use PF_MEMALLOC */ |
84 | current->flags |= PF_MEMALLOC | PF_NOFREEZE; | 83 | current->flags |= PF_MEMALLOC | PF_NOFREEZE; |
85 | 84 | ||
86 | daemonize("%sd", tr->name); | ||
87 | |||
88 | /* daemonize() doesn't do this for us since some kernel threads | ||
89 | actually want to deal with signals. We can't just call | ||
90 | exit_sighand() since that'll cause an oops when we finally | ||
91 | do exit. */ | ||
92 | spin_lock_irq(¤t->sighand->siglock); | ||
93 | sigfillset(¤t->blocked); | ||
94 | recalc_sigpending(); | ||
95 | spin_unlock_irq(¤t->sighand->siglock); | ||
96 | |||
97 | spin_lock_irq(rq->queue_lock); | 85 | spin_lock_irq(rq->queue_lock); |
98 | 86 | while (!kthread_should_stop()) { | |
99 | while (!tr->blkcore_priv->exiting) { | ||
100 | struct request *req; | 87 | struct request *req; |
101 | struct mtd_blktrans_dev *dev; | 88 | struct mtd_blktrans_dev *dev; |
102 | int res = 0; | 89 | int res = 0; |
103 | DECLARE_WAITQUEUE(wait, current); | ||
104 | 90 | ||
105 | req = elv_next_request(rq); | 91 | req = elv_next_request(rq); |
106 | 92 | ||
107 | if (!req) { | 93 | if (!req) { |
108 | add_wait_queue(&tr->blkcore_priv->thread_wq, &wait); | ||
109 | set_current_state(TASK_INTERRUPTIBLE); | 94 | set_current_state(TASK_INTERRUPTIBLE); |
110 | |||
111 | spin_unlock_irq(rq->queue_lock); | 95 | spin_unlock_irq(rq->queue_lock); |
112 | |||
113 | schedule(); | 96 | schedule(); |
114 | remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait); | ||
115 | |||
116 | spin_lock_irq(rq->queue_lock); | 97 | spin_lock_irq(rq->queue_lock); |
117 | |||
118 | continue; | 98 | continue; |
119 | } | 99 | } |
120 | 100 | ||
@@ -133,13 +113,13 @@ static int mtd_blktrans_thread(void *arg) | |||
133 | } | 113 | } |
134 | spin_unlock_irq(rq->queue_lock); | 114 | spin_unlock_irq(rq->queue_lock); |
135 | 115 | ||
136 | complete_and_exit(&tr->blkcore_priv->thread_dead, 0); | 116 | return 0; |
137 | } | 117 | } |
138 | 118 | ||
139 | static void mtd_blktrans_request(struct request_queue *rq) | 119 | static void mtd_blktrans_request(struct request_queue *rq) |
140 | { | 120 | { |
141 | struct mtd_blktrans_ops *tr = rq->queuedata; | 121 | struct mtd_blktrans_ops *tr = rq->queuedata; |
142 | wake_up(&tr->blkcore_priv->thread_wq); | 122 | wake_up_process(tr->blkcore_priv->thread); |
143 | } | 123 | } |
144 | 124 | ||
145 | 125 | ||
@@ -388,8 +368,6 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
388 | return ret; | 368 | return ret; |
389 | } | 369 | } |
390 | spin_lock_init(&tr->blkcore_priv->queue_lock); | 370 | spin_lock_init(&tr->blkcore_priv->queue_lock); |
391 | init_completion(&tr->blkcore_priv->thread_dead); | ||
392 | init_waitqueue_head(&tr->blkcore_priv->thread_wq); | ||
393 | 371 | ||
394 | tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock); | 372 | tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock); |
395 | if (!tr->blkcore_priv->rq) { | 373 | if (!tr->blkcore_priv->rq) { |
@@ -403,13 +381,14 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
403 | blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); | 381 | blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize); |
404 | tr->blkshift = ffs(tr->blksize) - 1; | 382 | tr->blkshift = ffs(tr->blksize) - 1; |
405 | 383 | ||
406 | ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL); | 384 | tr->blkcore_priv->thread = kthread_run(mtd_blktrans_thread, tr, |
407 | if (ret < 0) { | 385 | "%sd", tr->name); |
386 | if (IS_ERR(tr->blkcore_priv->thread)) { | ||
408 | blk_cleanup_queue(tr->blkcore_priv->rq); | 387 | blk_cleanup_queue(tr->blkcore_priv->rq); |
409 | unregister_blkdev(tr->major, tr->name); | 388 | unregister_blkdev(tr->major, tr->name); |
410 | kfree(tr->blkcore_priv); | 389 | kfree(tr->blkcore_priv); |
411 | mutex_unlock(&mtd_table_mutex); | 390 | mutex_unlock(&mtd_table_mutex); |
412 | return ret; | 391 | return PTR_ERR(tr->blkcore_priv->thread); |
413 | } | 392 | } |
414 | 393 | ||
415 | INIT_LIST_HEAD(&tr->devs); | 394 | INIT_LIST_HEAD(&tr->devs); |
@@ -432,9 +411,7 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) | |||
432 | mutex_lock(&mtd_table_mutex); | 411 | mutex_lock(&mtd_table_mutex); |
433 | 412 | ||
434 | /* Clean up the kernel thread */ | 413 | /* Clean up the kernel thread */ |
435 | tr->blkcore_priv->exiting = 1; | 414 | kthread_stop(tr->blkcore_priv->thread); |
436 | wake_up(&tr->blkcore_priv->thread_wq); | ||
437 | wait_for_completion(&tr->blkcore_priv->thread_dead); | ||
438 | 415 | ||
439 | /* Remove it from the list of active majors */ | 416 | /* Remove it from the list of active majors */ |
440 | list_del(&tr->list); | 417 | list_del(&tr->list); |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 1592eac64e57..8c86b802f212 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -553,7 +553,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
553 | ops.datbuf = NULL; | 553 | ops.datbuf = NULL; |
554 | ops.mode = MTD_OOB_PLACE; | 554 | ops.mode = MTD_OOB_PLACE; |
555 | 555 | ||
556 | if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs)) | 556 | if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) |
557 | return -EINVAL; | 557 | return -EINVAL; |
558 | 558 | ||
559 | ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); | 559 | ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); |
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 2d12dcdd740c..d05873b8c155 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -1,10 +1,7 @@ | |||
1 | # drivers/mtd/nand/Kconfig | 1 | # drivers/mtd/nand/Kconfig |
2 | # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ | 2 | # $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $ |
3 | 3 | ||
4 | menu "NAND Flash Device Drivers" | 4 | menuconfig MTD_NAND |
5 | depends on MTD!=n | ||
6 | |||
7 | config MTD_NAND | ||
8 | tristate "NAND Device Support" | 5 | tristate "NAND Device Support" |
9 | depends on MTD | 6 | depends on MTD |
10 | select MTD_NAND_IDS | 7 | select MTD_NAND_IDS |
@@ -13,9 +10,10 @@ config MTD_NAND | |||
13 | devices. For further information see | 10 | devices. For further information see |
14 | <http://www.linux-mtd.infradead.org/doc/nand.html>. | 11 | <http://www.linux-mtd.infradead.org/doc/nand.html>. |
15 | 12 | ||
13 | if MTD_NAND | ||
14 | |||
16 | config MTD_NAND_VERIFY_WRITE | 15 | config MTD_NAND_VERIFY_WRITE |
17 | bool "Verify NAND page writes" | 16 | bool "Verify NAND page writes" |
18 | depends on MTD_NAND | ||
19 | help | 17 | help |
20 | This adds an extra check when data is written to the flash. The | 18 | This adds an extra check when data is written to the flash. The |
21 | NAND flash device internally checks only bits transitioning | 19 | NAND flash device internally checks only bits transitioning |
@@ -25,53 +23,61 @@ config MTD_NAND_VERIFY_WRITE | |||
25 | 23 | ||
26 | config MTD_NAND_ECC_SMC | 24 | config MTD_NAND_ECC_SMC |
27 | bool "NAND ECC Smart Media byte order" | 25 | bool "NAND ECC Smart Media byte order" |
28 | depends on MTD_NAND | ||
29 | default n | 26 | default n |
30 | help | 27 | help |
31 | Software ECC according to the Smart Media Specification. | 28 | Software ECC according to the Smart Media Specification. |
32 | The original Linux implementation had byte 0 and 1 swapped. | 29 | The original Linux implementation had byte 0 and 1 swapped. |
33 | 30 | ||
31 | config MTD_NAND_MUSEUM_IDS | ||
32 | bool "Enable chip ids for obsolete ancient NAND devices" | ||
33 | depends on MTD_NAND | ||
34 | default n | ||
35 | help | ||
36 | Enable this option only when your board has first generation | ||
37 | NAND chips (page size 256 byte, erase size 4-8KiB). The IDs | ||
38 | of these chips were reused by later, larger chips. | ||
39 | |||
34 | config MTD_NAND_AUTCPU12 | 40 | config MTD_NAND_AUTCPU12 |
35 | tristate "SmartMediaCard on autronix autcpu12 board" | 41 | tristate "SmartMediaCard on autronix autcpu12 board" |
36 | depends on MTD_NAND && ARCH_AUTCPU12 | 42 | depends on ARCH_AUTCPU12 |
37 | help | 43 | help |
38 | This enables the driver for the autronix autcpu12 board to | 44 | This enables the driver for the autronix autcpu12 board to |
39 | access the SmartMediaCard. | 45 | access the SmartMediaCard. |
40 | 46 | ||
41 | config MTD_NAND_EDB7312 | 47 | config MTD_NAND_EDB7312 |
42 | tristate "Support for Cirrus Logic EBD7312 evaluation board" | 48 | tristate "Support for Cirrus Logic EBD7312 evaluation board" |
43 | depends on MTD_NAND && ARCH_EDB7312 | 49 | depends on ARCH_EDB7312 |
44 | help | 50 | help |
45 | This enables the driver for the Cirrus Logic EBD7312 evaluation | 51 | This enables the driver for the Cirrus Logic EBD7312 evaluation |
46 | board to access the onboard NAND Flash. | 52 | board to access the onboard NAND Flash. |
47 | 53 | ||
48 | config MTD_NAND_H1900 | 54 | config MTD_NAND_H1900 |
49 | tristate "iPAQ H1900 flash" | 55 | tristate "iPAQ H1900 flash" |
50 | depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS | 56 | depends on ARCH_PXA && MTD_PARTITIONS |
51 | help | 57 | help |
52 | This enables the driver for the iPAQ h1900 flash. | 58 | This enables the driver for the iPAQ h1900 flash. |
53 | 59 | ||
54 | config MTD_NAND_SPIA | 60 | config MTD_NAND_SPIA |
55 | tristate "NAND Flash device on SPIA board" | 61 | tristate "NAND Flash device on SPIA board" |
56 | depends on ARCH_P720T && MTD_NAND | 62 | depends on ARCH_P720T |
57 | help | 63 | help |
58 | If you had to ask, you don't have one. Say 'N'. | 64 | If you had to ask, you don't have one. Say 'N'. |
59 | 65 | ||
60 | config MTD_NAND_AMS_DELTA | 66 | config MTD_NAND_AMS_DELTA |
61 | tristate "NAND Flash device on Amstrad E3" | 67 | tristate "NAND Flash device on Amstrad E3" |
62 | depends on MACH_AMS_DELTA && MTD_NAND | 68 | depends on MACH_AMS_DELTA |
63 | help | 69 | help |
64 | Support for NAND flash on Amstrad E3 (Delta). | 70 | Support for NAND flash on Amstrad E3 (Delta). |
65 | 71 | ||
66 | config MTD_NAND_TOTO | 72 | config MTD_NAND_TOTO |
67 | tristate "NAND Flash device on TOTO board" | 73 | tristate "NAND Flash device on TOTO board" |
68 | depends on ARCH_OMAP && MTD_NAND && BROKEN | 74 | depends on ARCH_OMAP && BROKEN |
69 | help | 75 | help |
70 | Support for NAND flash on Texas Instruments Toto platform. | 76 | Support for NAND flash on Texas Instruments Toto platform. |
71 | 77 | ||
72 | config MTD_NAND_TS7250 | 78 | config MTD_NAND_TS7250 |
73 | tristate "NAND Flash device on TS-7250 board" | 79 | tristate "NAND Flash device on TS-7250 board" |
74 | depends on MACH_TS72XX && MTD_NAND | 80 | depends on MACH_TS72XX |
75 | help | 81 | help |
76 | Support for NAND flash on Technologic Systems TS-7250 platform. | 82 | Support for NAND flash on Technologic Systems TS-7250 platform. |
77 | 83 | ||
@@ -80,14 +86,14 @@ config MTD_NAND_IDS | |||
80 | 86 | ||
81 | config MTD_NAND_AU1550 | 87 | config MTD_NAND_AU1550 |
82 | tristate "Au1550/1200 NAND support" | 88 | tristate "Au1550/1200 NAND support" |
83 | depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND | 89 | depends on SOC_AU1200 || SOC_AU1550 |
84 | help | 90 | help |
85 | This enables the driver for the NAND flash controller on the | 91 | This enables the driver for the NAND flash controller on the |
86 | AMD/Alchemy 1550 SOC. | 92 | AMD/Alchemy 1550 SOC. |
87 | 93 | ||
88 | config MTD_NAND_RTC_FROM4 | 94 | config MTD_NAND_RTC_FROM4 |
89 | tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" | 95 | tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)" |
90 | depends on MTD_NAND && SH_SOLUTION_ENGINE | 96 | depends on SH_SOLUTION_ENGINE |
91 | select REED_SOLOMON | 97 | select REED_SOLOMON |
92 | select REED_SOLOMON_DEC8 | 98 | select REED_SOLOMON_DEC8 |
93 | select BITREVERSE | 99 | select BITREVERSE |
@@ -97,13 +103,13 @@ config MTD_NAND_RTC_FROM4 | |||
97 | 103 | ||
98 | config MTD_NAND_PPCHAMELEONEVB | 104 | config MTD_NAND_PPCHAMELEONEVB |
99 | tristate "NAND Flash device on PPChameleonEVB board" | 105 | tristate "NAND Flash device on PPChameleonEVB board" |
100 | depends on PPCHAMELEONEVB && MTD_NAND && BROKEN | 106 | depends on PPCHAMELEONEVB && BROKEN |
101 | help | 107 | help |
102 | This enables the NAND flash driver on the PPChameleon EVB Board. | 108 | This enables the NAND flash driver on the PPChameleon EVB Board. |
103 | 109 | ||
104 | config MTD_NAND_S3C2410 | 110 | config MTD_NAND_S3C2410 |
105 | tristate "NAND Flash support for S3C2410/S3C2440 SoC" | 111 | tristate "NAND Flash support for S3C2410/S3C2440 SoC" |
106 | depends on ARCH_S3C2410 && MTD_NAND | 112 | depends on ARCH_S3C2410 |
107 | help | 113 | help |
108 | This enables the NAND flash controller on the S3C2410 and S3C2440 | 114 | This enables the NAND flash controller on the S3C2410 and S3C2440 |
109 | SoCs | 115 | SoCs |
@@ -128,7 +134,7 @@ config MTD_NAND_S3C2410_HWECC | |||
128 | 134 | ||
129 | config MTD_NAND_NDFC | 135 | config MTD_NAND_NDFC |
130 | tristate "NDFC NanD Flash Controller" | 136 | tristate "NDFC NanD Flash Controller" |
131 | depends on MTD_NAND && 44x | 137 | depends on 44x |
132 | select MTD_NAND_ECC_SMC | 138 | select MTD_NAND_ECC_SMC |
133 | help | 139 | help |
134 | NDFC Nand Flash Controllers are integrated in EP44x SoCs | 140 | NDFC Nand Flash Controllers are integrated in EP44x SoCs |
@@ -145,7 +151,7 @@ config MTD_NAND_S3C2410_CLKSTOP | |||
145 | 151 | ||
146 | config MTD_NAND_DISKONCHIP | 152 | config MTD_NAND_DISKONCHIP |
147 | tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" | 153 | tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)" |
148 | depends on MTD_NAND && EXPERIMENTAL | 154 | depends on EXPERIMENTAL |
149 | select REED_SOLOMON | 155 | select REED_SOLOMON |
150 | select REED_SOLOMON_DEC16 | 156 | select REED_SOLOMON_DEC16 |
151 | help | 157 | help |
@@ -215,11 +221,11 @@ config MTD_NAND_DISKONCHIP_BBTWRITE | |||
215 | 221 | ||
216 | config MTD_NAND_SHARPSL | 222 | config MTD_NAND_SHARPSL |
217 | tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" | 223 | tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" |
218 | depends on MTD_NAND && ARCH_PXA | 224 | depends on ARCH_PXA |
219 | 225 | ||
220 | config MTD_NAND_BASLER_EXCITE | 226 | config MTD_NAND_BASLER_EXCITE |
221 | tristate "Support for NAND Flash on Basler eXcite" | 227 | tristate "Support for NAND Flash on Basler eXcite" |
222 | depends on MTD_NAND && BASLER_EXCITE | 228 | depends on BASLER_EXCITE |
223 | help | 229 | help |
224 | This enables the driver for the NAND flash device found on the | 230 | This enables the driver for the NAND flash device found on the |
225 | Basler eXcite Smart Camera. If built as a module, the driver | 231 | Basler eXcite Smart Camera. If built as a module, the driver |
@@ -227,14 +233,14 @@ config MTD_NAND_BASLER_EXCITE | |||
227 | 233 | ||
228 | config MTD_NAND_CAFE | 234 | config MTD_NAND_CAFE |
229 | tristate "NAND support for OLPC CAFÉ chip" | 235 | tristate "NAND support for OLPC CAFÉ chip" |
230 | depends on MTD_NAND && PCI | 236 | depends on PCI |
231 | help | 237 | help |
232 | Use NAND flash attached to the CAFÉ chip designed for the $100 | 238 | Use NAND flash attached to the CAFÉ chip designed for the $100 |
233 | laptop. | 239 | laptop. |
234 | 240 | ||
235 | config MTD_NAND_CS553X | 241 | config MTD_NAND_CS553X |
236 | tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" | 242 | tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" |
237 | depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH) | 243 | depends on X86_32 && (X86_PC || X86_GENERICARCH) |
238 | help | 244 | help |
239 | The CS553x companion chips for the AMD Geode processor | 245 | The CS553x companion chips for the AMD Geode processor |
240 | include NAND flash controllers with built-in hardware ECC | 246 | include NAND flash controllers with built-in hardware ECC |
@@ -247,16 +253,21 @@ config MTD_NAND_CS553X | |||
247 | 253 | ||
248 | config MTD_NAND_AT91 | 254 | config MTD_NAND_AT91 |
249 | bool "Support for NAND Flash / SmartMedia on AT91" | 255 | bool "Support for NAND Flash / SmartMedia on AT91" |
250 | depends on MTD_NAND && ARCH_AT91 | 256 | depends on ARCH_AT91 |
251 | help | 257 | help |
252 | Enables support for NAND Flash / Smart Media Card interface | 258 | Enables support for NAND Flash / Smart Media Card interface |
253 | on Atmel AT91 processors. | 259 | on Atmel AT91 processors. |
254 | 260 | ||
261 | config MTD_NAND_CM_X270 | ||
262 | tristate "Support for NAND Flash on CM-X270 modules" | ||
263 | depends on MTD_NAND && MACH_ARMCORE | ||
264 | |||
265 | |||
255 | config MTD_NAND_NANDSIM | 266 | config MTD_NAND_NANDSIM |
256 | tristate "Support for NAND Flash Simulator" | 267 | tristate "Support for NAND Flash Simulator" |
257 | depends on MTD_NAND && MTD_PARTITIONS | 268 | depends on MTD_PARTITIONS |
258 | help | 269 | help |
259 | The simulator may simulate various NAND flash chips for the | 270 | The simulator may simulate various NAND flash chips for the |
260 | MTD nand layer. | 271 | MTD nand layer. |
261 | 272 | ||
262 | endmenu | 273 | endif # MTD_NAND |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 80f1dfc77949..6872031a3fb2 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -24,6 +24,7 @@ obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o | |||
24 | obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o | 24 | obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o |
25 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o | 25 | obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o |
26 | obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o | 26 | obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o |
27 | obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o | ||
27 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o | 28 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o |
28 | 29 | ||
29 | nand-objs := nand_base.o nand_bbt.o | 30 | nand-objs := nand_base.o nand_bbt.o |
diff --git a/drivers/mtd/nand/cafe.c b/drivers/mtd/nand/cafe.c index fd6bb3ed40df..c328a7514510 100644 --- a/drivers/mtd/nand/cafe.c +++ b/drivers/mtd/nand/cafe.c | |||
@@ -530,7 +530,6 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
530 | { | 530 | { |
531 | struct mtd_info *mtd; | 531 | struct mtd_info *mtd; |
532 | struct cafe_priv *cafe; | 532 | struct cafe_priv *cafe; |
533 | uint32_t timing1, timing2, timing3; | ||
534 | uint32_t ctrl; | 533 | uint32_t ctrl; |
535 | int err = 0; | 534 | int err = 0; |
536 | 535 | ||
@@ -587,21 +586,19 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
587 | } | 586 | } |
588 | 587 | ||
589 | if (numtimings == 3) { | 588 | if (numtimings == 3) { |
590 | timing1 = timing[0]; | ||
591 | timing2 = timing[1]; | ||
592 | timing3 = timing[2]; | ||
593 | cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n", | 589 | cafe_dev_dbg(&cafe->pdev->dev, "Using provided timings (%08x %08x %08x)\n", |
594 | timing1, timing2, timing3); | 590 | timing[0], timing[1], timing[2]); |
595 | } else { | 591 | } else { |
596 | timing1 = cafe_readl(cafe, NAND_TIMING1); | 592 | timing[0] = cafe_readl(cafe, NAND_TIMING1); |
597 | timing2 = cafe_readl(cafe, NAND_TIMING2); | 593 | timing[1] = cafe_readl(cafe, NAND_TIMING2); |
598 | timing3 = cafe_readl(cafe, NAND_TIMING3); | 594 | timing[2] = cafe_readl(cafe, NAND_TIMING3); |
599 | 595 | ||
600 | if (timing1 | timing2 | timing3) { | 596 | if (timing[0] | timing[1] | timing[2]) { |
601 | cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", timing1, timing2, timing3); | 597 | cafe_dev_dbg(&cafe->pdev->dev, "Timing registers already set (%08x %08x %08x)\n", |
598 | timing[0], timing[1], timing[2]); | ||
602 | } else { | 599 | } else { |
603 | dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n"); | 600 | dev_warn(&cafe->pdev->dev, "Timing registers unset; using most conservative defaults\n"); |
604 | timing1 = timing2 = timing3 = 0xffffffff; | 601 | timing[0] = timing[1] = timing[2] = 0xffffffff; |
605 | } | 602 | } |
606 | } | 603 | } |
607 | 604 | ||
@@ -609,9 +606,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
609 | cafe_writel(cafe, 1, NAND_RESET); | 606 | cafe_writel(cafe, 1, NAND_RESET); |
610 | cafe_writel(cafe, 0, NAND_RESET); | 607 | cafe_writel(cafe, 0, NAND_RESET); |
611 | 608 | ||
612 | cafe_writel(cafe, timing1, NAND_TIMING1); | 609 | cafe_writel(cafe, timing[0], NAND_TIMING1); |
613 | cafe_writel(cafe, timing2, NAND_TIMING2); | 610 | cafe_writel(cafe, timing[1], NAND_TIMING2); |
614 | cafe_writel(cafe, timing3, NAND_TIMING3); | 611 | cafe_writel(cafe, timing[2], NAND_TIMING3); |
615 | 612 | ||
616 | cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); | 613 | cafe_writel(cafe, 0xffffffff, NAND_IRQ_MASK); |
617 | err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED, | 614 | err = request_irq(pdev->irq, &cafe_nand_interrupt, IRQF_SHARED, |
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c new file mode 100644 index 000000000000..cb663ef245d5 --- /dev/null +++ b/drivers/mtd/nand/cmx270_nand.c | |||
@@ -0,0 +1,267 @@ | |||
1 | /* | ||
2 | * linux/drivers/mtd/nand/cmx270-nand.c | ||
3 | * | ||
4 | * Copyright (C) 2006 Compulab, Ltd. | ||
5 | * Mike Rapoport <mike@compulab.co.il> | ||
6 | * | ||
7 | * Derived from drivers/mtd/nand/h1910.c | ||
8 | * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) | ||
9 | * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) | ||
10 | * | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | * | ||
16 | * Overview: | ||
17 | * This is a device driver for the NAND flash device found on the | ||
18 | * CM-X270 board. | ||
19 | */ | ||
20 | |||
21 | #include <linux/mtd/nand.h> | ||
22 | #include <linux/mtd/partitions.h> | ||
23 | |||
24 | #include <asm/io.h> | ||
25 | #include <asm/irq.h> | ||
26 | |||
27 | #include <asm/arch/hardware.h> | ||
28 | #include <asm/arch/pxa-regs.h> | ||
29 | |||
30 | #define GPIO_NAND_CS (11) | ||
31 | #define GPIO_NAND_RB (89) | ||
32 | |||
33 | /* This macro needed to ensure in-order operation of GPIO and local | ||
34 | * bus. Without both asm command and dummy uncached read there're | ||
35 | * states when NAND access is broken. I've looked for such macro(s) in | ||
36 | * include/asm-arm but found nothing approptiate. | ||
37 | * dmac_clean_range is close, but is makes cache invalidation | ||
38 | * unnecessary here and it cannot be used in module | ||
39 | */ | ||
40 | #define DRAIN_WB() \ | ||
41 | do { \ | ||
42 | unsigned char dummy; \ | ||
43 | asm volatile ("mcr p15, 0, r0, c7, c10, 4":::"r0"); \ | ||
44 | dummy=*((unsigned char*)UNCACHED_ADDR); \ | ||
45 | } while(0) | ||
46 | |||
47 | /* MTD structure for CM-X270 board */ | ||
48 | static struct mtd_info *cmx270_nand_mtd; | ||
49 | |||
50 | /* remaped IO address of the device */ | ||
51 | static void __iomem *cmx270_nand_io; | ||
52 | |||
53 | /* | ||
54 | * Define static partitions for flash device | ||
55 | */ | ||
56 | static struct mtd_partition partition_info[] = { | ||
57 | [0] = { | ||
58 | .name = "cmx270-0", | ||
59 | .offset = 0, | ||
60 | .size = MTDPART_SIZ_FULL | ||
61 | } | ||
62 | }; | ||
63 | #define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) | ||
64 | |||
65 | const char *part_probes[] = { "cmdlinepart", NULL }; | ||
66 | |||
67 | static u_char cmx270_read_byte(struct mtd_info *mtd) | ||
68 | { | ||
69 | struct nand_chip *this = mtd->priv; | ||
70 | |||
71 | return (readl(this->IO_ADDR_R) >> 16); | ||
72 | } | ||
73 | |||
74 | static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
75 | { | ||
76 | int i; | ||
77 | struct nand_chip *this = mtd->priv; | ||
78 | |||
79 | for (i=0; i<len; i++) | ||
80 | writel((*buf++ << 16), this->IO_ADDR_W); | ||
81 | } | ||
82 | |||
83 | static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len) | ||
84 | { | ||
85 | int i; | ||
86 | struct nand_chip *this = mtd->priv; | ||
87 | |||
88 | for (i=0; i<len; i++) | ||
89 | *buf++ = readl(this->IO_ADDR_R) >> 16; | ||
90 | } | ||
91 | |||
92 | static int cmx270_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
93 | { | ||
94 | int i; | ||
95 | struct nand_chip *this = mtd->priv; | ||
96 | |||
97 | for (i=0; i<len; i++) | ||
98 | if (buf[i] != (u_char)(readl(this->IO_ADDR_R) >> 16)) | ||
99 | return -EFAULT; | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static inline void nand_cs_on(void) | ||
105 | { | ||
106 | GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); | ||
107 | } | ||
108 | |||
109 | static void nand_cs_off(void) | ||
110 | { | ||
111 | DRAIN_WB(); | ||
112 | |||
113 | GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS); | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * hardware specific access to control-lines | ||
118 | */ | ||
119 | static void cmx270_hwcontrol(struct mtd_info *mtd, int dat, | ||
120 | unsigned int ctrl) | ||
121 | { | ||
122 | struct nand_chip* this = mtd->priv; | ||
123 | unsigned int nandaddr = (unsigned int)this->IO_ADDR_W; | ||
124 | |||
125 | DRAIN_WB(); | ||
126 | |||
127 | if (ctrl & NAND_CTRL_CHANGE) { | ||
128 | if ( ctrl & NAND_ALE ) | ||
129 | nandaddr |= (1 << 3); | ||
130 | else | ||
131 | nandaddr &= ~(1 << 3); | ||
132 | if ( ctrl & NAND_CLE ) | ||
133 | nandaddr |= (1 << 2); | ||
134 | else | ||
135 | nandaddr &= ~(1 << 2); | ||
136 | if ( ctrl & NAND_NCE ) | ||
137 | nand_cs_on(); | ||
138 | else | ||
139 | nand_cs_off(); | ||
140 | } | ||
141 | |||
142 | DRAIN_WB(); | ||
143 | this->IO_ADDR_W = (void __iomem*)nandaddr; | ||
144 | if (dat != NAND_CMD_NONE) | ||
145 | writel((dat << 16), this->IO_ADDR_W); | ||
146 | |||
147 | DRAIN_WB(); | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * read device ready pin | ||
152 | */ | ||
153 | static int cmx270_device_ready(struct mtd_info *mtd) | ||
154 | { | ||
155 | DRAIN_WB(); | ||
156 | |||
157 | return (GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB)); | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * Main initialization routine | ||
162 | */ | ||
163 | static int cmx270_init(void) | ||
164 | { | ||
165 | struct nand_chip *this; | ||
166 | const char *part_type; | ||
167 | struct mtd_partition *mtd_parts; | ||
168 | int mtd_parts_nb = 0; | ||
169 | int ret; | ||
170 | |||
171 | /* Allocate memory for MTD device structure and private data */ | ||
172 | cmx270_nand_mtd = kzalloc(sizeof(struct mtd_info) + | ||
173 | sizeof(struct nand_chip), | ||
174 | GFP_KERNEL); | ||
175 | if (!cmx270_nand_mtd) { | ||
176 | printk("Unable to allocate CM-X270 NAND MTD device structure.\n"); | ||
177 | return -ENOMEM; | ||
178 | } | ||
179 | |||
180 | cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12); | ||
181 | if (!cmx270_nand_io) { | ||
182 | printk("Unable to ioremap NAND device\n"); | ||
183 | ret = -EINVAL; | ||
184 | goto err1; | ||
185 | } | ||
186 | |||
187 | /* Get pointer to private data */ | ||
188 | this = (struct nand_chip *)(&cmx270_nand_mtd[1]); | ||
189 | |||
190 | /* Link the private data with the MTD structure */ | ||
191 | cmx270_nand_mtd->owner = THIS_MODULE; | ||
192 | cmx270_nand_mtd->priv = this; | ||
193 | |||
194 | /* insert callbacks */ | ||
195 | this->IO_ADDR_R = cmx270_nand_io; | ||
196 | this->IO_ADDR_W = cmx270_nand_io; | ||
197 | this->cmd_ctrl = cmx270_hwcontrol; | ||
198 | this->dev_ready = cmx270_device_ready; | ||
199 | |||
200 | /* 15 us command delay time */ | ||
201 | this->chip_delay = 20; | ||
202 | this->ecc.mode = NAND_ECC_SOFT; | ||
203 | |||
204 | /* read/write functions */ | ||
205 | this->read_byte = cmx270_read_byte; | ||
206 | this->read_buf = cmx270_read_buf; | ||
207 | this->write_buf = cmx270_write_buf; | ||
208 | this->verify_buf = cmx270_verify_buf; | ||
209 | |||
210 | /* Scan to find existence of the device */ | ||
211 | if (nand_scan (cmx270_nand_mtd, 1)) { | ||
212 | printk(KERN_NOTICE "No NAND device\n"); | ||
213 | ret = -ENXIO; | ||
214 | goto err2; | ||
215 | } | ||
216 | |||
217 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
218 | mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes, | ||
219 | &mtd_parts, 0); | ||
220 | if (mtd_parts_nb > 0) | ||
221 | part_type = "command line"; | ||
222 | else | ||
223 | mtd_parts_nb = 0; | ||
224 | #endif | ||
225 | if (!mtd_parts_nb) { | ||
226 | mtd_parts = partition_info; | ||
227 | mtd_parts_nb = NUM_PARTITIONS; | ||
228 | part_type = "static"; | ||
229 | } | ||
230 | |||
231 | /* Register the partitions */ | ||
232 | printk(KERN_NOTICE "Using %s partition definition\n", part_type); | ||
233 | ret = add_mtd_partitions(cmx270_nand_mtd, mtd_parts, mtd_parts_nb); | ||
234 | if (ret) | ||
235 | goto err2; | ||
236 | |||
237 | /* Return happy */ | ||
238 | return 0; | ||
239 | |||
240 | err2: | ||
241 | iounmap(cmx270_nand_io); | ||
242 | err1: | ||
243 | kfree(cmx270_nand_mtd); | ||
244 | |||
245 | return ret; | ||
246 | |||
247 | } | ||
248 | module_init(cmx270_init); | ||
249 | |||
250 | /* | ||
251 | * Clean up routine | ||
252 | */ | ||
253 | static void cmx270_cleanup(void) | ||
254 | { | ||
255 | /* Release resources, unregister device */ | ||
256 | nand_release(cmx270_nand_mtd); | ||
257 | |||
258 | iounmap(cmx270_nand_io); | ||
259 | |||
260 | /* Free the MTD device structure */ | ||
261 | kfree (cmx270_nand_mtd); | ||
262 | } | ||
263 | module_exit(cmx270_cleanup); | ||
264 | |||
265 | MODULE_LICENSE("GPL"); | ||
266 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | ||
267 | MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module"); | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 6af37b8cff65..04de315e4937 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -312,7 +312,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | |||
312 | /* Select the NAND device */ | 312 | /* Select the NAND device */ |
313 | chip->select_chip(mtd, chipnr); | 313 | chip->select_chip(mtd, chipnr); |
314 | } else | 314 | } else |
315 | page = (int)ofs; | 315 | page = (int)(ofs >> chip->page_shift); |
316 | 316 | ||
317 | if (chip->options & NAND_BUSWIDTH_16) { | 317 | if (chip->options & NAND_BUSWIDTH_16) { |
318 | chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, | 318 | chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, |
@@ -350,7 +350,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | |||
350 | int block, ret; | 350 | int block, ret; |
351 | 351 | ||
352 | /* Get block number */ | 352 | /* Get block number */ |
353 | block = ((int)ofs) >> chip->bbt_erase_shift; | 353 | block = (int)(ofs >> chip->bbt_erase_shift); |
354 | if (chip->bbt) | 354 | if (chip->bbt) |
355 | chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); | 355 | chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); |
356 | 356 | ||
@@ -771,7 +771,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
771 | uint8_t *ecc_code = chip->buffers->ecccode; | 771 | uint8_t *ecc_code = chip->buffers->ecccode; |
772 | int *eccpos = chip->ecc.layout->eccpos; | 772 | int *eccpos = chip->ecc.layout->eccpos; |
773 | 773 | ||
774 | nand_read_page_raw(mtd, chip, buf); | 774 | chip->ecc.read_page_raw(mtd, chip, buf); |
775 | 775 | ||
776 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) | 776 | for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) |
777 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); | 777 | chip->ecc.calculate(mtd, p, &ecc_calc[i]); |
@@ -1426,7 +1426,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, | |||
1426 | for (i = 0; i < chip->ecc.total; i++) | 1426 | for (i = 0; i < chip->ecc.total; i++) |
1427 | chip->oob_poi[eccpos[i]] = ecc_calc[i]; | 1427 | chip->oob_poi[eccpos[i]] = ecc_calc[i]; |
1428 | 1428 | ||
1429 | nand_write_page_raw(mtd, chip, buf); | 1429 | chip->ecc.write_page_raw(mtd, chip, buf); |
1430 | } | 1430 | } |
1431 | 1431 | ||
1432 | /** | 1432 | /** |
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 2e2cdf2fc91d..2fc674a190cf 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c | |||
@@ -24,6 +24,8 @@ | |||
24 | * 512 512 Byte page size | 24 | * 512 512 Byte page size |
25 | */ | 25 | */ |
26 | struct nand_flash_dev nand_flash_ids[] = { | 26 | struct nand_flash_dev nand_flash_ids[] = { |
27 | |||
28 | #ifdef CONFIG_MTD_NAND_MUSEUM_IDS | ||
27 | {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, | 29 | {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, |
28 | {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0}, | 30 | {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0}, |
29 | {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0}, | 31 | {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0}, |
@@ -39,6 +41,7 @@ struct nand_flash_dev nand_flash_ids[] = { | |||
39 | {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, | 41 | {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, |
40 | {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, | 42 | {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, |
41 | {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, | 43 | {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, |
44 | #endif | ||
42 | 45 | ||
43 | {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, | 46 | {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, |
44 | {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, | 47 | {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, |
@@ -137,6 +140,7 @@ struct nand_manufacturers nand_manuf_ids[] = { | |||
137 | {NAND_MFR_RENESAS, "Renesas"}, | 140 | {NAND_MFR_RENESAS, "Renesas"}, |
138 | {NAND_MFR_STMICRO, "ST Micro"}, | 141 | {NAND_MFR_STMICRO, "ST Micro"}, |
139 | {NAND_MFR_HYNIX, "Hynix"}, | 142 | {NAND_MFR_HYNIX, "Hynix"}, |
143 | {NAND_MFR_MICRON, "Micron"}, | ||
140 | {0x0, "Unknown"} | 144 | {0x0, "Unknown"} |
141 | }; | 145 | }; |
142 | 146 | ||
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c3bca9590ad2..205df0f771fe 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/mtd/nand.h> | 37 | #include <linux/mtd/nand.h> |
38 | #include <linux/mtd/partitions.h> | 38 | #include <linux/mtd/partitions.h> |
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/list.h> | ||
41 | #include <linux/random.h> | ||
40 | 42 | ||
41 | /* Default simulator parameters values */ | 43 | /* Default simulator parameters values */ |
42 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ | 44 | #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ |
@@ -90,6 +92,15 @@ static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH; | |||
90 | static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; | 92 | static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; |
91 | static uint log = CONFIG_NANDSIM_LOG; | 93 | static uint log = CONFIG_NANDSIM_LOG; |
92 | static uint dbg = CONFIG_NANDSIM_DBG; | 94 | static uint dbg = CONFIG_NANDSIM_DBG; |
95 | static unsigned long parts[MAX_MTD_DEVICES]; | ||
96 | static unsigned int parts_num; | ||
97 | static char *badblocks = NULL; | ||
98 | static char *weakblocks = NULL; | ||
99 | static char *weakpages = NULL; | ||
100 | static unsigned int bitflips = 0; | ||
101 | static char *gravepages = NULL; | ||
102 | static unsigned int rptwear = 0; | ||
103 | static unsigned int overridesize = 0; | ||
93 | 104 | ||
94 | module_param(first_id_byte, uint, 0400); | 105 | module_param(first_id_byte, uint, 0400); |
95 | module_param(second_id_byte, uint, 0400); | 106 | module_param(second_id_byte, uint, 0400); |
@@ -104,8 +115,16 @@ module_param(bus_width, uint, 0400); | |||
104 | module_param(do_delays, uint, 0400); | 115 | module_param(do_delays, uint, 0400); |
105 | module_param(log, uint, 0400); | 116 | module_param(log, uint, 0400); |
106 | module_param(dbg, uint, 0400); | 117 | module_param(dbg, uint, 0400); |
107 | 118 | module_param_array(parts, ulong, &parts_num, 0400); | |
108 | MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); | 119 | module_param(badblocks, charp, 0400); |
120 | module_param(weakblocks, charp, 0400); | ||
121 | module_param(weakpages, charp, 0400); | ||
122 | module_param(bitflips, uint, 0400); | ||
123 | module_param(gravepages, charp, 0400); | ||
124 | module_param(rptwear, uint, 0400); | ||
125 | module_param(overridesize, uint, 0400); | ||
126 | |||
127 | MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); | ||
109 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); | 128 | MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); |
110 | MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); | 129 | MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); |
111 | MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); | 130 | MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); |
@@ -118,6 +137,23 @@ MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)"); | |||
118 | MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero"); | 137 | MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero"); |
119 | MODULE_PARM_DESC(log, "Perform logging if not zero"); | 138 | MODULE_PARM_DESC(log, "Perform logging if not zero"); |
120 | MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | 139 | MODULE_PARM_DESC(dbg, "Output debug information if not zero"); |
140 | MODULE_PARM_DESC(parts, "Partition sizes (in erase blocks) separated by commas"); | ||
141 | /* Page and erase block positions for the following parameters are independent of any partitions */ | ||
142 | MODULE_PARM_DESC(badblocks, "Erase blocks that are initially marked bad, separated by commas"); | ||
143 | MODULE_PARM_DESC(weakblocks, "Weak erase blocks [: remaining erase cycles (defaults to 3)]" | ||
144 | " separated by commas e.g. 113:2 means eb 113" | ||
145 | " can be erased only twice before failing"); | ||
146 | MODULE_PARM_DESC(weakpages, "Weak pages [: maximum writes (defaults to 3)]" | ||
147 | " separated by commas e.g. 1401:2 means page 1401" | ||
148 | " can be written only twice before failing"); | ||
149 | MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (zero by default)"); | ||
150 | MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" | ||
151 | " separated by commas e.g. 1401:2 means page 1401" | ||
152 | " can be read only twice before failing"); | ||
153 | MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if not zero"); | ||
154 | MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " | ||
155 | "The size is specified in erase blocks and as the exponent of a power of two" | ||
156 | " e.g. 5 means a size of 32 erase blocks"); | ||
121 | 157 | ||
122 | /* The largest possible page size */ | 158 | /* The largest possible page size */ |
123 | #define NS_LARGEST_PAGE_SIZE 2048 | 159 | #define NS_LARGEST_PAGE_SIZE 2048 |
@@ -131,9 +167,11 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero"); | |||
131 | #define NS_DBG(args...) \ | 167 | #define NS_DBG(args...) \ |
132 | do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) | 168 | do { if (dbg) printk(KERN_DEBUG NS_OUTPUT_PREFIX " debug: " args); } while(0) |
133 | #define NS_WARN(args...) \ | 169 | #define NS_WARN(args...) \ |
134 | do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warnig: " args); } while(0) | 170 | do { printk(KERN_WARNING NS_OUTPUT_PREFIX " warning: " args); } while(0) |
135 | #define NS_ERR(args...) \ | 171 | #define NS_ERR(args...) \ |
136 | do { printk(KERN_ERR NS_OUTPUT_PREFIX " errorr: " args); } while(0) | 172 | do { printk(KERN_ERR NS_OUTPUT_PREFIX " error: " args); } while(0) |
173 | #define NS_INFO(args...) \ | ||
174 | do { printk(KERN_INFO NS_OUTPUT_PREFIX " " args); } while(0) | ||
137 | 175 | ||
138 | /* Busy-wait delay macros (microseconds, milliseconds) */ | 176 | /* Busy-wait delay macros (microseconds, milliseconds) */ |
139 | #define NS_UDELAY(us) \ | 177 | #define NS_UDELAY(us) \ |
@@ -238,7 +276,8 @@ union ns_mem { | |||
238 | * The structure which describes all the internal simulator data. | 276 | * The structure which describes all the internal simulator data. |
239 | */ | 277 | */ |
240 | struct nandsim { | 278 | struct nandsim { |
241 | struct mtd_partition part; | 279 | struct mtd_partition partitions[MAX_MTD_DEVICES]; |
280 | unsigned int nbparts; | ||
242 | 281 | ||
243 | uint busw; /* flash chip bus width (8 or 16) */ | 282 | uint busw; /* flash chip bus width (8 or 16) */ |
244 | u_char ids[4]; /* chip's ID bytes */ | 283 | u_char ids[4]; /* chip's ID bytes */ |
@@ -338,6 +377,38 @@ static struct nandsim_operations { | |||
338 | STATE_DATAOUT, STATE_READY}} | 377 | STATE_DATAOUT, STATE_READY}} |
339 | }; | 378 | }; |
340 | 379 | ||
380 | struct weak_block { | ||
381 | struct list_head list; | ||
382 | unsigned int erase_block_no; | ||
383 | unsigned int max_erases; | ||
384 | unsigned int erases_done; | ||
385 | }; | ||
386 | |||
387 | static LIST_HEAD(weak_blocks); | ||
388 | |||
389 | struct weak_page { | ||
390 | struct list_head list; | ||
391 | unsigned int page_no; | ||
392 | unsigned int max_writes; | ||
393 | unsigned int writes_done; | ||
394 | }; | ||
395 | |||
396 | static LIST_HEAD(weak_pages); | ||
397 | |||
398 | struct grave_page { | ||
399 | struct list_head list; | ||
400 | unsigned int page_no; | ||
401 | unsigned int max_reads; | ||
402 | unsigned int reads_done; | ||
403 | }; | ||
404 | |||
405 | static LIST_HEAD(grave_pages); | ||
406 | |||
407 | static unsigned long *erase_block_wear = NULL; | ||
408 | static unsigned int wear_eb_count = 0; | ||
409 | static unsigned long total_wear = 0; | ||
410 | static unsigned int rptwear_cnt = 0; | ||
411 | |||
341 | /* MTD structure for NAND controller */ | 412 | /* MTD structure for NAND controller */ |
342 | static struct mtd_info *nsmtd; | 413 | static struct mtd_info *nsmtd; |
343 | 414 | ||
@@ -381,6 +452,13 @@ static void free_device(struct nandsim *ns) | |||
381 | } | 452 | } |
382 | } | 453 | } |
383 | 454 | ||
455 | static char *get_partition_name(int i) | ||
456 | { | ||
457 | char buf[64]; | ||
458 | sprintf(buf, "NAND simulator partition %d", i); | ||
459 | return kstrdup(buf, GFP_KERNEL); | ||
460 | } | ||
461 | |||
384 | /* | 462 | /* |
385 | * Initialize the nandsim structure. | 463 | * Initialize the nandsim structure. |
386 | * | 464 | * |
@@ -390,7 +468,9 @@ static int init_nandsim(struct mtd_info *mtd) | |||
390 | { | 468 | { |
391 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; | 469 | struct nand_chip *chip = (struct nand_chip *)mtd->priv; |
392 | struct nandsim *ns = (struct nandsim *)(chip->priv); | 470 | struct nandsim *ns = (struct nandsim *)(chip->priv); |
393 | int i; | 471 | int i, ret = 0; |
472 | u_int32_t remains; | ||
473 | u_int32_t next_offset; | ||
394 | 474 | ||
395 | if (NS_IS_INITIALIZED(ns)) { | 475 | if (NS_IS_INITIALIZED(ns)) { |
396 | NS_ERR("init_nandsim: nandsim is already initialized\n"); | 476 | NS_ERR("init_nandsim: nandsim is already initialized\n"); |
@@ -448,6 +528,40 @@ static int init_nandsim(struct mtd_info *mtd) | |||
448 | } | 528 | } |
449 | } | 529 | } |
450 | 530 | ||
531 | /* Fill the partition_info structure */ | ||
532 | if (parts_num > ARRAY_SIZE(ns->partitions)) { | ||
533 | NS_ERR("too many partitions.\n"); | ||
534 | ret = -EINVAL; | ||
535 | goto error; | ||
536 | } | ||
537 | remains = ns->geom.totsz; | ||
538 | next_offset = 0; | ||
539 | for (i = 0; i < parts_num; ++i) { | ||
540 | unsigned long part = parts[i]; | ||
541 | if (!part || part > remains / ns->geom.secsz) { | ||
542 | NS_ERR("bad partition size.\n"); | ||
543 | ret = -EINVAL; | ||
544 | goto error; | ||
545 | } | ||
546 | ns->partitions[i].name = get_partition_name(i); | ||
547 | ns->partitions[i].offset = next_offset; | ||
548 | ns->partitions[i].size = part * ns->geom.secsz; | ||
549 | next_offset += ns->partitions[i].size; | ||
550 | remains -= ns->partitions[i].size; | ||
551 | } | ||
552 | ns->nbparts = parts_num; | ||
553 | if (remains) { | ||
554 | if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { | ||
555 | NS_ERR("too many partitions.\n"); | ||
556 | ret = -EINVAL; | ||
557 | goto error; | ||
558 | } | ||
559 | ns->partitions[i].name = get_partition_name(i); | ||
560 | ns->partitions[i].offset = next_offset; | ||
561 | ns->partitions[i].size = remains; | ||
562 | ns->nbparts += 1; | ||
563 | } | ||
564 | |||
451 | /* Detect how many ID bytes the NAND chip outputs */ | 565 | /* Detect how many ID bytes the NAND chip outputs */ |
452 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { | 566 | for (i = 0; nand_flash_ids[i].name != NULL; i++) { |
453 | if (second_id_byte != nand_flash_ids[i].id) | 567 | if (second_id_byte != nand_flash_ids[i].id) |
@@ -474,7 +588,7 @@ static int init_nandsim(struct mtd_info *mtd) | |||
474 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); | 588 | printk("sector address bytes: %u\n", ns->geom.secaddrbytes); |
475 | printk("options: %#x\n", ns->options); | 589 | printk("options: %#x\n", ns->options); |
476 | 590 | ||
477 | if (alloc_device(ns) != 0) | 591 | if ((ret = alloc_device(ns)) != 0) |
478 | goto error; | 592 | goto error; |
479 | 593 | ||
480 | /* Allocate / initialize the internal buffer */ | 594 | /* Allocate / initialize the internal buffer */ |
@@ -482,21 +596,17 @@ static int init_nandsim(struct mtd_info *mtd) | |||
482 | if (!ns->buf.byte) { | 596 | if (!ns->buf.byte) { |
483 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", | 597 | NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", |
484 | ns->geom.pgszoob); | 598 | ns->geom.pgszoob); |
599 | ret = -ENOMEM; | ||
485 | goto error; | 600 | goto error; |
486 | } | 601 | } |
487 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); | 602 | memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); |
488 | 603 | ||
489 | /* Fill the partition_info structure */ | ||
490 | ns->part.name = "NAND simulator partition"; | ||
491 | ns->part.offset = 0; | ||
492 | ns->part.size = ns->geom.totsz; | ||
493 | |||
494 | return 0; | 604 | return 0; |
495 | 605 | ||
496 | error: | 606 | error: |
497 | free_device(ns); | 607 | free_device(ns); |
498 | 608 | ||
499 | return -ENOMEM; | 609 | return ret; |
500 | } | 610 | } |
501 | 611 | ||
502 | /* | 612 | /* |
@@ -510,6 +620,287 @@ static void free_nandsim(struct nandsim *ns) | |||
510 | return; | 620 | return; |
511 | } | 621 | } |
512 | 622 | ||
623 | static int parse_badblocks(struct nandsim *ns, struct mtd_info *mtd) | ||
624 | { | ||
625 | char *w; | ||
626 | int zero_ok; | ||
627 | unsigned int erase_block_no; | ||
628 | loff_t offset; | ||
629 | |||
630 | if (!badblocks) | ||
631 | return 0; | ||
632 | w = badblocks; | ||
633 | do { | ||
634 | zero_ok = (*w == '0' ? 1 : 0); | ||
635 | erase_block_no = simple_strtoul(w, &w, 0); | ||
636 | if (!zero_ok && !erase_block_no) { | ||
637 | NS_ERR("invalid badblocks.\n"); | ||
638 | return -EINVAL; | ||
639 | } | ||
640 | offset = erase_block_no * ns->geom.secsz; | ||
641 | if (mtd->block_markbad(mtd, offset)) { | ||
642 | NS_ERR("invalid badblocks.\n"); | ||
643 | return -EINVAL; | ||
644 | } | ||
645 | if (*w == ',') | ||
646 | w += 1; | ||
647 | } while (*w); | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | static int parse_weakblocks(void) | ||
652 | { | ||
653 | char *w; | ||
654 | int zero_ok; | ||
655 | unsigned int erase_block_no; | ||
656 | unsigned int max_erases; | ||
657 | struct weak_block *wb; | ||
658 | |||
659 | if (!weakblocks) | ||
660 | return 0; | ||
661 | w = weakblocks; | ||
662 | do { | ||
663 | zero_ok = (*w == '0' ? 1 : 0); | ||
664 | erase_block_no = simple_strtoul(w, &w, 0); | ||
665 | if (!zero_ok && !erase_block_no) { | ||
666 | NS_ERR("invalid weakblocks.\n"); | ||
667 | return -EINVAL; | ||
668 | } | ||
669 | max_erases = 3; | ||
670 | if (*w == ':') { | ||
671 | w += 1; | ||
672 | max_erases = simple_strtoul(w, &w, 0); | ||
673 | } | ||
674 | if (*w == ',') | ||
675 | w += 1; | ||
676 | wb = kzalloc(sizeof(*wb), GFP_KERNEL); | ||
677 | if (!wb) { | ||
678 | NS_ERR("unable to allocate memory.\n"); | ||
679 | return -ENOMEM; | ||
680 | } | ||
681 | wb->erase_block_no = erase_block_no; | ||
682 | wb->max_erases = max_erases; | ||
683 | list_add(&wb->list, &weak_blocks); | ||
684 | } while (*w); | ||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static int erase_error(unsigned int erase_block_no) | ||
689 | { | ||
690 | struct weak_block *wb; | ||
691 | |||
692 | list_for_each_entry(wb, &weak_blocks, list) | ||
693 | if (wb->erase_block_no == erase_block_no) { | ||
694 | if (wb->erases_done >= wb->max_erases) | ||
695 | return 1; | ||
696 | wb->erases_done += 1; | ||
697 | return 0; | ||
698 | } | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int parse_weakpages(void) | ||
703 | { | ||
704 | char *w; | ||
705 | int zero_ok; | ||
706 | unsigned int page_no; | ||
707 | unsigned int max_writes; | ||
708 | struct weak_page *wp; | ||
709 | |||
710 | if (!weakpages) | ||
711 | return 0; | ||
712 | w = weakpages; | ||
713 | do { | ||
714 | zero_ok = (*w == '0' ? 1 : 0); | ||
715 | page_no = simple_strtoul(w, &w, 0); | ||
716 | if (!zero_ok && !page_no) { | ||
717 | NS_ERR("invalid weakpagess.\n"); | ||
718 | return -EINVAL; | ||
719 | } | ||
720 | max_writes = 3; | ||
721 | if (*w == ':') { | ||
722 | w += 1; | ||
723 | max_writes = simple_strtoul(w, &w, 0); | ||
724 | } | ||
725 | if (*w == ',') | ||
726 | w += 1; | ||
727 | wp = kzalloc(sizeof(*wp), GFP_KERNEL); | ||
728 | if (!wp) { | ||
729 | NS_ERR("unable to allocate memory.\n"); | ||
730 | return -ENOMEM; | ||
731 | } | ||
732 | wp->page_no = page_no; | ||
733 | wp->max_writes = max_writes; | ||
734 | list_add(&wp->list, &weak_pages); | ||
735 | } while (*w); | ||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static int write_error(unsigned int page_no) | ||
740 | { | ||
741 | struct weak_page *wp; | ||
742 | |||
743 | list_for_each_entry(wp, &weak_pages, list) | ||
744 | if (wp->page_no == page_no) { | ||
745 | if (wp->writes_done >= wp->max_writes) | ||
746 | return 1; | ||
747 | wp->writes_done += 1; | ||
748 | return 0; | ||
749 | } | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int parse_gravepages(void) | ||
754 | { | ||
755 | char *g; | ||
756 | int zero_ok; | ||
757 | unsigned int page_no; | ||
758 | unsigned int max_reads; | ||
759 | struct grave_page *gp; | ||
760 | |||
761 | if (!gravepages) | ||
762 | return 0; | ||
763 | g = gravepages; | ||
764 | do { | ||
765 | zero_ok = (*g == '0' ? 1 : 0); | ||
766 | page_no = simple_strtoul(g, &g, 0); | ||
767 | if (!zero_ok && !page_no) { | ||
768 | NS_ERR("invalid gravepagess.\n"); | ||
769 | return -EINVAL; | ||
770 | } | ||
771 | max_reads = 3; | ||
772 | if (*g == ':') { | ||
773 | g += 1; | ||
774 | max_reads = simple_strtoul(g, &g, 0); | ||
775 | } | ||
776 | if (*g == ',') | ||
777 | g += 1; | ||
778 | gp = kzalloc(sizeof(*gp), GFP_KERNEL); | ||
779 | if (!gp) { | ||
780 | NS_ERR("unable to allocate memory.\n"); | ||
781 | return -ENOMEM; | ||
782 | } | ||
783 | gp->page_no = page_no; | ||
784 | gp->max_reads = max_reads; | ||
785 | list_add(&gp->list, &grave_pages); | ||
786 | } while (*g); | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int read_error(unsigned int page_no) | ||
791 | { | ||
792 | struct grave_page *gp; | ||
793 | |||
794 | list_for_each_entry(gp, &grave_pages, list) | ||
795 | if (gp->page_no == page_no) { | ||
796 | if (gp->reads_done >= gp->max_reads) | ||
797 | return 1; | ||
798 | gp->reads_done += 1; | ||
799 | return 0; | ||
800 | } | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static void free_lists(void) | ||
805 | { | ||
806 | struct list_head *pos, *n; | ||
807 | list_for_each_safe(pos, n, &weak_blocks) { | ||
808 | list_del(pos); | ||
809 | kfree(list_entry(pos, struct weak_block, list)); | ||
810 | } | ||
811 | list_for_each_safe(pos, n, &weak_pages) { | ||
812 | list_del(pos); | ||
813 | kfree(list_entry(pos, struct weak_page, list)); | ||
814 | } | ||
815 | list_for_each_safe(pos, n, &grave_pages) { | ||
816 | list_del(pos); | ||
817 | kfree(list_entry(pos, struct grave_page, list)); | ||
818 | } | ||
819 | kfree(erase_block_wear); | ||
820 | } | ||
821 | |||
822 | static int setup_wear_reporting(struct mtd_info *mtd) | ||
823 | { | ||
824 | size_t mem; | ||
825 | |||
826 | if (!rptwear) | ||
827 | return 0; | ||
828 | wear_eb_count = mtd->size / mtd->erasesize; | ||
829 | mem = wear_eb_count * sizeof(unsigned long); | ||
830 | if (mem / sizeof(unsigned long) != wear_eb_count) { | ||
831 | NS_ERR("Too many erase blocks for wear reporting\n"); | ||
832 | return -ENOMEM; | ||
833 | } | ||
834 | erase_block_wear = kzalloc(mem, GFP_KERNEL); | ||
835 | if (!erase_block_wear) { | ||
836 | NS_ERR("Too many erase blocks for wear reporting\n"); | ||
837 | return -ENOMEM; | ||
838 | } | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | static void update_wear(unsigned int erase_block_no) | ||
843 | { | ||
844 | unsigned long wmin = -1, wmax = 0, avg; | ||
845 | unsigned long deciles[10], decile_max[10], tot = 0; | ||
846 | unsigned int i; | ||
847 | |||
848 | if (!erase_block_wear) | ||
849 | return; | ||
850 | total_wear += 1; | ||
851 | if (total_wear == 0) | ||
852 | NS_ERR("Erase counter total overflow\n"); | ||
853 | erase_block_wear[erase_block_no] += 1; | ||
854 | if (erase_block_wear[erase_block_no] == 0) | ||
855 | NS_ERR("Erase counter overflow for erase block %u\n", erase_block_no); | ||
856 | rptwear_cnt += 1; | ||
857 | if (rptwear_cnt < rptwear) | ||
858 | return; | ||
859 | rptwear_cnt = 0; | ||
860 | /* Calc wear stats */ | ||
861 | for (i = 0; i < wear_eb_count; ++i) { | ||
862 | unsigned long wear = erase_block_wear[i]; | ||
863 | if (wear < wmin) | ||
864 | wmin = wear; | ||
865 | if (wear > wmax) | ||
866 | wmax = wear; | ||
867 | tot += wear; | ||
868 | } | ||
869 | for (i = 0; i < 9; ++i) { | ||
870 | deciles[i] = 0; | ||
871 | decile_max[i] = (wmax * (i + 1) + 5) / 10; | ||
872 | } | ||
873 | deciles[9] = 0; | ||
874 | decile_max[9] = wmax; | ||
875 | for (i = 0; i < wear_eb_count; ++i) { | ||
876 | int d; | ||
877 | unsigned long wear = erase_block_wear[i]; | ||
878 | for (d = 0; d < 10; ++d) | ||
879 | if (wear <= decile_max[d]) { | ||
880 | deciles[d] += 1; | ||
881 | break; | ||
882 | } | ||
883 | } | ||
884 | avg = tot / wear_eb_count; | ||
885 | /* Output wear report */ | ||
886 | NS_INFO("*** Wear Report ***\n"); | ||
887 | NS_INFO("Total numbers of erases: %lu\n", tot); | ||
888 | NS_INFO("Number of erase blocks: %u\n", wear_eb_count); | ||
889 | NS_INFO("Average number of erases: %lu\n", avg); | ||
890 | NS_INFO("Maximum number of erases: %lu\n", wmax); | ||
891 | NS_INFO("Minimum number of erases: %lu\n", wmin); | ||
892 | for (i = 0; i < 10; ++i) { | ||
893 | unsigned long from = (i ? decile_max[i - 1] + 1 : 0); | ||
894 | if (from > decile_max[i]) | ||
895 | continue; | ||
896 | NS_INFO("Number of ebs with erase counts from %lu to %lu : %lu\n", | ||
897 | from, | ||
898 | decile_max[i], | ||
899 | deciles[i]); | ||
900 | } | ||
901 | NS_INFO("*** End of Wear Report ***\n"); | ||
902 | } | ||
903 | |||
513 | /* | 904 | /* |
514 | * Returns the string representation of 'state' state. | 905 | * Returns the string representation of 'state' state. |
515 | */ | 906 | */ |
@@ -822,9 +1213,31 @@ static void read_page(struct nandsim *ns, int num) | |||
822 | NS_DBG("read_page: page %d not allocated\n", ns->regs.row); | 1213 | NS_DBG("read_page: page %d not allocated\n", ns->regs.row); |
823 | memset(ns->buf.byte, 0xFF, num); | 1214 | memset(ns->buf.byte, 0xFF, num); |
824 | } else { | 1215 | } else { |
1216 | unsigned int page_no = ns->regs.row; | ||
825 | NS_DBG("read_page: page %d allocated, reading from %d\n", | 1217 | NS_DBG("read_page: page %d allocated, reading from %d\n", |
826 | ns->regs.row, ns->regs.column + ns->regs.off); | 1218 | ns->regs.row, ns->regs.column + ns->regs.off); |
1219 | if (read_error(page_no)) { | ||
1220 | int i; | ||
1221 | memset(ns->buf.byte, 0xFF, num); | ||
1222 | for (i = 0; i < num; ++i) | ||
1223 | ns->buf.byte[i] = random32(); | ||
1224 | NS_WARN("simulating read error in page %u\n", page_no); | ||
1225 | return; | ||
1226 | } | ||
827 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); | 1227 | memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); |
1228 | if (bitflips && random32() < (1 << 22)) { | ||
1229 | int flips = 1; | ||
1230 | if (bitflips > 1) | ||
1231 | flips = (random32() % (int) bitflips) + 1; | ||
1232 | while (flips--) { | ||
1233 | int pos = random32() % (num * 8); | ||
1234 | ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); | ||
1235 | NS_WARN("read_page: flipping bit %d in page %d " | ||
1236 | "reading from %d ecc: corrected=%u failed=%u\n", | ||
1237 | pos, ns->regs.row, ns->regs.column + ns->regs.off, | ||
1238 | nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); | ||
1239 | } | ||
1240 | } | ||
828 | } | 1241 | } |
829 | } | 1242 | } |
830 | 1243 | ||
@@ -883,6 +1296,7 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
883 | { | 1296 | { |
884 | int num; | 1297 | int num; |
885 | int busdiv = ns->busw == 8 ? 1 : 2; | 1298 | int busdiv = ns->busw == 8 ? 1 : 2; |
1299 | unsigned int erase_block_no, page_no; | ||
886 | 1300 | ||
887 | action &= ACTION_MASK; | 1301 | action &= ACTION_MASK; |
888 | 1302 | ||
@@ -942,14 +1356,24 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
942 | 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; | 1356 | 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; |
943 | ns->regs.column = 0; | 1357 | ns->regs.column = 0; |
944 | 1358 | ||
1359 | erase_block_no = ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift); | ||
1360 | |||
945 | NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", | 1361 | NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", |
946 | ns->regs.row, NS_RAW_OFFSET(ns)); | 1362 | ns->regs.row, NS_RAW_OFFSET(ns)); |
947 | NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); | 1363 | NS_LOG("erase sector %u\n", erase_block_no); |
948 | 1364 | ||
949 | erase_sector(ns); | 1365 | erase_sector(ns); |
950 | 1366 | ||
951 | NS_MDELAY(erase_delay); | 1367 | NS_MDELAY(erase_delay); |
952 | 1368 | ||
1369 | if (erase_block_wear) | ||
1370 | update_wear(erase_block_no); | ||
1371 | |||
1372 | if (erase_error(erase_block_no)) { | ||
1373 | NS_WARN("simulating erase failure in erase block %u\n", erase_block_no); | ||
1374 | return -1; | ||
1375 | } | ||
1376 | |||
953 | break; | 1377 | break; |
954 | 1378 | ||
955 | case ACTION_PRGPAGE: | 1379 | case ACTION_PRGPAGE: |
@@ -972,6 +1396,8 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
972 | if (prog_page(ns, num) == -1) | 1396 | if (prog_page(ns, num) == -1) |
973 | return -1; | 1397 | return -1; |
974 | 1398 | ||
1399 | page_no = ns->regs.row; | ||
1400 | |||
975 | NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", | 1401 | NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", |
976 | num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); | 1402 | num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); |
977 | NS_LOG("programm page %d\n", ns->regs.row); | 1403 | NS_LOG("programm page %d\n", ns->regs.row); |
@@ -979,6 +1405,11 @@ static int do_state_action(struct nandsim *ns, uint32_t action) | |||
979 | NS_UDELAY(programm_delay); | 1405 | NS_UDELAY(programm_delay); |
980 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); | 1406 | NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); |
981 | 1407 | ||
1408 | if (write_error(page_no)) { | ||
1409 | NS_WARN("simulating write failure in page %u\n", page_no); | ||
1410 | return -1; | ||
1411 | } | ||
1412 | |||
982 | break; | 1413 | break; |
983 | 1414 | ||
984 | case ACTION_ZEROOFF: | 1415 | case ACTION_ZEROOFF: |
@@ -1503,7 +1934,7 @@ static int __init ns_init_module(void) | |||
1503 | { | 1934 | { |
1504 | struct nand_chip *chip; | 1935 | struct nand_chip *chip; |
1505 | struct nandsim *nand; | 1936 | struct nandsim *nand; |
1506 | int retval = -ENOMEM; | 1937 | int retval = -ENOMEM, i; |
1507 | 1938 | ||
1508 | if (bus_width != 8 && bus_width != 16) { | 1939 | if (bus_width != 8 && bus_width != 16) { |
1509 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); | 1940 | NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); |
@@ -1533,6 +1964,8 @@ static int __init ns_init_module(void) | |||
1533 | chip->verify_buf = ns_nand_verify_buf; | 1964 | chip->verify_buf = ns_nand_verify_buf; |
1534 | chip->read_word = ns_nand_read_word; | 1965 | chip->read_word = ns_nand_read_word; |
1535 | chip->ecc.mode = NAND_ECC_SOFT; | 1966 | chip->ecc.mode = NAND_ECC_SOFT; |
1967 | /* The NAND_SKIP_BBTSCAN option is necessary for 'overridesize' */ | ||
1968 | /* and 'badblocks' parameters to work */ | ||
1536 | chip->options |= NAND_SKIP_BBTSCAN; | 1969 | chip->options |= NAND_SKIP_BBTSCAN; |
1537 | 1970 | ||
1538 | /* | 1971 | /* |
@@ -1557,6 +1990,15 @@ static int __init ns_init_module(void) | |||
1557 | 1990 | ||
1558 | nsmtd->owner = THIS_MODULE; | 1991 | nsmtd->owner = THIS_MODULE; |
1559 | 1992 | ||
1993 | if ((retval = parse_weakblocks()) != 0) | ||
1994 | goto error; | ||
1995 | |||
1996 | if ((retval = parse_weakpages()) != 0) | ||
1997 | goto error; | ||
1998 | |||
1999 | if ((retval = parse_gravepages()) != 0) | ||
2000 | goto error; | ||
2001 | |||
1560 | if ((retval = nand_scan(nsmtd, 1)) != 0) { | 2002 | if ((retval = nand_scan(nsmtd, 1)) != 0) { |
1561 | NS_ERR("can't register NAND Simulator\n"); | 2003 | NS_ERR("can't register NAND Simulator\n"); |
1562 | if (retval > 0) | 2004 | if (retval > 0) |
@@ -1564,23 +2006,44 @@ static int __init ns_init_module(void) | |||
1564 | goto error; | 2006 | goto error; |
1565 | } | 2007 | } |
1566 | 2008 | ||
1567 | if ((retval = init_nandsim(nsmtd)) != 0) { | 2009 | if (overridesize) { |
1568 | NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); | 2010 | u_int32_t new_size = nsmtd->erasesize << overridesize; |
1569 | goto error; | 2011 | if (new_size >> overridesize != nsmtd->erasesize) { |
2012 | NS_ERR("overridesize is too big\n"); | ||
2013 | goto err_exit; | ||
2014 | } | ||
2015 | /* N.B. This relies on nand_scan not doing anything with the size before we change it */ | ||
2016 | nsmtd->size = new_size; | ||
2017 | chip->chipsize = new_size; | ||
2018 | chip->chip_shift = ffs(new_size) - 1; | ||
1570 | } | 2019 | } |
1571 | 2020 | ||
1572 | if ((retval = nand_default_bbt(nsmtd)) != 0) { | 2021 | if ((retval = setup_wear_reporting(nsmtd)) != 0) |
1573 | free_nandsim(nand); | 2022 | goto err_exit; |
1574 | goto error; | 2023 | |
1575 | } | 2024 | if ((retval = init_nandsim(nsmtd)) != 0) |
2025 | goto err_exit; | ||
1576 | 2026 | ||
1577 | /* Register NAND as one big partition */ | 2027 | if ((retval = parse_badblocks(nand, nsmtd)) != 0) |
1578 | add_mtd_partitions(nsmtd, &nand->part, 1); | 2028 | goto err_exit; |
2029 | |||
2030 | if ((retval = nand_default_bbt(nsmtd)) != 0) | ||
2031 | goto err_exit; | ||
2032 | |||
2033 | /* Register NAND partitions */ | ||
2034 | if ((retval = add_mtd_partitions(nsmtd, &nand->partitions[0], nand->nbparts)) != 0) | ||
2035 | goto err_exit; | ||
1579 | 2036 | ||
1580 | return 0; | 2037 | return 0; |
1581 | 2038 | ||
2039 | err_exit: | ||
2040 | free_nandsim(nand); | ||
2041 | nand_release(nsmtd); | ||
2042 | for (i = 0;i < ARRAY_SIZE(nand->partitions); ++i) | ||
2043 | kfree(nand->partitions[i].name); | ||
1582 | error: | 2044 | error: |
1583 | kfree(nsmtd); | 2045 | kfree(nsmtd); |
2046 | free_lists(); | ||
1584 | 2047 | ||
1585 | return retval; | 2048 | return retval; |
1586 | } | 2049 | } |
@@ -1593,10 +2056,14 @@ module_init(ns_init_module); | |||
1593 | static void __exit ns_cleanup_module(void) | 2056 | static void __exit ns_cleanup_module(void) |
1594 | { | 2057 | { |
1595 | struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); | 2058 | struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); |
2059 | int i; | ||
1596 | 2060 | ||
1597 | free_nandsim(ns); /* Free nandsim private resources */ | 2061 | free_nandsim(ns); /* Free nandsim private resources */ |
1598 | nand_release(nsmtd); /* Unregisterd drived */ | 2062 | nand_release(nsmtd); /* Unregister driver */ |
2063 | for (i = 0;i < ARRAY_SIZE(ns->partitions); ++i) | ||
2064 | kfree(ns->partitions[i].name); | ||
1599 | kfree(nsmtd); /* Free other structures */ | 2065 | kfree(nsmtd); /* Free other structures */ |
2066 | free_lists(); | ||
1600 | } | 2067 | } |
1601 | 2068 | ||
1602 | module_exit(ns_cleanup_module); | 2069 | module_exit(ns_cleanup_module); |
@@ -1604,4 +2071,3 @@ module_exit(ns_cleanup_module); | |||
1604 | MODULE_LICENSE ("GPL"); | 2071 | MODULE_LICENSE ("GPL"); |
1605 | MODULE_AUTHOR ("Artem B. Bityuckiy"); | 2072 | MODULE_AUTHOR ("Artem B. Bityuckiy"); |
1606 | MODULE_DESCRIPTION ("The NAND flash simulator"); | 2073 | MODULE_DESCRIPTION ("The NAND flash simulator"); |
1607 | |||
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index 373bddce8f1c..c257d397d08a 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig | |||
@@ -2,20 +2,18 @@ | |||
2 | # linux/drivers/mtd/onenand/Kconfig | 2 | # linux/drivers/mtd/onenand/Kconfig |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "OneNAND Flash Device Drivers" | 5 | menuconfig MTD_ONENAND |
6 | depends on MTD != n | ||
7 | |||
8 | config MTD_ONENAND | ||
9 | tristate "OneNAND Device Support" | 6 | tristate "OneNAND Device Support" |
10 | depends on MTD | 7 | depends on MTD |
11 | help | 8 | help |
12 | This enables support for accessing all type of OneNAND flash | 9 | This enables support for accessing all type of OneNAND flash |
13 | devices. For further information see | 10 | devices. For further information see |
14 | <http://www.samsung.com/Products/Semiconductor/Flash/OneNAND_TM/index.htm>. | 11 | <http://www.samsung.com/Products/Semiconductor/OneNAND/index.htm> |
12 | |||
13 | if MTD_ONENAND | ||
15 | 14 | ||
16 | config MTD_ONENAND_VERIFY_WRITE | 15 | config MTD_ONENAND_VERIFY_WRITE |
17 | bool "Verify OneNAND page writes" | 16 | bool "Verify OneNAND page writes" |
18 | depends on MTD_ONENAND | ||
19 | help | 17 | help |
20 | This adds an extra check when data is written to the flash. The | 18 | This adds an extra check when data is written to the flash. The |
21 | OneNAND flash device internally checks only bits transitioning | 19 | OneNAND flash device internally checks only bits transitioning |
@@ -25,13 +23,12 @@ config MTD_ONENAND_VERIFY_WRITE | |||
25 | 23 | ||
26 | config MTD_ONENAND_GENERIC | 24 | config MTD_ONENAND_GENERIC |
27 | tristate "OneNAND Flash device via platform device driver" | 25 | tristate "OneNAND Flash device via platform device driver" |
28 | depends on MTD_ONENAND && ARM | 26 | depends on ARM |
29 | help | 27 | help |
30 | Support for OneNAND flash via platform device driver. | 28 | Support for OneNAND flash via platform device driver. |
31 | 29 | ||
32 | config MTD_ONENAND_OTP | 30 | config MTD_ONENAND_OTP |
33 | bool "OneNAND OTP Support" | 31 | bool "OneNAND OTP Support" |
34 | depends on MTD_ONENAND | ||
35 | help | 32 | help |
36 | One Block of the NAND Flash Array memory is reserved as | 33 | One Block of the NAND Flash Array memory is reserved as |
37 | a One-Time Programmable Block memory area. | 34 | a One-Time Programmable Block memory area. |
@@ -43,4 +40,4 @@ config MTD_ONENAND_OTP | |||
43 | 40 | ||
44 | OTP block is fully-guaranteed to be a valid block. | 41 | OTP block is fully-guaranteed to be a valid block. |
45 | 42 | ||
46 | endmenu | 43 | endif # MTD_ONENAND |
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 9e14a26ca4e8..000794c6caf5 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
@@ -836,9 +836,11 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col | |||
836 | int readcol = column; | 836 | int readcol = column; |
837 | int readend = column + thislen; | 837 | int readend = column + thislen; |
838 | int lastgap = 0; | 838 | int lastgap = 0; |
839 | unsigned int i; | ||
839 | uint8_t *oob_buf = this->oob_buf; | 840 | uint8_t *oob_buf = this->oob_buf; |
840 | 841 | ||
841 | for (free = this->ecclayout->oobfree; free->length; ++free) { | 842 | free = this->ecclayout->oobfree; |
843 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
842 | if (readcol >= lastgap) | 844 | if (readcol >= lastgap) |
843 | readcol += free->offset - lastgap; | 845 | readcol += free->offset - lastgap; |
844 | if (readend >= lastgap) | 846 | if (readend >= lastgap) |
@@ -846,7 +848,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col | |||
846 | lastgap = free->offset + free->length; | 848 | lastgap = free->offset + free->length; |
847 | } | 849 | } |
848 | this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); | 850 | this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); |
849 | for (free = this->ecclayout->oobfree; free->length; ++free) { | 851 | free = this->ecclayout->oobfree; |
852 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
850 | int free_end = free->offset + free->length; | 853 | int free_end = free->offset + free->length; |
851 | if (free->offset < readend && free_end > readcol) { | 854 | if (free->offset < readend && free_end > readcol) { |
852 | int st = max_t(int,free->offset,readcol); | 855 | int st = max_t(int,free->offset,readcol); |
@@ -854,7 +857,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col | |||
854 | int n = ed - st; | 857 | int n = ed - st; |
855 | memcpy(buf, oob_buf + st, n); | 858 | memcpy(buf, oob_buf + st, n); |
856 | buf += n; | 859 | buf += n; |
857 | } else | 860 | } else if (column == 0) |
858 | break; | 861 | break; |
859 | } | 862 | } |
860 | return 0; | 863 | return 0; |
@@ -1280,15 +1283,18 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, | |||
1280 | int writecol = column; | 1283 | int writecol = column; |
1281 | int writeend = column + thislen; | 1284 | int writeend = column + thislen; |
1282 | int lastgap = 0; | 1285 | int lastgap = 0; |
1286 | unsigned int i; | ||
1283 | 1287 | ||
1284 | for (free = this->ecclayout->oobfree; free->length; ++free) { | 1288 | free = this->ecclayout->oobfree; |
1289 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
1285 | if (writecol >= lastgap) | 1290 | if (writecol >= lastgap) |
1286 | writecol += free->offset - lastgap; | 1291 | writecol += free->offset - lastgap; |
1287 | if (writeend >= lastgap) | 1292 | if (writeend >= lastgap) |
1288 | writeend += free->offset - lastgap; | 1293 | writeend += free->offset - lastgap; |
1289 | lastgap = free->offset + free->length; | 1294 | lastgap = free->offset + free->length; |
1290 | } | 1295 | } |
1291 | for (free = this->ecclayout->oobfree; free->length; ++free) { | 1296 | free = this->ecclayout->oobfree; |
1297 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && free->length; i++, free++) { | ||
1292 | int free_end = free->offset + free->length; | 1298 | int free_end = free->offset + free->length; |
1293 | if (free->offset < writeend && free_end > writecol) { | 1299 | if (free->offset < writeend && free_end > writecol) { |
1294 | int st = max_t(int,free->offset,writecol); | 1300 | int st = max_t(int,free->offset,writecol); |
@@ -1296,7 +1302,7 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, | |||
1296 | int n = ed - st; | 1302 | int n = ed - st; |
1297 | memcpy(oob_buf + st, buf, n); | 1303 | memcpy(oob_buf + st, buf, n); |
1298 | buf += n; | 1304 | buf += n; |
1299 | } else | 1305 | } else if (column == 0) |
1300 | break; | 1306 | break; |
1301 | } | 1307 | } |
1302 | return 0; | 1308 | return 0; |
@@ -2386,7 +2392,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
2386 | * the out of band area | 2392 | * the out of band area |
2387 | */ | 2393 | */ |
2388 | this->ecclayout->oobavail = 0; | 2394 | this->ecclayout->oobavail = 0; |
2389 | for (i = 0; this->ecclayout->oobfree[i].length; i++) | 2395 | for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES && |
2396 | this->ecclayout->oobfree[i].length; i++) | ||
2390 | this->ecclayout->oobavail += | 2397 | this->ecclayout->oobavail += |
2391 | this->ecclayout->oobfree[i].length; | 2398 | this->ecclayout->oobfree[i].length; |
2392 | mtd->oobavail = this->ecclayout->oobavail; | 2399 | mtd->oobavail = this->ecclayout->oobavail; |