diff options
75 files changed, 2678 insertions, 1724 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; |
diff --git a/fs/jffs2/LICENCE b/fs/jffs2/LICENCE index cd81d83e4ad2..562885908135 100644 --- a/fs/jffs2/LICENCE +++ b/fs/jffs2/LICENCE | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | The files in this directory and elsewhere which refer to this LICENCE | 1 | The files in this directory and elsewhere which refer to this LICENCE |
| 2 | file are part of JFFS2, the Journalling Flash File System v2. | 2 | file are part of JFFS2, the Journalling Flash File System v2. |
| 3 | 3 | ||
| 4 | Copyright (C) 2001, 2002 Red Hat, Inc. | 4 | Copyright © 2001-2007 Red Hat, Inc. and others |
| 5 | 5 | ||
| 6 | JFFS2 is free software; you can redistribute it and/or modify it under | 6 | JFFS2 is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free | 7 | the terms of the GNU General Public License as published by the Free |
| @@ -28,8 +28,3 @@ of the GNU General Public License. | |||
| 28 | This exception does not invalidate any other reasons why a work based on | 28 | This exception does not invalidate any other reasons why a work based on |
| 29 | this file might be covered by the GNU General Public License. | 29 | this file might be covered by the GNU General Public License. |
| 30 | 30 | ||
| 31 | For information on obtaining alternative licences for JFFS2, see | ||
| 32 | http://sources.redhat.com/jffs2/jffs2-licence.html | ||
| 33 | |||
| 34 | |||
| 35 | $Id: LICENCE,v 1.1 2002/05/20 14:56:37 dwmw2 Exp $ | ||
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 7f28ee0bd132..c32b241e3d91 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # | 1 | # |
| 2 | # Makefile for the Linux Journalling Flash File System v2 (JFFS2) | 2 | # Makefile for the Linux Journalling Flash File System v2 (JFFS2) |
| 3 | # | 3 | # |
| 4 | # $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $ | ||
| 5 | # | 4 | # |
| 6 | 5 | ||
| 7 | obj-$(CONFIG_JFFS2_FS) += jffs2.o | 6 | obj-$(CONFIG_JFFS2_FS) += jffs2.o |
diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking index c8f0bd64e53e..d14d5a4dc5ac 100644 --- a/fs/jffs2/README.Locking +++ b/fs/jffs2/README.Locking | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | $Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $ | ||
| 2 | 1 | ||
| 3 | JFFS2 LOCKING DOCUMENTATION | 2 | JFFS2 LOCKING DOCUMENTATION |
| 4 | --------------------------- | 3 | --------------------------- |
diff --git a/fs/jffs2/TODO b/fs/jffs2/TODO index d0e23b26fa50..5d3ea4070f01 100644 --- a/fs/jffs2/TODO +++ b/fs/jffs2/TODO | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | $Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $ | ||
| 2 | 1 | ||
| 3 | - support asynchronous operation -- add a per-fs 'reserved_space' count, | 2 | - support asynchronous operation -- add a per-fs 'reserved_space' count, |
| 4 | let each outstanding write reserve the _maximum_ amount of physical | 3 | let each outstanding write reserve the _maximum_ amount of physical |
| @@ -30,8 +29,6 @@ $Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $ | |||
| 30 | the full dirent, we only need to go to the flash in lookup() when we think we've | 29 | the full dirent, we only need to go to the flash in lookup() when we think we've |
| 31 | got a match, and in readdir(). | 30 | got a match, and in readdir(). |
| 32 | - Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately? | 31 | - Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately? |
| 33 | - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into | ||
| 34 | jffs2_mark_node_obsolete(). Can all callers work it out? | ||
| 35 | - Remove size from jffs2_raw_node_frag. | 32 | - Remove size from jffs2_raw_node_frag. |
| 36 | 33 | ||
| 37 | dedekind: | 34 | dedekind: |
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 73f0d60f73a5..a46101ee867a 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2006 NEC Corporation | 4 | * Copyright © 2006 NEC Corporation |
| 5 | * | 5 | * |
| 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> | 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | */ | 10 | */ |
| 11 | |||
| 11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 12 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 13 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index fa327dbd3171..c84378cee82a 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2006 NEC Corporation | 4 | * Copyright © 2006 NEC Corporation |
| 5 | * | 5 | * |
| 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> | 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | */ | 10 | */ |
| 11 | |||
| 11 | struct jffs2_acl_entry { | 12 | struct jffs2_acl_entry { |
| 12 | jint16_t e_tag; | 13 | jint16_t e_tag; |
| 13 | jint16_t e_perm; | 14 | jint16_t e_perm; |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 888f236e5494..0c82dfcfd246 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 07119c42a861..0ca2fff2617f 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: build.c,v 1.85 2005/11/07 11:14:38 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 7001ba26c067..485d065de41f 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c | |||
| @@ -1,16 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Created by Arjan van de Ven <arjanv@redhat.com> | 5 | * Created by Arjan van de Ven <arjanv@redhat.com> |
| 6 | * | 6 | * |
| 7 | * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 7 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
| 8 | * University of Szeged, Hungary | 8 | * University of Szeged, Hungary |
| 9 | * | 9 | * |
| 10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
| 11 | * | 11 | * |
| 12 | * $Id: compr.c,v 1.46 2005/11/07 11:14:38 gleixner Exp $ | ||
| 13 | * | ||
| 14 | */ | 12 | */ |
| 15 | 13 | ||
| 16 | #include "compr.h" | 14 | #include "compr.h" |
| @@ -268,144 +266,6 @@ int jffs2_unregister_compressor(struct jffs2_compressor *comp) | |||
| 268 | return 0; | 266 | return 0; |
| 269 | } | 267 | } |
| 270 | 268 | ||
| 271 | #ifdef CONFIG_JFFS2_PROC | ||
| 272 | |||
| 273 | #define JFFS2_STAT_BUF_SIZE 16000 | ||
| 274 | |||
| 275 | char *jffs2_list_compressors(void) | ||
| 276 | { | ||
| 277 | struct jffs2_compressor *this; | ||
| 278 | char *buf, *act_buf; | ||
| 279 | |||
| 280 | act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL); | ||
| 281 | list_for_each_entry(this, &jffs2_compressor_list, list) { | ||
| 282 | act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority); | ||
| 283 | if ((this->disabled)||(!this->compress)) | ||
| 284 | act_buf += sprintf(act_buf,"disabled"); | ||
| 285 | else | ||
| 286 | act_buf += sprintf(act_buf,"enabled"); | ||
| 287 | act_buf += sprintf(act_buf,"\n"); | ||
| 288 | } | ||
| 289 | return buf; | ||
| 290 | } | ||
| 291 | |||
| 292 | char *jffs2_stats(void) | ||
| 293 | { | ||
| 294 | struct jffs2_compressor *this; | ||
| 295 | char *buf, *act_buf; | ||
| 296 | |||
| 297 | act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL); | ||
| 298 | |||
| 299 | act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n"); | ||
| 300 | act_buf += sprintf(act_buf,"%10s ","none"); | ||
| 301 | act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks, | ||
| 302 | none_stat_compr_size, none_stat_decompr_blocks); | ||
| 303 | spin_lock(&jffs2_compressor_list_lock); | ||
| 304 | list_for_each_entry(this, &jffs2_compressor_list, list) { | ||
| 305 | act_buf += sprintf(act_buf,"%10s ",this->name); | ||
| 306 | if ((this->disabled)||(!this->compress)) | ||
| 307 | act_buf += sprintf(act_buf,"- "); | ||
| 308 | else | ||
| 309 | act_buf += sprintf(act_buf,"+ "); | ||
| 310 | act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this->stat_compr_blocks, | ||
| 311 | this->stat_compr_new_size, this->stat_compr_orig_size, | ||
| 312 | this->stat_decompr_blocks); | ||
| 313 | act_buf += sprintf(act_buf,"\n"); | ||
| 314 | } | ||
| 315 | spin_unlock(&jffs2_compressor_list_lock); | ||
| 316 | |||
| 317 | return buf; | ||
| 318 | } | ||
| 319 | |||
| 320 | char *jffs2_get_compression_mode_name(void) | ||
| 321 | { | ||
| 322 | switch (jffs2_compression_mode) { | ||
| 323 | case JFFS2_COMPR_MODE_NONE: | ||
| 324 | return "none"; | ||
| 325 | case JFFS2_COMPR_MODE_PRIORITY: | ||
| 326 | return "priority"; | ||
| 327 | case JFFS2_COMPR_MODE_SIZE: | ||
| 328 | return "size"; | ||
| 329 | } | ||
| 330 | return "unkown"; | ||
| 331 | } | ||
| 332 | |||
| 333 | int jffs2_set_compression_mode_name(const char *name) | ||
| 334 | { | ||
| 335 | if (!strcmp("none",name)) { | ||
| 336 | jffs2_compression_mode = JFFS2_COMPR_MODE_NONE; | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | if (!strcmp("priority",name)) { | ||
| 340 | jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY; | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | if (!strcmp("size",name)) { | ||
| 344 | jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE; | ||
| 345 | return 0; | ||
| 346 | } | ||
| 347 | return 1; | ||
| 348 | } | ||
| 349 | |||
| 350 | static int jffs2_compressor_Xable(const char *name, int disabled) | ||
| 351 | { | ||
| 352 | struct jffs2_compressor *this; | ||
| 353 | spin_lock(&jffs2_compressor_list_lock); | ||
| 354 | list_for_each_entry(this, &jffs2_compressor_list, list) { | ||
| 355 | if (!strcmp(this->name, name)) { | ||
| 356 | this->disabled = disabled; | ||
| 357 | spin_unlock(&jffs2_compressor_list_lock); | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | spin_unlock(&jffs2_compressor_list_lock); | ||
| 362 | printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name); | ||
| 363 | return 1; | ||
| 364 | } | ||
| 365 | |||
| 366 | int jffs2_enable_compressor_name(const char *name) | ||
| 367 | { | ||
| 368 | return jffs2_compressor_Xable(name, 0); | ||
| 369 | } | ||
| 370 | |||
| 371 | int jffs2_disable_compressor_name(const char *name) | ||
| 372 | { | ||
| 373 | return jffs2_compressor_Xable(name, 1); | ||
| 374 | } | ||
| 375 | |||
| 376 | int jffs2_set_compressor_priority(const char *name, int priority) | ||
| 377 | { | ||
| 378 | struct jffs2_compressor *this,*comp; | ||
| 379 | spin_lock(&jffs2_compressor_list_lock); | ||
| 380 | list_for_each_entry(this, &jffs2_compressor_list, list) { | ||
| 381 | if (!strcmp(this->name, name)) { | ||
| 382 | this->priority = priority; | ||
| 383 | comp = this; | ||
| 384 | goto reinsert; | ||
| 385 | } | ||
| 386 | } | ||
| 387 | spin_unlock(&jffs2_compressor_list_lock); | ||
| 388 | printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name); | ||
| 389 | return 1; | ||
| 390 | reinsert: | ||
| 391 | /* list is sorted in the order of priority, so if | ||
| 392 | we change it we have to reinsert it into the | ||
| 393 | good place */ | ||
| 394 | list_del(&comp->list); | ||
| 395 | list_for_each_entry(this, &jffs2_compressor_list, list) { | ||
| 396 | if (this->priority < comp->priority) { | ||
| 397 | list_add(&comp->list, this->list.prev); | ||
| 398 | spin_unlock(&jffs2_compressor_list_lock); | ||
| 399 | return 0; | ||
| 400 | } | ||
| 401 | } | ||
| 402 | list_add_tail(&comp->list, &jffs2_compressor_list); | ||
| 403 | spin_unlock(&jffs2_compressor_list_lock); | ||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 407 | #endif | ||
| 408 | |||
| 409 | void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) | 269 | void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) |
| 410 | { | 270 | { |
| 411 | if (orig != comprbuf) | 271 | if (orig != comprbuf) |
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 509b8b1c0811..68cc7010dbdf 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h | |||
| @@ -1,13 +1,10 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
| 5 | * University of Szeged, Hungary | 5 | * University of Szeged, Hungary |
| 6 | * | 6 | * |
| 7 | * For licensing information, see the file 'LICENCE' in the | 7 | * For licensing information, see the file 'LICENCE' in this directory. |
| 8 | * jffs2 directory. | ||
| 9 | * | ||
| 10 | * $Id: compr.h,v 1.9 2005/11/07 11:14:38 gleixner Exp $ | ||
| 11 | * | 8 | * |
| 12 | */ | 9 | */ |
| 13 | 10 | ||
| @@ -76,16 +73,6 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | |||
| 76 | 73 | ||
| 77 | void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); | 74 | void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); |
| 78 | 75 | ||
| 79 | #ifdef CONFIG_JFFS2_PROC | ||
| 80 | int jffs2_enable_compressor_name(const char *name); | ||
| 81 | int jffs2_disable_compressor_name(const char *name); | ||
| 82 | int jffs2_set_compression_mode_name(const char *mode_name); | ||
| 83 | char *jffs2_get_compression_mode_name(void); | ||
| 84 | int jffs2_set_compressor_priority(const char *mode_name, int priority); | ||
| 85 | char *jffs2_list_compressors(void); | ||
| 86 | char *jffs2_stats(void); | ||
| 87 | #endif | ||
| 88 | |||
| 89 | /* Compressor modules */ | 76 | /* Compressor modules */ |
| 90 | /* These functions will be called by jffs2_compressors_init/exit */ | 77 | /* These functions will be called by jffs2_compressors_init/exit */ |
| 91 | 78 | ||
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 2eb1b7428d16..0d0bfd2e4e0d 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c | |||
| @@ -1,13 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by Arjan van de Ven <arjanv@redhat.com> | 6 | * Created by Arjan van de Ven <arjanv@redhat.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: compr_rtime.c,v 1.14 2004/06/23 16:34:40 havasi Exp $ | ||
| 11 | * | 10 | * |
| 12 | * | 11 | * |
| 13 | * Very simple lz77-ish encoder. | 12 | * Very simple lz77-ish encoder. |
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index e792e675d624..ea0431e047d5 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c | |||
| @@ -1,23 +1,94 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001, 2002 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by Arjan van de Ven <arjanv@redhat.com> | 6 | * Created by Arjan van de Ven <arjanv@redhat.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: compr_rubin.c,v 1.20 2004/06/23 16:34:40 havasi Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/string.h> | 12 | #include <linux/string.h> |
| 15 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 16 | #include <linux/jffs2.h> | 14 | #include <linux/jffs2.h> |
| 17 | #include "compr_rubin.h" | 15 | #include <linux/errno.h> |
| 18 | #include "histo_mips.h" | ||
| 19 | #include "compr.h" | 16 | #include "compr.h" |
| 20 | 17 | ||
| 18 | |||
| 19 | #define RUBIN_REG_SIZE 16 | ||
| 20 | #define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1)) | ||
| 21 | #define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1) | ||
| 22 | |||
| 23 | |||
| 24 | #define BIT_DIVIDER_MIPS 1043 | ||
| 25 | static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */ | ||
| 26 | |||
| 27 | #include <linux/errno.h> | ||
| 28 | |||
| 29 | struct pushpull { | ||
| 30 | unsigned char *buf; | ||
| 31 | unsigned int buflen; | ||
| 32 | unsigned int ofs; | ||
| 33 | unsigned int reserve; | ||
| 34 | }; | ||
| 35 | |||
| 36 | struct rubin_state { | ||
| 37 | unsigned long p; | ||
| 38 | unsigned long q; | ||
| 39 | unsigned long rec_q; | ||
| 40 | long bit_number; | ||
| 41 | struct pushpull pp; | ||
| 42 | int bit_divider; | ||
| 43 | int bits[8]; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve) | ||
| 47 | { | ||
| 48 | pp->buf = buf; | ||
| 49 | pp->buflen = buflen; | ||
| 50 | pp->ofs = ofs; | ||
| 51 | pp->reserve = reserve; | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline int pushbit(struct pushpull *pp, int bit, int use_reserved) | ||
| 55 | { | ||
| 56 | if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) { | ||
| 57 | return -ENOSPC; | ||
| 58 | } | ||
| 59 | |||
| 60 | if (bit) { | ||
| 61 | pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7))); | ||
| 62 | } | ||
| 63 | else { | ||
| 64 | pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7))); | ||
| 65 | } | ||
| 66 | pp->ofs++; | ||
| 67 | |||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static inline int pushedbits(struct pushpull *pp) | ||
| 72 | { | ||
| 73 | return pp->ofs; | ||
| 74 | } | ||
| 75 | |||
| 76 | static inline int pullbit(struct pushpull *pp) | ||
| 77 | { | ||
| 78 | int bit; | ||
| 79 | |||
| 80 | bit = (pp->buf[pp->ofs >> 3] >> (7-(pp->ofs & 7))) & 1; | ||
| 81 | |||
| 82 | pp->ofs++; | ||
| 83 | return bit; | ||
| 84 | } | ||
| 85 | |||
| 86 | static inline int pulledbits(struct pushpull *pp) | ||
| 87 | { | ||
| 88 | return pp->ofs; | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 21 | static void init_rubin(struct rubin_state *rs, int div, int *bits) | 92 | static void init_rubin(struct rubin_state *rs, int div, int *bits) |
| 22 | { | 93 | { |
| 23 | int c; | 94 | int c; |
diff --git a/fs/jffs2/compr_rubin.h b/fs/jffs2/compr_rubin.h deleted file mode 100644 index bf1a93451621..000000000000 --- a/fs/jffs2/compr_rubin.h +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | /* Rubin encoder/decoder header */ | ||
| 2 | /* work started at : aug 3, 1994 */ | ||
| 3 | /* last modification : aug 15, 1994 */ | ||
| 4 | /* $Id: compr_rubin.h,v 1.7 2005/11/07 11:14:38 gleixner Exp $ */ | ||
| 5 | |||
| 6 | #include "pushpull.h" | ||
| 7 | |||
| 8 | #define RUBIN_REG_SIZE 16 | ||
| 9 | #define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1)) | ||
| 10 | #define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1) | ||
| 11 | |||
| 12 | |||
| 13 | struct rubin_state { | ||
| 14 | unsigned long p; | ||
| 15 | unsigned long q; | ||
| 16 | unsigned long rec_q; | ||
| 17 | long bit_number; | ||
| 18 | struct pushpull pp; | ||
| 19 | int bit_divider; | ||
| 20 | int bits[8]; | ||
| 21 | }; | ||
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 0c1fc6e20b43..2b87fccc1557 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: compr_zlib.c,v 1.32 2005/11/07 11:14:38 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #if !defined(__KERNEL__) && !defined(__ECOS) | 12 | #if !defined(__KERNEL__) && !defined(__ECOS) |
diff --git a/fs/jffs2/comprtest.c b/fs/jffs2/comprtest.c deleted file mode 100644 index f0fb8be7740c..000000000000 --- a/fs/jffs2/comprtest.c +++ /dev/null | |||
| @@ -1,307 +0,0 @@ | |||
| 1 | /* $Id: comprtest.c,v 1.6 2005/11/07 11:14:38 gleixner Exp $ */ | ||
| 2 | |||
| 3 | #include <linux/kernel.h> | ||
| 4 | #include <linux/string.h> | ||
| 5 | #include <linux/module.h> | ||
| 6 | #include <asm/types.h> | ||
| 7 | #if 0 | ||
| 8 | #define TESTDATA_LEN 512 | ||
| 9 | static unsigned char testdata[TESTDATA_LEN] = { | ||
| 10 | 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 11 | 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x83, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, | ||
| 12 | 0xb0, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x06, 0x00, 0x28, 0x00, | ||
| 13 | 0x1e, 0x00, 0x1b, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x80, 0x04, 0x08, | ||
| 14 | 0x34, 0x80, 0x04, 0x08, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 15 | 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x80, 0x04, 0x08, | ||
| 16 | 0xf4, 0x80, 0x04, 0x08, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 17 | 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08, | ||
| 18 | 0x00, 0x80, 0x04, 0x08, 0x0d, 0x05, 0x00, 0x00, 0x0d, 0x05, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | ||
| 19 | 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x10, 0x95, 0x04, 0x08, | ||
| 20 | 0x10, 0x95, 0x04, 0x08, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 21 | 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x58, 0x95, 0x04, 0x08, | ||
| 22 | 0x58, 0x95, 0x04, 0x08, 0xa0, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, | ||
| 23 | 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08, 0x81, 0x04, 0x08, | ||
| 24 | 0x08, 0x81, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | ||
| 25 | 0x04, 0x00, 0x00, 0x00, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6c, 0x69, 0x6e, 0x75, | ||
| 26 | 0x78, 0x2e, 0x73, 0x6f, 0x2e, 0x32, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, | ||
| 27 | 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, | ||
| 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, | ||
| 29 | 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 30 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 31 | 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, | ||
| 33 | 0x0c, 0x83, 0x04, 0x08, 0x81, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, | ||
| 34 | 0x1c, 0x83, 0x04, 0x08, 0xac, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, | ||
| 35 | 0x2c, 0x83, 0x04, 0x08, 0xdd, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, | ||
| 36 | 0x3c, 0x83, 0x04, 0x08, 0x2e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, | ||
| 37 | 0x4c, 0x83, 0x04, 0x08, 0x7d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, | ||
| 38 | 0x00, 0x85, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x00, 0x00, | ||
| 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x67, | ||
| 40 | 0x6d, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x5f, 0x00, 0x6c, 0x69, 0x62, 0x63, | ||
| 41 | 0x2e, 0x73, 0x6f, 0x2e, 0x36, 0x00, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x00, 0x5f, 0x5f, 0x63}; | ||
| 42 | #else | ||
| 43 | #define TESTDATA_LEN 3481 | ||
| 44 | static unsigned char testdata[TESTDATA_LEN] = { | ||
| 45 | 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x22, 0x64, 0x62, 0x65, 0x6e, 0x63, 0x68, | ||
| 46 | 0x2e, 0x68, 0x22, 0x0a, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4d, 0x41, 0x58, | ||
| 47 | 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x20, 0x31, 0x30, 0x30, 0x30, 0x0a, 0x0a, 0x73, 0x74, 0x61, | ||
| 48 | 0x74, 0x69, 0x63, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x62, 0x75, 0x66, 0x5b, 0x37, 0x30, 0x30, | ||
| 49 | 0x30, 0x30, 0x5d, 0x3b, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x69, 0x6e, 0x74, 0x20, | ||
| 50 | 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x73, 0x74, 0x61, | ||
| 51 | 0x74, 0x69, 0x63, 0x20, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x7b, 0x0a, 0x09, 0x69, 0x6e, | ||
| 52 | 0x74, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, | ||
| 53 | 0x65, 0x3b, 0x0a, 0x7d, 0x20, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x4d, 0x41, 0x58, 0x5f, | ||
| 54 | 0x46, 0x49, 0x4c, 0x45, 0x53, 0x5d, 0x3b, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, | ||
| 55 | 0x5f, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, | ||
| 56 | 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, | ||
| 57 | 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x75, | ||
| 58 | 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, | ||
| 59 | 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, | ||
| 60 | 0x25, 0x64, 0x29, 0x20, 0x75, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, | ||
| 61 | 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, | ||
| 62 | 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, | ||
| 63 | 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, | ||
| 64 | 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, | ||
| 65 | 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, | ||
| 66 | 0x69, 0x6c, 0x65, 0x28, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, | ||
| 67 | 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x3b, 0x0a, | ||
| 68 | 0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, | ||
| 69 | 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x4d, 0x49, 0x4e, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x6f, 0x66, | ||
| 70 | 0x28, 0x62, 0x75, 0x66, 0x29, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, | ||
| 71 | 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, | ||
| 72 | 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x3d, 0x20, 0x73, 0x3b, 0x0a, | ||
| 73 | 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6f, 0x70, | ||
| 74 | 0x65, 0x6e, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, | ||
| 75 | 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, | ||
| 76 | 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x64, 0x2c, | ||
| 77 | 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d, | ||
| 78 | 0x20, 0x4f, 0x5f, 0x52, 0x44, 0x57, 0x52, 0x7c, 0x4f, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x3b, | ||
| 79 | 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74, | ||
| 80 | 0x3b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x63, 0x6f, | ||
| 81 | 0x75, 0x6e, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, | ||
| 82 | 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, | ||
| 83 | 0x7a, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x20, 0x7c, | ||
| 84 | 0x3d, 0x20, 0x4f, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x43, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x64, 0x20, | ||
| 85 | 0x3d, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x66, 0x6c, | ||
| 86 | 0x61, 0x67, 0x73, 0x2c, 0x20, 0x30, 0x36, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, | ||
| 87 | 0x28, 0x66, 0x64, 0x20, 0x3d, 0x3d, 0x20, 0x2d, 0x31, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, | ||
| 88 | 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x6f, 0x70, 0x65, 0x6e, | ||
| 89 | 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x68, | ||
| 90 | 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, | ||
| 91 | 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, | ||
| 92 | 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x68, | ||
| 93 | 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, | ||
| 94 | 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, | ||
| 95 | 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x64, 0x2c, | ||
| 96 | 0x20, 0x26, 0x73, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, | ||
| 97 | 0x20, 0x3e, 0x20, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, | ||
| 98 | 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, | ||
| 99 | 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, | ||
| 100 | 0x69, 0x6e, 0x67, 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, | ||
| 101 | 0x6d, 0x20, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, | ||
| 102 | 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, | ||
| 103 | 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, | ||
| 104 | 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x23, 0x65, | ||
| 105 | 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x65, 0x78, 0x70, 0x61, 0x6e, 0x64, 0x5f, 0x66, 0x69, | ||
| 106 | 0x6c, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x2d, 0x20, 0x73, 0x74, | ||
| 107 | 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x20, 0x65, 0x6c, | ||
| 108 | 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3c, 0x20, 0x73, 0x74, | ||
| 109 | 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, | ||
| 110 | 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x69, 0x6e, 0x67, | ||
| 111 | 0x20, 0x25, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x25, 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x25, | ||
| 112 | 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||
| 113 | 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, | ||
| 114 | 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, | ||
| 115 | 0x09, 0x66, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x28, 0x66, 0x64, 0x2c, 0x20, 0x73, | ||
| 116 | 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, | ||
| 117 | 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, | ||
| 118 | 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, | ||
| 119 | 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, | ||
| 120 | 0x30, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, | ||
| 121 | 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, | ||
| 122 | 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x66, 0x69, | ||
| 123 | 0x6c, 0x65, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x66, 0x6f, | ||
| 124 | 0x72, 0x20, 0x25, 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, | ||
| 125 | 0x0a, 0x09, 0x09, 0x65, 0x78, 0x69, 0x74, 0x28, 0x31, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, | ||
| 126 | 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, | ||
| 127 | 0x20, 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, 0x62, | ||
| 128 | 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x64, 0x3b, 0x0a, 0x09, | ||
| 129 | 0x69, 0x66, 0x20, 0x28, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2b, 0x2b, 0x20, 0x25, 0x20, 0x31, 0x30, | ||
| 130 | 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, | ||
| 131 | 0x74, 0x66, 0x28, 0x22, 0x2e, 0x22, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, | ||
| 132 | 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x69, 0x6e, 0x74, | ||
| 133 | 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x7a, | ||
| 134 | 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x0a, 0x7b, | ||
| 135 | 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x62, | ||
| 136 | 0x75, 0x66, 0x5b, 0x30, 0x5d, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x6d, 0x65, 0x6d, 0x73, | ||
| 137 | 0x65, 0x74, 0x28, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x6f, | ||
| 138 | 0x66, 0x28, 0x62, 0x75, 0x66, 0x29, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, | ||
| 139 | 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, | ||
| 140 | 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, | ||
| 141 | 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, | ||
| 142 | 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, | ||
| 143 | 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, | ||
| 144 | 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x31, 0x0a, | ||
| 145 | 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, | ||
| 146 | 0x6f, 0x5f, 0x77, 0x72, 0x69, 0x74, 0x65, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, | ||
| 147 | 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, | ||
| 148 | 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, | ||
| 149 | 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, | ||
| 150 | 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, | ||
| 151 | 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, | ||
| 152 | 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, | ||
| 153 | 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, | ||
| 154 | 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x2c, | ||
| 155 | 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, 0x69, 0x66, 0x20, | ||
| 156 | 0x28, 0x77, 0x72, 0x69, 0x74, 0x65, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, | ||
| 157 | 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, | ||
| 158 | 0x21, 0x3d, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, | ||
| 159 | 0x6e, 0x74, 0x66, 0x28, 0x22, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, | ||
| 160 | 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x5c, 0x6e, | ||
| 161 | 0x22, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, | ||
| 162 | 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, 0x64, 0x28, 0x69, | ||
| 163 | 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x73, | ||
| 164 | 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, | ||
| 165 | 0x0a, 0x7b, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, | ||
| 166 | 0x28, 0x69, 0x3d, 0x30, 0x3b, 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, | ||
| 167 | 0x3b, 0x69, 0x2b, 0x2b, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, | ||
| 168 | 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, | ||
| 169 | 0x3d, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, | ||
| 170 | 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, | ||
| 171 | 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, | ||
| 172 | 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x65, 0x61, | ||
| 173 | 0x64, 0x3a, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, | ||
| 174 | 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, | ||
| 175 | 0x64, 0x20, 0x6f, 0x66, 0x73, 0x3d, 0x25, 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, | ||
| 176 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, | ||
| 177 | 0x74, 0x2c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, | ||
| 178 | 0x20, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, | ||
| 179 | 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x6c, 0x73, 0x65, 0x65, 0x6b, 0x28, 0x66, 0x74, | ||
| 180 | 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x2c, 0x20, 0x6f, 0x66, 0x66, 0x73, | ||
| 181 | 0x65, 0x74, 0x2c, 0x20, 0x53, 0x45, 0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x29, 0x3b, 0x0a, 0x09, | ||
| 182 | 0x72, 0x65, 0x61, 0x64, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, | ||
| 183 | 0x64, 0x2c, 0x20, 0x62, 0x75, 0x66, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x7d, | ||
| 184 | 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, | ||
| 185 | 0x69, 0x6e, 0x74, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x69, | ||
| 186 | 0x6e, 0x74, 0x20, 0x69, 0x3b, 0x0a, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x28, 0x69, 0x3d, 0x30, 0x3b, | ||
| 187 | 0x69, 0x3c, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x3b, 0x69, 0x2b, 0x2b, 0x29, | ||
| 188 | 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x66, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5b, | ||
| 189 | 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x68, 0x61, 0x6e, | ||
| 190 | 0x64, 0x6c, 0x65, 0x29, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, | ||
| 191 | 0x69, 0x66, 0x20, 0x28, 0x69, 0x20, 0x3d, 0x3d, 0x20, 0x4d, 0x41, 0x58, 0x5f, 0x46, 0x49, 0x4c, | ||
| 192 | 0x45, 0x53, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, | ||
| 193 | 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x3a, 0x20, 0x68, | ||
| 194 | 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x25, 0x64, 0x20, 0x77, 0x61, 0x73, 0x20, 0x6e, 0x6f, 0x74, | ||
| 195 | 0x20, 0x6f, 0x70, 0x65, 0x6e, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, | ||
| 196 | 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, | ||
| 197 | 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, | ||
| 198 | 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, 0x66, 0x74, 0x61, | ||
| 199 | 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x66, 0x64, 0x29, 0x3b, 0x0a, 0x09, 0x66, 0x74, 0x61, | ||
| 200 | 0x62, 0x6c, 0x65, 0x5b, 0x69, 0x5d, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x3d, 0x20, | ||
| 201 | 0x30, 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x6d, 0x6b, | ||
| 202 | 0x64, 0x69, 0x72, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, | ||
| 203 | 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, | ||
| 204 | 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6d, 0x6b, 0x64, 0x69, 0x72, | ||
| 205 | 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x30, 0x37, 0x30, 0x30, 0x29, 0x20, 0x21, 0x3d, | ||
| 206 | 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x23, 0x69, 0x66, 0x20, 0x44, 0x45, 0x42, 0x55, 0x47, 0x0a, | ||
| 207 | 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x6d, 0x6b, 0x64, 0x69, 0x72, 0x20, | ||
| 208 | 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, | ||
| 209 | 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, | ||
| 210 | 0x6d, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, | ||
| 211 | 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, 0x09, 0x7d, 0x0a, | ||
| 212 | 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x72, 0x6d, 0x64, 0x69, 0x72, | ||
| 213 | 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x7b, 0x0a, | ||
| 214 | 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, | ||
| 215 | 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x28, 0x66, 0x6e, | ||
| 216 | 0x61, 0x6d, 0x65, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, | ||
| 217 | 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x6d, 0x64, 0x69, 0x72, 0x20, 0x25, 0x73, 0x20, | ||
| 218 | 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, | ||
| 219 | 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, | ||
| 220 | 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, | ||
| 221 | 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, | ||
| 222 | 0x5f, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6f, 0x6c, | ||
| 223 | 0x64, 0x2c, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x6e, 0x65, 0x77, 0x29, 0x0a, 0x7b, 0x0a, | ||
| 224 | 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6f, 0x6c, 0x64, 0x29, 0x3b, 0x0a, | ||
| 225 | 0x09, 0x73, 0x74, 0x72, 0x75, 0x70, 0x70, 0x65, 0x72, 0x28, 0x6e, 0x65, 0x77, 0x29, 0x3b, 0x0a, | ||
| 226 | 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x28, 0x6f, 0x6c, 0x64, | ||
| 227 | 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, | ||
| 228 | 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x72, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x20, | ||
| 229 | 0x25, 0x73, 0x20, 0x25, 0x73, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x28, 0x25, 0x73, | ||
| 230 | 0x29, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||
| 231 | 0x6f, 0x6c, 0x64, 0x2c, 0x20, 0x6e, 0x65, 0x77, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, | ||
| 232 | 0x6f, 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, | ||
| 233 | 0x0a, 0x0a, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x28, | ||
| 234 | 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, | ||
| 235 | 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, | ||
| 236 | 0x20, 0x73, 0x74, 0x61, 0x74, 0x20, 0x73, 0x74, 0x3b, 0x0a, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x75, | ||
| 237 | 0x70, 0x70, 0x65, 0x72, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x3b, 0x0a, 0x0a, 0x09, 0x69, | ||
| 238 | 0x66, 0x20, 0x28, 0x73, 0x74, 0x61, 0x74, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x26, | ||
| 239 | 0x73, 0x74, 0x29, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, | ||
| 240 | 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, | ||
| 241 | 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x3d, 0x25, 0x64, 0x20, 0x25, | ||
| 242 | 0x73, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||
| 243 | 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, | ||
| 244 | 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x74, 0x72, 0x65, 0x72, 0x72, 0x6f, | ||
| 245 | 0x72, 0x28, 0x65, 0x72, 0x72, 0x6e, 0x6f, 0x29, 0x29, 0x3b, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x74, | ||
| 246 | 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, 0x53, 0x5f, 0x49, | ||
| 247 | 0x53, 0x44, 0x49, 0x52, 0x28, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x29, | ||
| 248 | 0x29, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x3b, 0x0a, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x28, | ||
| 249 | 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x21, 0x3d, 0x20, 0x73, 0x69, | ||
| 250 | 0x7a, 0x65, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x28, 0x22, | ||
| 251 | 0x28, 0x25, 0x64, 0x29, 0x20, 0x64, 0x6f, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x3a, 0x20, 0x25, 0x73, | ||
| 252 | 0x20, 0x77, 0x72, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x25, 0x64, 0x20, 0x25, | ||
| 253 | 0x64, 0x5c, 0x6e, 0x22, 0x2c, 0x20, 0x0a, 0x09, 0x09, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||
| 254 | 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2c, 0x20, 0x66, 0x6e, 0x61, 0x6d, | ||
| 255 | 0x65, 0x2c, 0x20, 0x28, 0x69, 0x6e, 0x74, 0x29, 0x73, 0x74, 0x2e, 0x73, 0x74, 0x5f, 0x73, 0x69, | ||
| 256 | 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x7d, 0x0a, 0x7d, 0x0a, | ||
| 257 | 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x64, 0x6f, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, | ||
| 258 | 0x63, 0x68, 0x61, 0x72, 0x20, 0x2a, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x74, | ||
| 259 | 0x20, 0x73, 0x69, 0x7a, 0x65, 0x29, 0x0a, 0x7b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x6f, 0x70, 0x65, | ||
| 260 | 0x6e, 0x28, 0x66, 0x6e, 0x61, 0x6d, 0x65, 0x2c, 0x20, 0x35, 0x30, 0x30, 0x30, 0x2c, 0x20, 0x73, | ||
| 261 | 0x69, 0x7a, 0x65, 0x29, 0x3b, 0x0a, 0x09, 0x64, 0x6f, 0x5f, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x28, | ||
| 262 | 0x35, 0x30, 0x30, 0x30, 0x29, 0x3b, 0x0a, 0x7d, 0x0a | ||
| 263 | }; | ||
| 264 | #endif | ||
| 265 | static unsigned char comprbuf[TESTDATA_LEN]; | ||
| 266 | static unsigned char decomprbuf[TESTDATA_LEN]; | ||
| 267 | |||
| 268 | int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, | ||
| 269 | unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); | ||
| 270 | unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, | ||
| 271 | uint32_t *datalen, uint32_t *cdatalen); | ||
| 272 | |||
| 273 | int init_module(void ) { | ||
| 274 | unsigned char comprtype; | ||
| 275 | uint32_t c, d; | ||
| 276 | int ret; | ||
| 277 | |||
| 278 | printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
| 279 | testdata[0],testdata[1],testdata[2],testdata[3], | ||
| 280 | testdata[4],testdata[5],testdata[6],testdata[7], | ||
| 281 | testdata[8],testdata[9],testdata[10],testdata[11], | ||
| 282 | testdata[12],testdata[13],testdata[14],testdata[15]); | ||
| 283 | d = TESTDATA_LEN; | ||
| 284 | c = TESTDATA_LEN; | ||
| 285 | comprtype = jffs2_compress(testdata, comprbuf, &d, &c); | ||
| 286 | |||
| 287 | printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n", | ||
| 288 | comprtype, c, d); | ||
| 289 | printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
| 290 | comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3], | ||
| 291 | comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7], | ||
| 292 | comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11], | ||
| 293 | comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]); | ||
| 294 | |||
| 295 | ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d); | ||
| 296 | printk("jffs2_decompress returned %d\n", ret); | ||
| 297 | printk("Decompressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
| 298 | decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3], | ||
| 299 | decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7], | ||
| 300 | decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11], | ||
| 301 | decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]); | ||
| 302 | if (memcmp(decomprbuf, testdata, d)) | ||
| 303 | printk("Compression and decompression corrupted data\n"); | ||
| 304 | else | ||
| 305 | printk("Compression good for %d bytes\n", d); | ||
| 306 | return 1; | ||
| 307 | } | ||
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index 4189e4a36050..3a32c64ed497 100644 --- a/fs/jffs2/debug.c +++ b/fs/jffs2/debug.c | |||
| @@ -1,15 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 11 | |||
| 13 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 14 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 15 | #include <linux/pagemap.h> | 14 | #include <linux/pagemap.h> |
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index f89c85d5a3f8..2a49f2c51a9f 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h | |||
| @@ -1,15 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: debug.h,v 1.21 2005/11/07 11:14:39 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 11 | |||
| 13 | #ifndef _JFFS2_DEBUG_H_ | 12 | #ifndef _JFFS2_DEBUG_H_ |
| 14 | #define _JFFS2_DEBUG_H_ | 13 | #define _JFFS2_DEBUG_H_ |
| 15 | 14 | ||
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 9fa2e27f0641..c1dfca310dd6 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: dir.c,v 1.90 2005/11/07 11:14:39 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index ad0121088dde..66e7c2f1e644 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: erase.c,v 1.85 2005/09/20 14:53:15 dedekind Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| @@ -333,7 +331,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl | |||
| 333 | 331 | ||
| 334 | *bad_offset = ofs; | 332 | *bad_offset = ofs; |
| 335 | 333 | ||
| 336 | ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); | 334 | ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); |
| 337 | if (ret) { | 335 | if (ret) { |
| 338 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); | 336 | printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); |
| 339 | goto fail; | 337 | goto fail; |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index e82eeaf7590d..99871279a1ed 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: file.c,v 1.104 2005/10/18 23:29:35 tpoynor Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 8a649f602767..1d3b7a9fc828 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: fs.c,v 1.66 2005/09/27 13:17:29 dedekind Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/capability.h> | 12 | #include <linux/capability.h> |
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 3a3cf225981f..2d99e06ab223 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: gc.c,v 1.155 2005/11/07 11:14:39 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| @@ -144,7 +142,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
| 144 | c->unchecked_size); | 142 | c->unchecked_size); |
| 145 | jffs2_dbg_dump_block_lists_nolock(c); | 143 | jffs2_dbg_dump_block_lists_nolock(c); |
| 146 | spin_unlock(&c->erase_completion_lock); | 144 | spin_unlock(&c->erase_completion_lock); |
| 147 | BUG(); | 145 | up(&c->alloc_sem); |
| 146 | return -ENOSPC; | ||
| 148 | } | 147 | } |
| 149 | 148 | ||
| 150 | spin_unlock(&c->erase_completion_lock); | 149 | spin_unlock(&c->erase_completion_lock); |
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c index 69099835de1c..f4d525b0ea53 100644 --- a/fs/jffs2/ioctl.c +++ b/fs/jffs2/ioctl.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: ioctl.c,v 1.10 2005/11/07 11:14:40 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index 3a566077ac95..0b78fdc9773b 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h | |||
| @@ -1,4 +1,13 @@ | |||
| 1 | /* $Id: jffs2_fs_i.h,v 1.19 2005/11/07 11:14:52 gleixner Exp $ */ | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
| 3 | * | ||
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | ||
| 5 | * | ||
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | ||
| 7 | * | ||
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | ||
| 9 | * | ||
| 10 | */ | ||
| 2 | 11 | ||
| 3 | #ifndef _JFFS2_FS_I | 12 | #ifndef _JFFS2_FS_I |
| 4 | #define _JFFS2_FS_I | 13 | #define _JFFS2_FS_I |
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index ea88f69af130..b13298a824ed 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
| @@ -1,4 +1,13 @@ | |||
| 1 | /* $Id: jffs2_fs_sb.h,v 1.54 2005/09/21 13:37:34 dedekind Exp $ */ | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
| 3 | * | ||
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | ||
| 5 | * | ||
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | ||
| 7 | * | ||
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | ||
| 9 | * | ||
| 10 | */ | ||
| 2 | 11 | ||
| 3 | #ifndef _JFFS2_FS_SB | 12 | #ifndef _JFFS2_FS_SB |
| 4 | #define _JFFS2_FS_SB | 13 | #define _JFFS2_FS_SB |
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index 83f9881ec4cc..35c1a5e30ba1 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: malloc.c,v 1.31 2005/11/07 11:14:40 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 5a6b4d64206c..4bf86088b3ae 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: nodelist.c,v 1.115 2005/11/07 11:14:40 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| @@ -54,7 +52,7 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new | |||
| 54 | *prev = new; | 52 | *prev = new; |
| 55 | } | 53 | } |
| 56 | 54 | ||
| 57 | void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) | 55 | uint32_t jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) |
| 58 | { | 56 | { |
| 59 | struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); | 57 | struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); |
| 60 | 58 | ||
| @@ -76,18 +74,24 @@ void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint | |||
| 76 | } | 74 | } |
| 77 | 75 | ||
| 78 | if (size == 0) | 76 | if (size == 0) |
| 79 | return; | 77 | return 0; |
| 80 | 78 | ||
| 81 | /* | ||
| 82 | * If the last fragment starts at the RAM page boundary, it is | ||
| 83 | * REF_PRISTINE irrespective of its size. | ||
| 84 | */ | ||
| 85 | frag = frag_last(list); | 79 | frag = frag_last(list); |
| 80 | |||
| 81 | /* Sanity check for truncation to longer than we started with... */ | ||
| 82 | if (!frag) | ||
| 83 | return 0; | ||
| 84 | if (frag->ofs + frag->size < size) | ||
| 85 | return frag->ofs + frag->size; | ||
| 86 | |||
| 87 | /* If the last fragment starts at the RAM page boundary, it is | ||
| 88 | * REF_PRISTINE irrespective of its size. */ | ||
| 86 | if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) { | 89 | if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) { |
| 87 | dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n", | 90 | dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n", |
| 88 | frag->ofs, frag->ofs + frag->size); | 91 | frag->ofs, frag->ofs + frag->size); |
| 89 | frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE; | 92 | frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE; |
| 90 | } | 93 | } |
| 94 | return size; | ||
| 91 | } | 95 | } |
| 92 | 96 | ||
| 93 | static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, | 97 | static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, |
| @@ -397,466 +401,6 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in | |||
| 397 | return 0; | 401 | return 0; |
| 398 | } | 402 | } |
| 399 | 403 | ||
| 400 | /* | ||
| 401 | * Check the data CRC of the node. | ||
| 402 | * | ||
| 403 | * Returns: 0 if the data CRC is correct; | ||
| 404 | * 1 - if incorrect; | ||
| 405 | * error code if an error occured. | ||
| 406 | */ | ||
| 407 | static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) | ||
| 408 | { | ||
| 409 | struct jffs2_raw_node_ref *ref = tn->fn->raw; | ||
| 410 | int err = 0, pointed = 0; | ||
| 411 | struct jffs2_eraseblock *jeb; | ||
| 412 | unsigned char *buffer; | ||
| 413 | uint32_t crc, ofs, len; | ||
| 414 | size_t retlen; | ||
| 415 | |||
| 416 | BUG_ON(tn->csize == 0); | ||
| 417 | |||
| 418 | if (!jffs2_is_writebuffered(c)) | ||
| 419 | goto adj_acc; | ||
| 420 | |||
| 421 | /* Calculate how many bytes were already checked */ | ||
| 422 | ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode); | ||
| 423 | len = ofs % c->wbuf_pagesize; | ||
| 424 | if (likely(len)) | ||
| 425 | len = c->wbuf_pagesize - len; | ||
| 426 | |||
| 427 | if (len >= tn->csize) { | ||
| 428 | dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n", | ||
| 429 | ref_offset(ref), tn->csize, ofs); | ||
| 430 | goto adj_acc; | ||
| 431 | } | ||
| 432 | |||
| 433 | ofs += len; | ||
| 434 | len = tn->csize - len; | ||
| 435 | |||
| 436 | dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n", | ||
| 437 | ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); | ||
| 438 | |||
| 439 | #ifndef __ECOS | ||
| 440 | /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), | ||
| 441 | * adding and jffs2_flash_read_end() interface. */ | ||
| 442 | if (c->mtd->point) { | ||
| 443 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); | ||
| 444 | if (!err && retlen < tn->csize) { | ||
| 445 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); | ||
| 446 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | ||
| 447 | } else if (err) | ||
| 448 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); | ||
| 449 | else | ||
| 450 | pointed = 1; /* succefully pointed to device */ | ||
| 451 | } | ||
| 452 | #endif | ||
| 453 | |||
| 454 | if (!pointed) { | ||
| 455 | buffer = kmalloc(len, GFP_KERNEL); | ||
| 456 | if (unlikely(!buffer)) | ||
| 457 | return -ENOMEM; | ||
| 458 | |||
| 459 | /* TODO: this is very frequent pattern, make it a separate | ||
| 460 | * routine */ | ||
| 461 | err = jffs2_flash_read(c, ofs, len, &retlen, buffer); | ||
| 462 | if (err) { | ||
| 463 | JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); | ||
| 464 | goto free_out; | ||
| 465 | } | ||
| 466 | |||
| 467 | if (retlen != len) { | ||
| 468 | JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); | ||
| 469 | err = -EIO; | ||
| 470 | goto free_out; | ||
| 471 | } | ||
| 472 | } | ||
| 473 | |||
| 474 | /* Continue calculating CRC */ | ||
| 475 | crc = crc32(tn->partial_crc, buffer, len); | ||
| 476 | if(!pointed) | ||
| 477 | kfree(buffer); | ||
| 478 | #ifndef __ECOS | ||
| 479 | else | ||
| 480 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | ||
| 481 | #endif | ||
| 482 | |||
| 483 | if (crc != tn->data_crc) { | ||
| 484 | JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", | ||
| 485 | ofs, tn->data_crc, crc); | ||
| 486 | return 1; | ||
| 487 | } | ||
| 488 | |||
| 489 | adj_acc: | ||
| 490 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | ||
| 491 | len = ref_totlen(c, jeb, ref); | ||
| 492 | |||
| 493 | /* | ||
| 494 | * Mark the node as having been checked and fix the | ||
| 495 | * accounting accordingly. | ||
| 496 | */ | ||
| 497 | spin_lock(&c->erase_completion_lock); | ||
| 498 | jeb->used_size += len; | ||
| 499 | jeb->unchecked_size -= len; | ||
| 500 | c->used_size += len; | ||
| 501 | c->unchecked_size -= len; | ||
| 502 | spin_unlock(&c->erase_completion_lock); | ||
| 503 | |||
| 504 | return 0; | ||
| 505 | |||
| 506 | free_out: | ||
| 507 | if(!pointed) | ||
| 508 | kfree(buffer); | ||
| 509 | #ifndef __ECOS | ||
| 510 | else | ||
| 511 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | ||
| 512 | #endif | ||
| 513 | return err; | ||
| 514 | } | ||
| 515 | |||
| 516 | /* | ||
| 517 | * Helper function for jffs2_add_older_frag_to_fragtree(). | ||
| 518 | * | ||
| 519 | * Checks the node if we are in the checking stage. | ||
| 520 | */ | ||
| 521 | static int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn) | ||
| 522 | { | ||
| 523 | int ret; | ||
| 524 | |||
| 525 | BUG_ON(ref_obsolete(tn->fn->raw)); | ||
| 526 | |||
| 527 | /* We only check the data CRC of unchecked nodes */ | ||
| 528 | if (ref_flags(tn->fn->raw) != REF_UNCHECKED) | ||
| 529 | return 0; | ||
| 530 | |||
| 531 | dbg_fragtree2("check node %#04x-%#04x, phys offs %#08x.\n", | ||
| 532 | tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw)); | ||
| 533 | |||
| 534 | ret = check_node_data(c, tn); | ||
| 535 | if (unlikely(ret < 0)) { | ||
| 536 | JFFS2_ERROR("check_node_data() returned error: %d.\n", | ||
| 537 | ret); | ||
| 538 | } else if (unlikely(ret > 0)) { | ||
| 539 | dbg_fragtree2("CRC error, mark it obsolete.\n"); | ||
| 540 | jffs2_mark_node_obsolete(c, tn->fn->raw); | ||
| 541 | } | ||
| 542 | |||
| 543 | return ret; | ||
| 544 | } | ||
| 545 | |||
| 546 | /* | ||
| 547 | * Helper function for jffs2_add_older_frag_to_fragtree(). | ||
| 548 | * | ||
| 549 | * Called when the new fragment that is being inserted | ||
| 550 | * splits a hole fragment. | ||
| 551 | */ | ||
| 552 | static int split_hole(struct jffs2_sb_info *c, struct rb_root *root, | ||
| 553 | struct jffs2_node_frag *newfrag, struct jffs2_node_frag *hole) | ||
| 554 | { | ||
| 555 | dbg_fragtree2("fragment %#04x-%#04x splits the hole %#04x-%#04x\n", | ||
| 556 | newfrag->ofs, newfrag->ofs + newfrag->size, hole->ofs, hole->ofs + hole->size); | ||
| 557 | |||
| 558 | if (hole->ofs == newfrag->ofs) { | ||
| 559 | /* | ||
| 560 | * Well, the new fragment actually starts at the same offset as | ||
| 561 | * the hole. | ||
| 562 | */ | ||
| 563 | if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) { | ||
| 564 | /* | ||
| 565 | * We replace the overlapped left part of the hole by | ||
| 566 | * the new node. | ||
| 567 | */ | ||
| 568 | |||
| 569 | dbg_fragtree2("insert fragment %#04x-%#04x and cut the left part of the hole\n", | ||
| 570 | newfrag->ofs, newfrag->ofs + newfrag->size); | ||
| 571 | rb_replace_node(&hole->rb, &newfrag->rb, root); | ||
| 572 | |||
| 573 | hole->ofs += newfrag->size; | ||
| 574 | hole->size -= newfrag->size; | ||
| 575 | |||
| 576 | /* | ||
| 577 | * We know that 'hole' should be the right hand | ||
| 578 | * fragment. | ||
| 579 | */ | ||
| 580 | jffs2_fragtree_insert(hole, newfrag); | ||
| 581 | rb_insert_color(&hole->rb, root); | ||
| 582 | } else { | ||
| 583 | /* | ||
| 584 | * Ah, the new fragment is of the same size as the hole. | ||
| 585 | * Relace the hole by it. | ||
| 586 | */ | ||
| 587 | dbg_fragtree2("insert fragment %#04x-%#04x and overwrite hole\n", | ||
| 588 | newfrag->ofs, newfrag->ofs + newfrag->size); | ||
| 589 | rb_replace_node(&hole->rb, &newfrag->rb, root); | ||
| 590 | jffs2_free_node_frag(hole); | ||
| 591 | } | ||
| 592 | } else { | ||
| 593 | /* The new fragment lefts some hole space at the left */ | ||
| 594 | |||
| 595 | struct jffs2_node_frag * newfrag2 = NULL; | ||
| 596 | |||
| 597 | if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) { | ||
| 598 | /* The new frag also lefts some space at the right */ | ||
| 599 | newfrag2 = new_fragment(NULL, newfrag->ofs + | ||
| 600 | newfrag->size, hole->ofs + hole->size | ||
| 601 | - newfrag->ofs - newfrag->size); | ||
| 602 | if (unlikely(!newfrag2)) { | ||
| 603 | jffs2_free_node_frag(newfrag); | ||
| 604 | return -ENOMEM; | ||
| 605 | } | ||
| 606 | } | ||
| 607 | |||
| 608 | hole->size = newfrag->ofs - hole->ofs; | ||
| 609 | dbg_fragtree2("left the hole %#04x-%#04x at the left and inserd fragment %#04x-%#04x\n", | ||
| 610 | hole->ofs, hole->ofs + hole->size, newfrag->ofs, newfrag->ofs + newfrag->size); | ||
| 611 | |||
| 612 | jffs2_fragtree_insert(newfrag, hole); | ||
| 613 | rb_insert_color(&newfrag->rb, root); | ||
| 614 | |||
| 615 | if (newfrag2) { | ||
| 616 | dbg_fragtree2("left the hole %#04x-%#04x at the right\n", | ||
| 617 | newfrag2->ofs, newfrag2->ofs + newfrag2->size); | ||
| 618 | jffs2_fragtree_insert(newfrag2, newfrag); | ||
| 619 | rb_insert_color(&newfrag2->rb, root); | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 623 | return 0; | ||
| 624 | } | ||
| 625 | |||
| 626 | /* | ||
| 627 | * This function is used when we build inode. It expects the nodes are passed | ||
| 628 | * in the decreasing version order. The whole point of this is to improve the | ||
| 629 | * inodes checking on NAND: we check the nodes' data CRC only when they are not | ||
| 630 | * obsoleted. Previously, add_frag_to_fragtree() function was used and | ||
| 631 | * nodes were passed to it in the increasing version ordes and CRCs of all | ||
| 632 | * nodes were checked. | ||
| 633 | * | ||
| 634 | * Note: tn->fn->size shouldn't be zero. | ||
| 635 | * | ||
| 636 | * Returns 0 if the node was inserted | ||
| 637 | * 1 if it wasn't inserted (since it is obsolete) | ||
| 638 | * < 0 an if error occured | ||
| 639 | */ | ||
| 640 | int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | ||
| 641 | struct jffs2_tmp_dnode_info *tn) | ||
| 642 | { | ||
| 643 | struct jffs2_node_frag *this, *newfrag; | ||
| 644 | uint32_t lastend; | ||
| 645 | struct jffs2_full_dnode *fn = tn->fn; | ||
| 646 | struct rb_root *root = &f->fragtree; | ||
| 647 | uint32_t fn_size = fn->size, fn_ofs = fn->ofs; | ||
| 648 | int err, checked = 0; | ||
| 649 | int ref_flag; | ||
| 650 | |||
| 651 | dbg_fragtree("insert fragment %#04x-%#04x, ver %u\n", fn_ofs, fn_ofs + fn_size, tn->version); | ||
| 652 | |||
| 653 | /* Skip all the nodes which are completed before this one starts */ | ||
| 654 | this = jffs2_lookup_node_frag(root, fn_ofs); | ||
| 655 | if (this) | ||
| 656 | dbg_fragtree2("'this' found %#04x-%#04x (%s)\n", this->ofs, this->ofs + this->size, this->node ? "data" : "hole"); | ||
| 657 | |||
| 658 | if (this) | ||
| 659 | lastend = this->ofs + this->size; | ||
| 660 | else | ||
| 661 | lastend = 0; | ||
| 662 | |||
| 663 | /* Detect the preliminary type of node */ | ||
| 664 | if (fn->size >= PAGE_CACHE_SIZE) | ||
| 665 | ref_flag = REF_PRISTINE; | ||
| 666 | else | ||
| 667 | ref_flag = REF_NORMAL; | ||
| 668 | |||
| 669 | /* See if we ran off the end of the root */ | ||
| 670 | if (lastend <= fn_ofs) { | ||
| 671 | /* We did */ | ||
| 672 | |||
| 673 | /* | ||
| 674 | * We are going to insert the new node into the | ||
| 675 | * fragment tree, so check it. | ||
| 676 | */ | ||
| 677 | err = check_node(c, f, tn); | ||
| 678 | if (err != 0) | ||
| 679 | return err; | ||
| 680 | |||
| 681 | fn->frags = 1; | ||
| 682 | |||
| 683 | newfrag = new_fragment(fn, fn_ofs, fn_size); | ||
| 684 | if (unlikely(!newfrag)) | ||
| 685 | return -ENOMEM; | ||
| 686 | |||
| 687 | err = no_overlapping_node(c, root, newfrag, this, lastend); | ||
| 688 | if (unlikely(err != 0)) { | ||
| 689 | jffs2_free_node_frag(newfrag); | ||
| 690 | return err; | ||
| 691 | } | ||
| 692 | |||
| 693 | goto out_ok; | ||
| 694 | } | ||
| 695 | |||
| 696 | fn->frags = 0; | ||
| 697 | |||
| 698 | while (1) { | ||
| 699 | /* | ||
| 700 | * Here we have: | ||
| 701 | * fn_ofs < this->ofs + this->size && fn_ofs >= this->ofs. | ||
| 702 | * | ||
| 703 | * Remember, 'this' has higher version, any non-hole node | ||
| 704 | * which is already in the fragtree is newer then the newly | ||
| 705 | * inserted. | ||
| 706 | */ | ||
| 707 | if (!this->node) { | ||
| 708 | /* | ||
| 709 | * 'this' is the hole fragment, so at least the | ||
| 710 | * beginning of the new fragment is valid. | ||
| 711 | */ | ||
| 712 | |||
| 713 | /* | ||
| 714 | * We are going to insert the new node into the | ||
| 715 | * fragment tree, so check it. | ||
| 716 | */ | ||
| 717 | if (!checked) { | ||
| 718 | err = check_node(c, f, tn); | ||
| 719 | if (unlikely(err != 0)) | ||
| 720 | return err; | ||
| 721 | checked = 1; | ||
| 722 | } | ||
| 723 | |||
| 724 | if (this->ofs + this->size >= fn_ofs + fn_size) { | ||
| 725 | /* We split the hole on two parts */ | ||
| 726 | |||
| 727 | fn->frags += 1; | ||
| 728 | newfrag = new_fragment(fn, fn_ofs, fn_size); | ||
| 729 | if (unlikely(!newfrag)) | ||
| 730 | return -ENOMEM; | ||
| 731 | |||
| 732 | err = split_hole(c, root, newfrag, this); | ||
| 733 | if (unlikely(err)) | ||
| 734 | return err; | ||
| 735 | goto out_ok; | ||
| 736 | } | ||
| 737 | |||
| 738 | /* | ||
| 739 | * The beginning of the new fragment is valid since it | ||
| 740 | * overlaps the hole node. | ||
| 741 | */ | ||
| 742 | |||
| 743 | ref_flag = REF_NORMAL; | ||
| 744 | |||
| 745 | fn->frags += 1; | ||
| 746 | newfrag = new_fragment(fn, fn_ofs, | ||
| 747 | this->ofs + this->size - fn_ofs); | ||
| 748 | if (unlikely(!newfrag)) | ||
| 749 | return -ENOMEM; | ||
| 750 | |||
| 751 | if (fn_ofs == this->ofs) { | ||
| 752 | /* | ||
| 753 | * The new node starts at the same offset as | ||
| 754 | * the hole and supersieds the hole. | ||
| 755 | */ | ||
| 756 | dbg_fragtree2("add the new fragment instead of hole %#04x-%#04x, refcnt %d\n", | ||
| 757 | fn_ofs, fn_ofs + this->ofs + this->size - fn_ofs, fn->frags); | ||
| 758 | |||
| 759 | rb_replace_node(&this->rb, &newfrag->rb, root); | ||
| 760 | jffs2_free_node_frag(this); | ||
| 761 | } else { | ||
| 762 | /* | ||
| 763 | * The hole becomes shorter as its right part | ||
| 764 | * is supersieded by the new fragment. | ||
| 765 | */ | ||
| 766 | dbg_fragtree2("reduce size of hole %#04x-%#04x to %#04x-%#04x\n", | ||
| 767 | this->ofs, this->ofs + this->size, this->ofs, this->ofs + this->size - newfrag->size); | ||
| 768 | |||
| 769 | dbg_fragtree2("add new fragment %#04x-%#04x, refcnt %d\n", fn_ofs, | ||
| 770 | fn_ofs + this->ofs + this->size - fn_ofs, fn->frags); | ||
| 771 | |||
| 772 | this->size -= newfrag->size; | ||
| 773 | jffs2_fragtree_insert(newfrag, this); | ||
| 774 | rb_insert_color(&newfrag->rb, root); | ||
| 775 | } | ||
| 776 | |||
| 777 | fn_ofs += newfrag->size; | ||
| 778 | fn_size -= newfrag->size; | ||
| 779 | this = rb_entry(rb_next(&newfrag->rb), | ||
| 780 | struct jffs2_node_frag, rb); | ||
| 781 | |||
| 782 | dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n", | ||
| 783 | this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)"); | ||
| 784 | } | ||
| 785 | |||
| 786 | /* | ||
| 787 | * 'This' node is not the hole so it obsoletes the new fragment | ||
| 788 | * either fully or partially. | ||
| 789 | */ | ||
| 790 | if (this->ofs + this->size >= fn_ofs + fn_size) { | ||
| 791 | /* The new node is obsolete, drop it */ | ||
| 792 | if (fn->frags == 0) { | ||
| 793 | dbg_fragtree2("%#04x-%#04x is obsolete, mark it obsolete\n", fn_ofs, fn_ofs + fn_size); | ||
| 794 | ref_flag = REF_OBSOLETE; | ||
| 795 | } | ||
| 796 | goto out_ok; | ||
| 797 | } else { | ||
| 798 | struct jffs2_node_frag *new_this; | ||
| 799 | |||
| 800 | /* 'This' node obsoletes the beginning of the new node */ | ||
| 801 | dbg_fragtree2("the beginning %#04x-%#04x is obsolete\n", fn_ofs, this->ofs + this->size); | ||
| 802 | |||
| 803 | ref_flag = REF_NORMAL; | ||
| 804 | |||
| 805 | fn_size -= this->ofs + this->size - fn_ofs; | ||
| 806 | fn_ofs = this->ofs + this->size; | ||
| 807 | dbg_fragtree2("now considering %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size); | ||
| 808 | |||
| 809 | new_this = rb_entry(rb_next(&this->rb), struct jffs2_node_frag, rb); | ||
| 810 | if (!new_this) { | ||
| 811 | /* | ||
| 812 | * There is no next fragment. Add the rest of | ||
| 813 | * the new node as the right-hand child. | ||
| 814 | */ | ||
| 815 | if (!checked) { | ||
| 816 | err = check_node(c, f, tn); | ||
| 817 | if (unlikely(err != 0)) | ||
| 818 | return err; | ||
| 819 | checked = 1; | ||
| 820 | } | ||
| 821 | |||
| 822 | fn->frags += 1; | ||
| 823 | newfrag = new_fragment(fn, fn_ofs, fn_size); | ||
| 824 | if (unlikely(!newfrag)) | ||
| 825 | return -ENOMEM; | ||
| 826 | |||
| 827 | dbg_fragtree2("there are no more fragments, insert %#04x-%#04x\n", | ||
| 828 | newfrag->ofs, newfrag->ofs + newfrag->size); | ||
| 829 | rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); | ||
| 830 | rb_insert_color(&newfrag->rb, root); | ||
| 831 | goto out_ok; | ||
| 832 | } else { | ||
| 833 | this = new_this; | ||
| 834 | dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n", | ||
| 835 | this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)"); | ||
| 836 | } | ||
| 837 | } | ||
| 838 | } | ||
| 839 | |||
| 840 | out_ok: | ||
| 841 | BUG_ON(fn->size < PAGE_CACHE_SIZE && ref_flag == REF_PRISTINE); | ||
| 842 | |||
| 843 | if (ref_flag == REF_OBSOLETE) { | ||
| 844 | dbg_fragtree2("the node is obsolete now\n"); | ||
| 845 | /* jffs2_mark_node_obsolete() will adjust space accounting */ | ||
| 846 | jffs2_mark_node_obsolete(c, fn->raw); | ||
| 847 | return 1; | ||
| 848 | } | ||
| 849 | |||
| 850 | dbg_fragtree2("the node is \"%s\" now\n", ref_flag == REF_NORMAL ? "REF_NORMAL" : "REF_PRISTINE"); | ||
| 851 | |||
| 852 | /* Space accounting was adjusted at check_node_data() */ | ||
| 853 | spin_lock(&c->erase_completion_lock); | ||
| 854 | fn->raw->flash_offset = ref_offset(fn->raw) | ref_flag; | ||
| 855 | spin_unlock(&c->erase_completion_lock); | ||
| 856 | |||
| 857 | return 0; | ||
| 858 | } | ||
| 859 | |||
| 860 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) | 404 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) |
| 861 | { | 405 | { |
| 862 | spin_lock(&c->inocache_lock); | 406 | spin_lock(&c->inocache_lock); |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 4178b4b55948..25126a062cae 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #ifndef __JFFS2_NODELIST_H__ | 12 | #ifndef __JFFS2_NODELIST_H__ |
| @@ -40,6 +38,9 @@ | |||
| 40 | #define cpu_to_je32(x) ((jint32_t){x}) | 38 | #define cpu_to_je32(x) ((jint32_t){x}) |
| 41 | #define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)}) | 39 | #define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)}) |
| 42 | 40 | ||
| 41 | #define constant_cpu_to_je16(x) ((jint16_t){x}) | ||
| 42 | #define constant_cpu_to_je32(x) ((jint32_t){x}) | ||
| 43 | |||
| 43 | #define je16_to_cpu(x) ((x).v16) | 44 | #define je16_to_cpu(x) ((x).v16) |
| 44 | #define je32_to_cpu(x) ((x).v32) | 45 | #define je32_to_cpu(x) ((x).v32) |
| 45 | #define jemode_to_cpu(x) (jffs2_to_os_mode((x).m)) | 46 | #define jemode_to_cpu(x) (jffs2_to_os_mode((x).m)) |
| @@ -48,6 +49,9 @@ | |||
| 48 | #define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)}) | 49 | #define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)}) |
| 49 | #define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))}) | 50 | #define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))}) |
| 50 | 51 | ||
| 52 | #define constant_cpu_to_je16(x) ((jint16_t){__constant_cpu_to_be16(x)}) | ||
| 53 | #define constant_cpu_to_je32(x) ((jint32_t){__constant_cpu_to_be32(x)}) | ||
| 54 | |||
| 51 | #define je16_to_cpu(x) (be16_to_cpu(x.v16)) | 55 | #define je16_to_cpu(x) (be16_to_cpu(x.v16)) |
| 52 | #define je32_to_cpu(x) (be32_to_cpu(x.v32)) | 56 | #define je32_to_cpu(x) (be32_to_cpu(x.v32)) |
| 53 | #define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m))) | 57 | #define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m))) |
| @@ -56,6 +60,9 @@ | |||
| 56 | #define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)}) | 60 | #define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)}) |
| 57 | #define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))}) | 61 | #define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))}) |
| 58 | 62 | ||
| 63 | #define constant_cpu_to_je16(x) ((jint16_t){__constant_cpu_to_le16(x)}) | ||
| 64 | #define constant_cpu_to_je32(x) ((jint32_t){__constant_cpu_to_le32(x)}) | ||
| 65 | |||
| 59 | #define je16_to_cpu(x) (le16_to_cpu(x.v16)) | 66 | #define je16_to_cpu(x) (le16_to_cpu(x.v16)) |
| 60 | #define je32_to_cpu(x) (le32_to_cpu(x.v32)) | 67 | #define je32_to_cpu(x) (le32_to_cpu(x.v32)) |
| 61 | #define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) | 68 | #define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) |
| @@ -216,7 +223,20 @@ struct jffs2_tmp_dnode_info | |||
| 216 | uint32_t version; | 223 | uint32_t version; |
| 217 | uint32_t data_crc; | 224 | uint32_t data_crc; |
| 218 | uint32_t partial_crc; | 225 | uint32_t partial_crc; |
| 219 | uint32_t csize; | 226 | uint16_t csize; |
| 227 | uint16_t overlapped; | ||
| 228 | }; | ||
| 229 | |||
| 230 | /* Temporary data structure used during readinode. */ | ||
| 231 | struct jffs2_readinode_info | ||
| 232 | { | ||
| 233 | struct rb_root tn_root; | ||
| 234 | struct jffs2_tmp_dnode_info *mdata_tn; | ||
| 235 | uint32_t highest_version; | ||
| 236 | uint32_t latest_mctime; | ||
| 237 | uint32_t mctime_ver; | ||
| 238 | struct jffs2_full_dirent *fds; | ||
| 239 | struct jffs2_raw_node_ref *latest_ref; | ||
| 220 | }; | 240 | }; |
| 221 | 241 | ||
| 222 | struct jffs2_full_dirent | 242 | struct jffs2_full_dirent |
| @@ -319,6 +339,15 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root) | |||
| 319 | #define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb) | 339 | #define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb) |
| 320 | #define frag_erase(frag, list) rb_erase(&frag->rb, list); | 340 | #define frag_erase(frag, list) rb_erase(&frag->rb, list); |
| 321 | 341 | ||
| 342 | #define tn_next(tn) rb_entry(rb_next(&(tn)->rb), struct jffs2_tmp_dnode_info, rb) | ||
| 343 | #define tn_prev(tn) rb_entry(rb_prev(&(tn)->rb), struct jffs2_tmp_dnode_info, rb) | ||
| 344 | #define tn_parent(tn) rb_entry(rb_parent(&(tn)->rb), struct jffs2_tmp_dnode_info, rb) | ||
| 345 | #define tn_left(tn) rb_entry((tn)->rb.rb_left, struct jffs2_tmp_dnode_info, rb) | ||
| 346 | #define tn_right(tn) rb_entry((tn)->rb.rb_right, struct jffs2_tmp_dnode_info, rb) | ||
| 347 | #define tn_erase(tn, list) rb_erase(&tn->rb, list); | ||
| 348 | #define tn_last(list) rb_entry(rb_last(list), struct jffs2_tmp_dnode_info, rb) | ||
| 349 | #define tn_first(list) rb_entry(rb_first(list), struct jffs2_tmp_dnode_info, rb) | ||
| 350 | |||
| 322 | /* nodelist.c */ | 351 | /* nodelist.c */ |
| 323 | void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); | 352 | void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); |
| 324 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); | 353 | void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); |
| @@ -333,8 +362,7 @@ struct rb_node *rb_next(struct rb_node *); | |||
| 333 | struct rb_node *rb_prev(struct rb_node *); | 362 | struct rb_node *rb_prev(struct rb_node *); |
| 334 | void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); | 363 | void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); |
| 335 | int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); | 364 | int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); |
| 336 | void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); | 365 | uint32_t jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); |
| 337 | int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn); | ||
| 338 | struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, | 366 | struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, |
| 339 | struct jffs2_eraseblock *jeb, | 367 | struct jffs2_eraseblock *jeb, |
| 340 | uint32_t ofs, uint32_t len, | 368 | uint32_t ofs, uint32_t len, |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index d88376992ed9..dbc908ad622b 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: nodemgmt.c,v 1.127 2005/09/20 15:49:12 dedekind Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| @@ -172,6 +170,11 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, | |||
| 172 | static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) | 170 | static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) |
| 173 | { | 171 | { |
| 174 | 172 | ||
| 173 | if (c->nextblock == NULL) { | ||
| 174 | D1(printk(KERN_DEBUG "jffs2_close_nextblock: Erase block at 0x%08x has already been placed in a list\n", | ||
| 175 | jeb->offset)); | ||
| 176 | return; | ||
| 177 | } | ||
| 175 | /* Check, if we have a dirty block now, or if it was dirty already */ | 178 | /* Check, if we have a dirty block now, or if it was dirty already */ |
| 176 | if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { | 179 | if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { |
| 177 | c->dirty_size += jeb->wasted_size; | 180 | c->dirty_size += jeb->wasted_size; |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 8d92e45168ca..80daea96bbc2 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2002-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: os-linux.h,v 1.64 2005/09/30 13:59:13 dedekind Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #ifndef __JFFS2_OS_LINUX_H__ | 12 | #ifndef __JFFS2_OS_LINUX_H__ |
diff --git a/fs/jffs2/pushpull.h b/fs/jffs2/pushpull.h deleted file mode 100644 index c0c2a9158dff..000000000000 --- a/fs/jffs2/pushpull.h +++ /dev/null | |||
| @@ -1,72 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001, 2002 Red Hat, Inc. | ||
| 5 | * | ||
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | ||
| 7 | * | ||
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | ||
| 9 | * | ||
| 10 | * $Id: pushpull.h,v 1.10 2004/11/16 20:36:11 dwmw2 Exp $ | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __PUSHPULL_H__ | ||
| 15 | #define __PUSHPULL_H__ | ||
| 16 | |||
| 17 | #include <linux/errno.h> | ||
| 18 | |||
| 19 | struct pushpull { | ||
| 20 | unsigned char *buf; | ||
| 21 | unsigned int buflen; | ||
| 22 | unsigned int ofs; | ||
| 23 | unsigned int reserve; | ||
| 24 | }; | ||
| 25 | |||
| 26 | |||
| 27 | static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve) | ||
| 28 | { | ||
| 29 | pp->buf = buf; | ||
| 30 | pp->buflen = buflen; | ||
| 31 | pp->ofs = ofs; | ||
| 32 | pp->reserve = reserve; | ||
| 33 | } | ||
| 34 | |||
| 35 | static inline int pushbit(struct pushpull *pp, int bit, int use_reserved) | ||
| 36 | { | ||
| 37 | if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) { | ||
| 38 | return -ENOSPC; | ||
| 39 | } | ||
| 40 | |||
| 41 | if (bit) { | ||
| 42 | pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7))); | ||
| 43 | } | ||
| 44 | else { | ||
| 45 | pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7))); | ||
| 46 | } | ||
| 47 | pp->ofs++; | ||
| 48 | |||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | static inline int pushedbits(struct pushpull *pp) | ||
| 53 | { | ||
| 54 | return pp->ofs; | ||
| 55 | } | ||
| 56 | |||
| 57 | static inline int pullbit(struct pushpull *pp) | ||
| 58 | { | ||
| 59 | int bit; | ||
| 60 | |||
| 61 | bit = (pp->buf[pp->ofs >> 3] >> (7-(pp->ofs & 7))) & 1; | ||
| 62 | |||
| 63 | pp->ofs++; | ||
| 64 | return bit; | ||
| 65 | } | ||
| 66 | |||
| 67 | static inline int pulledbits(struct pushpull *pp) | ||
| 68 | { | ||
| 69 | return pp->ofs; | ||
| 70 | } | ||
| 71 | |||
| 72 | #endif /* __PUSHPULL_H__ */ | ||
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index f3b86da833ba..cfe05c1966a5 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: read.c,v 1.42 2005/11/07 11:14:41 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 717a48cf7df2..6aff38930b50 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: readinode.c,v 1.143 2005/11/07 11:14:41 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| @@ -22,30 +20,510 @@ | |||
| 22 | #include "nodelist.h" | 20 | #include "nodelist.h" |
| 23 | 21 | ||
| 24 | /* | 22 | /* |
| 25 | * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in | 23 | * Check the data CRC of the node. |
| 26 | * order of increasing version. | 24 | * |
| 25 | * Returns: 0 if the data CRC is correct; | ||
| 26 | * 1 - if incorrect; | ||
| 27 | * error code if an error occured. | ||
| 27 | */ | 28 | */ |
| 28 | static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) | 29 | static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) |
| 29 | { | 30 | { |
| 30 | struct rb_node **p = &list->rb_node; | 31 | struct jffs2_raw_node_ref *ref = tn->fn->raw; |
| 31 | struct rb_node * parent = NULL; | 32 | int err = 0, pointed = 0; |
| 32 | struct jffs2_tmp_dnode_info *this; | 33 | struct jffs2_eraseblock *jeb; |
| 33 | 34 | unsigned char *buffer; | |
| 34 | while (*p) { | 35 | uint32_t crc, ofs, len; |
| 35 | parent = *p; | 36 | size_t retlen; |
| 36 | this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); | 37 | |
| 37 | 38 | BUG_ON(tn->csize == 0); | |
| 38 | /* There may actually be a collision here, but it doesn't | 39 | |
| 39 | actually matter. As long as the two nodes with the same | 40 | if (!jffs2_is_writebuffered(c)) |
| 40 | version are together, it's all fine. */ | 41 | goto adj_acc; |
| 41 | if (tn->version > this->version) | 42 | |
| 42 | p = &(*p)->rb_left; | 43 | /* Calculate how many bytes were already checked */ |
| 44 | ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode); | ||
| 45 | len = ofs % c->wbuf_pagesize; | ||
| 46 | if (likely(len)) | ||
| 47 | len = c->wbuf_pagesize - len; | ||
| 48 | |||
| 49 | if (len >= tn->csize) { | ||
| 50 | dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n", | ||
| 51 | ref_offset(ref), tn->csize, ofs); | ||
| 52 | goto adj_acc; | ||
| 53 | } | ||
| 54 | |||
| 55 | ofs += len; | ||
| 56 | len = tn->csize - len; | ||
| 57 | |||
| 58 | dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n", | ||
| 59 | ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); | ||
| 60 | |||
| 61 | #ifndef __ECOS | ||
| 62 | /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(), | ||
| 63 | * adding and jffs2_flash_read_end() interface. */ | ||
| 64 | if (c->mtd->point) { | ||
| 65 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); | ||
| 66 | if (!err && retlen < tn->csize) { | ||
| 67 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); | ||
| 68 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | ||
| 69 | } else if (err) | ||
| 70 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); | ||
| 43 | else | 71 | else |
| 44 | p = &(*p)->rb_right; | 72 | pointed = 1; /* succefully pointed to device */ |
| 73 | } | ||
| 74 | #endif | ||
| 75 | |||
| 76 | if (!pointed) { | ||
| 77 | buffer = kmalloc(len, GFP_KERNEL); | ||
| 78 | if (unlikely(!buffer)) | ||
| 79 | return -ENOMEM; | ||
| 80 | |||
| 81 | /* TODO: this is very frequent pattern, make it a separate | ||
| 82 | * routine */ | ||
| 83 | err = jffs2_flash_read(c, ofs, len, &retlen, buffer); | ||
| 84 | if (err) { | ||
| 85 | JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); | ||
| 86 | goto free_out; | ||
| 87 | } | ||
| 88 | |||
| 89 | if (retlen != len) { | ||
| 90 | JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); | ||
| 91 | err = -EIO; | ||
| 92 | goto free_out; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | /* Continue calculating CRC */ | ||
| 97 | crc = crc32(tn->partial_crc, buffer, len); | ||
| 98 | if(!pointed) | ||
| 99 | kfree(buffer); | ||
| 100 | #ifndef __ECOS | ||
| 101 | else | ||
| 102 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | ||
| 103 | #endif | ||
| 104 | |||
| 105 | if (crc != tn->data_crc) { | ||
| 106 | JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n", | ||
| 107 | ofs, tn->data_crc, crc); | ||
| 108 | return 1; | ||
| 45 | } | 109 | } |
| 46 | 110 | ||
| 47 | rb_link_node(&tn->rb, parent, p); | 111 | adj_acc: |
| 48 | rb_insert_color(&tn->rb, list); | 112 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; |
| 113 | len = ref_totlen(c, jeb, ref); | ||
| 114 | /* If it should be REF_NORMAL, it'll get marked as such when | ||
| 115 | we build the fragtree, shortly. No need to worry about GC | ||
| 116 | moving it while it's marked REF_PRISTINE -- GC won't happen | ||
| 117 | till we've finished checking every inode anyway. */ | ||
| 118 | ref->flash_offset |= REF_PRISTINE; | ||
| 119 | /* | ||
| 120 | * Mark the node as having been checked and fix the | ||
| 121 | * accounting accordingly. | ||
| 122 | */ | ||
| 123 | spin_lock(&c->erase_completion_lock); | ||
| 124 | jeb->used_size += len; | ||
| 125 | jeb->unchecked_size -= len; | ||
| 126 | c->used_size += len; | ||
| 127 | c->unchecked_size -= len; | ||
| 128 | jffs2_dbg_acct_paranoia_check_nolock(c, jeb); | ||
| 129 | spin_unlock(&c->erase_completion_lock); | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | |||
| 133 | free_out: | ||
| 134 | if(!pointed) | ||
| 135 | kfree(buffer); | ||
| 136 | #ifndef __ECOS | ||
| 137 | else | ||
| 138 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | ||
| 139 | #endif | ||
| 140 | return err; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* | ||
| 144 | * Helper function for jffs2_add_older_frag_to_fragtree(). | ||
| 145 | * | ||
| 146 | * Checks the node if we are in the checking stage. | ||
| 147 | */ | ||
| 148 | static int check_tn_node(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) | ||
| 149 | { | ||
| 150 | int ret; | ||
| 151 | |||
| 152 | BUG_ON(ref_obsolete(tn->fn->raw)); | ||
| 153 | |||
| 154 | /* We only check the data CRC of unchecked nodes */ | ||
| 155 | if (ref_flags(tn->fn->raw) != REF_UNCHECKED) | ||
| 156 | return 0; | ||
| 157 | |||
| 158 | dbg_readinode("check node %#04x-%#04x, phys offs %#08x\n", | ||
| 159 | tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw)); | ||
| 160 | |||
| 161 | ret = check_node_data(c, tn); | ||
| 162 | if (unlikely(ret < 0)) { | ||
| 163 | JFFS2_ERROR("check_node_data() returned error: %d.\n", | ||
| 164 | ret); | ||
| 165 | } else if (unlikely(ret > 0)) { | ||
| 166 | dbg_readinode("CRC error, mark it obsolete.\n"); | ||
| 167 | jffs2_mark_node_obsolete(c, tn->fn->raw); | ||
| 168 | } | ||
| 169 | |||
| 170 | return ret; | ||
| 171 | } | ||
| 172 | |||
| 173 | static struct jffs2_tmp_dnode_info *jffs2_lookup_tn(struct rb_root *tn_root, uint32_t offset) | ||
| 174 | { | ||
| 175 | struct rb_node *next; | ||
| 176 | struct jffs2_tmp_dnode_info *tn = NULL; | ||
| 177 | |||
| 178 | dbg_readinode("root %p, offset %d\n", tn_root, offset); | ||
| 179 | |||
| 180 | next = tn_root->rb_node; | ||
| 181 | |||
| 182 | while (next) { | ||
| 183 | tn = rb_entry(next, struct jffs2_tmp_dnode_info, rb); | ||
| 184 | |||
| 185 | if (tn->fn->ofs < offset) | ||
| 186 | next = tn->rb.rb_right; | ||
| 187 | else if (tn->fn->ofs >= offset) | ||
| 188 | next = tn->rb.rb_left; | ||
| 189 | else | ||
| 190 | break; | ||
| 191 | } | ||
| 192 | |||
| 193 | return tn; | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn) | ||
| 198 | { | ||
| 199 | jffs2_mark_node_obsolete(c, tn->fn->raw); | ||
| 200 | jffs2_free_full_dnode(tn->fn); | ||
| 201 | jffs2_free_tmp_dnode_info(tn); | ||
| 202 | } | ||
| 203 | /* | ||
| 204 | * This function is used when we read an inode. Data nodes arrive in | ||
| 205 | * arbitrary order -- they may be older or newer than the nodes which | ||
| 206 | * are already in the tree. Where overlaps occur, the older node can | ||
| 207 | * be discarded as long as the newer passes the CRC check. We don't | ||
| 208 | * bother to keep track of holes in this rbtree, and neither do we deal | ||
| 209 | * with frags -- we can have multiple entries starting at the same | ||
| 210 | * offset, and the one with the smallest length will come first in the | ||
| 211 | * ordering. | ||
| 212 | * | ||
| 213 | * Returns 0 if the node was inserted | ||
| 214 | * 1 if the node is obsolete (because we can't mark it so yet) | ||
| 215 | * < 0 an if error occurred | ||
| 216 | */ | ||
| 217 | static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | ||
| 218 | struct jffs2_readinode_info *rii, | ||
| 219 | struct jffs2_tmp_dnode_info *tn) | ||
| 220 | { | ||
| 221 | uint32_t fn_end = tn->fn->ofs + tn->fn->size; | ||
| 222 | struct jffs2_tmp_dnode_info *insert_point = NULL, *this; | ||
| 223 | |||
| 224 | dbg_readinode("insert fragment %#04x-%#04x, ver %u\n", tn->fn->ofs, fn_end, tn->version); | ||
| 225 | |||
| 226 | /* If a node has zero dsize, we only have to keep if it if it might be the | ||
| 227 | node with highest version -- i.e. the one which will end up as f->metadata. | ||
| 228 | Note that such nodes won't be REF_UNCHECKED since there are no data to | ||
| 229 | check anyway. */ | ||
| 230 | if (!tn->fn->size) { | ||
| 231 | if (rii->mdata_tn) { | ||
| 232 | /* We had a candidate mdata node already */ | ||
| 233 | dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version); | ||
| 234 | jffs2_kill_tn(c, rii->mdata_tn); | ||
| 235 | } | ||
| 236 | rii->mdata_tn = tn; | ||
| 237 | dbg_readinode("keep new mdata with ver %d\n", tn->version); | ||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | /* Find the earliest node which _may_ be relevant to this one */ | ||
| 242 | this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs); | ||
| 243 | if (!this) { | ||
| 244 | /* First addition to empty tree. $DEITY how I love the easy cases */ | ||
| 245 | rb_link_node(&tn->rb, NULL, &rii->tn_root.rb_node); | ||
| 246 | rb_insert_color(&tn->rb, &rii->tn_root); | ||
| 247 | dbg_readinode("keep new frag\n"); | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | /* If we add a new node it'll be somewhere under here. */ | ||
| 252 | insert_point = this; | ||
| 253 | |||
| 254 | /* If the node is coincident with another at a lower address, | ||
| 255 | back up until the other node is found. It may be relevant */ | ||
| 256 | while (tn->overlapped) | ||
| 257 | tn = tn_prev(tn); | ||
| 258 | |||
| 259 | dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole"); | ||
| 260 | |||
| 261 | while (this) { | ||
| 262 | if (this->fn->ofs > fn_end) | ||
| 263 | break; | ||
| 264 | dbg_readinode("Ponder this ver %d, 0x%x-0x%x\n", | ||
| 265 | this->version, this->fn->ofs, this->fn->size); | ||
| 266 | |||
| 267 | if (this->version == tn->version) { | ||
| 268 | /* Version number collision means REF_PRISTINE GC. Accept either of them | ||
| 269 | as long as the CRC is correct. Check the one we have already... */ | ||
| 270 | if (!check_tn_node(c, this)) { | ||
| 271 | /* The one we already had was OK. Keep it and throw away the new one */ | ||
| 272 | dbg_readinode("Like old node. Throw away new\n"); | ||
| 273 | jffs2_kill_tn(c, tn); | ||
| 274 | return 0; | ||
| 275 | } else { | ||
| 276 | /* Who cares if the new one is good; keep it for now anyway. */ | ||
| 277 | rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); | ||
| 278 | /* Same overlapping from in front and behind */ | ||
| 279 | tn->overlapped = this->overlapped; | ||
| 280 | jffs2_kill_tn(c, this); | ||
| 281 | dbg_readinode("Like new node. Throw away old\n"); | ||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | } | ||
| 285 | if (this->version < tn->version && | ||
| 286 | this->fn->ofs >= tn->fn->ofs && | ||
| 287 | this->fn->ofs + this->fn->size <= fn_end) { | ||
| 288 | /* New node entirely overlaps 'this' */ | ||
| 289 | if (check_tn_node(c, tn)) { | ||
| 290 | dbg_readinode("new node bad CRC\n"); | ||
| 291 | jffs2_kill_tn(c, tn); | ||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | /* ... and is good. Kill 'this'... */ | ||
| 295 | rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); | ||
| 296 | tn->overlapped = this->overlapped; | ||
| 297 | jffs2_kill_tn(c, this); | ||
| 298 | /* ... and any subsequent nodes which are also overlapped */ | ||
| 299 | this = tn_next(tn); | ||
| 300 | while (this && this->fn->ofs + this->fn->size < fn_end) { | ||
| 301 | struct jffs2_tmp_dnode_info *next = tn_next(this); | ||
| 302 | if (this->version < tn->version) { | ||
| 303 | tn_erase(this, &rii->tn_root); | ||
| 304 | dbg_readinode("Kill overlapped ver %d, 0x%x-0x%x\n", | ||
| 305 | this->version, this->fn->ofs, | ||
| 306 | this->fn->ofs+this->fn->size); | ||
| 307 | jffs2_kill_tn(c, this); | ||
| 308 | } | ||
| 309 | this = next; | ||
| 310 | } | ||
| 311 | dbg_readinode("Done inserting new\n"); | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | if (this->version > tn->version && | ||
| 315 | this->fn->ofs <= tn->fn->ofs && | ||
| 316 | this->fn->ofs+this->fn->size >= fn_end) { | ||
| 317 | /* New node entirely overlapped by 'this' */ | ||
| 318 | if (!check_tn_node(c, this)) { | ||
| 319 | dbg_readinode("Good CRC on old node. Kill new\n"); | ||
| 320 | jffs2_kill_tn(c, tn); | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | /* ... but 'this' was bad. Replace it... */ | ||
| 324 | rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); | ||
| 325 | dbg_readinode("Bad CRC on old overlapping node. Kill it\n"); | ||
| 326 | jffs2_kill_tn(c, this); | ||
| 327 | return 0; | ||
| 328 | } | ||
| 329 | /* We want to be inserted under the last node which is | ||
| 330 | either at a lower offset _or_ has a smaller range */ | ||
| 331 | if (this->fn->ofs < tn->fn->ofs || | ||
| 332 | (this->fn->ofs == tn->fn->ofs && | ||
| 333 | this->fn->size <= tn->fn->size)) | ||
| 334 | insert_point = this; | ||
| 335 | |||
| 336 | this = tn_next(this); | ||
| 337 | } | ||
| 338 | dbg_readinode("insert_point %p, ver %d, 0x%x-0x%x, ov %d\n", | ||
| 339 | insert_point, insert_point->version, insert_point->fn->ofs, | ||
| 340 | insert_point->fn->ofs+insert_point->fn->size, | ||
| 341 | insert_point->overlapped); | ||
| 342 | /* We neither completely obsoleted nor were completely | ||
| 343 | obsoleted by an earlier node. Insert under insert_point */ | ||
| 344 | { | ||
| 345 | struct rb_node *parent = &insert_point->rb; | ||
| 346 | struct rb_node **link = &parent; | ||
| 347 | |||
| 348 | while (*link) { | ||
| 349 | parent = *link; | ||
| 350 | insert_point = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); | ||
| 351 | if (tn->fn->ofs > insert_point->fn->ofs) | ||
| 352 | link = &insert_point->rb.rb_right; | ||
| 353 | else if (tn->fn->ofs < insert_point->fn->ofs || | ||
| 354 | tn->fn->size < insert_point->fn->size) | ||
| 355 | link = &insert_point->rb.rb_left; | ||
| 356 | else | ||
| 357 | link = &insert_point->rb.rb_right; | ||
| 358 | } | ||
| 359 | rb_link_node(&tn->rb, &insert_point->rb, link); | ||
| 360 | rb_insert_color(&tn->rb, &rii->tn_root); | ||
| 361 | } | ||
| 362 | /* If there's anything behind that overlaps us, note it */ | ||
| 363 | this = tn_prev(tn); | ||
| 364 | if (this) { | ||
| 365 | while (1) { | ||
| 366 | if (this->fn->ofs + this->fn->size > tn->fn->ofs) { | ||
| 367 | dbg_readinode("Node is overlapped by %p (v %d, 0x%x-0x%x)\n", | ||
| 368 | this, this->version, this->fn->ofs, | ||
| 369 | this->fn->ofs+this->fn->size); | ||
| 370 | tn->overlapped = 1; | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | if (!this->overlapped) | ||
| 374 | break; | ||
| 375 | this = tn_prev(this); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | /* If the new node overlaps anything ahead, note it */ | ||
| 380 | this = tn_next(tn); | ||
| 381 | while (this && this->fn->ofs < fn_end) { | ||
| 382 | this->overlapped = 1; | ||
| 383 | dbg_readinode("Node ver %d, 0x%x-0x%x is overlapped\n", | ||
| 384 | this->version, this->fn->ofs, | ||
| 385 | this->fn->ofs+this->fn->size); | ||
| 386 | this = tn_next(this); | ||
| 387 | } | ||
| 388 | return 0; | ||
| 389 | } | ||
| 390 | |||
| 391 | /* Trivial function to remove the last node in the tree. Which by definition | ||
| 392 | has no right-hand -- so can be removed just by making its only child (if | ||
| 393 | any) take its place under its parent. */ | ||
| 394 | static void eat_last(struct rb_root *root, struct rb_node *node) | ||
| 395 | { | ||
| 396 | struct rb_node *parent = rb_parent(node); | ||
| 397 | struct rb_node **link; | ||
| 398 | |||
| 399 | /* LAST! */ | ||
| 400 | BUG_ON(node->rb_right); | ||
| 401 | |||
| 402 | if (!parent) | ||
| 403 | link = &root->rb_node; | ||
| 404 | else if (node == parent->rb_left) | ||
| 405 | link = &parent->rb_left; | ||
| 406 | else | ||
| 407 | link = &parent->rb_right; | ||
| 408 | |||
| 409 | *link = node->rb_left; | ||
| 410 | /* Colour doesn't matter now. Only the parent pointer. */ | ||
| 411 | if (node->rb_left) | ||
| 412 | node->rb_left->rb_parent_color = node->rb_parent_color; | ||
| 413 | } | ||
| 414 | |||
| 415 | /* We put this in reverse order, so we can just use eat_last */ | ||
| 416 | static void ver_insert(struct rb_root *ver_root, struct jffs2_tmp_dnode_info *tn) | ||
| 417 | { | ||
| 418 | struct rb_node **link = &ver_root->rb_node; | ||
| 419 | struct rb_node *parent = NULL; | ||
| 420 | struct jffs2_tmp_dnode_info *this_tn; | ||
| 421 | |||
| 422 | while (*link) { | ||
| 423 | parent = *link; | ||
| 424 | this_tn = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); | ||
| 425 | |||
| 426 | if (tn->version > this_tn->version) | ||
| 427 | link = &parent->rb_left; | ||
| 428 | else | ||
| 429 | link = &parent->rb_right; | ||
| 430 | } | ||
| 431 | dbg_readinode("Link new node at %p (root is %p)\n", link, ver_root); | ||
| 432 | rb_link_node(&tn->rb, parent, link); | ||
| 433 | rb_insert_color(&tn->rb, ver_root); | ||
| 434 | } | ||
| 435 | |||
| 436 | /* Build final, normal fragtree from tn tree. It doesn't matter which order | ||
| 437 | we add nodes to the real fragtree, as long as they don't overlap. And | ||
| 438 | having thrown away the majority of overlapped nodes as we went, there | ||
| 439 | really shouldn't be many sets of nodes which do overlap. If we start at | ||
| 440 | the end, we can use the overlap markers -- we can just eat nodes which | ||
| 441 | aren't overlapped, and when we encounter nodes which _do_ overlap we | ||
| 442 | sort them all into a temporary tree in version order before replaying them. */ | ||
| 443 | static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, | ||
| 444 | struct jffs2_inode_info *f, | ||
| 445 | struct jffs2_readinode_info *rii) | ||
| 446 | { | ||
| 447 | struct jffs2_tmp_dnode_info *pen, *last, *this; | ||
| 448 | struct rb_root ver_root = RB_ROOT; | ||
| 449 | uint32_t high_ver = 0; | ||
| 450 | |||
| 451 | if (rii->mdata_tn) { | ||
| 452 | dbg_readinode("potential mdata is ver %d at %p\n", rii->mdata_tn->version, rii->mdata_tn); | ||
| 453 | high_ver = rii->mdata_tn->version; | ||
| 454 | rii->latest_ref = rii->mdata_tn->fn->raw; | ||
| 455 | } | ||
| 456 | #ifdef JFFS2_DBG_READINODE_MESSAGES | ||
| 457 | this = tn_last(&rii->tn_root); | ||
| 458 | while (this) { | ||
| 459 | dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs, | ||
| 460 | this->fn->ofs+this->fn->size, this->overlapped); | ||
| 461 | this = tn_prev(this); | ||
| 462 | } | ||
| 463 | #endif | ||
| 464 | pen = tn_last(&rii->tn_root); | ||
| 465 | while ((last = pen)) { | ||
| 466 | pen = tn_prev(last); | ||
| 467 | |||
| 468 | eat_last(&rii->tn_root, &last->rb); | ||
| 469 | ver_insert(&ver_root, last); | ||
| 470 | |||
| 471 | if (unlikely(last->overlapped)) | ||
| 472 | continue; | ||
| 473 | |||
| 474 | /* Now we have a bunch of nodes in reverse version | ||
| 475 | order, in the tree at ver_root. Most of the time, | ||
| 476 | there'll actually be only one node in the 'tree', | ||
| 477 | in fact. */ | ||
| 478 | this = tn_last(&ver_root); | ||
| 479 | |||
| 480 | while (this) { | ||
| 481 | struct jffs2_tmp_dnode_info *vers_next; | ||
| 482 | int ret; | ||
| 483 | vers_next = tn_prev(this); | ||
| 484 | eat_last(&ver_root, &this->rb); | ||
| 485 | if (check_tn_node(c, this)) { | ||
| 486 | dbg_readinode("node ver %x, 0x%x-0x%x failed CRC\n", | ||
| 487 | this->version, this->fn->ofs, | ||
| 488 | this->fn->ofs+this->fn->size); | ||
| 489 | jffs2_kill_tn(c, this); | ||
| 490 | } else { | ||
| 491 | if (this->version > high_ver) { | ||
| 492 | /* Note that this is different from the other | ||
| 493 | highest_version, because this one is only | ||
| 494 | counting _valid_ nodes which could give the | ||
| 495 | latest inode metadata */ | ||
| 496 | high_ver = this->version; | ||
| 497 | rii->latest_ref = this->fn->raw; | ||
| 498 | } | ||
| 499 | dbg_readinode("Add %p (v %x, 0x%x-0x%x, ov %d) to fragtree\n", | ||
| 500 | this, this->version, this->fn->ofs, | ||
| 501 | this->fn->ofs+this->fn->size, this->overlapped); | ||
| 502 | |||
| 503 | ret = jffs2_add_full_dnode_to_inode(c, f, this->fn); | ||
| 504 | if (ret) { | ||
| 505 | /* Free the nodes in vers_root; let the caller | ||
| 506 | deal with the rest */ | ||
| 507 | JFFS2_ERROR("Add node to tree failed %d\n", ret); | ||
| 508 | while (1) { | ||
| 509 | vers_next = tn_prev(this); | ||
| 510 | if (check_tn_node(c, this)) | ||
| 511 | jffs2_mark_node_obsolete(c, this->fn->raw); | ||
| 512 | jffs2_free_full_dnode(this->fn); | ||
| 513 | jffs2_free_tmp_dnode_info(this); | ||
| 514 | this = vers_next; | ||
| 515 | if (!this) | ||
| 516 | break; | ||
| 517 | eat_last(&ver_root, &vers_next->rb); | ||
| 518 | } | ||
| 519 | return ret; | ||
| 520 | } | ||
| 521 | jffs2_free_tmp_dnode_info(this); | ||
| 522 | } | ||
| 523 | this = vers_next; | ||
| 524 | } | ||
| 525 | } | ||
| 526 | return 0; | ||
| 49 | } | 527 | } |
| 50 | 528 | ||
| 51 | static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) | 529 | static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) |
| @@ -112,8 +590,8 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r | |||
| 112 | * negative error code on failure. | 590 | * negative error code on failure. |
| 113 | */ | 591 | */ |
| 114 | static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, | 592 | static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, |
| 115 | struct jffs2_raw_dirent *rd, size_t read, struct jffs2_full_dirent **fdp, | 593 | struct jffs2_raw_dirent *rd, size_t read, |
| 116 | uint32_t *latest_mctime, uint32_t *mctime_ver) | 594 | struct jffs2_readinode_info *rii) |
| 117 | { | 595 | { |
| 118 | struct jffs2_full_dirent *fd; | 596 | struct jffs2_full_dirent *fd; |
| 119 | uint32_t crc; | 597 | uint32_t crc; |
| @@ -125,7 +603,8 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
| 125 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { | 603 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { |
| 126 | JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n", | 604 | JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n", |
| 127 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); | 605 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); |
| 128 | return 1; | 606 | jffs2_mark_node_obsolete(c, ref); |
| 607 | return 0; | ||
| 129 | } | 608 | } |
| 130 | 609 | ||
| 131 | /* If we've never checked the CRCs on this node, check them now */ | 610 | /* If we've never checked the CRCs on this node, check them now */ |
| @@ -137,7 +616,8 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
| 137 | if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { | 616 | if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { |
| 138 | JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", | 617 | JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", |
| 139 | ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); | 618 | ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); |
| 140 | return 1; | 619 | jffs2_mark_node_obsolete(c, ref); |
| 620 | return 0; | ||
| 141 | } | 621 | } |
| 142 | 622 | ||
| 143 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | 623 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; |
| @@ -161,10 +641,13 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
| 161 | fd->ino = je32_to_cpu(rd->ino); | 641 | fd->ino = je32_to_cpu(rd->ino); |
| 162 | fd->type = rd->type; | 642 | fd->type = rd->type; |
| 163 | 643 | ||
| 644 | if (fd->version > rii->highest_version) | ||
| 645 | rii->highest_version = fd->version; | ||
| 646 | |||
| 164 | /* Pick out the mctime of the latest dirent */ | 647 | /* Pick out the mctime of the latest dirent */ |
| 165 | if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) { | 648 | if(fd->version > rii->mctime_ver && je32_to_cpu(rd->mctime)) { |
| 166 | *mctime_ver = fd->version; | 649 | rii->mctime_ver = fd->version; |
| 167 | *latest_mctime = je32_to_cpu(rd->mctime); | 650 | rii->latest_mctime = je32_to_cpu(rd->mctime); |
| 168 | } | 651 | } |
| 169 | 652 | ||
| 170 | /* | 653 | /* |
| @@ -201,7 +684,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
| 201 | * Wheee. We now have a complete jffs2_full_dirent structure, with | 684 | * Wheee. We now have a complete jffs2_full_dirent structure, with |
| 202 | * the name in it and everything. Link it into the list | 685 | * the name in it and everything. Link it into the list |
| 203 | */ | 686 | */ |
| 204 | jffs2_add_fd_to_list(c, fd, fdp); | 687 | jffs2_add_fd_to_list(c, fd, &rii->fds); |
| 205 | 688 | ||
| 206 | return 0; | 689 | return 0; |
| 207 | } | 690 | } |
| @@ -210,13 +693,13 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
| 210 | * Helper function for jffs2_get_inode_nodes(). | 693 | * Helper function for jffs2_get_inode_nodes(). |
| 211 | * It is called every time an inode node is found. | 694 | * It is called every time an inode node is found. |
| 212 | * | 695 | * |
| 213 | * Returns: 0 on succes; | 696 | * Returns: 0 on success; |
| 214 | * 1 if the node should be marked obsolete; | 697 | * 1 if the node should be marked obsolete; |
| 215 | * negative error code on failure. | 698 | * negative error code on failure. |
| 216 | */ | 699 | */ |
| 217 | static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, | 700 | static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, |
| 218 | struct jffs2_raw_inode *rd, struct rb_root *tnp, int rdlen, | 701 | struct jffs2_raw_inode *rd, int rdlen, |
| 219 | uint32_t *latest_mctime, uint32_t *mctime_ver) | 702 | struct jffs2_readinode_info *rii) |
| 220 | { | 703 | { |
| 221 | struct jffs2_tmp_dnode_info *tn; | 704 | struct jffs2_tmp_dnode_info *tn; |
| 222 | uint32_t len, csize; | 705 | uint32_t len, csize; |
| @@ -230,7 +713,8 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
| 230 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { | 713 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { |
| 231 | JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n", | 714 | JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n", |
| 232 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); | 715 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); |
| 233 | return 1; | 716 | jffs2_mark_node_obsolete(c, ref); |
| 717 | return 0; | ||
| 234 | } | 718 | } |
| 235 | 719 | ||
| 236 | tn = jffs2_alloc_tmp_dnode_info(); | 720 | tn = jffs2_alloc_tmp_dnode_info(); |
| @@ -342,6 +826,10 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
| 342 | tn->data_crc = je32_to_cpu(rd->data_crc); | 826 | tn->data_crc = je32_to_cpu(rd->data_crc); |
| 343 | tn->csize = csize; | 827 | tn->csize = csize; |
| 344 | tn->fn->raw = ref; | 828 | tn->fn->raw = ref; |
| 829 | tn->overlapped = 0; | ||
| 830 | |||
| 831 | if (tn->version > rii->highest_version) | ||
| 832 | rii->highest_version = tn->version; | ||
| 345 | 833 | ||
| 346 | /* There was a bug where we wrote hole nodes out with | 834 | /* There was a bug where we wrote hole nodes out with |
| 347 | csize/dsize swapped. Deal with it */ | 835 | csize/dsize swapped. Deal with it */ |
| @@ -353,13 +841,25 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
| 353 | dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", | 841 | dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n", |
| 354 | ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); | 842 | ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize); |
| 355 | 843 | ||
| 356 | jffs2_add_tn_to_tree(tn, tnp); | 844 | ret = jffs2_add_tn_to_tree(c, rii, tn); |
| 357 | 845 | ||
| 846 | if (ret) { | ||
| 847 | jffs2_free_full_dnode(tn->fn); | ||
| 848 | free_out: | ||
| 849 | jffs2_free_tmp_dnode_info(tn); | ||
| 850 | return ret; | ||
| 851 | } | ||
| 852 | #ifdef JFFS2_DBG_READINODE_MESSAGES | ||
| 853 | dbg_readinode("After adding ver %d:\n", tn->version); | ||
| 854 | tn = tn_first(&rii->tn_root); | ||
| 855 | while (tn) { | ||
| 856 | dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n", | ||
| 857 | tn, tn->version, tn->fn->ofs, | ||
| 858 | tn->fn->ofs+tn->fn->size, tn->overlapped); | ||
| 859 | tn = tn_next(tn); | ||
| 860 | } | ||
| 861 | #endif | ||
| 358 | return 0; | 862 | return 0; |
| 359 | |||
| 360 | free_out: | ||
| 361 | jffs2_free_tmp_dnode_info(tn); | ||
| 362 | return ret; | ||
| 363 | } | 863 | } |
| 364 | 864 | ||
| 365 | /* | 865 | /* |
| @@ -379,7 +879,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re | |||
| 379 | JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n", | 879 | JFFS2_ERROR("Node is {%04x,%04x,%08x,%08x}. Please report this error.\n", |
| 380 | je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), | 880 | je16_to_cpu(un->magic), je16_to_cpu(un->nodetype), |
| 381 | je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); | 881 | je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)); |
| 382 | return 1; | 882 | jffs2_mark_node_obsolete(c, ref); |
| 883 | return 0; | ||
| 383 | } | 884 | } |
| 384 | 885 | ||
| 385 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); | 886 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); |
| @@ -407,7 +908,8 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re | |||
| 407 | case JFFS2_FEATURE_RWCOMPAT_DELETE: | 908 | case JFFS2_FEATURE_RWCOMPAT_DELETE: |
| 408 | JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", | 909 | JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", |
| 409 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 910 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
| 410 | return 1; | 911 | jffs2_mark_node_obsolete(c, ref); |
| 912 | return 0; | ||
| 411 | } | 913 | } |
| 412 | 914 | ||
| 413 | return 0; | 915 | return 0; |
| @@ -421,92 +923,62 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re | |||
| 421 | * negative error code on failure. | 923 | * negative error code on failure. |
| 422 | */ | 924 | */ |
| 423 | static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, | 925 | static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, |
| 424 | int right_size, int *rdlen, unsigned char *buf, unsigned char *bufstart) | 926 | int needed_len, int *rdlen, unsigned char *buf) |
| 425 | { | 927 | { |
| 426 | int right_len, err, len; | 928 | int err, to_read = needed_len - *rdlen; |
| 427 | size_t retlen; | 929 | size_t retlen; |
| 428 | uint32_t offs; | 930 | uint32_t offs; |
| 429 | 931 | ||
| 430 | if (jffs2_is_writebuffered(c)) { | 932 | if (jffs2_is_writebuffered(c)) { |
| 431 | right_len = c->wbuf_pagesize - (bufstart - buf); | 933 | int rem = to_read % c->wbuf_pagesize; |
| 432 | if (right_size + (int)(bufstart - buf) > c->wbuf_pagesize) | ||
| 433 | right_len += c->wbuf_pagesize; | ||
| 434 | } else | ||
| 435 | right_len = right_size; | ||
| 436 | 934 | ||
| 437 | if (*rdlen == right_len) | 935 | if (rem) |
| 438 | return 0; | 936 | to_read += c->wbuf_pagesize - rem; |
| 937 | } | ||
| 439 | 938 | ||
| 440 | /* We need to read more data */ | 939 | /* We need to read more data */ |
| 441 | offs = ref_offset(ref) + *rdlen; | 940 | offs = ref_offset(ref) + *rdlen; |
| 442 | if (jffs2_is_writebuffered(c)) { | ||
| 443 | bufstart = buf + c->wbuf_pagesize; | ||
| 444 | len = c->wbuf_pagesize; | ||
| 445 | } else { | ||
| 446 | bufstart = buf + *rdlen; | ||
| 447 | len = right_size - *rdlen; | ||
| 448 | } | ||
| 449 | 941 | ||
| 450 | dbg_readinode("read more %d bytes\n", len); | 942 | dbg_readinode("read more %d bytes\n", to_read); |
| 451 | 943 | ||
| 452 | err = jffs2_flash_read(c, offs, len, &retlen, bufstart); | 944 | err = jffs2_flash_read(c, offs, to_read, &retlen, buf + *rdlen); |
| 453 | if (err) { | 945 | if (err) { |
| 454 | JFFS2_ERROR("can not read %d bytes from 0x%08x, " | 946 | JFFS2_ERROR("can not read %d bytes from 0x%08x, " |
| 455 | "error code: %d.\n", len, offs, err); | 947 | "error code: %d.\n", to_read, offs, err); |
| 456 | return err; | 948 | return err; |
| 457 | } | 949 | } |
| 458 | 950 | ||
| 459 | if (retlen < len) { | 951 | if (retlen < to_read) { |
| 460 | JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n", | 952 | JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n", |
| 461 | offs, retlen, len); | 953 | offs, retlen, to_read); |
| 462 | return -EIO; | 954 | return -EIO; |
| 463 | } | 955 | } |
| 464 | 956 | ||
| 465 | *rdlen = right_len; | 957 | *rdlen += to_read; |
| 466 | |||
| 467 | return 0; | 958 | return 0; |
| 468 | } | 959 | } |
| 469 | 960 | ||
| 470 | /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated | 961 | /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated |
| 471 | with this ino, returning the former in order of version */ | 962 | with this ino. Perform a preliminary ordering on data nodes, throwing away |
| 963 | those which are completely obsoleted by newer ones. The naïve approach we | ||
| 964 | use to take of just returning them _all_ in version order will cause us to | ||
| 965 | run out of memory in certain degenerate cases. */ | ||
| 472 | static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, | 966 | static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, |
| 473 | struct rb_root *tnp, struct jffs2_full_dirent **fdp, | 967 | struct jffs2_readinode_info *rii) |
| 474 | uint32_t *highest_version, uint32_t *latest_mctime, | ||
| 475 | uint32_t *mctime_ver) | ||
| 476 | { | 968 | { |
| 477 | struct jffs2_raw_node_ref *ref, *valid_ref; | 969 | struct jffs2_raw_node_ref *ref, *valid_ref; |
| 478 | struct rb_root ret_tn = RB_ROOT; | ||
| 479 | struct jffs2_full_dirent *ret_fd = NULL; | ||
| 480 | unsigned char *buf = NULL; | 970 | unsigned char *buf = NULL; |
| 481 | union jffs2_node_union *node; | 971 | union jffs2_node_union *node; |
| 482 | size_t retlen; | 972 | size_t retlen; |
| 483 | int len, err; | 973 | int len, err; |
| 484 | 974 | ||
| 485 | *mctime_ver = 0; | 975 | rii->mctime_ver = 0; |
| 486 | 976 | ||
| 487 | dbg_readinode("ino #%u\n", f->inocache->ino); | 977 | dbg_readinode("ino #%u\n", f->inocache->ino); |
| 488 | 978 | ||
| 489 | if (jffs2_is_writebuffered(c)) { | ||
| 490 | /* | ||
| 491 | * If we have the write buffer, we assume the minimal I/O unit | ||
| 492 | * is c->wbuf_pagesize. We implement some optimizations which in | ||
| 493 | * this case and we need a temporary buffer of size = | ||
| 494 | * 2*c->wbuf_pagesize bytes (see comments in read_dnode()). | ||
| 495 | * Basically, we want to read not only the node header, but the | ||
| 496 | * whole wbuf (NAND page in case of NAND) or 2, if the node | ||
| 497 | * header overlaps the border between the 2 wbufs. | ||
| 498 | */ | ||
| 499 | len = 2*c->wbuf_pagesize; | ||
| 500 | } else { | ||
| 501 | /* | ||
| 502 | * When there is no write buffer, the size of the temporary | ||
| 503 | * buffer is the size of the larges node header. | ||
| 504 | */ | ||
| 505 | len = sizeof(union jffs2_node_union); | ||
| 506 | } | ||
| 507 | |||
| 508 | /* FIXME: in case of NOR and available ->point() this | 979 | /* FIXME: in case of NOR and available ->point() this |
| 509 | * needs to be fixed. */ | 980 | * needs to be fixed. */ |
| 981 | len = sizeof(union jffs2_node_union) + c->wbuf_pagesize; | ||
| 510 | buf = kmalloc(len, GFP_KERNEL); | 982 | buf = kmalloc(len, GFP_KERNEL); |
| 511 | if (!buf) | 983 | if (!buf) |
| 512 | return -ENOMEM; | 984 | return -ENOMEM; |
| @@ -516,8 +988,6 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
| 516 | if (!valid_ref && f->inocache->ino != 1) | 988 | if (!valid_ref && f->inocache->ino != 1) |
| 517 | JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino); | 989 | JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino); |
| 518 | while (valid_ref) { | 990 | while (valid_ref) { |
| 519 | unsigned char *bufstart; | ||
| 520 | |||
| 521 | /* We can hold a pointer to a non-obsolete node without the spinlock, | 991 | /* We can hold a pointer to a non-obsolete node without the spinlock, |
| 522 | but _obsolete_ nodes may disappear at any time, if the block | 992 | but _obsolete_ nodes may disappear at any time, if the block |
| 523 | they're in gets erased. So if we mark 'ref' obsolete while we're | 993 | they're in gets erased. So if we mark 'ref' obsolete while we're |
| @@ -533,32 +1003,31 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
| 533 | /* | 1003 | /* |
| 534 | * At this point we don't know the type of the node we're going | 1004 | * At this point we don't know the type of the node we're going |
| 535 | * to read, so we do not know the size of its header. In order | 1005 | * to read, so we do not know the size of its header. In order |
| 536 | * to minimize the amount of flash IO we assume the node has | 1006 | * to minimize the amount of flash IO we assume the header is |
| 537 | * size = JFFS2_MIN_NODE_HEADER. | 1007 | * of size = JFFS2_MIN_NODE_HEADER. |
| 538 | */ | 1008 | */ |
| 1009 | len = JFFS2_MIN_NODE_HEADER; | ||
| 539 | if (jffs2_is_writebuffered(c)) { | 1010 | if (jffs2_is_writebuffered(c)) { |
| 1011 | int end, rem; | ||
| 1012 | |||
| 540 | /* | 1013 | /* |
| 541 | * We treat 'buf' as 2 adjacent wbufs. We want to | 1014 | * We are about to read JFFS2_MIN_NODE_HEADER bytes, |
| 542 | * adjust bufstart such as it points to the | 1015 | * but this flash has some minimal I/O unit. It is |
| 543 | * beginning of the node within this wbuf. | 1016 | * possible that we'll need to read more soon, so read |
| 1017 | * up to the next min. I/O unit, in order not to | ||
| 1018 | * re-read the same min. I/O unit twice. | ||
| 544 | */ | 1019 | */ |
| 545 | bufstart = buf + (ref_offset(ref) % c->wbuf_pagesize); | 1020 | end = ref_offset(ref) + len; |
| 546 | /* We will read either one wbuf or 2 wbufs. */ | 1021 | rem = end % c->wbuf_pagesize; |
| 547 | len = c->wbuf_pagesize - (bufstart - buf); | 1022 | if (rem) |
| 548 | if (JFFS2_MIN_NODE_HEADER + (int)(bufstart - buf) > c->wbuf_pagesize) { | 1023 | end += c->wbuf_pagesize - rem; |
| 549 | /* The header spans the border of the first wbuf */ | 1024 | len = end - ref_offset(ref); |
| 550 | len += c->wbuf_pagesize; | ||
| 551 | } | ||
| 552 | } else { | ||
| 553 | bufstart = buf; | ||
| 554 | len = JFFS2_MIN_NODE_HEADER; | ||
| 555 | } | 1025 | } |
| 556 | 1026 | ||
| 557 | dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref)); | 1027 | dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref)); |
| 558 | 1028 | ||
| 559 | /* FIXME: point() */ | 1029 | /* FIXME: point() */ |
| 560 | err = jffs2_flash_read(c, ref_offset(ref), len, | 1030 | err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, buf); |
| 561 | &retlen, bufstart); | ||
| 562 | if (err) { | 1031 | if (err) { |
| 563 | JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", len, ref_offset(ref), err); | 1032 | JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", len, ref_offset(ref), err); |
| 564 | goto free_out; | 1033 | goto free_out; |
| @@ -570,7 +1039,7 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
| 570 | goto free_out; | 1039 | goto free_out; |
| 571 | } | 1040 | } |
| 572 | 1041 | ||
| 573 | node = (union jffs2_node_union *)bufstart; | 1042 | node = (union jffs2_node_union *)buf; |
| 574 | 1043 | ||
| 575 | /* No need to mask in the valid bit; it shouldn't be invalid */ | 1044 | /* No need to mask in the valid bit; it shouldn't be invalid */ |
| 576 | if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) { | 1045 | if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) { |
| @@ -583,10 +1052,10 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
| 583 | jffs2_mark_node_obsolete(c, ref); | 1052 | jffs2_mark_node_obsolete(c, ref); |
| 584 | goto cont; | 1053 | goto cont; |
| 585 | } | 1054 | } |
| 586 | /* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */ | 1055 | if (je16_to_cpu(node->u.magic) != JFFS2_MAGIC_BITMASK) { |
| 587 | if (!je32_to_cpu(node->u.hdr_crc) && !je16_to_cpu(node->u.nodetype) && | 1056 | /* Not a JFFS2 node, whinge and move on */ |
| 588 | !je16_to_cpu(node->u.magic) && !je32_to_cpu(node->u.totlen)) { | 1057 | JFFS2_NOTICE("Wrong magic bitmask 0x%04x in node header at %#08x.\n", |
| 589 | JFFS2_NOTICE("All zero node header at %#08x.\n", ref_offset(ref)); | 1058 | je16_to_cpu(node->u.magic), ref_offset(ref)); |
| 590 | jffs2_mark_node_obsolete(c, ref); | 1059 | jffs2_mark_node_obsolete(c, ref); |
| 591 | goto cont; | 1060 | goto cont; |
| 592 | } | 1061 | } |
| @@ -596,46 +1065,34 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
| 596 | case JFFS2_NODETYPE_DIRENT: | 1065 | case JFFS2_NODETYPE_DIRENT: |
| 597 | 1066 | ||
| 598 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) { | 1067 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) { |
| 599 | err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf, bufstart); | 1068 | err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf); |
| 600 | if (unlikely(err)) | 1069 | if (unlikely(err)) |
| 601 | goto free_out; | 1070 | goto free_out; |
| 602 | } | 1071 | } |
| 603 | 1072 | ||
| 604 | err = read_direntry(c, ref, &node->d, retlen, &ret_fd, latest_mctime, mctime_ver); | 1073 | err = read_direntry(c, ref, &node->d, retlen, rii); |
| 605 | if (err == 1) { | 1074 | if (unlikely(err)) |
| 606 | jffs2_mark_node_obsolete(c, ref); | ||
| 607 | break; | ||
| 608 | } else if (unlikely(err)) | ||
| 609 | goto free_out; | 1075 | goto free_out; |
| 610 | 1076 | ||
| 611 | if (je32_to_cpu(node->d.version) > *highest_version) | ||
| 612 | *highest_version = je32_to_cpu(node->d.version); | ||
| 613 | |||
| 614 | break; | 1077 | break; |
| 615 | 1078 | ||
| 616 | case JFFS2_NODETYPE_INODE: | 1079 | case JFFS2_NODETYPE_INODE: |
| 617 | 1080 | ||
| 618 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) { | 1081 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) { |
| 619 | err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf, bufstart); | 1082 | err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf); |
| 620 | if (unlikely(err)) | 1083 | if (unlikely(err)) |
| 621 | goto free_out; | 1084 | goto free_out; |
| 622 | } | 1085 | } |
| 623 | 1086 | ||
| 624 | err = read_dnode(c, ref, &node->i, &ret_tn, len, latest_mctime, mctime_ver); | 1087 | err = read_dnode(c, ref, &node->i, len, rii); |
| 625 | if (err == 1) { | 1088 | if (unlikely(err)) |
| 626 | jffs2_mark_node_obsolete(c, ref); | ||
| 627 | break; | ||
| 628 | } else if (unlikely(err)) | ||
| 629 | goto free_out; | 1089 | goto free_out; |
| 630 | 1090 | ||
| 631 | if (je32_to_cpu(node->i.version) > *highest_version) | ||
| 632 | *highest_version = je32_to_cpu(node->i.version); | ||
| 633 | |||
| 634 | break; | 1091 | break; |
| 635 | 1092 | ||
| 636 | default: | 1093 | default: |
| 637 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) { | 1094 | if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) { |
| 638 | err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf, bufstart); | 1095 | err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf); |
| 639 | if (unlikely(err)) | 1096 | if (unlikely(err)) |
| 640 | goto free_out; | 1097 | goto free_out; |
| 641 | } | 1098 | } |
| @@ -653,17 +1110,19 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
| 653 | } | 1110 | } |
| 654 | 1111 | ||
| 655 | spin_unlock(&c->erase_completion_lock); | 1112 | spin_unlock(&c->erase_completion_lock); |
| 656 | *tnp = ret_tn; | ||
| 657 | *fdp = ret_fd; | ||
| 658 | kfree(buf); | 1113 | kfree(buf); |
| 659 | 1114 | ||
| 1115 | f->highest_version = rii->highest_version; | ||
| 1116 | |||
| 660 | dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n", | 1117 | dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n", |
| 661 | f->inocache->ino, *highest_version, *latest_mctime, *mctime_ver); | 1118 | f->inocache->ino, rii->highest_version, rii->latest_mctime, |
| 1119 | rii->mctime_ver); | ||
| 662 | return 0; | 1120 | return 0; |
| 663 | 1121 | ||
| 664 | free_out: | 1122 | free_out: |
| 665 | jffs2_free_tmp_dnode_info_list(&ret_tn); | 1123 | jffs2_free_tmp_dnode_info_list(&rii->tn_root); |
| 666 | jffs2_free_full_dirent_list(ret_fd); | 1124 | jffs2_free_full_dirent_list(rii->fds); |
| 1125 | rii->fds = NULL; | ||
| 667 | kfree(buf); | 1126 | kfree(buf); |
| 668 | return err; | 1127 | return err; |
| 669 | } | 1128 | } |
| @@ -672,20 +1131,17 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
| 672 | struct jffs2_inode_info *f, | 1131 | struct jffs2_inode_info *f, |
| 673 | struct jffs2_raw_inode *latest_node) | 1132 | struct jffs2_raw_inode *latest_node) |
| 674 | { | 1133 | { |
| 675 | struct jffs2_tmp_dnode_info *tn; | 1134 | struct jffs2_readinode_info rii; |
| 676 | struct rb_root tn_list; | 1135 | uint32_t crc, new_size; |
| 677 | struct rb_node *rb, *repl_rb; | ||
| 678 | struct jffs2_full_dirent *fd_list; | ||
| 679 | struct jffs2_full_dnode *fn, *first_fn = NULL; | ||
| 680 | uint32_t crc; | ||
| 681 | uint32_t latest_mctime, mctime_ver; | ||
| 682 | size_t retlen; | 1136 | size_t retlen; |
| 683 | int ret; | 1137 | int ret; |
| 684 | 1138 | ||
| 685 | dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink); | 1139 | dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink); |
| 686 | 1140 | ||
| 1141 | memset(&rii, 0, sizeof(rii)); | ||
| 1142 | |||
| 687 | /* Grab all nodes relevant to this ino */ | 1143 | /* Grab all nodes relevant to this ino */ |
| 688 | ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); | 1144 | ret = jffs2_get_inode_nodes(c, f, &rii); |
| 689 | 1145 | ||
| 690 | if (ret) { | 1146 | if (ret) { |
| 691 | JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret); | 1147 | JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret); |
| @@ -693,74 +1149,42 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
| 693 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); | 1149 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
| 694 | return ret; | 1150 | return ret; |
| 695 | } | 1151 | } |
| 696 | f->dents = fd_list; | ||
| 697 | |||
| 698 | rb = rb_first(&tn_list); | ||
| 699 | 1152 | ||
| 700 | while (rb) { | 1153 | ret = jffs2_build_inode_fragtree(c, f, &rii); |
| 701 | cond_resched(); | 1154 | if (ret) { |
| 702 | tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); | 1155 | JFFS2_ERROR("Failed to build final fragtree for inode #%u: error %d\n", |
| 703 | fn = tn->fn; | 1156 | f->inocache->ino, ret); |
| 704 | ret = 1; | 1157 | if (f->inocache->state == INO_STATE_READING) |
| 705 | dbg_readinode("consider node ver %u, phys offset " | 1158 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
| 706 | "%#08x(%d), range %u-%u.\n", tn->version, | 1159 | jffs2_free_tmp_dnode_info_list(&rii.tn_root); |
| 707 | ref_offset(fn->raw), ref_flags(fn->raw), | 1160 | /* FIXME: We could at least crc-check them all */ |
| 708 | fn->ofs, fn->ofs + fn->size); | 1161 | if (rii.mdata_tn) { |
| 709 | 1162 | jffs2_free_full_dnode(rii.mdata_tn->fn); | |
| 710 | if (fn->size) { | 1163 | jffs2_free_tmp_dnode_info(rii.mdata_tn); |
| 711 | ret = jffs2_add_older_frag_to_fragtree(c, f, tn); | 1164 | rii.mdata_tn = NULL; |
| 712 | /* TODO: the error code isn't checked, check it */ | 1165 | } |
| 713 | jffs2_dbg_fragtree_paranoia_check_nolock(f); | 1166 | return ret; |
| 714 | BUG_ON(ret < 0); | 1167 | } |
| 715 | if (!first_fn && ret == 0) | ||
| 716 | first_fn = fn; | ||
| 717 | } else if (!first_fn) { | ||
| 718 | first_fn = fn; | ||
| 719 | f->metadata = fn; | ||
| 720 | ret = 0; /* Prevent freeing the metadata update node */ | ||
| 721 | } else | ||
| 722 | jffs2_mark_node_obsolete(c, fn->raw); | ||
| 723 | |||
| 724 | BUG_ON(rb->rb_left); | ||
| 725 | if (rb_parent(rb) && rb_parent(rb)->rb_left == rb) { | ||
| 726 | /* We were then left-hand child of our parent. We need | ||
| 727 | * to move our own right-hand child into our place. */ | ||
| 728 | repl_rb = rb->rb_right; | ||
| 729 | if (repl_rb) | ||
| 730 | rb_set_parent(repl_rb, rb_parent(rb)); | ||
| 731 | } else | ||
| 732 | repl_rb = NULL; | ||
| 733 | |||
| 734 | rb = rb_next(rb); | ||
| 735 | |||
| 736 | /* Remove the spent tn from the tree; don't bother rebalancing | ||
| 737 | * but put our right-hand child in our own place. */ | ||
| 738 | if (rb_parent(&tn->rb)) { | ||
| 739 | if (rb_parent(&tn->rb)->rb_left == &tn->rb) | ||
| 740 | rb_parent(&tn->rb)->rb_left = repl_rb; | ||
| 741 | else if (rb_parent(&tn->rb)->rb_right == &tn->rb) | ||
| 742 | rb_parent(&tn->rb)->rb_right = repl_rb; | ||
| 743 | else BUG(); | ||
| 744 | } else if (tn->rb.rb_right) | ||
| 745 | rb_set_parent(tn->rb.rb_right, NULL); | ||
| 746 | 1168 | ||
| 747 | jffs2_free_tmp_dnode_info(tn); | 1169 | if (rii.mdata_tn) { |
| 748 | if (ret) { | 1170 | if (rii.mdata_tn->fn->raw == rii.latest_ref) { |
| 749 | dbg_readinode("delete dnode %u-%u.\n", | 1171 | f->metadata = rii.mdata_tn->fn; |
| 750 | fn->ofs, fn->ofs + fn->size); | 1172 | jffs2_free_tmp_dnode_info(rii.mdata_tn); |
| 751 | jffs2_free_full_dnode(fn); | 1173 | } else { |
| 1174 | jffs2_kill_tn(c, rii.mdata_tn); | ||
| 752 | } | 1175 | } |
| 1176 | rii.mdata_tn = NULL; | ||
| 753 | } | 1177 | } |
| 754 | jffs2_dbg_fragtree_paranoia_check_nolock(f); | ||
| 755 | 1178 | ||
| 756 | BUG_ON(first_fn && ref_obsolete(first_fn->raw)); | 1179 | f->dents = rii.fds; |
| 757 | 1180 | ||
| 758 | fn = first_fn; | 1181 | jffs2_dbg_fragtree_paranoia_check_nolock(f); |
| 759 | if (unlikely(!first_fn)) { | 1182 | |
| 1183 | if (unlikely(!rii.latest_ref)) { | ||
| 760 | /* No data nodes for this inode. */ | 1184 | /* No data nodes for this inode. */ |
| 761 | if (f->inocache->ino != 1) { | 1185 | if (f->inocache->ino != 1) { |
| 762 | JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino); | 1186 | JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino); |
| 763 | if (!fd_list) { | 1187 | if (!rii.fds) { |
| 764 | if (f->inocache->state == INO_STATE_READING) | 1188 | if (f->inocache->state == INO_STATE_READING) |
| 765 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); | 1189 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
| 766 | return -EIO; | 1190 | return -EIO; |
| @@ -778,7 +1202,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
| 778 | return 0; | 1202 | return 0; |
| 779 | } | 1203 | } |
| 780 | 1204 | ||
| 781 | ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); | 1205 | ret = jffs2_flash_read(c, ref_offset(rii.latest_ref), sizeof(*latest_node), &retlen, (void *)latest_node); |
| 782 | if (ret || retlen != sizeof(*latest_node)) { | 1206 | if (ret || retlen != sizeof(*latest_node)) { |
| 783 | JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", | 1207 | JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n", |
| 784 | ret, retlen, sizeof(*latest_node)); | 1208 | ret, retlen, sizeof(*latest_node)); |
| @@ -791,7 +1215,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
| 791 | crc = crc32(0, latest_node, sizeof(*latest_node)-8); | 1215 | crc = crc32(0, latest_node, sizeof(*latest_node)-8); |
| 792 | if (crc != je32_to_cpu(latest_node->node_crc)) { | 1216 | if (crc != je32_to_cpu(latest_node->node_crc)) { |
| 793 | JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", | 1217 | JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n", |
| 794 | f->inocache->ino, ref_offset(fn->raw)); | 1218 | f->inocache->ino, ref_offset(rii.latest_ref)); |
| 795 | up(&f->sem); | 1219 | up(&f->sem); |
| 796 | jffs2_do_clear_inode(c, f); | 1220 | jffs2_do_clear_inode(c, f); |
| 797 | return -EIO; | 1221 | return -EIO; |
| @@ -799,17 +1223,22 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
| 799 | 1223 | ||
| 800 | switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { | 1224 | switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { |
| 801 | case S_IFDIR: | 1225 | case S_IFDIR: |
| 802 | if (mctime_ver > je32_to_cpu(latest_node->version)) { | 1226 | if (rii.mctime_ver > je32_to_cpu(latest_node->version)) { |
| 803 | /* The times in the latest_node are actually older than | 1227 | /* The times in the latest_node are actually older than |
| 804 | mctime in the latest dirent. Cheat. */ | 1228 | mctime in the latest dirent. Cheat. */ |
| 805 | latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime); | 1229 | latest_node->ctime = latest_node->mtime = cpu_to_je32(rii.latest_mctime); |
| 806 | } | 1230 | } |
| 807 | break; | 1231 | break; |
| 808 | 1232 | ||
| 809 | 1233 | ||
| 810 | case S_IFREG: | 1234 | case S_IFREG: |
| 811 | /* If it was a regular file, truncate it to the latest node's isize */ | 1235 | /* If it was a regular file, truncate it to the latest node's isize */ |
| 812 | jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); | 1236 | new_size = jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); |
| 1237 | if (new_size != je32_to_cpu(latest_node->isize)) { | ||
| 1238 | JFFS2_WARNING("Truncating ino #%u to %d bytes failed because it only had %d bytes to start with!\n", | ||
| 1239 | f->inocache->ino, je32_to_cpu(latest_node->isize), new_size); | ||
| 1240 | latest_node->isize = cpu_to_je32(new_size); | ||
| 1241 | } | ||
| 813 | break; | 1242 | break; |
| 814 | 1243 | ||
| 815 | case S_IFLNK: | 1244 | case S_IFLNK: |
| @@ -832,7 +1261,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
| 832 | return -ENOMEM; | 1261 | return -ENOMEM; |
| 833 | } | 1262 | } |
| 834 | 1263 | ||
| 835 | ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), | 1264 | ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node), |
| 836 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->target); | 1265 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->target); |
| 837 | 1266 | ||
| 838 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { | 1267 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 7fb45bd4915c..2a1c976c7924 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
| @@ -1,15 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: scan.c,v 1.125 2005/09/30 13:59:13 dedekind Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 11 | |||
| 13 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 14 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
| 15 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| @@ -636,16 +635,17 @@ scan_more: | |||
| 636 | 635 | ||
| 637 | if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) { | 636 | if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) { |
| 638 | uint32_t inbuf_ofs; | 637 | uint32_t inbuf_ofs; |
| 639 | uint32_t empty_start; | 638 | uint32_t empty_start, scan_end; |
| 640 | 639 | ||
| 641 | empty_start = ofs; | 640 | empty_start = ofs; |
| 642 | ofs += 4; | 641 | ofs += 4; |
| 642 | scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(c->sector_size)/8, buf_len); | ||
| 643 | 643 | ||
| 644 | D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs)); | 644 | D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs)); |
| 645 | more_empty: | 645 | more_empty: |
| 646 | inbuf_ofs = ofs - buf_ofs; | 646 | inbuf_ofs = ofs - buf_ofs; |
| 647 | while (inbuf_ofs < buf_len) { | 647 | while (inbuf_ofs < scan_end) { |
| 648 | if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) { | 648 | if (unlikely(*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)) { |
| 649 | printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", | 649 | printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", |
| 650 | empty_start, ofs); | 650 | empty_start, ofs); |
| 651 | if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start))) | 651 | if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start))) |
| @@ -666,7 +666,11 @@ scan_more: | |||
| 666 | D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); | 666 | D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); |
| 667 | return BLK_STATE_CLEANMARKER; | 667 | return BLK_STATE_CLEANMARKER; |
| 668 | } | 668 | } |
| 669 | 669 | if (!buf_size && (scan_end != buf_len)) {/* XIP/point case */ | |
| 670 | scan_end = buf_len; | ||
| 671 | goto more_empty; | ||
| 672 | } | ||
| 673 | |||
| 670 | /* See how much more there is to read in this eraseblock... */ | 674 | /* See how much more there is to read in this eraseblock... */ |
| 671 | buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); | 675 | buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); |
| 672 | if (!buf_len) { | 676 | if (!buf_len) { |
| @@ -676,6 +680,8 @@ scan_more: | |||
| 676 | empty_start)); | 680 | empty_start)); |
| 677 | break; | 681 | break; |
| 678 | } | 682 | } |
| 683 | /* point never reaches here */ | ||
| 684 | scan_end = buf_len; | ||
| 679 | D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs)); | 685 | D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs)); |
| 680 | err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); | 686 | err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); |
| 681 | if (err) | 687 | if (err) |
| @@ -734,18 +740,8 @@ scan_more: | |||
| 734 | ofs += 4; | 740 | ofs += 4; |
| 735 | continue; | 741 | continue; |
| 736 | } | 742 | } |
| 737 | /* Due to poor choice of crc32 seed, an all-zero node will have a correct CRC */ | ||
| 738 | if (!je32_to_cpu(node->hdr_crc) && !je16_to_cpu(node->nodetype) && | ||
| 739 | !je16_to_cpu(node->magic) && !je32_to_cpu(node->totlen)) { | ||
| 740 | noisy_printk(&noise, "jffs2_scan_eraseblock(): All zero node header at 0x%08x.\n", ofs); | ||
| 741 | if ((err = jffs2_scan_dirty_space(c, jeb, 4))) | ||
| 742 | return err; | ||
| 743 | ofs += 4; | ||
| 744 | continue; | ||
| 745 | } | ||
| 746 | 743 | ||
| 747 | if (ofs + je32_to_cpu(node->totlen) > | 744 | if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) { |
| 748 | jeb->offset + c->sector_size) { | ||
| 749 | /* Eep. Node goes over the end of the erase block. */ | 745 | /* Eep. Node goes over the end of the erase block. */ |
| 750 | printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", | 746 | printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", |
| 751 | ofs, je32_to_cpu(node->totlen)); | 747 | ofs, je32_to_cpu(node->totlen)); |
| @@ -952,8 +948,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
| 952 | struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s) | 948 | struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s) |
| 953 | { | 949 | { |
| 954 | struct jffs2_inode_cache *ic; | 950 | struct jffs2_inode_cache *ic; |
| 955 | uint32_t ino = je32_to_cpu(ri->ino); | 951 | uint32_t crc, ino = je32_to_cpu(ri->ino); |
| 956 | int err; | ||
| 957 | 952 | ||
| 958 | D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); | 953 | D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); |
| 959 | 954 | ||
| @@ -966,21 +961,22 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc | |||
| 966 | Which means that the _full_ amount of time to get to proper write mode with GC | 961 | Which means that the _full_ amount of time to get to proper write mode with GC |
| 967 | operational may actually be _longer_ than before. Sucks to be me. */ | 962 | operational may actually be _longer_ than before. Sucks to be me. */ |
| 968 | 963 | ||
| 964 | /* Check the node CRC in any case. */ | ||
| 965 | crc = crc32(0, ri, sizeof(*ri)-8); | ||
| 966 | if (crc != je32_to_cpu(ri->node_crc)) { | ||
| 967 | printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on " | ||
| 968 | "node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", | ||
| 969 | ofs, je32_to_cpu(ri->node_crc), crc); | ||
| 970 | /* | ||
| 971 | * We believe totlen because the CRC on the node | ||
| 972 | * _header_ was OK, just the node itself failed. | ||
| 973 | */ | ||
| 974 | return jffs2_scan_dirty_space(c, jeb, | ||
| 975 | PAD(je32_to_cpu(ri->totlen))); | ||
| 976 | } | ||
| 977 | |||
| 969 | ic = jffs2_get_ino_cache(c, ino); | 978 | ic = jffs2_get_ino_cache(c, ino); |
| 970 | if (!ic) { | 979 | if (!ic) { |
| 971 | /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the | ||
| 972 | first node we found for this inode. Do a CRC check to protect against the former | ||
| 973 | case */ | ||
| 974 | uint32_t crc = crc32(0, ri, sizeof(*ri)-8); | ||
| 975 | |||
| 976 | if (crc != je32_to_cpu(ri->node_crc)) { | ||
| 977 | printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", | ||
| 978 | ofs, je32_to_cpu(ri->node_crc), crc); | ||
| 979 | /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ | ||
| 980 | if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(ri->totlen))))) | ||
| 981 | return err; | ||
| 982 | return 0; | ||
| 983 | } | ||
| 984 | ic = jffs2_scan_make_ino_cache(c, ino); | 980 | ic = jffs2_scan_make_ino_cache(c, ino); |
| 985 | if (!ic) | 981 | if (!ic) |
| 986 | return -ENOMEM; | 982 | return -ENOMEM; |
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c index 52a9894a6364..bc9f6ba10823 100644 --- a/fs/jffs2/security.c +++ b/fs/jffs2/security.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2006 NEC Corporation | 4 | * Copyright © 2006 NEC Corporation |
| 5 | * | 5 | * |
| 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> | 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | */ | 10 | */ |
| 11 | |||
| 11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 12 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 13 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 30f888414ce7..d828b296392a 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c | |||
| @@ -1,16 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
| 5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, | 5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, |
| 6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, | 6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, |
| 7 | * University of Szeged, Hungary | 7 | * University of Szeged, Hungary |
| 8 | * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> | 8 | * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> |
| 9 | * | 9 | * |
| 10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
| 11 | * | 11 | * |
| 12 | * $Id: summary.c,v 1.4 2005/09/26 11:37:21 havasi Exp $ | ||
| 13 | * | ||
| 14 | */ | 12 | */ |
| 15 | 13 | ||
| 16 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index 6bf1f6aa4552..0c6669e21390 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h | |||
| @@ -1,15 +1,13 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
| 5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, | 5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, |
| 6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, | 6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, |
| 7 | * University of Szeged, Hungary | 7 | * University of Szeged, Hungary |
| 8 | * | 8 | * |
| 9 | * For licensing information, see the file 'LICENCE' in this directory. | 9 | * For licensing information, see the file 'LICENCE' in this directory. |
| 10 | * | 10 | * |
| 11 | * $Id: summary.h,v 1.2 2005/09/26 11:37:21 havasi Exp $ | ||
| 12 | * | ||
| 13 | */ | 11 | */ |
| 14 | 12 | ||
| 15 | #ifndef JFFS2_SUMMARY_H | 13 | #ifndef JFFS2_SUMMARY_H |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index cc7e8e71ad46..e51164a8a8d4 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| @@ -347,7 +345,7 @@ static int __init init_jffs2_fs(void) | |||
| 347 | #ifdef CONFIG_JFFS2_SUMMARY | 345 | #ifdef CONFIG_JFFS2_SUMMARY |
| 348 | " (SUMMARY) " | 346 | " (SUMMARY) " |
| 349 | #endif | 347 | #endif |
| 350 | " (C) 2001-2006 Red Hat, Inc.\n"); | 348 | " © 2001-2006 Red Hat, Inc.\n"); |
| 351 | 349 | ||
| 352 | jffs2_inode_cachep = kmem_cache_create("jffs2_i", | 350 | jffs2_inode_cachep = kmem_cache_create("jffs2_i", |
| 353 | sizeof(struct jffs2_inode_info), | 351 | sizeof(struct jffs2_inode_info), |
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 7e4882c8a7ed..b7339c3b6ad9 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c | |||
| @@ -1,17 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001, 2002 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: symlink.c,v 1.19 2005/11/07 11:14:42 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | |||
| 15 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 16 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 17 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index ab86031b3c07..c556e85a565c 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
| @@ -1,16 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de> | 5 | * Copyright © 2004 Thomas Gleixner <tglx@linutronix.de> |
| 6 | * | 6 | * |
| 7 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 8 | * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de> | 8 | * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de> |
| 9 | * | 9 | * |
| 10 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
| 11 | * | 11 | * |
| 12 | * $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $ | ||
| 13 | * | ||
| 14 | */ | 12 | */ |
| 15 | 13 | ||
| 16 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| @@ -345,6 +343,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) | |||
| 345 | return; | 343 | return; |
| 346 | } | 344 | } |
| 347 | 345 | ||
| 346 | /* The summary is not recovered, so it must be disabled for this erase block */ | ||
| 347 | jffs2_sum_disable_collecting(c->summary); | ||
| 348 | |||
| 348 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); | 349 | ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile); |
| 349 | if (ret) { | 350 | if (ret) { |
| 350 | printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n"); | 351 | printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n"); |
| @@ -967,9 +968,9 @@ exit: | |||
| 967 | 968 | ||
| 968 | static const struct jffs2_unknown_node oob_cleanmarker = | 969 | static const struct jffs2_unknown_node oob_cleanmarker = |
| 969 | { | 970 | { |
| 970 | .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK), | 971 | .magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK), |
| 971 | .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), | 972 | .nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), |
| 972 | .totlen = cpu_to_je32(8) | 973 | .totlen = constant_cpu_to_je32(8) |
| 973 | }; | 974 | }; |
| 974 | 975 | ||
| 975 | /* | 976 | /* |
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 67176792e138..c9fe0ab3a329 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2003 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| @@ -507,8 +505,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
| 507 | uint32_t alloclen; | 505 | uint32_t alloclen; |
| 508 | int ret; | 506 | int ret; |
| 509 | 507 | ||
| 510 | if (1 /* alternative branch needs testing */ || | 508 | if (!jffs2_can_mark_obsolete(c)) { |
| 511 | !jffs2_can_mark_obsolete(c)) { | ||
| 512 | /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */ | 509 | /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */ |
| 513 | 510 | ||
| 514 | rd = jffs2_alloc_raw_dirent(); | 511 | rd = jffs2_alloc_raw_dirent(); |
diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c index c638ae1008de..b9276b11bac6 100644 --- a/fs/jffs2/writev.c +++ b/fs/jffs2/writev.c | |||
| @@ -1,14 +1,12 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001, 2002 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * | 5 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 6 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | * $Id: writev.c,v 1.8 2005/09/09 15:11:58 havasi Exp $ | ||
| 11 | * | ||
| 12 | */ | 10 | */ |
| 13 | 11 | ||
| 14 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index 4bb3f1897330..78fc08893a6c 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2006 NEC Corporation | 4 | * Copyright © 2006 NEC Corporation |
| 5 | * | 5 | * |
| 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> | 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | */ | 10 | */ |
| 11 | |||
| 11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 12 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 13 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h index 06a5c69dcf8b..3b0ff2925937 100644 --- a/fs/jffs2/xattr.h +++ b/fs/jffs2/xattr.h | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2006 NEC Corporation | 4 | * Copyright © 2006 NEC Corporation |
| 5 | * | 5 | * |
| 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> | 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | */ | 10 | */ |
| 11 | |||
| 11 | #ifndef _JFFS2_FS_XATTR_H_ | 12 | #ifndef _JFFS2_FS_XATTR_H_ |
| 12 | #define _JFFS2_FS_XATTR_H_ | 13 | #define _JFFS2_FS_XATTR_H_ |
| 13 | 14 | ||
diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c index ed046e19dbfa..8ec5765ef348 100644 --- a/fs/jffs2/xattr_trusted.c +++ b/fs/jffs2/xattr_trusted.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2006 NEC Corporation | 4 | * Copyright © 2006 NEC Corporation |
| 5 | * | 5 | * |
| 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> | 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | */ | 10 | */ |
| 11 | |||
| 11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 12 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
| 13 | #include <linux/jffs2.h> | 14 | #include <linux/jffs2.h> |
diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c index 2f8e9aa01ea0..40942bc516bb 100644 --- a/fs/jffs2/xattr_user.c +++ b/fs/jffs2/xattr_user.c | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2006 NEC Corporation | 4 | * Copyright © 2006 NEC Corporation |
| 5 | * | 5 | * |
| 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> | 6 | * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> |
| 7 | * | 7 | * |
| 8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 9 | * | 9 | * |
| 10 | */ | 10 | */ |
| 11 | |||
| 11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 12 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
| 13 | #include <linux/jffs2.h> | 14 | #include <linux/jffs2.h> |
diff --git a/include/linux/mtd/iflash.h b/include/linux/mtd/iflash.h deleted file mode 100644 index 9aa5b4f02666..000000000000 --- a/include/linux/mtd/iflash.h +++ /dev/null | |||
| @@ -1,98 +0,0 @@ | |||
| 1 | /* $Id: iflash.h,v 1.2 2000/11/13 18:01:54 dwmw2 Exp $ */ | ||
| 2 | |||
| 3 | #ifndef __MTD_IFLASH_H__ | ||
| 4 | #define __MTD_IFLASH_H__ | ||
| 5 | |||
| 6 | /* Extended CIS registers for Series 2 and 2+ cards */ | ||
| 7 | /* The registers are all offsets from 0x4000 */ | ||
| 8 | #define CISREG_CSR 0x0100 | ||
| 9 | #define CISREG_WP 0x0104 | ||
| 10 | #define CISREG_RDYBSY 0x0140 | ||
| 11 | |||
| 12 | /* Extended CIS registers for Series 2 cards */ | ||
| 13 | #define CISREG_SLEEP 0x0118 | ||
| 14 | #define CISREG_RDY_MASK 0x0120 | ||
| 15 | #define CISREG_RDY_STATUS 0x0130 | ||
| 16 | |||
| 17 | /* Extended CIS registers for Series 2+ cards */ | ||
| 18 | #define CISREG_VCR 0x010c | ||
| 19 | |||
| 20 | /* Card Status Register */ | ||
| 21 | #define CSR_SRESET 0x20 /* Soft reset */ | ||
| 22 | #define CSR_CMWP 0x10 /* Common memory write protect */ | ||
| 23 | #define CSR_PWRDOWN 0x08 /* Power down status */ | ||
| 24 | #define CSR_CISWP 0x04 /* Common memory CIS WP */ | ||
| 25 | #define CSR_WP 0x02 /* Mechanical write protect */ | ||
| 26 | #define CSR_READY 0x01 /* Ready/busy status */ | ||
| 27 | |||
| 28 | /* Write Protection Register */ | ||
| 29 | #define WP_BLKEN 0x04 /* Enable block locking */ | ||
| 30 | #define WP_CMWP 0x02 /* Common memory write protect */ | ||
| 31 | #define WP_CISWP 0x01 /* Common memory CIS WP */ | ||
| 32 | |||
| 33 | /* Voltage Control Register */ | ||
| 34 | #define VCR_VCC_LEVEL 0x80 /* 0 = 5V, 1 = 3.3V */ | ||
| 35 | #define VCR_VPP_VALID 0x02 /* Vpp Valid */ | ||
| 36 | #define VCR_VPP_GEN 0x01 /* Integrated Vpp generator */ | ||
| 37 | |||
| 38 | /* Ready/Busy Mode Register */ | ||
| 39 | #define RDYBSY_RACK 0x02 /* Ready acknowledge */ | ||
| 40 | #define RDYBSY_MODE 0x01 /* 1 = high performance */ | ||
| 41 | |||
| 42 | #define LOW(x) ((x) & 0xff) | ||
| 43 | |||
| 44 | /* 28F008SA-Compatible Command Set */ | ||
| 45 | #define IF_READ_ARRAY 0xffff | ||
| 46 | #define IF_INTEL_ID 0x9090 | ||
| 47 | #define IF_READ_CSR 0x7070 | ||
| 48 | #define IF_CLEAR_CSR 0x5050 | ||
| 49 | #define IF_WRITE 0x4040 | ||
| 50 | #define IF_BLOCK_ERASE 0x2020 | ||
| 51 | #define IF_ERASE_SUSPEND 0xb0b0 | ||
| 52 | #define IF_CONFIRM 0xd0d0 | ||
| 53 | |||
| 54 | /* 28F016SA Performance Enhancement Commands */ | ||
| 55 | #define IF_READ_PAGE 0x7575 | ||
| 56 | #define IF_PAGE_SWAP 0x7272 | ||
| 57 | #define IF_SINGLE_LOAD 0x7474 | ||
| 58 | #define IF_SEQ_LOAD 0xe0e0 | ||
| 59 | #define IF_PAGE_WRITE 0x0c0c | ||
| 60 | #define IF_RDY_MODE 0x9696 | ||
| 61 | #define IF_RDY_LEVEL 0x0101 | ||
| 62 | #define IF_RDY_PULSE_WRITE 0x0202 | ||
| 63 | #define IF_RDY_PULSE_ERASE 0x0303 | ||
| 64 | #define IF_RDY_DISABLE 0x0404 | ||
| 65 | #define IF_LOCK_BLOCK 0x7777 | ||
| 66 | #define IF_UPLOAD_STATUS 0x9797 | ||
| 67 | #define IF_READ_ESR 0x7171 | ||
| 68 | #define IF_ERASE_UNLOCKED 0xa7a7 | ||
| 69 | #define IF_SLEEP 0xf0f0 | ||
| 70 | #define IF_ABORT 0x8080 | ||
| 71 | #define IF_UPLOAD_DEVINFO 0x9999 | ||
| 72 | |||
| 73 | /* Definitions for Compatible Status Register */ | ||
| 74 | #define CSR_WR_READY 0x8080 /* Write state machine status */ | ||
| 75 | #define CSR_ERA_SUSPEND 0x4040 /* Erase suspend status */ | ||
| 76 | #define CSR_ERA_ERR 0x2020 /* Erase status */ | ||
| 77 | #define CSR_WR_ERR 0x1010 /* Data write status */ | ||
| 78 | #define CSR_VPP_LOW 0x0808 /* Vpp status */ | ||
| 79 | |||
| 80 | /* Definitions for Global Status Register */ | ||
| 81 | #define GSR_WR_READY 0x8080 /* Write state machine status */ | ||
| 82 | #define GSR_OP_SUSPEND 0x4040 /* Operation suspend status */ | ||
| 83 | #define GSR_OP_ERR 0x2020 /* Device operation status */ | ||
| 84 | #define GSR_SLEEP 0x1010 /* Device sleep status */ | ||
| 85 | #define GSR_QUEUE_FULL 0x0808 /* Queue status */ | ||
| 86 | #define GSR_PAGE_AVAIL 0x0404 /* Page buffer available status */ | ||
| 87 | #define GSR_PAGE_READY 0x0202 /* Page buffer status */ | ||
| 88 | #define GSR_PAGE_SELECT 0x0101 /* Page buffer select status */ | ||
| 89 | |||
| 90 | /* Definitions for Block Status Register */ | ||
| 91 | #define BSR_READY 0x8080 /* Block status */ | ||
| 92 | #define BSR_UNLOCK 0x4040 /* Block lock status */ | ||
| 93 | #define BSR_FAILED 0x2020 /* Block operation status */ | ||
| 94 | #define BSR_ABORTED 0x1010 /* Operation abort status */ | ||
| 95 | #define BSR_QUEUE_FULL 0x0808 /* Queue status */ | ||
| 96 | #define BSR_VPP_LOW 0x0404 /* Vpp status */ | ||
| 97 | |||
| 98 | #endif /* __MTD_IFLASH_H__ */ | ||
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 3d956c3abb31..45d482ce8397 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
| @@ -53,6 +53,7 @@ struct mtd_erase_region_info { | |||
| 53 | u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ | 53 | u_int32_t offset; /* At which this region starts, from the beginning of the MTD */ |
| 54 | u_int32_t erasesize; /* For this region */ | 54 | u_int32_t erasesize; /* For this region */ |
| 55 | u_int32_t numblocks; /* Number of blocks of erasesize in this region */ | 55 | u_int32_t numblocks; /* Number of blocks of erasesize in this region */ |
| 56 | unsigned long *lockmap; /* If keeping bitmap of locks */ | ||
| 56 | }; | 57 | }; |
| 57 | 58 | ||
| 58 | /* | 59 | /* |
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 97523887fe5d..cf197ad62da6 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
| @@ -431,6 +431,7 @@ struct nand_chip { | |||
| 431 | #define NAND_MFR_RENESAS 0x07 | 431 | #define NAND_MFR_RENESAS 0x07 |
| 432 | #define NAND_MFR_STMICRO 0x20 | 432 | #define NAND_MFR_STMICRO 0x20 |
| 433 | #define NAND_MFR_HYNIX 0xad | 433 | #define NAND_MFR_HYNIX 0xad |
| 434 | #define NAND_MFR_MICRON 0x2c | ||
| 434 | 435 | ||
| 435 | /** | 436 | /** |
| 436 | * struct nand_flash_dev - NAND Flash Device ID Structure | 437 | * struct nand_flash_dev - NAND Flash Device ID Structure |
