diff options
66 files changed, 4848 insertions, 2085 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 8848e8ac705d..e8503341e3b1 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
| @@ -150,6 +150,14 @@ config MTD_AFS_PARTS | |||
| 150 | for your particular device. It won't happen automatically. The | 150 | for your particular device. It won't happen automatically. The |
| 151 | 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. | 151 | 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. |
| 152 | 152 | ||
| 153 | config MTD_OF_PARTS | ||
| 154 | tristate "Flash partition map based on OF description" | ||
| 155 | depends on PPC_OF && MTD_PARTITIONS | ||
| 156 | help | ||
| 157 | This provides a partition parsing function which derives | ||
| 158 | the partition map from the children of the flash node, | ||
| 159 | as described in Documentation/powerpc/booting-without-of.txt. | ||
| 160 | |||
| 153 | comment "User Modules And Translation Layers" | 161 | comment "User Modules And Translation Layers" |
| 154 | 162 | ||
| 155 | config MTD_CHAR | 163 | config MTD_CHAR |
| @@ -286,6 +294,9 @@ config MTD_OOPS | |||
| 286 | buffer in a flash partition where it can be read back at some | 294 | buffer in a flash partition where it can be read back at some |
| 287 | later point. | 295 | later point. |
| 288 | 296 | ||
| 297 | To use, add console=ttyMTDx to the kernel command line, | ||
| 298 | where x is the MTD device number to use. | ||
| 299 | |||
| 289 | source "drivers/mtd/chips/Kconfig" | 300 | source "drivers/mtd/chips/Kconfig" |
| 290 | 301 | ||
| 291 | source "drivers/mtd/maps/Kconfig" | 302 | source "drivers/mtd/maps/Kconfig" |
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 7f0b04b4caa7..538e33d11d46 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile | |||
| @@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o | |||
| 11 | obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o | 11 | obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o |
| 12 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o | 12 | obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o |
| 13 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o | 13 | obj-$(CONFIG_MTD_AFS_PARTS) += afs.o |
| 14 | obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o | ||
| 14 | 15 | ||
| 15 | # 'Users' - code which presents functionality to userspace. | 16 | # 'Users' - code which presents functionality to userspace. |
| 16 | obj-$(CONFIG_MTD_CHAR) += mtdchar.o | 17 | obj-$(CONFIG_MTD_CHAR) += mtdchar.o |
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 1707f98c322c..47794d23a42e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #define I82802AC 0x00ac | 50 | #define I82802AC 0x00ac |
| 51 | #define MANUFACTURER_ST 0x0020 | 51 | #define MANUFACTURER_ST 0x0020 |
| 52 | #define M50LPW080 0x002F | 52 | #define M50LPW080 0x002F |
| 53 | #define AT49BV640D 0x02de | ||
| 53 | 54 | ||
| 54 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 55 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
| 55 | static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 56 | static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
| @@ -157,6 +158,47 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp) | |||
| 157 | } | 158 | } |
| 158 | #endif | 159 | #endif |
| 159 | 160 | ||
| 161 | /* Atmel chips don't use the same PRI format as Intel chips */ | ||
| 162 | static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) | ||
| 163 | { | ||
| 164 | struct map_info *map = mtd->priv; | ||
| 165 | struct cfi_private *cfi = map->fldrv_priv; | ||
| 166 | struct cfi_pri_intelext *extp = cfi->cmdset_priv; | ||
| 167 | struct cfi_pri_atmel atmel_pri; | ||
| 168 | uint32_t features = 0; | ||
| 169 | |||
| 170 | /* Reverse byteswapping */ | ||
| 171 | extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport); | ||
| 172 | extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask); | ||
| 173 | extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr); | ||
| 174 | |||
| 175 | memcpy(&atmel_pri, extp, sizeof(atmel_pri)); | ||
| 176 | memset((char *)extp + 5, 0, sizeof(*extp) - 5); | ||
| 177 | |||
| 178 | printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features); | ||
| 179 | |||
| 180 | if (atmel_pri.Features & 0x01) /* chip erase supported */ | ||
| 181 | features |= (1<<0); | ||
| 182 | if (atmel_pri.Features & 0x02) /* erase suspend supported */ | ||
| 183 | features |= (1<<1); | ||
| 184 | if (atmel_pri.Features & 0x04) /* program suspend supported */ | ||
| 185 | features |= (1<<2); | ||
| 186 | if (atmel_pri.Features & 0x08) /* simultaneous operations supported */ | ||
| 187 | features |= (1<<9); | ||
| 188 | if (atmel_pri.Features & 0x20) /* page mode read supported */ | ||
| 189 | features |= (1<<7); | ||
| 190 | if (atmel_pri.Features & 0x40) /* queued erase supported */ | ||
| 191 | features |= (1<<4); | ||
| 192 | if (atmel_pri.Features & 0x80) /* Protection bits supported */ | ||
| 193 | features |= (1<<6); | ||
| 194 | |||
| 195 | extp->FeatureSupport = features; | ||
| 196 | |||
| 197 | /* burst write mode not supported */ | ||
| 198 | cfi->cfiq->BufWriteTimeoutTyp = 0; | ||
| 199 | cfi->cfiq->BufWriteTimeoutMax = 0; | ||
| 200 | } | ||
| 201 | |||
| 160 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 202 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
| 161 | /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ | 203 | /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ |
| 162 | static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) | 204 | static void fixup_intel_strataflash(struct mtd_info *mtd, void* param) |
| @@ -227,13 +269,20 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param) | |||
| 227 | /* | 269 | /* |
| 228 | * Some chips power-up with all sectors locked by default. | 270 | * Some chips power-up with all sectors locked by default. |
| 229 | */ | 271 | */ |
| 230 | static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param) | 272 | static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param) |
| 231 | { | 273 | { |
| 232 | printk(KERN_INFO "Using auto-unlock on power-up/resume\n" ); | 274 | struct map_info *map = mtd->priv; |
| 233 | mtd->flags |= MTD_STUPID_LOCK; | 275 | struct cfi_private *cfi = map->fldrv_priv; |
| 276 | struct cfi_pri_intelext *cfip = cfi->cmdset_priv; | ||
| 277 | |||
| 278 | if (cfip->FeatureSupport&32) { | ||
| 279 | printk(KERN_INFO "Using auto-unlock on power-up/resume\n" ); | ||
| 280 | mtd->flags |= MTD_POWERUP_LOCK; | ||
| 281 | } | ||
| 234 | } | 282 | } |
| 235 | 283 | ||
| 236 | static struct cfi_fixup cfi_fixup_table[] = { | 284 | static struct cfi_fixup cfi_fixup_table[] = { |
| 285 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, | ||
| 237 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE | 286 | #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE |
| 238 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, | 287 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, |
| 239 | #endif | 288 | #endif |
| @@ -245,7 +294,7 @@ static struct cfi_fixup cfi_fixup_table[] = { | |||
| 245 | #endif | 294 | #endif |
| 246 | { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, | 295 | { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL }, |
| 247 | { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, | 296 | { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL }, |
| 248 | { MANUFACTURER_INTEL, 0x891c, fixup_use_powerup_lock, NULL, }, | 297 | { MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, }, |
| 249 | { 0, 0, NULL, NULL } | 298 | { 0, 0, NULL, NULL } |
| 250 | }; | 299 | }; |
| 251 | 300 | ||
| @@ -277,7 +326,7 @@ read_pri_intelext(struct map_info *map, __u16 adr) | |||
| 277 | return NULL; | 326 | return NULL; |
| 278 | 327 | ||
| 279 | if (extp->MajorVersion != '1' || | 328 | if (extp->MajorVersion != '1' || |
| 280 | (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { | 329 | (extp->MinorVersion < '0' || extp->MinorVersion > '5')) { |
| 281 | printk(KERN_ERR " Unknown Intel/Sharp Extended Query " | 330 | printk(KERN_ERR " Unknown Intel/Sharp Extended Query " |
| 282 | "version %c.%c.\n", extp->MajorVersion, | 331 | "version %c.%c.\n", extp->MajorVersion, |
| 283 | extp->MinorVersion); | 332 | extp->MinorVersion); |
| @@ -752,6 +801,7 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long | |||
| 752 | static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) | 801 | static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) |
| 753 | { | 802 | { |
| 754 | int ret; | 803 | int ret; |
| 804 | DECLARE_WAITQUEUE(wait, current); | ||
| 755 | 805 | ||
| 756 | retry: | 806 | retry: |
| 757 | if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING | 807 | if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING |
| @@ -808,6 +858,20 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
| 808 | spin_unlock(contender->mutex); | 858 | spin_unlock(contender->mutex); |
| 809 | } | 859 | } |
| 810 | 860 | ||
| 861 | /* Check if we already have suspended erase | ||
| 862 | * on this chip. Sleep. */ | ||
| 863 | if (mode == FL_ERASING && shared->erasing | ||
| 864 | && shared->erasing->oldstate == FL_ERASING) { | ||
| 865 | spin_unlock(&shared->lock); | ||
| 866 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 867 | add_wait_queue(&chip->wq, &wait); | ||
| 868 | spin_unlock(chip->mutex); | ||
| 869 | schedule(); | ||
| 870 | remove_wait_queue(&chip->wq, &wait); | ||
| 871 | spin_lock(chip->mutex); | ||
| 872 | goto retry; | ||
| 873 | } | ||
| 874 | |||
| 811 | /* We now own it */ | 875 | /* We now own it */ |
| 812 | shared->writing = chip; | 876 | shared->writing = chip; |
| 813 | if (mode == FL_ERASING) | 877 | if (mode == FL_ERASING) |
| @@ -2294,7 +2358,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd) | |||
| 2294 | struct flchip *chip; | 2358 | struct flchip *chip; |
| 2295 | int ret = 0; | 2359 | int ret = 0; |
| 2296 | 2360 | ||
| 2297 | if ((mtd->flags & MTD_STUPID_LOCK) | 2361 | if ((mtd->flags & MTD_POWERUP_LOCK) |
| 2298 | && extp && (extp->FeatureSupport & (1 << 5))) | 2362 | && extp && (extp->FeatureSupport & (1 << 5))) |
| 2299 | cfi_intelext_save_locks(mtd); | 2363 | cfi_intelext_save_locks(mtd); |
| 2300 | 2364 | ||
| @@ -2405,7 +2469,7 @@ static void cfi_intelext_resume(struct mtd_info *mtd) | |||
| 2405 | spin_unlock(chip->mutex); | 2469 | spin_unlock(chip->mutex); |
| 2406 | } | 2470 | } |
| 2407 | 2471 | ||
| 2408 | if ((mtd->flags & MTD_STUPID_LOCK) | 2472 | if ((mtd->flags & MTD_POWERUP_LOCK) |
| 2409 | && extp && (extp->FeatureSupport & (1 << 5))) | 2473 | && extp && (extp->FeatureSupport & (1 << 5))) |
| 2410 | cfi_intelext_restore_locks(mtd); | 2474 | cfi_intelext_restore_locks(mtd); |
| 2411 | } | 2475 | } |
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 389acc600f5e..d072e87ce4e2 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
| @@ -185,6 +185,10 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param) | |||
| 185 | extp->TopBottom = 2; | 185 | extp->TopBottom = 2; |
| 186 | else | 186 | else |
| 187 | extp->TopBottom = 3; | 187 | extp->TopBottom = 3; |
| 188 | |||
| 189 | /* burst write mode not supported */ | ||
| 190 | cfi->cfiq->BufWriteTimeoutTyp = 0; | ||
| 191 | cfi->cfiq->BufWriteTimeoutMax = 0; | ||
| 188 | } | 192 | } |
| 189 | 193 | ||
| 190 | static void fixup_use_secsi(struct mtd_info *mtd, void *param) | 194 | static void fixup_use_secsi(struct mtd_info *mtd, void *param) |
| @@ -213,10 +217,11 @@ static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param) | |||
| 213 | { | 217 | { |
| 214 | mtd->lock = cfi_atmel_lock; | 218 | mtd->lock = cfi_atmel_lock; |
| 215 | mtd->unlock = cfi_atmel_unlock; | 219 | mtd->unlock = cfi_atmel_unlock; |
| 216 | mtd->flags |= MTD_STUPID_LOCK; | 220 | mtd->flags |= MTD_POWERUP_LOCK; |
| 217 | } | 221 | } |
| 218 | 222 | ||
| 219 | static struct cfi_fixup cfi_fixup_table[] = { | 223 | static struct cfi_fixup cfi_fixup_table[] = { |
| 224 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, | ||
| 220 | #ifdef AMD_BOOTLOC_BUG | 225 | #ifdef AMD_BOOTLOC_BUG |
| 221 | { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, | 226 | { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL }, |
| 222 | #endif | 227 | #endif |
| @@ -229,7 +234,6 @@ static struct cfi_fixup cfi_fixup_table[] = { | |||
| 229 | #if !FORCE_WORD_WRITE | 234 | #if !FORCE_WORD_WRITE |
| 230 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, | 235 | { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, }, |
| 231 | #endif | 236 | #endif |
| 232 | { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL }, | ||
| 233 | { 0, 0, NULL, NULL } | 237 | { 0, 0, NULL, NULL } |
| 234 | }; | 238 | }; |
| 235 | static struct cfi_fixup jedec_fixup_table[] = { | 239 | static struct cfi_fixup jedec_fixup_table[] = { |
| @@ -338,10 +342,12 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
| 338 | /* Modify the unlock address if we are in compatibility mode */ | 342 | /* Modify the unlock address if we are in compatibility mode */ |
| 339 | if ( /* x16 in x8 mode */ | 343 | if ( /* x16 in x8 mode */ |
| 340 | ((cfi->device_type == CFI_DEVICETYPE_X8) && | 344 | ((cfi->device_type == CFI_DEVICETYPE_X8) && |
| 341 | (cfi->cfiq->InterfaceDesc == 2)) || | 345 | (cfi->cfiq->InterfaceDesc == |
| 346 | CFI_INTERFACE_X8_BY_X16_ASYNC)) || | ||
| 342 | /* x32 in x16 mode */ | 347 | /* x32 in x16 mode */ |
| 343 | ((cfi->device_type == CFI_DEVICETYPE_X16) && | 348 | ((cfi->device_type == CFI_DEVICETYPE_X16) && |
| 344 | (cfi->cfiq->InterfaceDesc == 4))) | 349 | (cfi->cfiq->InterfaceDesc == |
| 350 | CFI_INTERFACE_X16_BY_X32_ASYNC))) | ||
| 345 | { | 351 | { |
| 346 | cfi->addr_unlock1 = 0xaaa; | 352 | cfi->addr_unlock1 = 0xaaa; |
| 347 | cfi->addr_unlock2 = 0x555; | 353 | cfi->addr_unlock2 = 0x555; |
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c index 60e11a0ada97..f651b6ef1c5d 100644 --- a/drivers/mtd/chips/cfi_probe.c +++ b/drivers/mtd/chips/cfi_probe.c | |||
| @@ -370,27 +370,27 @@ static void print_cfi_ident(struct cfi_ident *cfip) | |||
| 370 | printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20)); | 370 | printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20)); |
| 371 | printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc); | 371 | printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc); |
| 372 | switch(cfip->InterfaceDesc) { | 372 | switch(cfip->InterfaceDesc) { |
| 373 | case 0: | 373 | case CFI_INTERFACE_X8_ASYNC: |
| 374 | printk(" - x8-only asynchronous interface\n"); | 374 | printk(" - x8-only asynchronous interface\n"); |
| 375 | break; | 375 | break; |
| 376 | 376 | ||
| 377 | case 1: | 377 | case CFI_INTERFACE_X16_ASYNC: |
| 378 | printk(" - x16-only asynchronous interface\n"); | 378 | printk(" - x16-only asynchronous interface\n"); |
| 379 | break; | 379 | break; |
| 380 | 380 | ||
| 381 | case 2: | 381 | case CFI_INTERFACE_X8_BY_X16_ASYNC: |
| 382 | printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n"); | 382 | printk(" - supports x8 and x16 via BYTE# with asynchronous interface\n"); |
| 383 | break; | 383 | break; |
| 384 | 384 | ||
| 385 | case 3: | 385 | case CFI_INTERFACE_X32_ASYNC: |
| 386 | printk(" - x32-only asynchronous interface\n"); | 386 | printk(" - x32-only asynchronous interface\n"); |
| 387 | break; | 387 | break; |
| 388 | 388 | ||
| 389 | case 4: | 389 | case CFI_INTERFACE_X16_BY_X32_ASYNC: |
| 390 | printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); | 390 | printk(" - supports x16 and x32 via Word# with asynchronous interface\n"); |
| 391 | break; | 391 | break; |
| 392 | 392 | ||
| 393 | case 65535: | 393 | case CFI_INTERFACE_NOT_ALLOWED: |
| 394 | printk(" - Not Allowed / Reserved\n"); | 394 | printk(" - Not Allowed / Reserved\n"); |
| 395 | break; | 395 | break; |
| 396 | 396 | ||
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index 2eb696d7b97b..d338b8c92780 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c | |||
| @@ -112,7 +112,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi | |||
| 112 | max_chips = 1; | 112 | max_chips = 1; |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG; | 115 | mapsize = sizeof(long) * ( (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG ); |
| 116 | chip_map = kzalloc(mapsize, GFP_KERNEL); | 116 | chip_map = kzalloc(mapsize, GFP_KERNEL); |
| 117 | if (!chip_map) { | 117 | if (!chip_map) { |
| 118 | printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); | 118 | printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); |
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index a67b23b87fc0..4be51a86a85c 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c | |||
| @@ -194,8 +194,8 @@ enum uaddr { | |||
| 194 | 194 | ||
| 195 | 195 | ||
| 196 | struct unlock_addr { | 196 | struct unlock_addr { |
| 197 | u32 addr1; | 197 | uint32_t addr1; |
| 198 | u32 addr2; | 198 | uint32_t addr2; |
| 199 | }; | 199 | }; |
| 200 | 200 | ||
| 201 | 201 | ||
| @@ -246,16 +246,16 @@ static const struct unlock_addr unlock_addrs[] = { | |||
| 246 | } | 246 | } |
| 247 | }; | 247 | }; |
| 248 | 248 | ||
| 249 | |||
| 250 | struct amd_flash_info { | 249 | struct amd_flash_info { |
| 251 | const __u16 mfr_id; | ||
| 252 | const __u16 dev_id; | ||
| 253 | const char *name; | 250 | const char *name; |
| 254 | const int DevSize; | 251 | const uint16_t mfr_id; |
| 255 | const int NumEraseRegions; | 252 | const uint16_t dev_id; |
| 256 | const int CmdSet; | 253 | const uint8_t dev_size; |
| 257 | const __u8 uaddr[4]; /* unlock addrs for 8, 16, 32, 64 */ | 254 | const uint8_t nr_regions; |
| 258 | const ulong regions[6]; | 255 | const uint16_t cmd_set; |
| 256 | const uint32_t regions[6]; | ||
| 257 | const uint8_t devtypes; /* Bitmask for x8, x16 etc. */ | ||
| 258 | const uint8_t uaddr; /* unlock addrs for 8, 16, 32, 64 */ | ||
| 259 | }; | 259 | }; |
| 260 | 260 | ||
| 261 | #define ERASEINFO(size,blocks) (size<<8)|(blocks-1) | 261 | #define ERASEINFO(size,blocks) (size<<8)|(blocks-1) |
| @@ -280,12 +280,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 280 | .mfr_id = MANUFACTURER_AMD, | 280 | .mfr_id = MANUFACTURER_AMD, |
| 281 | .dev_id = AM29F032B, | 281 | .dev_id = AM29F032B, |
| 282 | .name = "AMD AM29F032B", | 282 | .name = "AMD AM29F032B", |
| 283 | .uaddr = { | 283 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 284 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 284 | .devtypes = CFI_DEVICETYPE_X8, |
| 285 | }, | 285 | .dev_size = SIZE_4MiB, |
| 286 | .DevSize = SIZE_4MiB, | 286 | .cmd_set = P_ID_AMD_STD, |
| 287 | .CmdSet = P_ID_AMD_STD, | 287 | .nr_regions = 1, |
| 288 | .NumEraseRegions= 1, | ||
| 289 | .regions = { | 288 | .regions = { |
| 290 | ERASEINFO(0x10000,64) | 289 | ERASEINFO(0x10000,64) |
| 291 | } | 290 | } |
| @@ -293,13 +292,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 293 | .mfr_id = MANUFACTURER_AMD, | 292 | .mfr_id = MANUFACTURER_AMD, |
| 294 | .dev_id = AM29LV160DT, | 293 | .dev_id = AM29LV160DT, |
| 295 | .name = "AMD AM29LV160DT", | 294 | .name = "AMD AM29LV160DT", |
| 296 | .uaddr = { | 295 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 297 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 296 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 298 | [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ | 297 | .dev_size = SIZE_2MiB, |
| 299 | }, | 298 | .cmd_set = P_ID_AMD_STD, |
| 300 | .DevSize = SIZE_2MiB, | 299 | .nr_regions = 4, |
| 301 | .CmdSet = P_ID_AMD_STD, | ||
| 302 | .NumEraseRegions= 4, | ||
| 303 | .regions = { | 300 | .regions = { |
| 304 | ERASEINFO(0x10000,31), | 301 | ERASEINFO(0x10000,31), |
| 305 | ERASEINFO(0x08000,1), | 302 | ERASEINFO(0x08000,1), |
| @@ -310,13 +307,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 310 | .mfr_id = MANUFACTURER_AMD, | 307 | .mfr_id = MANUFACTURER_AMD, |
| 311 | .dev_id = AM29LV160DB, | 308 | .dev_id = AM29LV160DB, |
| 312 | .name = "AMD AM29LV160DB", | 309 | .name = "AMD AM29LV160DB", |
| 313 | .uaddr = { | 310 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 314 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 311 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 315 | [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ | 312 | .dev_size = SIZE_2MiB, |
| 316 | }, | 313 | .cmd_set = P_ID_AMD_STD, |
| 317 | .DevSize = SIZE_2MiB, | 314 | .nr_regions = 4, |
| 318 | .CmdSet = P_ID_AMD_STD, | ||
| 319 | .NumEraseRegions= 4, | ||
| 320 | .regions = { | 315 | .regions = { |
| 321 | ERASEINFO(0x04000,1), | 316 | ERASEINFO(0x04000,1), |
| 322 | ERASEINFO(0x02000,2), | 317 | ERASEINFO(0x02000,2), |
| @@ -327,13 +322,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 327 | .mfr_id = MANUFACTURER_AMD, | 322 | .mfr_id = MANUFACTURER_AMD, |
| 328 | .dev_id = AM29LV400BB, | 323 | .dev_id = AM29LV400BB, |
| 329 | .name = "AMD AM29LV400BB", | 324 | .name = "AMD AM29LV400BB", |
| 330 | .uaddr = { | 325 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 331 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 326 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 332 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 327 | .dev_size = SIZE_512KiB, |
| 333 | }, | 328 | .cmd_set = P_ID_AMD_STD, |
| 334 | .DevSize = SIZE_512KiB, | 329 | .nr_regions = 4, |
| 335 | .CmdSet = P_ID_AMD_STD, | ||
| 336 | .NumEraseRegions= 4, | ||
| 337 | .regions = { | 330 | .regions = { |
| 338 | ERASEINFO(0x04000,1), | 331 | ERASEINFO(0x04000,1), |
| 339 | ERASEINFO(0x02000,2), | 332 | ERASEINFO(0x02000,2), |
| @@ -344,13 +337,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 344 | .mfr_id = MANUFACTURER_AMD, | 337 | .mfr_id = MANUFACTURER_AMD, |
| 345 | .dev_id = AM29LV400BT, | 338 | .dev_id = AM29LV400BT, |
| 346 | .name = "AMD AM29LV400BT", | 339 | .name = "AMD AM29LV400BT", |
| 347 | .uaddr = { | 340 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 348 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 341 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 349 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 342 | .dev_size = SIZE_512KiB, |
| 350 | }, | 343 | .cmd_set = P_ID_AMD_STD, |
| 351 | .DevSize = SIZE_512KiB, | 344 | .nr_regions = 4, |
| 352 | .CmdSet = P_ID_AMD_STD, | ||
| 353 | .NumEraseRegions= 4, | ||
| 354 | .regions = { | 345 | .regions = { |
| 355 | ERASEINFO(0x10000,7), | 346 | ERASEINFO(0x10000,7), |
| 356 | ERASEINFO(0x08000,1), | 347 | ERASEINFO(0x08000,1), |
| @@ -361,13 +352,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 361 | .mfr_id = MANUFACTURER_AMD, | 352 | .mfr_id = MANUFACTURER_AMD, |
| 362 | .dev_id = AM29LV800BB, | 353 | .dev_id = AM29LV800BB, |
| 363 | .name = "AMD AM29LV800BB", | 354 | .name = "AMD AM29LV800BB", |
| 364 | .uaddr = { | 355 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 365 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 356 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 366 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 357 | .dev_size = SIZE_1MiB, |
| 367 | }, | 358 | .cmd_set = P_ID_AMD_STD, |
| 368 | .DevSize = SIZE_1MiB, | 359 | .nr_regions = 4, |
| 369 | .CmdSet = P_ID_AMD_STD, | ||
| 370 | .NumEraseRegions= 4, | ||
| 371 | .regions = { | 360 | .regions = { |
| 372 | ERASEINFO(0x04000,1), | 361 | ERASEINFO(0x04000,1), |
| 373 | ERASEINFO(0x02000,2), | 362 | ERASEINFO(0x02000,2), |
| @@ -379,13 +368,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 379 | .mfr_id = MANUFACTURER_AMD, | 368 | .mfr_id = MANUFACTURER_AMD, |
| 380 | .dev_id = AM29DL800BB, | 369 | .dev_id = AM29DL800BB, |
| 381 | .name = "AMD AM29DL800BB", | 370 | .name = "AMD AM29DL800BB", |
| 382 | .uaddr = { | 371 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 383 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 372 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 384 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 373 | .dev_size = SIZE_1MiB, |
| 385 | }, | 374 | .cmd_set = P_ID_AMD_STD, |
| 386 | .DevSize = SIZE_1MiB, | 375 | .nr_regions = 6, |
| 387 | .CmdSet = P_ID_AMD_STD, | ||
| 388 | .NumEraseRegions= 6, | ||
| 389 | .regions = { | 376 | .regions = { |
| 390 | ERASEINFO(0x04000,1), | 377 | ERASEINFO(0x04000,1), |
| 391 | ERASEINFO(0x08000,1), | 378 | ERASEINFO(0x08000,1), |
| @@ -398,13 +385,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 398 | .mfr_id = MANUFACTURER_AMD, | 385 | .mfr_id = MANUFACTURER_AMD, |
| 399 | .dev_id = AM29DL800BT, | 386 | .dev_id = AM29DL800BT, |
| 400 | .name = "AMD AM29DL800BT", | 387 | .name = "AMD AM29DL800BT", |
| 401 | .uaddr = { | 388 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 402 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 389 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 403 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 390 | .dev_size = SIZE_1MiB, |
| 404 | }, | 391 | .cmd_set = P_ID_AMD_STD, |
| 405 | .DevSize = SIZE_1MiB, | 392 | .nr_regions = 6, |
| 406 | .CmdSet = P_ID_AMD_STD, | ||
| 407 | .NumEraseRegions= 6, | ||
| 408 | .regions = { | 393 | .regions = { |
| 409 | ERASEINFO(0x10000,14), | 394 | ERASEINFO(0x10000,14), |
| 410 | ERASEINFO(0x04000,1), | 395 | ERASEINFO(0x04000,1), |
| @@ -417,13 +402,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 417 | .mfr_id = MANUFACTURER_AMD, | 402 | .mfr_id = MANUFACTURER_AMD, |
| 418 | .dev_id = AM29F800BB, | 403 | .dev_id = AM29F800BB, |
| 419 | .name = "AMD AM29F800BB", | 404 | .name = "AMD AM29F800BB", |
| 420 | .uaddr = { | 405 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 421 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 406 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 422 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 407 | .dev_size = SIZE_1MiB, |
| 423 | }, | 408 | .cmd_set = P_ID_AMD_STD, |
| 424 | .DevSize = SIZE_1MiB, | 409 | .nr_regions = 4, |
| 425 | .CmdSet = P_ID_AMD_STD, | ||
| 426 | .NumEraseRegions= 4, | ||
| 427 | .regions = { | 410 | .regions = { |
| 428 | ERASEINFO(0x04000,1), | 411 | ERASEINFO(0x04000,1), |
| 429 | ERASEINFO(0x02000,2), | 412 | ERASEINFO(0x02000,2), |
| @@ -434,13 +417,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 434 | .mfr_id = MANUFACTURER_AMD, | 417 | .mfr_id = MANUFACTURER_AMD, |
| 435 | .dev_id = AM29LV800BT, | 418 | .dev_id = AM29LV800BT, |
| 436 | .name = "AMD AM29LV800BT", | 419 | .name = "AMD AM29LV800BT", |
| 437 | .uaddr = { | 420 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 438 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 421 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 439 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 422 | .dev_size = SIZE_1MiB, |
| 440 | }, | 423 | .cmd_set = P_ID_AMD_STD, |
| 441 | .DevSize = SIZE_1MiB, | 424 | .nr_regions = 4, |
| 442 | .CmdSet = P_ID_AMD_STD, | ||
| 443 | .NumEraseRegions= 4, | ||
| 444 | .regions = { | 425 | .regions = { |
| 445 | ERASEINFO(0x10000,15), | 426 | ERASEINFO(0x10000,15), |
| 446 | ERASEINFO(0x08000,1), | 427 | ERASEINFO(0x08000,1), |
| @@ -451,13 +432,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 451 | .mfr_id = MANUFACTURER_AMD, | 432 | .mfr_id = MANUFACTURER_AMD, |
| 452 | .dev_id = AM29F800BT, | 433 | .dev_id = AM29F800BT, |
| 453 | .name = "AMD AM29F800BT", | 434 | .name = "AMD AM29F800BT", |
| 454 | .uaddr = { | 435 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 455 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 436 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 456 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 437 | .dev_size = SIZE_1MiB, |
| 457 | }, | 438 | .cmd_set = P_ID_AMD_STD, |
| 458 | .DevSize = SIZE_1MiB, | 439 | .nr_regions = 4, |
| 459 | .CmdSet = P_ID_AMD_STD, | ||
| 460 | .NumEraseRegions= 4, | ||
| 461 | .regions = { | 440 | .regions = { |
| 462 | ERASEINFO(0x10000,15), | 441 | ERASEINFO(0x10000,15), |
| 463 | ERASEINFO(0x08000,1), | 442 | ERASEINFO(0x08000,1), |
| @@ -468,12 +447,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 468 | .mfr_id = MANUFACTURER_AMD, | 447 | .mfr_id = MANUFACTURER_AMD, |
| 469 | .dev_id = AM29F017D, | 448 | .dev_id = AM29F017D, |
| 470 | .name = "AMD AM29F017D", | 449 | .name = "AMD AM29F017D", |
| 471 | .uaddr = { | 450 | .devtypes = CFI_DEVICETYPE_X8, |
| 472 | [0] = MTD_UADDR_DONT_CARE /* x8 */ | 451 | .uaddr = MTD_UADDR_DONT_CARE, |
| 473 | }, | 452 | .dev_size = SIZE_2MiB, |
| 474 | .DevSize = SIZE_2MiB, | 453 | .cmd_set = P_ID_AMD_STD, |
| 475 | .CmdSet = P_ID_AMD_STD, | 454 | .nr_regions = 1, |
| 476 | .NumEraseRegions= 1, | ||
| 477 | .regions = { | 455 | .regions = { |
| 478 | ERASEINFO(0x10000,32), | 456 | ERASEINFO(0x10000,32), |
| 479 | } | 457 | } |
| @@ -481,12 +459,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 481 | .mfr_id = MANUFACTURER_AMD, | 459 | .mfr_id = MANUFACTURER_AMD, |
| 482 | .dev_id = AM29F016D, | 460 | .dev_id = AM29F016D, |
| 483 | .name = "AMD AM29F016D", | 461 | .name = "AMD AM29F016D", |
| 484 | .uaddr = { | 462 | .devtypes = CFI_DEVICETYPE_X8, |
| 485 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 463 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 486 | }, | 464 | .dev_size = SIZE_2MiB, |
| 487 | .DevSize = SIZE_2MiB, | 465 | .cmd_set = P_ID_AMD_STD, |
| 488 | .CmdSet = P_ID_AMD_STD, | 466 | .nr_regions = 1, |
| 489 | .NumEraseRegions= 1, | ||
| 490 | .regions = { | 467 | .regions = { |
| 491 | ERASEINFO(0x10000,32), | 468 | ERASEINFO(0x10000,32), |
| 492 | } | 469 | } |
| @@ -494,12 +471,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 494 | .mfr_id = MANUFACTURER_AMD, | 471 | .mfr_id = MANUFACTURER_AMD, |
| 495 | .dev_id = AM29F080, | 472 | .dev_id = AM29F080, |
| 496 | .name = "AMD AM29F080", | 473 | .name = "AMD AM29F080", |
| 497 | .uaddr = { | 474 | .devtypes = CFI_DEVICETYPE_X8, |
| 498 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 475 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 499 | }, | 476 | .dev_size = SIZE_1MiB, |
| 500 | .DevSize = SIZE_1MiB, | 477 | .cmd_set = P_ID_AMD_STD, |
| 501 | .CmdSet = P_ID_AMD_STD, | 478 | .nr_regions = 1, |
| 502 | .NumEraseRegions= 1, | ||
| 503 | .regions = { | 479 | .regions = { |
| 504 | ERASEINFO(0x10000,16), | 480 | ERASEINFO(0x10000,16), |
| 505 | } | 481 | } |
| @@ -507,12 +483,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 507 | .mfr_id = MANUFACTURER_AMD, | 483 | .mfr_id = MANUFACTURER_AMD, |
| 508 | .dev_id = AM29F040, | 484 | .dev_id = AM29F040, |
| 509 | .name = "AMD AM29F040", | 485 | .name = "AMD AM29F040", |
| 510 | .uaddr = { | 486 | .devtypes = CFI_DEVICETYPE_X8, |
| 511 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 487 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 512 | }, | 488 | .dev_size = SIZE_512KiB, |
| 513 | .DevSize = SIZE_512KiB, | 489 | .cmd_set = P_ID_AMD_STD, |
| 514 | .CmdSet = P_ID_AMD_STD, | 490 | .nr_regions = 1, |
| 515 | .NumEraseRegions= 1, | ||
| 516 | .regions = { | 491 | .regions = { |
| 517 | ERASEINFO(0x10000,8), | 492 | ERASEINFO(0x10000,8), |
| 518 | } | 493 | } |
| @@ -520,12 +495,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 520 | .mfr_id = MANUFACTURER_AMD, | 495 | .mfr_id = MANUFACTURER_AMD, |
| 521 | .dev_id = AM29LV040B, | 496 | .dev_id = AM29LV040B, |
| 522 | .name = "AMD AM29LV040B", | 497 | .name = "AMD AM29LV040B", |
| 523 | .uaddr = { | 498 | .devtypes = CFI_DEVICETYPE_X8, |
| 524 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 499 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 525 | }, | 500 | .dev_size = SIZE_512KiB, |
| 526 | .DevSize = SIZE_512KiB, | 501 | .cmd_set = P_ID_AMD_STD, |
| 527 | .CmdSet = P_ID_AMD_STD, | 502 | .nr_regions = 1, |
| 528 | .NumEraseRegions= 1, | ||
| 529 | .regions = { | 503 | .regions = { |
| 530 | ERASEINFO(0x10000,8), | 504 | ERASEINFO(0x10000,8), |
| 531 | } | 505 | } |
| @@ -533,12 +507,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 533 | .mfr_id = MANUFACTURER_AMD, | 507 | .mfr_id = MANUFACTURER_AMD, |
| 534 | .dev_id = AM29F002T, | 508 | .dev_id = AM29F002T, |
| 535 | .name = "AMD AM29F002T", | 509 | .name = "AMD AM29F002T", |
| 536 | .uaddr = { | 510 | .devtypes = CFI_DEVICETYPE_X8, |
| 537 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 511 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 538 | }, | 512 | .dev_size = SIZE_256KiB, |
| 539 | .DevSize = SIZE_256KiB, | 513 | .cmd_set = P_ID_AMD_STD, |
| 540 | .CmdSet = P_ID_AMD_STD, | 514 | .nr_regions = 4, |
| 541 | .NumEraseRegions= 4, | ||
| 542 | .regions = { | 515 | .regions = { |
| 543 | ERASEINFO(0x10000,3), | 516 | ERASEINFO(0x10000,3), |
| 544 | ERASEINFO(0x08000,1), | 517 | ERASEINFO(0x08000,1), |
| @@ -549,12 +522,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 549 | .mfr_id = MANUFACTURER_ATMEL, | 522 | .mfr_id = MANUFACTURER_ATMEL, |
| 550 | .dev_id = AT49BV512, | 523 | .dev_id = AT49BV512, |
| 551 | .name = "Atmel AT49BV512", | 524 | .name = "Atmel AT49BV512", |
| 552 | .uaddr = { | 525 | .devtypes = CFI_DEVICETYPE_X8, |
| 553 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 526 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 554 | }, | 527 | .dev_size = SIZE_64KiB, |
| 555 | .DevSize = SIZE_64KiB, | 528 | .cmd_set = P_ID_AMD_STD, |
| 556 | .CmdSet = P_ID_AMD_STD, | 529 | .nr_regions = 1, |
| 557 | .NumEraseRegions= 1, | ||
| 558 | .regions = { | 530 | .regions = { |
| 559 | ERASEINFO(0x10000,1) | 531 | ERASEINFO(0x10000,1) |
| 560 | } | 532 | } |
| @@ -562,12 +534,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 562 | .mfr_id = MANUFACTURER_ATMEL, | 534 | .mfr_id = MANUFACTURER_ATMEL, |
| 563 | .dev_id = AT29LV512, | 535 | .dev_id = AT29LV512, |
| 564 | .name = "Atmel AT29LV512", | 536 | .name = "Atmel AT29LV512", |
| 565 | .uaddr = { | 537 | .devtypes = CFI_DEVICETYPE_X8, |
| 566 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 538 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 567 | }, | 539 | .dev_size = SIZE_64KiB, |
| 568 | .DevSize = SIZE_64KiB, | 540 | .cmd_set = P_ID_AMD_STD, |
| 569 | .CmdSet = P_ID_AMD_STD, | 541 | .nr_regions = 1, |
| 570 | .NumEraseRegions= 1, | ||
| 571 | .regions = { | 542 | .regions = { |
| 572 | ERASEINFO(0x80,256), | 543 | ERASEINFO(0x80,256), |
| 573 | ERASEINFO(0x80,256) | 544 | ERASEINFO(0x80,256) |
| @@ -576,13 +547,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 576 | .mfr_id = MANUFACTURER_ATMEL, | 547 | .mfr_id = MANUFACTURER_ATMEL, |
| 577 | .dev_id = AT49BV16X, | 548 | .dev_id = AT49BV16X, |
| 578 | .name = "Atmel AT49BV16X", | 549 | .name = "Atmel AT49BV16X", |
| 579 | .uaddr = { | 550 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 580 | [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ | 551 | .uaddr = MTD_UADDR_0x0555_0x0AAA, /* ???? */ |
| 581 | [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ | 552 | .dev_size = SIZE_2MiB, |
| 582 | }, | 553 | .cmd_set = P_ID_AMD_STD, |
| 583 | .DevSize = SIZE_2MiB, | 554 | .nr_regions = 2, |
| 584 | .CmdSet = P_ID_AMD_STD, | ||
| 585 | .NumEraseRegions= 2, | ||
| 586 | .regions = { | 555 | .regions = { |
| 587 | ERASEINFO(0x02000,8), | 556 | ERASEINFO(0x02000,8), |
| 588 | ERASEINFO(0x10000,31) | 557 | ERASEINFO(0x10000,31) |
| @@ -591,13 +560,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 591 | .mfr_id = MANUFACTURER_ATMEL, | 560 | .mfr_id = MANUFACTURER_ATMEL, |
| 592 | .dev_id = AT49BV16XT, | 561 | .dev_id = AT49BV16XT, |
| 593 | .name = "Atmel AT49BV16XT", | 562 | .name = "Atmel AT49BV16XT", |
| 594 | .uaddr = { | 563 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 595 | [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ | 564 | .uaddr = MTD_UADDR_0x0555_0x0AAA, /* ???? */ |
| 596 | [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ | 565 | .dev_size = SIZE_2MiB, |
| 597 | }, | 566 | .cmd_set = P_ID_AMD_STD, |
| 598 | .DevSize = SIZE_2MiB, | 567 | .nr_regions = 2, |
| 599 | .CmdSet = P_ID_AMD_STD, | ||
| 600 | .NumEraseRegions= 2, | ||
| 601 | .regions = { | 568 | .regions = { |
| 602 | ERASEINFO(0x10000,31), | 569 | ERASEINFO(0x10000,31), |
| 603 | ERASEINFO(0x02000,8) | 570 | ERASEINFO(0x02000,8) |
| @@ -606,13 +573,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 606 | .mfr_id = MANUFACTURER_ATMEL, | 573 | .mfr_id = MANUFACTURER_ATMEL, |
| 607 | .dev_id = AT49BV32X, | 574 | .dev_id = AT49BV32X, |
| 608 | .name = "Atmel AT49BV32X", | 575 | .name = "Atmel AT49BV32X", |
| 609 | .uaddr = { | 576 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 610 | [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ | 577 | .uaddr = MTD_UADDR_0x0555_0x0AAA, /* ???? */ |
| 611 | [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ | 578 | .dev_size = SIZE_4MiB, |
| 612 | }, | 579 | .cmd_set = P_ID_AMD_STD, |
| 613 | .DevSize = SIZE_4MiB, | 580 | .nr_regions = 2, |
| 614 | .CmdSet = P_ID_AMD_STD, | ||
| 615 | .NumEraseRegions= 2, | ||
| 616 | .regions = { | 581 | .regions = { |
| 617 | ERASEINFO(0x02000,8), | 582 | ERASEINFO(0x02000,8), |
| 618 | ERASEINFO(0x10000,63) | 583 | ERASEINFO(0x10000,63) |
| @@ -621,13 +586,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 621 | .mfr_id = MANUFACTURER_ATMEL, | 586 | .mfr_id = MANUFACTURER_ATMEL, |
| 622 | .dev_id = AT49BV32XT, | 587 | .dev_id = AT49BV32XT, |
| 623 | .name = "Atmel AT49BV32XT", | 588 | .name = "Atmel AT49BV32XT", |
| 624 | .uaddr = { | 589 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 625 | [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ | 590 | .uaddr = MTD_UADDR_0x0555_0x0AAA, /* ???? */ |
| 626 | [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ | 591 | .dev_size = SIZE_4MiB, |
| 627 | }, | 592 | .cmd_set = P_ID_AMD_STD, |
| 628 | .DevSize = SIZE_4MiB, | 593 | .nr_regions = 2, |
| 629 | .CmdSet = P_ID_AMD_STD, | ||
| 630 | .NumEraseRegions= 2, | ||
| 631 | .regions = { | 594 | .regions = { |
| 632 | ERASEINFO(0x10000,63), | 595 | ERASEINFO(0x10000,63), |
| 633 | ERASEINFO(0x02000,8) | 596 | ERASEINFO(0x02000,8) |
| @@ -636,12 +599,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 636 | .mfr_id = MANUFACTURER_FUJITSU, | 599 | .mfr_id = MANUFACTURER_FUJITSU, |
| 637 | .dev_id = MBM29F040C, | 600 | .dev_id = MBM29F040C, |
| 638 | .name = "Fujitsu MBM29F040C", | 601 | .name = "Fujitsu MBM29F040C", |
| 639 | .uaddr = { | 602 | .devtypes = CFI_DEVICETYPE_X8, |
| 640 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 603 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 641 | }, | 604 | .dev_size = SIZE_512KiB, |
| 642 | .DevSize = SIZE_512KiB, | 605 | .cmd_set = P_ID_AMD_STD, |
| 643 | .CmdSet = P_ID_AMD_STD, | 606 | .nr_regions = 1, |
| 644 | .NumEraseRegions= 1, | ||
| 645 | .regions = { | 607 | .regions = { |
| 646 | ERASEINFO(0x10000,8) | 608 | ERASEINFO(0x10000,8) |
| 647 | } | 609 | } |
| @@ -649,13 +611,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 649 | .mfr_id = MANUFACTURER_FUJITSU, | 611 | .mfr_id = MANUFACTURER_FUJITSU, |
| 650 | .dev_id = MBM29F800BA, | 612 | .dev_id = MBM29F800BA, |
| 651 | .name = "Fujitsu MBM29F800BA", | 613 | .name = "Fujitsu MBM29F800BA", |
| 652 | .uaddr = { | 614 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 653 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 615 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 654 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 616 | .dev_size = SIZE_1MiB, |
| 655 | }, | 617 | .cmd_set = P_ID_AMD_STD, |
| 656 | .DevSize = SIZE_1MiB, | 618 | .nr_regions = 4, |
| 657 | .CmdSet = P_ID_AMD_STD, | ||
| 658 | .NumEraseRegions= 4, | ||
| 659 | .regions = { | 619 | .regions = { |
| 660 | ERASEINFO(0x04000,1), | 620 | ERASEINFO(0x04000,1), |
| 661 | ERASEINFO(0x02000,2), | 621 | ERASEINFO(0x02000,2), |
| @@ -666,12 +626,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 666 | .mfr_id = MANUFACTURER_FUJITSU, | 626 | .mfr_id = MANUFACTURER_FUJITSU, |
| 667 | .dev_id = MBM29LV650UE, | 627 | .dev_id = MBM29LV650UE, |
| 668 | .name = "Fujitsu MBM29LV650UE", | 628 | .name = "Fujitsu MBM29LV650UE", |
| 669 | .uaddr = { | 629 | .devtypes = CFI_DEVICETYPE_X8, |
| 670 | [0] = MTD_UADDR_DONT_CARE /* x16 */ | 630 | .uaddr = MTD_UADDR_DONT_CARE, |
| 671 | }, | 631 | .dev_size = SIZE_8MiB, |
| 672 | .DevSize = SIZE_8MiB, | 632 | .cmd_set = P_ID_AMD_STD, |
| 673 | .CmdSet = P_ID_AMD_STD, | 633 | .nr_regions = 1, |
| 674 | .NumEraseRegions= 1, | ||
| 675 | .regions = { | 634 | .regions = { |
| 676 | ERASEINFO(0x10000,128) | 635 | ERASEINFO(0x10000,128) |
| 677 | } | 636 | } |
| @@ -679,13 +638,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 679 | .mfr_id = MANUFACTURER_FUJITSU, | 638 | .mfr_id = MANUFACTURER_FUJITSU, |
| 680 | .dev_id = MBM29LV320TE, | 639 | .dev_id = MBM29LV320TE, |
| 681 | .name = "Fujitsu MBM29LV320TE", | 640 | .name = "Fujitsu MBM29LV320TE", |
| 682 | .uaddr = { | 641 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 683 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 642 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 684 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 643 | .dev_size = SIZE_4MiB, |
| 685 | }, | 644 | .cmd_set = P_ID_AMD_STD, |
| 686 | .DevSize = SIZE_4MiB, | 645 | .nr_regions = 2, |
| 687 | .CmdSet = P_ID_AMD_STD, | ||
| 688 | .NumEraseRegions= 2, | ||
| 689 | .regions = { | 646 | .regions = { |
| 690 | ERASEINFO(0x10000,63), | 647 | ERASEINFO(0x10000,63), |
| 691 | ERASEINFO(0x02000,8) | 648 | ERASEINFO(0x02000,8) |
| @@ -694,13 +651,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 694 | .mfr_id = MANUFACTURER_FUJITSU, | 651 | .mfr_id = MANUFACTURER_FUJITSU, |
| 695 | .dev_id = MBM29LV320BE, | 652 | .dev_id = MBM29LV320BE, |
| 696 | .name = "Fujitsu MBM29LV320BE", | 653 | .name = "Fujitsu MBM29LV320BE", |
| 697 | .uaddr = { | 654 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 698 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 655 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 699 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 656 | .dev_size = SIZE_4MiB, |
| 700 | }, | 657 | .cmd_set = P_ID_AMD_STD, |
| 701 | .DevSize = SIZE_4MiB, | 658 | .nr_regions = 2, |
| 702 | .CmdSet = P_ID_AMD_STD, | ||
| 703 | .NumEraseRegions= 2, | ||
| 704 | .regions = { | 659 | .regions = { |
| 705 | ERASEINFO(0x02000,8), | 660 | ERASEINFO(0x02000,8), |
| 706 | ERASEINFO(0x10000,63) | 661 | ERASEINFO(0x10000,63) |
| @@ -709,13 +664,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 709 | .mfr_id = MANUFACTURER_FUJITSU, | 664 | .mfr_id = MANUFACTURER_FUJITSU, |
| 710 | .dev_id = MBM29LV160TE, | 665 | .dev_id = MBM29LV160TE, |
| 711 | .name = "Fujitsu MBM29LV160TE", | 666 | .name = "Fujitsu MBM29LV160TE", |
| 712 | .uaddr = { | 667 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 713 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 668 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 714 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 669 | .dev_size = SIZE_2MiB, |
| 715 | }, | 670 | .cmd_set = P_ID_AMD_STD, |
| 716 | .DevSize = SIZE_2MiB, | 671 | .nr_regions = 4, |
| 717 | .CmdSet = P_ID_AMD_STD, | ||
| 718 | .NumEraseRegions= 4, | ||
| 719 | .regions = { | 672 | .regions = { |
| 720 | ERASEINFO(0x10000,31), | 673 | ERASEINFO(0x10000,31), |
| 721 | ERASEINFO(0x08000,1), | 674 | ERASEINFO(0x08000,1), |
| @@ -726,13 +679,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 726 | .mfr_id = MANUFACTURER_FUJITSU, | 679 | .mfr_id = MANUFACTURER_FUJITSU, |
| 727 | .dev_id = MBM29LV160BE, | 680 | .dev_id = MBM29LV160BE, |
| 728 | .name = "Fujitsu MBM29LV160BE", | 681 | .name = "Fujitsu MBM29LV160BE", |
| 729 | .uaddr = { | 682 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 730 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 683 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 731 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 684 | .dev_size = SIZE_2MiB, |
| 732 | }, | 685 | .cmd_set = P_ID_AMD_STD, |
| 733 | .DevSize = SIZE_2MiB, | 686 | .nr_regions = 4, |
| 734 | .CmdSet = P_ID_AMD_STD, | ||
| 735 | .NumEraseRegions= 4, | ||
| 736 | .regions = { | 687 | .regions = { |
| 737 | ERASEINFO(0x04000,1), | 688 | ERASEINFO(0x04000,1), |
| 738 | ERASEINFO(0x02000,2), | 689 | ERASEINFO(0x02000,2), |
| @@ -743,13 +694,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 743 | .mfr_id = MANUFACTURER_FUJITSU, | 694 | .mfr_id = MANUFACTURER_FUJITSU, |
| 744 | .dev_id = MBM29LV800BA, | 695 | .dev_id = MBM29LV800BA, |
| 745 | .name = "Fujitsu MBM29LV800BA", | 696 | .name = "Fujitsu MBM29LV800BA", |
| 746 | .uaddr = { | 697 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 747 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 698 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 748 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 699 | .dev_size = SIZE_1MiB, |
| 749 | }, | 700 | .cmd_set = P_ID_AMD_STD, |
| 750 | .DevSize = SIZE_1MiB, | 701 | .nr_regions = 4, |
| 751 | .CmdSet = P_ID_AMD_STD, | ||
| 752 | .NumEraseRegions= 4, | ||
| 753 | .regions = { | 702 | .regions = { |
| 754 | ERASEINFO(0x04000,1), | 703 | ERASEINFO(0x04000,1), |
| 755 | ERASEINFO(0x02000,2), | 704 | ERASEINFO(0x02000,2), |
| @@ -760,13 +709,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 760 | .mfr_id = MANUFACTURER_FUJITSU, | 709 | .mfr_id = MANUFACTURER_FUJITSU, |
| 761 | .dev_id = MBM29LV800TA, | 710 | .dev_id = MBM29LV800TA, |
| 762 | .name = "Fujitsu MBM29LV800TA", | 711 | .name = "Fujitsu MBM29LV800TA", |
| 763 | .uaddr = { | 712 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 764 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 713 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 765 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 714 | .dev_size = SIZE_1MiB, |
| 766 | }, | 715 | .cmd_set = P_ID_AMD_STD, |
| 767 | .DevSize = SIZE_1MiB, | 716 | .nr_regions = 4, |
| 768 | .CmdSet = P_ID_AMD_STD, | ||
| 769 | .NumEraseRegions= 4, | ||
| 770 | .regions = { | 717 | .regions = { |
| 771 | ERASEINFO(0x10000,15), | 718 | ERASEINFO(0x10000,15), |
| 772 | ERASEINFO(0x08000,1), | 719 | ERASEINFO(0x08000,1), |
| @@ -777,13 +724,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 777 | .mfr_id = MANUFACTURER_FUJITSU, | 724 | .mfr_id = MANUFACTURER_FUJITSU, |
| 778 | .dev_id = MBM29LV400BC, | 725 | .dev_id = MBM29LV400BC, |
| 779 | .name = "Fujitsu MBM29LV400BC", | 726 | .name = "Fujitsu MBM29LV400BC", |
| 780 | .uaddr = { | 727 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 781 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 728 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 782 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 729 | .dev_size = SIZE_512KiB, |
| 783 | }, | 730 | .cmd_set = P_ID_AMD_STD, |
| 784 | .DevSize = SIZE_512KiB, | 731 | .nr_regions = 4, |
| 785 | .CmdSet = P_ID_AMD_STD, | ||
| 786 | .NumEraseRegions= 4, | ||
| 787 | .regions = { | 732 | .regions = { |
| 788 | ERASEINFO(0x04000,1), | 733 | ERASEINFO(0x04000,1), |
| 789 | ERASEINFO(0x02000,2), | 734 | ERASEINFO(0x02000,2), |
| @@ -794,13 +739,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 794 | .mfr_id = MANUFACTURER_FUJITSU, | 739 | .mfr_id = MANUFACTURER_FUJITSU, |
| 795 | .dev_id = MBM29LV400TC, | 740 | .dev_id = MBM29LV400TC, |
| 796 | .name = "Fujitsu MBM29LV400TC", | 741 | .name = "Fujitsu MBM29LV400TC", |
| 797 | .uaddr = { | 742 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 798 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 743 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 799 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 744 | .dev_size = SIZE_512KiB, |
| 800 | }, | 745 | .cmd_set = P_ID_AMD_STD, |
| 801 | .DevSize = SIZE_512KiB, | 746 | .nr_regions = 4, |
| 802 | .CmdSet = P_ID_AMD_STD, | ||
| 803 | .NumEraseRegions= 4, | ||
| 804 | .regions = { | 747 | .regions = { |
| 805 | ERASEINFO(0x10000,7), | 748 | ERASEINFO(0x10000,7), |
| 806 | ERASEINFO(0x08000,1), | 749 | ERASEINFO(0x08000,1), |
| @@ -811,12 +754,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 811 | .mfr_id = MANUFACTURER_HYUNDAI, | 754 | .mfr_id = MANUFACTURER_HYUNDAI, |
| 812 | .dev_id = HY29F002T, | 755 | .dev_id = HY29F002T, |
| 813 | .name = "Hyundai HY29F002T", | 756 | .name = "Hyundai HY29F002T", |
| 814 | .uaddr = { | 757 | .devtypes = CFI_DEVICETYPE_X8, |
| 815 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 758 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 816 | }, | 759 | .dev_size = SIZE_256KiB, |
| 817 | .DevSize = SIZE_256KiB, | 760 | .cmd_set = P_ID_AMD_STD, |
| 818 | .CmdSet = P_ID_AMD_STD, | 761 | .nr_regions = 4, |
| 819 | .NumEraseRegions= 4, | ||
| 820 | .regions = { | 762 | .regions = { |
| 821 | ERASEINFO(0x10000,3), | 763 | ERASEINFO(0x10000,3), |
| 822 | ERASEINFO(0x08000,1), | 764 | ERASEINFO(0x08000,1), |
| @@ -827,12 +769,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 827 | .mfr_id = MANUFACTURER_INTEL, | 769 | .mfr_id = MANUFACTURER_INTEL, |
| 828 | .dev_id = I28F004B3B, | 770 | .dev_id = I28F004B3B, |
| 829 | .name = "Intel 28F004B3B", | 771 | .name = "Intel 28F004B3B", |
| 830 | .uaddr = { | 772 | .devtypes = CFI_DEVICETYPE_X8, |
| 831 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 773 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 832 | }, | 774 | .dev_size = SIZE_512KiB, |
| 833 | .DevSize = SIZE_512KiB, | 775 | .cmd_set = P_ID_INTEL_STD, |
| 834 | .CmdSet = P_ID_INTEL_STD, | 776 | .nr_regions = 2, |
| 835 | .NumEraseRegions= 2, | ||
| 836 | .regions = { | 777 | .regions = { |
| 837 | ERASEINFO(0x02000, 8), | 778 | ERASEINFO(0x02000, 8), |
| 838 | ERASEINFO(0x10000, 7), | 779 | ERASEINFO(0x10000, 7), |
| @@ -841,12 +782,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 841 | .mfr_id = MANUFACTURER_INTEL, | 782 | .mfr_id = MANUFACTURER_INTEL, |
| 842 | .dev_id = I28F004B3T, | 783 | .dev_id = I28F004B3T, |
| 843 | .name = "Intel 28F004B3T", | 784 | .name = "Intel 28F004B3T", |
| 844 | .uaddr = { | 785 | .devtypes = CFI_DEVICETYPE_X8, |
| 845 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 786 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 846 | }, | 787 | .dev_size = SIZE_512KiB, |
| 847 | .DevSize = SIZE_512KiB, | 788 | .cmd_set = P_ID_INTEL_STD, |
| 848 | .CmdSet = P_ID_INTEL_STD, | 789 | .nr_regions = 2, |
| 849 | .NumEraseRegions= 2, | ||
| 850 | .regions = { | 790 | .regions = { |
| 851 | ERASEINFO(0x10000, 7), | 791 | ERASEINFO(0x10000, 7), |
| 852 | ERASEINFO(0x02000, 8), | 792 | ERASEINFO(0x02000, 8), |
| @@ -855,13 +795,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 855 | .mfr_id = MANUFACTURER_INTEL, | 795 | .mfr_id = MANUFACTURER_INTEL, |
| 856 | .dev_id = I28F400B3B, | 796 | .dev_id = I28F400B3B, |
| 857 | .name = "Intel 28F400B3B", | 797 | .name = "Intel 28F400B3B", |
| 858 | .uaddr = { | 798 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 859 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 799 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 860 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 800 | .dev_size = SIZE_512KiB, |
| 861 | }, | 801 | .cmd_set = P_ID_INTEL_STD, |
| 862 | .DevSize = SIZE_512KiB, | 802 | .nr_regions = 2, |
| 863 | .CmdSet = P_ID_INTEL_STD, | ||
| 864 | .NumEraseRegions= 2, | ||
| 865 | .regions = { | 803 | .regions = { |
| 866 | ERASEINFO(0x02000, 8), | 804 | ERASEINFO(0x02000, 8), |
| 867 | ERASEINFO(0x10000, 7), | 805 | ERASEINFO(0x10000, 7), |
| @@ -870,13 +808,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 870 | .mfr_id = MANUFACTURER_INTEL, | 808 | .mfr_id = MANUFACTURER_INTEL, |
| 871 | .dev_id = I28F400B3T, | 809 | .dev_id = I28F400B3T, |
| 872 | .name = "Intel 28F400B3T", | 810 | .name = "Intel 28F400B3T", |
| 873 | .uaddr = { | 811 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 874 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 812 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 875 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 813 | .dev_size = SIZE_512KiB, |
| 876 | }, | 814 | .cmd_set = P_ID_INTEL_STD, |
| 877 | .DevSize = SIZE_512KiB, | 815 | .nr_regions = 2, |
| 878 | .CmdSet = P_ID_INTEL_STD, | ||
| 879 | .NumEraseRegions= 2, | ||
| 880 | .regions = { | 816 | .regions = { |
| 881 | ERASEINFO(0x10000, 7), | 817 | ERASEINFO(0x10000, 7), |
| 882 | ERASEINFO(0x02000, 8), | 818 | ERASEINFO(0x02000, 8), |
| @@ -885,12 +821,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 885 | .mfr_id = MANUFACTURER_INTEL, | 821 | .mfr_id = MANUFACTURER_INTEL, |
| 886 | .dev_id = I28F008B3B, | 822 | .dev_id = I28F008B3B, |
| 887 | .name = "Intel 28F008B3B", | 823 | .name = "Intel 28F008B3B", |
| 888 | .uaddr = { | 824 | .devtypes = CFI_DEVICETYPE_X8, |
| 889 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 825 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 890 | }, | 826 | .dev_size = SIZE_1MiB, |
| 891 | .DevSize = SIZE_1MiB, | 827 | .cmd_set = P_ID_INTEL_STD, |
| 892 | .CmdSet = P_ID_INTEL_STD, | 828 | .nr_regions = 2, |
| 893 | .NumEraseRegions= 2, | ||
| 894 | .regions = { | 829 | .regions = { |
| 895 | ERASEINFO(0x02000, 8), | 830 | ERASEINFO(0x02000, 8), |
| 896 | ERASEINFO(0x10000, 15), | 831 | ERASEINFO(0x10000, 15), |
| @@ -899,12 +834,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 899 | .mfr_id = MANUFACTURER_INTEL, | 834 | .mfr_id = MANUFACTURER_INTEL, |
| 900 | .dev_id = I28F008B3T, | 835 | .dev_id = I28F008B3T, |
| 901 | .name = "Intel 28F008B3T", | 836 | .name = "Intel 28F008B3T", |
| 902 | .uaddr = { | 837 | .devtypes = CFI_DEVICETYPE_X8, |
| 903 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 838 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 904 | }, | 839 | .dev_size = SIZE_1MiB, |
| 905 | .DevSize = SIZE_1MiB, | 840 | .cmd_set = P_ID_INTEL_STD, |
| 906 | .CmdSet = P_ID_INTEL_STD, | 841 | .nr_regions = 2, |
| 907 | .NumEraseRegions= 2, | ||
| 908 | .regions = { | 842 | .regions = { |
| 909 | ERASEINFO(0x10000, 15), | 843 | ERASEINFO(0x10000, 15), |
| 910 | ERASEINFO(0x02000, 8), | 844 | ERASEINFO(0x02000, 8), |
| @@ -913,12 +847,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 913 | .mfr_id = MANUFACTURER_INTEL, | 847 | .mfr_id = MANUFACTURER_INTEL, |
| 914 | .dev_id = I28F008S5, | 848 | .dev_id = I28F008S5, |
| 915 | .name = "Intel 28F008S5", | 849 | .name = "Intel 28F008S5", |
| 916 | .uaddr = { | 850 | .devtypes = CFI_DEVICETYPE_X8, |
| 917 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 851 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 918 | }, | 852 | .dev_size = SIZE_1MiB, |
| 919 | .DevSize = SIZE_1MiB, | 853 | .cmd_set = P_ID_INTEL_EXT, |
| 920 | .CmdSet = P_ID_INTEL_EXT, | 854 | .nr_regions = 1, |
| 921 | .NumEraseRegions= 1, | ||
| 922 | .regions = { | 855 | .regions = { |
| 923 | ERASEINFO(0x10000,16), | 856 | ERASEINFO(0x10000,16), |
| 924 | } | 857 | } |
| @@ -926,12 +859,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 926 | .mfr_id = MANUFACTURER_INTEL, | 859 | .mfr_id = MANUFACTURER_INTEL, |
| 927 | .dev_id = I28F016S5, | 860 | .dev_id = I28F016S5, |
| 928 | .name = "Intel 28F016S5", | 861 | .name = "Intel 28F016S5", |
| 929 | .uaddr = { | 862 | .devtypes = CFI_DEVICETYPE_X8, |
| 930 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 863 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 931 | }, | 864 | .dev_size = SIZE_2MiB, |
| 932 | .DevSize = SIZE_2MiB, | 865 | .cmd_set = P_ID_INTEL_EXT, |
| 933 | .CmdSet = P_ID_INTEL_EXT, | 866 | .nr_regions = 1, |
| 934 | .NumEraseRegions= 1, | ||
| 935 | .regions = { | 867 | .regions = { |
| 936 | ERASEINFO(0x10000,32), | 868 | ERASEINFO(0x10000,32), |
| 937 | } | 869 | } |
| @@ -939,12 +871,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 939 | .mfr_id = MANUFACTURER_INTEL, | 871 | .mfr_id = MANUFACTURER_INTEL, |
| 940 | .dev_id = I28F008SA, | 872 | .dev_id = I28F008SA, |
| 941 | .name = "Intel 28F008SA", | 873 | .name = "Intel 28F008SA", |
| 942 | .uaddr = { | 874 | .devtypes = CFI_DEVICETYPE_X8, |
| 943 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 875 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 944 | }, | 876 | .dev_size = SIZE_1MiB, |
| 945 | .DevSize = SIZE_1MiB, | 877 | .cmd_set = P_ID_INTEL_STD, |
| 946 | .CmdSet = P_ID_INTEL_STD, | 878 | .nr_regions = 1, |
| 947 | .NumEraseRegions= 1, | ||
| 948 | .regions = { | 879 | .regions = { |
| 949 | ERASEINFO(0x10000, 16), | 880 | ERASEINFO(0x10000, 16), |
| 950 | } | 881 | } |
| @@ -952,12 +883,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 952 | .mfr_id = MANUFACTURER_INTEL, | 883 | .mfr_id = MANUFACTURER_INTEL, |
| 953 | .dev_id = I28F800B3B, | 884 | .dev_id = I28F800B3B, |
| 954 | .name = "Intel 28F800B3B", | 885 | .name = "Intel 28F800B3B", |
| 955 | .uaddr = { | 886 | .devtypes = CFI_DEVICETYPE_X16, |
| 956 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 887 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 957 | }, | 888 | .dev_size = SIZE_1MiB, |
| 958 | .DevSize = SIZE_1MiB, | 889 | .cmd_set = P_ID_INTEL_STD, |
| 959 | .CmdSet = P_ID_INTEL_STD, | 890 | .nr_regions = 2, |
| 960 | .NumEraseRegions= 2, | ||
| 961 | .regions = { | 891 | .regions = { |
| 962 | ERASEINFO(0x02000, 8), | 892 | ERASEINFO(0x02000, 8), |
| 963 | ERASEINFO(0x10000, 15), | 893 | ERASEINFO(0x10000, 15), |
| @@ -966,12 +896,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 966 | .mfr_id = MANUFACTURER_INTEL, | 896 | .mfr_id = MANUFACTURER_INTEL, |
| 967 | .dev_id = I28F800B3T, | 897 | .dev_id = I28F800B3T, |
| 968 | .name = "Intel 28F800B3T", | 898 | .name = "Intel 28F800B3T", |
| 969 | .uaddr = { | 899 | .devtypes = CFI_DEVICETYPE_X16, |
| 970 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 900 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 971 | }, | 901 | .dev_size = SIZE_1MiB, |
| 972 | .DevSize = SIZE_1MiB, | 902 | .cmd_set = P_ID_INTEL_STD, |
| 973 | .CmdSet = P_ID_INTEL_STD, | 903 | .nr_regions = 2, |
| 974 | .NumEraseRegions= 2, | ||
| 975 | .regions = { | 904 | .regions = { |
| 976 | ERASEINFO(0x10000, 15), | 905 | ERASEINFO(0x10000, 15), |
| 977 | ERASEINFO(0x02000, 8), | 906 | ERASEINFO(0x02000, 8), |
| @@ -980,12 +909,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 980 | .mfr_id = MANUFACTURER_INTEL, | 909 | .mfr_id = MANUFACTURER_INTEL, |
| 981 | .dev_id = I28F016B3B, | 910 | .dev_id = I28F016B3B, |
| 982 | .name = "Intel 28F016B3B", | 911 | .name = "Intel 28F016B3B", |
| 983 | .uaddr = { | 912 | .devtypes = CFI_DEVICETYPE_X8, |
| 984 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 913 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 985 | }, | 914 | .dev_size = SIZE_2MiB, |
| 986 | .DevSize = SIZE_2MiB, | 915 | .cmd_set = P_ID_INTEL_STD, |
| 987 | .CmdSet = P_ID_INTEL_STD, | 916 | .nr_regions = 2, |
| 988 | .NumEraseRegions= 2, | ||
| 989 | .regions = { | 917 | .regions = { |
| 990 | ERASEINFO(0x02000, 8), | 918 | ERASEINFO(0x02000, 8), |
| 991 | ERASEINFO(0x10000, 31), | 919 | ERASEINFO(0x10000, 31), |
| @@ -994,12 +922,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 994 | .mfr_id = MANUFACTURER_INTEL, | 922 | .mfr_id = MANUFACTURER_INTEL, |
| 995 | .dev_id = I28F016S3, | 923 | .dev_id = I28F016S3, |
| 996 | .name = "Intel I28F016S3", | 924 | .name = "Intel I28F016S3", |
| 997 | .uaddr = { | 925 | .devtypes = CFI_DEVICETYPE_X8, |
| 998 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 926 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 999 | }, | 927 | .dev_size = SIZE_2MiB, |
| 1000 | .DevSize = SIZE_2MiB, | 928 | .cmd_set = P_ID_INTEL_STD, |
| 1001 | .CmdSet = P_ID_INTEL_STD, | 929 | .nr_regions = 1, |
| 1002 | .NumEraseRegions= 1, | ||
| 1003 | .regions = { | 930 | .regions = { |
| 1004 | ERASEINFO(0x10000, 32), | 931 | ERASEINFO(0x10000, 32), |
| 1005 | } | 932 | } |
| @@ -1007,12 +934,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1007 | .mfr_id = MANUFACTURER_INTEL, | 934 | .mfr_id = MANUFACTURER_INTEL, |
| 1008 | .dev_id = I28F016B3T, | 935 | .dev_id = I28F016B3T, |
| 1009 | .name = "Intel 28F016B3T", | 936 | .name = "Intel 28F016B3T", |
| 1010 | .uaddr = { | 937 | .devtypes = CFI_DEVICETYPE_X8, |
| 1011 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 938 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1012 | }, | 939 | .dev_size = SIZE_2MiB, |
| 1013 | .DevSize = SIZE_2MiB, | 940 | .cmd_set = P_ID_INTEL_STD, |
| 1014 | .CmdSet = P_ID_INTEL_STD, | 941 | .nr_regions = 2, |
| 1015 | .NumEraseRegions= 2, | ||
| 1016 | .regions = { | 942 | .regions = { |
| 1017 | ERASEINFO(0x10000, 31), | 943 | ERASEINFO(0x10000, 31), |
| 1018 | ERASEINFO(0x02000, 8), | 944 | ERASEINFO(0x02000, 8), |
| @@ -1021,12 +947,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1021 | .mfr_id = MANUFACTURER_INTEL, | 947 | .mfr_id = MANUFACTURER_INTEL, |
| 1022 | .dev_id = I28F160B3B, | 948 | .dev_id = I28F160B3B, |
| 1023 | .name = "Intel 28F160B3B", | 949 | .name = "Intel 28F160B3B", |
| 1024 | .uaddr = { | 950 | .devtypes = CFI_DEVICETYPE_X16, |
| 1025 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 951 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1026 | }, | 952 | .dev_size = SIZE_2MiB, |
| 1027 | .DevSize = SIZE_2MiB, | 953 | .cmd_set = P_ID_INTEL_STD, |
| 1028 | .CmdSet = P_ID_INTEL_STD, | 954 | .nr_regions = 2, |
| 1029 | .NumEraseRegions= 2, | ||
| 1030 | .regions = { | 955 | .regions = { |
| 1031 | ERASEINFO(0x02000, 8), | 956 | ERASEINFO(0x02000, 8), |
| 1032 | ERASEINFO(0x10000, 31), | 957 | ERASEINFO(0x10000, 31), |
| @@ -1035,12 +960,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1035 | .mfr_id = MANUFACTURER_INTEL, | 960 | .mfr_id = MANUFACTURER_INTEL, |
| 1036 | .dev_id = I28F160B3T, | 961 | .dev_id = I28F160B3T, |
| 1037 | .name = "Intel 28F160B3T", | 962 | .name = "Intel 28F160B3T", |
| 1038 | .uaddr = { | 963 | .devtypes = CFI_DEVICETYPE_X16, |
| 1039 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 964 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1040 | }, | 965 | .dev_size = SIZE_2MiB, |
| 1041 | .DevSize = SIZE_2MiB, | 966 | .cmd_set = P_ID_INTEL_STD, |
| 1042 | .CmdSet = P_ID_INTEL_STD, | 967 | .nr_regions = 2, |
| 1043 | .NumEraseRegions= 2, | ||
| 1044 | .regions = { | 968 | .regions = { |
| 1045 | ERASEINFO(0x10000, 31), | 969 | ERASEINFO(0x10000, 31), |
| 1046 | ERASEINFO(0x02000, 8), | 970 | ERASEINFO(0x02000, 8), |
| @@ -1049,12 +973,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1049 | .mfr_id = MANUFACTURER_INTEL, | 973 | .mfr_id = MANUFACTURER_INTEL, |
| 1050 | .dev_id = I28F320B3B, | 974 | .dev_id = I28F320B3B, |
| 1051 | .name = "Intel 28F320B3B", | 975 | .name = "Intel 28F320B3B", |
| 1052 | .uaddr = { | 976 | .devtypes = CFI_DEVICETYPE_X16, |
| 1053 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 977 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1054 | }, | 978 | .dev_size = SIZE_4MiB, |
| 1055 | .DevSize = SIZE_4MiB, | 979 | .cmd_set = P_ID_INTEL_STD, |
| 1056 | .CmdSet = P_ID_INTEL_STD, | 980 | .nr_regions = 2, |
| 1057 | .NumEraseRegions= 2, | ||
| 1058 | .regions = { | 981 | .regions = { |
| 1059 | ERASEINFO(0x02000, 8), | 982 | ERASEINFO(0x02000, 8), |
| 1060 | ERASEINFO(0x10000, 63), | 983 | ERASEINFO(0x10000, 63), |
| @@ -1063,12 +986,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1063 | .mfr_id = MANUFACTURER_INTEL, | 986 | .mfr_id = MANUFACTURER_INTEL, |
| 1064 | .dev_id = I28F320B3T, | 987 | .dev_id = I28F320B3T, |
| 1065 | .name = "Intel 28F320B3T", | 988 | .name = "Intel 28F320B3T", |
| 1066 | .uaddr = { | 989 | .devtypes = CFI_DEVICETYPE_X16, |
| 1067 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 990 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1068 | }, | 991 | .dev_size = SIZE_4MiB, |
| 1069 | .DevSize = SIZE_4MiB, | 992 | .cmd_set = P_ID_INTEL_STD, |
| 1070 | .CmdSet = P_ID_INTEL_STD, | 993 | .nr_regions = 2, |
| 1071 | .NumEraseRegions= 2, | ||
| 1072 | .regions = { | 994 | .regions = { |
| 1073 | ERASEINFO(0x10000, 63), | 995 | ERASEINFO(0x10000, 63), |
| 1074 | ERASEINFO(0x02000, 8), | 996 | ERASEINFO(0x02000, 8), |
| @@ -1077,12 +999,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1077 | .mfr_id = MANUFACTURER_INTEL, | 999 | .mfr_id = MANUFACTURER_INTEL, |
| 1078 | .dev_id = I28F640B3B, | 1000 | .dev_id = I28F640B3B, |
| 1079 | .name = "Intel 28F640B3B", | 1001 | .name = "Intel 28F640B3B", |
| 1080 | .uaddr = { | 1002 | .devtypes = CFI_DEVICETYPE_X16, |
| 1081 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 1003 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1082 | }, | 1004 | .dev_size = SIZE_8MiB, |
| 1083 | .DevSize = SIZE_8MiB, | 1005 | .cmd_set = P_ID_INTEL_STD, |
| 1084 | .CmdSet = P_ID_INTEL_STD, | 1006 | .nr_regions = 2, |
| 1085 | .NumEraseRegions= 2, | ||
| 1086 | .regions = { | 1007 | .regions = { |
| 1087 | ERASEINFO(0x02000, 8), | 1008 | ERASEINFO(0x02000, 8), |
| 1088 | ERASEINFO(0x10000, 127), | 1009 | ERASEINFO(0x10000, 127), |
| @@ -1091,12 +1012,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1091 | .mfr_id = MANUFACTURER_INTEL, | 1012 | .mfr_id = MANUFACTURER_INTEL, |
| 1092 | .dev_id = I28F640B3T, | 1013 | .dev_id = I28F640B3T, |
| 1093 | .name = "Intel 28F640B3T", | 1014 | .name = "Intel 28F640B3T", |
| 1094 | .uaddr = { | 1015 | .devtypes = CFI_DEVICETYPE_X16, |
| 1095 | [1] = MTD_UADDR_UNNECESSARY, /* x16 */ | 1016 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1096 | }, | 1017 | .dev_size = SIZE_8MiB, |
| 1097 | .DevSize = SIZE_8MiB, | 1018 | .cmd_set = P_ID_INTEL_STD, |
| 1098 | .CmdSet = P_ID_INTEL_STD, | 1019 | .nr_regions = 2, |
| 1099 | .NumEraseRegions= 2, | ||
| 1100 | .regions = { | 1020 | .regions = { |
| 1101 | ERASEINFO(0x10000, 127), | 1021 | ERASEINFO(0x10000, 127), |
| 1102 | ERASEINFO(0x02000, 8), | 1022 | ERASEINFO(0x02000, 8), |
| @@ -1105,12 +1025,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1105 | .mfr_id = MANUFACTURER_INTEL, | 1025 | .mfr_id = MANUFACTURER_INTEL, |
| 1106 | .dev_id = I82802AB, | 1026 | .dev_id = I82802AB, |
| 1107 | .name = "Intel 82802AB", | 1027 | .name = "Intel 82802AB", |
| 1108 | .uaddr = { | 1028 | .devtypes = CFI_DEVICETYPE_X8, |
| 1109 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 1029 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1110 | }, | 1030 | .dev_size = SIZE_512KiB, |
| 1111 | .DevSize = SIZE_512KiB, | 1031 | .cmd_set = P_ID_INTEL_EXT, |
| 1112 | .CmdSet = P_ID_INTEL_EXT, | 1032 | .nr_regions = 1, |
| 1113 | .NumEraseRegions= 1, | ||
| 1114 | .regions = { | 1033 | .regions = { |
| 1115 | ERASEINFO(0x10000,8), | 1034 | ERASEINFO(0x10000,8), |
| 1116 | } | 1035 | } |
| @@ -1118,12 +1037,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1118 | .mfr_id = MANUFACTURER_INTEL, | 1037 | .mfr_id = MANUFACTURER_INTEL, |
| 1119 | .dev_id = I82802AC, | 1038 | .dev_id = I82802AC, |
| 1120 | .name = "Intel 82802AC", | 1039 | .name = "Intel 82802AC", |
| 1121 | .uaddr = { | 1040 | .devtypes = CFI_DEVICETYPE_X8, |
| 1122 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 1041 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1123 | }, | 1042 | .dev_size = SIZE_1MiB, |
| 1124 | .DevSize = SIZE_1MiB, | 1043 | .cmd_set = P_ID_INTEL_EXT, |
| 1125 | .CmdSet = P_ID_INTEL_EXT, | 1044 | .nr_regions = 1, |
| 1126 | .NumEraseRegions= 1, | ||
| 1127 | .regions = { | 1045 | .regions = { |
| 1128 | ERASEINFO(0x10000,16), | 1046 | ERASEINFO(0x10000,16), |
| 1129 | } | 1047 | } |
| @@ -1131,12 +1049,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1131 | .mfr_id = MANUFACTURER_MACRONIX, | 1049 | .mfr_id = MANUFACTURER_MACRONIX, |
| 1132 | .dev_id = MX29LV040C, | 1050 | .dev_id = MX29LV040C, |
| 1133 | .name = "Macronix MX29LV040C", | 1051 | .name = "Macronix MX29LV040C", |
| 1134 | .uaddr = { | 1052 | .devtypes = CFI_DEVICETYPE_X8, |
| 1135 | [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ | 1053 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 1136 | }, | 1054 | .dev_size = SIZE_512KiB, |
| 1137 | .DevSize = SIZE_512KiB, | 1055 | .cmd_set = P_ID_AMD_STD, |
| 1138 | .CmdSet = P_ID_AMD_STD, | 1056 | .nr_regions = 1, |
| 1139 | .NumEraseRegions= 1, | ||
| 1140 | .regions = { | 1057 | .regions = { |
| 1141 | ERASEINFO(0x10000,8), | 1058 | ERASEINFO(0x10000,8), |
| 1142 | } | 1059 | } |
| @@ -1144,13 +1061,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1144 | .mfr_id = MANUFACTURER_MACRONIX, | 1061 | .mfr_id = MANUFACTURER_MACRONIX, |
| 1145 | .dev_id = MX29LV160T, | 1062 | .dev_id = MX29LV160T, |
| 1146 | .name = "MXIC MX29LV160T", | 1063 | .name = "MXIC MX29LV160T", |
| 1147 | .uaddr = { | 1064 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1148 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1065 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1149 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 1066 | .dev_size = SIZE_2MiB, |
| 1150 | }, | 1067 | .cmd_set = P_ID_AMD_STD, |
| 1151 | .DevSize = SIZE_2MiB, | 1068 | .nr_regions = 4, |
| 1152 | .CmdSet = P_ID_AMD_STD, | ||
| 1153 | .NumEraseRegions= 4, | ||
| 1154 | .regions = { | 1069 | .regions = { |
| 1155 | ERASEINFO(0x10000,31), | 1070 | ERASEINFO(0x10000,31), |
| 1156 | ERASEINFO(0x08000,1), | 1071 | ERASEINFO(0x08000,1), |
| @@ -1161,13 +1076,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1161 | .mfr_id = MANUFACTURER_NEC, | 1076 | .mfr_id = MANUFACTURER_NEC, |
| 1162 | .dev_id = UPD29F064115, | 1077 | .dev_id = UPD29F064115, |
| 1163 | .name = "NEC uPD29F064115", | 1078 | .name = "NEC uPD29F064115", |
| 1164 | .uaddr = { | 1079 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1165 | [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ | 1080 | .uaddr = MTD_UADDR_0x0555_0x02AA, /* ???? */ |
| 1166 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 1081 | .dev_size = SIZE_8MiB, |
| 1167 | }, | 1082 | .cmd_set = P_ID_AMD_STD, |
| 1168 | .DevSize = SIZE_8MiB, | 1083 | .nr_regions = 3, |
| 1169 | .CmdSet = P_ID_AMD_STD, | ||
| 1170 | .NumEraseRegions= 3, | ||
| 1171 | .regions = { | 1084 | .regions = { |
| 1172 | ERASEINFO(0x2000,8), | 1085 | ERASEINFO(0x2000,8), |
| 1173 | ERASEINFO(0x10000,126), | 1086 | ERASEINFO(0x10000,126), |
| @@ -1177,13 +1090,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1177 | .mfr_id = MANUFACTURER_MACRONIX, | 1090 | .mfr_id = MANUFACTURER_MACRONIX, |
| 1178 | .dev_id = MX29LV160B, | 1091 | .dev_id = MX29LV160B, |
| 1179 | .name = "MXIC MX29LV160B", | 1092 | .name = "MXIC MX29LV160B", |
| 1180 | .uaddr = { | 1093 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1181 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1094 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1182 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 1095 | .dev_size = SIZE_2MiB, |
| 1183 | }, | 1096 | .cmd_set = P_ID_AMD_STD, |
| 1184 | .DevSize = SIZE_2MiB, | 1097 | .nr_regions = 4, |
| 1185 | .CmdSet = P_ID_AMD_STD, | ||
| 1186 | .NumEraseRegions= 4, | ||
| 1187 | .regions = { | 1098 | .regions = { |
| 1188 | ERASEINFO(0x04000,1), | 1099 | ERASEINFO(0x04000,1), |
| 1189 | ERASEINFO(0x02000,2), | 1100 | ERASEINFO(0x02000,2), |
| @@ -1194,12 +1105,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1194 | .mfr_id = MANUFACTURER_MACRONIX, | 1105 | .mfr_id = MANUFACTURER_MACRONIX, |
| 1195 | .dev_id = MX29F040, | 1106 | .dev_id = MX29F040, |
| 1196 | .name = "Macronix MX29F040", | 1107 | .name = "Macronix MX29F040", |
| 1197 | .uaddr = { | 1108 | .devtypes = CFI_DEVICETYPE_X8, |
| 1198 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 1109 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 1199 | }, | 1110 | .dev_size = SIZE_512KiB, |
| 1200 | .DevSize = SIZE_512KiB, | 1111 | .cmd_set = P_ID_AMD_STD, |
| 1201 | .CmdSet = P_ID_AMD_STD, | 1112 | .nr_regions = 1, |
| 1202 | .NumEraseRegions= 1, | ||
| 1203 | .regions = { | 1113 | .regions = { |
| 1204 | ERASEINFO(0x10000,8), | 1114 | ERASEINFO(0x10000,8), |
| 1205 | } | 1115 | } |
| @@ -1207,12 +1117,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1207 | .mfr_id = MANUFACTURER_MACRONIX, | 1117 | .mfr_id = MANUFACTURER_MACRONIX, |
| 1208 | .dev_id = MX29F016, | 1118 | .dev_id = MX29F016, |
| 1209 | .name = "Macronix MX29F016", | 1119 | .name = "Macronix MX29F016", |
| 1210 | .uaddr = { | 1120 | .devtypes = CFI_DEVICETYPE_X8, |
| 1211 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 1121 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 1212 | }, | 1122 | .dev_size = SIZE_2MiB, |
| 1213 | .DevSize = SIZE_2MiB, | 1123 | .cmd_set = P_ID_AMD_STD, |
| 1214 | .CmdSet = P_ID_AMD_STD, | 1124 | .nr_regions = 1, |
| 1215 | .NumEraseRegions= 1, | ||
| 1216 | .regions = { | 1125 | .regions = { |
| 1217 | ERASEINFO(0x10000,32), | 1126 | ERASEINFO(0x10000,32), |
| 1218 | } | 1127 | } |
| @@ -1220,12 +1129,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1220 | .mfr_id = MANUFACTURER_MACRONIX, | 1129 | .mfr_id = MANUFACTURER_MACRONIX, |
| 1221 | .dev_id = MX29F004T, | 1130 | .dev_id = MX29F004T, |
| 1222 | .name = "Macronix MX29F004T", | 1131 | .name = "Macronix MX29F004T", |
| 1223 | .uaddr = { | 1132 | .devtypes = CFI_DEVICETYPE_X8, |
| 1224 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 1133 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 1225 | }, | 1134 | .dev_size = SIZE_512KiB, |
| 1226 | .DevSize = SIZE_512KiB, | 1135 | .cmd_set = P_ID_AMD_STD, |
| 1227 | .CmdSet = P_ID_AMD_STD, | 1136 | .nr_regions = 4, |
| 1228 | .NumEraseRegions= 4, | ||
| 1229 | .regions = { | 1137 | .regions = { |
| 1230 | ERASEINFO(0x10000,7), | 1138 | ERASEINFO(0x10000,7), |
| 1231 | ERASEINFO(0x08000,1), | 1139 | ERASEINFO(0x08000,1), |
| @@ -1236,12 +1144,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1236 | .mfr_id = MANUFACTURER_MACRONIX, | 1144 | .mfr_id = MANUFACTURER_MACRONIX, |
| 1237 | .dev_id = MX29F004B, | 1145 | .dev_id = MX29F004B, |
| 1238 | .name = "Macronix MX29F004B", | 1146 | .name = "Macronix MX29F004B", |
| 1239 | .uaddr = { | 1147 | .devtypes = CFI_DEVICETYPE_X8, |
| 1240 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 1148 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 1241 | }, | 1149 | .dev_size = SIZE_512KiB, |
| 1242 | .DevSize = SIZE_512KiB, | 1150 | .cmd_set = P_ID_AMD_STD, |
| 1243 | .CmdSet = P_ID_AMD_STD, | 1151 | .nr_regions = 4, |
| 1244 | .NumEraseRegions= 4, | ||
| 1245 | .regions = { | 1152 | .regions = { |
| 1246 | ERASEINFO(0x04000,1), | 1153 | ERASEINFO(0x04000,1), |
| 1247 | ERASEINFO(0x02000,2), | 1154 | ERASEINFO(0x02000,2), |
| @@ -1252,12 +1159,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1252 | .mfr_id = MANUFACTURER_MACRONIX, | 1159 | .mfr_id = MANUFACTURER_MACRONIX, |
| 1253 | .dev_id = MX29F002T, | 1160 | .dev_id = MX29F002T, |
| 1254 | .name = "Macronix MX29F002T", | 1161 | .name = "Macronix MX29F002T", |
| 1255 | .uaddr = { | 1162 | .devtypes = CFI_DEVICETYPE_X8, |
| 1256 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 1163 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 1257 | }, | 1164 | .dev_size = SIZE_256KiB, |
| 1258 | .DevSize = SIZE_256KiB, | 1165 | .cmd_set = P_ID_AMD_STD, |
| 1259 | .CmdSet = P_ID_AMD_STD, | 1166 | .nr_regions = 4, |
| 1260 | .NumEraseRegions= 4, | ||
| 1261 | .regions = { | 1167 | .regions = { |
| 1262 | ERASEINFO(0x10000,3), | 1168 | ERASEINFO(0x10000,3), |
| 1263 | ERASEINFO(0x08000,1), | 1169 | ERASEINFO(0x08000,1), |
| @@ -1268,12 +1174,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1268 | .mfr_id = MANUFACTURER_PMC, | 1174 | .mfr_id = MANUFACTURER_PMC, |
| 1269 | .dev_id = PM49FL002, | 1175 | .dev_id = PM49FL002, |
| 1270 | .name = "PMC Pm49FL002", | 1176 | .name = "PMC Pm49FL002", |
| 1271 | .uaddr = { | 1177 | .devtypes = CFI_DEVICETYPE_X8, |
| 1272 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1178 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1273 | }, | 1179 | .dev_size = SIZE_256KiB, |
| 1274 | .DevSize = SIZE_256KiB, | 1180 | .cmd_set = P_ID_AMD_STD, |
| 1275 | .CmdSet = P_ID_AMD_STD, | 1181 | .nr_regions = 1, |
| 1276 | .NumEraseRegions= 1, | ||
| 1277 | .regions = { | 1182 | .regions = { |
| 1278 | ERASEINFO( 0x01000, 64 ) | 1183 | ERASEINFO( 0x01000, 64 ) |
| 1279 | } | 1184 | } |
| @@ -1281,12 +1186,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1281 | .mfr_id = MANUFACTURER_PMC, | 1186 | .mfr_id = MANUFACTURER_PMC, |
| 1282 | .dev_id = PM49FL004, | 1187 | .dev_id = PM49FL004, |
| 1283 | .name = "PMC Pm49FL004", | 1188 | .name = "PMC Pm49FL004", |
| 1284 | .uaddr = { | 1189 | .devtypes = CFI_DEVICETYPE_X8, |
| 1285 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1190 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1286 | }, | 1191 | .dev_size = SIZE_512KiB, |
| 1287 | .DevSize = SIZE_512KiB, | 1192 | .cmd_set = P_ID_AMD_STD, |
| 1288 | .CmdSet = P_ID_AMD_STD, | 1193 | .nr_regions = 1, |
| 1289 | .NumEraseRegions= 1, | ||
| 1290 | .regions = { | 1194 | .regions = { |
| 1291 | ERASEINFO( 0x01000, 128 ) | 1195 | ERASEINFO( 0x01000, 128 ) |
| 1292 | } | 1196 | } |
| @@ -1294,12 +1198,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1294 | .mfr_id = MANUFACTURER_PMC, | 1198 | .mfr_id = MANUFACTURER_PMC, |
| 1295 | .dev_id = PM49FL008, | 1199 | .dev_id = PM49FL008, |
| 1296 | .name = "PMC Pm49FL008", | 1200 | .name = "PMC Pm49FL008", |
| 1297 | .uaddr = { | 1201 | .devtypes = CFI_DEVICETYPE_X8, |
| 1298 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1202 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1299 | }, | 1203 | .dev_size = SIZE_1MiB, |
| 1300 | .DevSize = SIZE_1MiB, | 1204 | .cmd_set = P_ID_AMD_STD, |
| 1301 | .CmdSet = P_ID_AMD_STD, | 1205 | .nr_regions = 1, |
| 1302 | .NumEraseRegions= 1, | ||
| 1303 | .regions = { | 1206 | .regions = { |
| 1304 | ERASEINFO( 0x01000, 256 ) | 1207 | ERASEINFO( 0x01000, 256 ) |
| 1305 | } | 1208 | } |
| @@ -1307,25 +1210,23 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1307 | .mfr_id = MANUFACTURER_SHARP, | 1210 | .mfr_id = MANUFACTURER_SHARP, |
| 1308 | .dev_id = LH28F640BF, | 1211 | .dev_id = LH28F640BF, |
| 1309 | .name = "LH28F640BF", | 1212 | .name = "LH28F640BF", |
| 1310 | .uaddr = { | 1213 | .devtypes = CFI_DEVICETYPE_X8, |
| 1311 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 1214 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1312 | }, | 1215 | .dev_size = SIZE_4MiB, |
| 1313 | .DevSize = SIZE_4MiB, | 1216 | .cmd_set = P_ID_INTEL_STD, |
| 1314 | .CmdSet = P_ID_INTEL_STD, | 1217 | .nr_regions = 1, |
| 1315 | .NumEraseRegions= 1, | 1218 | .regions = { |
| 1316 | .regions = { | ||
| 1317 | ERASEINFO(0x40000,16), | 1219 | ERASEINFO(0x40000,16), |
| 1318 | } | 1220 | } |
| 1319 | }, { | 1221 | }, { |
| 1320 | .mfr_id = MANUFACTURER_SST, | 1222 | .mfr_id = MANUFACTURER_SST, |
| 1321 | .dev_id = SST39LF512, | 1223 | .dev_id = SST39LF512, |
| 1322 | .name = "SST 39LF512", | 1224 | .name = "SST 39LF512", |
| 1323 | .uaddr = { | 1225 | .devtypes = CFI_DEVICETYPE_X8, |
| 1324 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1226 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1325 | }, | 1227 | .dev_size = SIZE_64KiB, |
| 1326 | .DevSize = SIZE_64KiB, | 1228 | .cmd_set = P_ID_AMD_STD, |
| 1327 | .CmdSet = P_ID_AMD_STD, | 1229 | .nr_regions = 1, |
| 1328 | .NumEraseRegions= 1, | ||
| 1329 | .regions = { | 1230 | .regions = { |
| 1330 | ERASEINFO(0x01000,16), | 1231 | ERASEINFO(0x01000,16), |
| 1331 | } | 1232 | } |
| @@ -1333,12 +1234,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1333 | .mfr_id = MANUFACTURER_SST, | 1234 | .mfr_id = MANUFACTURER_SST, |
| 1334 | .dev_id = SST39LF010, | 1235 | .dev_id = SST39LF010, |
| 1335 | .name = "SST 39LF010", | 1236 | .name = "SST 39LF010", |
| 1336 | .uaddr = { | 1237 | .devtypes = CFI_DEVICETYPE_X8, |
| 1337 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1238 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1338 | }, | 1239 | .dev_size = SIZE_128KiB, |
| 1339 | .DevSize = SIZE_128KiB, | 1240 | .cmd_set = P_ID_AMD_STD, |
| 1340 | .CmdSet = P_ID_AMD_STD, | 1241 | .nr_regions = 1, |
| 1341 | .NumEraseRegions= 1, | ||
| 1342 | .regions = { | 1242 | .regions = { |
| 1343 | ERASEINFO(0x01000,32), | 1243 | ERASEINFO(0x01000,32), |
| 1344 | } | 1244 | } |
| @@ -1346,36 +1246,33 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1346 | .mfr_id = MANUFACTURER_SST, | 1246 | .mfr_id = MANUFACTURER_SST, |
| 1347 | .dev_id = SST29EE020, | 1247 | .dev_id = SST29EE020, |
| 1348 | .name = "SST 29EE020", | 1248 | .name = "SST 29EE020", |
| 1349 | .uaddr = { | 1249 | .devtypes = CFI_DEVICETYPE_X8, |
| 1350 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1250 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1351 | }, | 1251 | .dev_size = SIZE_256KiB, |
| 1352 | .DevSize = SIZE_256KiB, | 1252 | .cmd_set = P_ID_SST_PAGE, |
| 1353 | .CmdSet = P_ID_SST_PAGE, | 1253 | .nr_regions = 1, |
| 1354 | .NumEraseRegions= 1, | 1254 | .regions = {ERASEINFO(0x01000,64), |
| 1355 | .regions = {ERASEINFO(0x01000,64), | 1255 | } |
| 1356 | } | 1256 | }, { |
| 1357 | }, { | ||
| 1358 | .mfr_id = MANUFACTURER_SST, | 1257 | .mfr_id = MANUFACTURER_SST, |
| 1359 | .dev_id = SST29LE020, | 1258 | .dev_id = SST29LE020, |
| 1360 | .name = "SST 29LE020", | 1259 | .name = "SST 29LE020", |
| 1361 | .uaddr = { | 1260 | .devtypes = CFI_DEVICETYPE_X8, |
| 1362 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1261 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1363 | }, | 1262 | .dev_size = SIZE_256KiB, |
| 1364 | .DevSize = SIZE_256KiB, | 1263 | .cmd_set = P_ID_SST_PAGE, |
| 1365 | .CmdSet = P_ID_SST_PAGE, | 1264 | .nr_regions = 1, |
| 1366 | .NumEraseRegions= 1, | 1265 | .regions = {ERASEINFO(0x01000,64), |
| 1367 | .regions = {ERASEINFO(0x01000,64), | 1266 | } |
| 1368 | } | ||
| 1369 | }, { | 1267 | }, { |
| 1370 | .mfr_id = MANUFACTURER_SST, | 1268 | .mfr_id = MANUFACTURER_SST, |
| 1371 | .dev_id = SST39LF020, | 1269 | .dev_id = SST39LF020, |
| 1372 | .name = "SST 39LF020", | 1270 | .name = "SST 39LF020", |
| 1373 | .uaddr = { | 1271 | .devtypes = CFI_DEVICETYPE_X8, |
| 1374 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1272 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1375 | }, | 1273 | .dev_size = SIZE_256KiB, |
| 1376 | .DevSize = SIZE_256KiB, | 1274 | .cmd_set = P_ID_AMD_STD, |
| 1377 | .CmdSet = P_ID_AMD_STD, | 1275 | .nr_regions = 1, |
| 1378 | .NumEraseRegions= 1, | ||
| 1379 | .regions = { | 1276 | .regions = { |
| 1380 | ERASEINFO(0x01000,64), | 1277 | ERASEINFO(0x01000,64), |
| 1381 | } | 1278 | } |
| @@ -1383,12 +1280,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1383 | .mfr_id = MANUFACTURER_SST, | 1280 | .mfr_id = MANUFACTURER_SST, |
| 1384 | .dev_id = SST39LF040, | 1281 | .dev_id = SST39LF040, |
| 1385 | .name = "SST 39LF040", | 1282 | .name = "SST 39LF040", |
| 1386 | .uaddr = { | 1283 | .devtypes = CFI_DEVICETYPE_X8, |
| 1387 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1284 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1388 | }, | 1285 | .dev_size = SIZE_512KiB, |
| 1389 | .DevSize = SIZE_512KiB, | 1286 | .cmd_set = P_ID_AMD_STD, |
| 1390 | .CmdSet = P_ID_AMD_STD, | 1287 | .nr_regions = 1, |
| 1391 | .NumEraseRegions= 1, | ||
| 1392 | .regions = { | 1288 | .regions = { |
| 1393 | ERASEINFO(0x01000,128), | 1289 | ERASEINFO(0x01000,128), |
| 1394 | } | 1290 | } |
| @@ -1396,12 +1292,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1396 | .mfr_id = MANUFACTURER_SST, | 1292 | .mfr_id = MANUFACTURER_SST, |
| 1397 | .dev_id = SST39SF010A, | 1293 | .dev_id = SST39SF010A, |
| 1398 | .name = "SST 39SF010A", | 1294 | .name = "SST 39SF010A", |
| 1399 | .uaddr = { | 1295 | .devtypes = CFI_DEVICETYPE_X8, |
| 1400 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1296 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1401 | }, | 1297 | .dev_size = SIZE_128KiB, |
| 1402 | .DevSize = SIZE_128KiB, | 1298 | .cmd_set = P_ID_AMD_STD, |
| 1403 | .CmdSet = P_ID_AMD_STD, | 1299 | .nr_regions = 1, |
| 1404 | .NumEraseRegions= 1, | ||
| 1405 | .regions = { | 1300 | .regions = { |
| 1406 | ERASEINFO(0x01000,32), | 1301 | ERASEINFO(0x01000,32), |
| 1407 | } | 1302 | } |
| @@ -1409,26 +1304,24 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1409 | .mfr_id = MANUFACTURER_SST, | 1304 | .mfr_id = MANUFACTURER_SST, |
| 1410 | .dev_id = SST39SF020A, | 1305 | .dev_id = SST39SF020A, |
| 1411 | .name = "SST 39SF020A", | 1306 | .name = "SST 39SF020A", |
| 1412 | .uaddr = { | 1307 | .devtypes = CFI_DEVICETYPE_X8, |
| 1413 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1308 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1414 | }, | 1309 | .dev_size = SIZE_256KiB, |
| 1415 | .DevSize = SIZE_256KiB, | 1310 | .cmd_set = P_ID_AMD_STD, |
| 1416 | .CmdSet = P_ID_AMD_STD, | 1311 | .nr_regions = 1, |
| 1417 | .NumEraseRegions= 1, | ||
| 1418 | .regions = { | 1312 | .regions = { |
| 1419 | ERASEINFO(0x01000,64), | 1313 | ERASEINFO(0x01000,64), |
| 1420 | } | 1314 | } |
| 1421 | }, { | 1315 | }, { |
| 1422 | .mfr_id = MANUFACTURER_SST, | 1316 | .mfr_id = MANUFACTURER_SST, |
| 1423 | .dev_id = SST49LF040B, | 1317 | .dev_id = SST49LF040B, |
| 1424 | .name = "SST 49LF040B", | 1318 | .name = "SST 49LF040B", |
| 1425 | .uaddr = { | 1319 | .devtypes = CFI_DEVICETYPE_X8, |
| 1426 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1320 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1427 | }, | 1321 | .dev_size = SIZE_512KiB, |
| 1428 | .DevSize = SIZE_512KiB, | 1322 | .cmd_set = P_ID_AMD_STD, |
| 1429 | .CmdSet = P_ID_AMD_STD, | 1323 | .nr_regions = 1, |
| 1430 | .NumEraseRegions= 1, | 1324 | .regions = { |
| 1431 | .regions = { | ||
| 1432 | ERASEINFO(0x01000,128), | 1325 | ERASEINFO(0x01000,128), |
| 1433 | } | 1326 | } |
| 1434 | }, { | 1327 | }, { |
| @@ -1436,12 +1329,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1436 | .mfr_id = MANUFACTURER_SST, | 1329 | .mfr_id = MANUFACTURER_SST, |
| 1437 | .dev_id = SST49LF004B, | 1330 | .dev_id = SST49LF004B, |
| 1438 | .name = "SST 49LF004B", | 1331 | .name = "SST 49LF004B", |
| 1439 | .uaddr = { | 1332 | .devtypes = CFI_DEVICETYPE_X8, |
| 1440 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1333 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1441 | }, | 1334 | .dev_size = SIZE_512KiB, |
| 1442 | .DevSize = SIZE_512KiB, | 1335 | .cmd_set = P_ID_AMD_STD, |
| 1443 | .CmdSet = P_ID_AMD_STD, | 1336 | .nr_regions = 1, |
| 1444 | .NumEraseRegions= 1, | ||
| 1445 | .regions = { | 1337 | .regions = { |
| 1446 | ERASEINFO(0x01000,128), | 1338 | ERASEINFO(0x01000,128), |
| 1447 | } | 1339 | } |
| @@ -1449,12 +1341,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1449 | .mfr_id = MANUFACTURER_SST, | 1341 | .mfr_id = MANUFACTURER_SST, |
| 1450 | .dev_id = SST49LF008A, | 1342 | .dev_id = SST49LF008A, |
| 1451 | .name = "SST 49LF008A", | 1343 | .name = "SST 49LF008A", |
| 1452 | .uaddr = { | 1344 | .devtypes = CFI_DEVICETYPE_X8, |
| 1453 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1345 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1454 | }, | 1346 | .dev_size = SIZE_1MiB, |
| 1455 | .DevSize = SIZE_1MiB, | 1347 | .cmd_set = P_ID_AMD_STD, |
| 1456 | .CmdSet = P_ID_AMD_STD, | 1348 | .nr_regions = 1, |
| 1457 | .NumEraseRegions= 1, | ||
| 1458 | .regions = { | 1349 | .regions = { |
| 1459 | ERASEINFO(0x01000,256), | 1350 | ERASEINFO(0x01000,256), |
| 1460 | } | 1351 | } |
| @@ -1462,12 +1353,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1462 | .mfr_id = MANUFACTURER_SST, | 1353 | .mfr_id = MANUFACTURER_SST, |
| 1463 | .dev_id = SST49LF030A, | 1354 | .dev_id = SST49LF030A, |
| 1464 | .name = "SST 49LF030A", | 1355 | .name = "SST 49LF030A", |
| 1465 | .uaddr = { | 1356 | .devtypes = CFI_DEVICETYPE_X8, |
| 1466 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1357 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1467 | }, | 1358 | .dev_size = SIZE_512KiB, |
| 1468 | .DevSize = SIZE_512KiB, | 1359 | .cmd_set = P_ID_AMD_STD, |
| 1469 | .CmdSet = P_ID_AMD_STD, | 1360 | .nr_regions = 1, |
| 1470 | .NumEraseRegions= 1, | ||
| 1471 | .regions = { | 1361 | .regions = { |
| 1472 | ERASEINFO(0x01000,96), | 1362 | ERASEINFO(0x01000,96), |
| 1473 | } | 1363 | } |
| @@ -1475,12 +1365,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1475 | .mfr_id = MANUFACTURER_SST, | 1365 | .mfr_id = MANUFACTURER_SST, |
| 1476 | .dev_id = SST49LF040A, | 1366 | .dev_id = SST49LF040A, |
| 1477 | .name = "SST 49LF040A", | 1367 | .name = "SST 49LF040A", |
| 1478 | .uaddr = { | 1368 | .devtypes = CFI_DEVICETYPE_X8, |
| 1479 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1369 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1480 | }, | 1370 | .dev_size = SIZE_512KiB, |
| 1481 | .DevSize = SIZE_512KiB, | 1371 | .cmd_set = P_ID_AMD_STD, |
| 1482 | .CmdSet = P_ID_AMD_STD, | 1372 | .nr_regions = 1, |
| 1483 | .NumEraseRegions= 1, | ||
| 1484 | .regions = { | 1373 | .regions = { |
| 1485 | ERASEINFO(0x01000,128), | 1374 | ERASEINFO(0x01000,128), |
| 1486 | } | 1375 | } |
| @@ -1488,57 +1377,49 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1488 | .mfr_id = MANUFACTURER_SST, | 1377 | .mfr_id = MANUFACTURER_SST, |
| 1489 | .dev_id = SST49LF080A, | 1378 | .dev_id = SST49LF080A, |
| 1490 | .name = "SST 49LF080A", | 1379 | .name = "SST 49LF080A", |
| 1491 | .uaddr = { | 1380 | .devtypes = CFI_DEVICETYPE_X8, |
| 1492 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1381 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1493 | }, | 1382 | .dev_size = SIZE_1MiB, |
| 1494 | .DevSize = SIZE_1MiB, | 1383 | .cmd_set = P_ID_AMD_STD, |
| 1495 | .CmdSet = P_ID_AMD_STD, | 1384 | .nr_regions = 1, |
| 1496 | .NumEraseRegions= 1, | ||
| 1497 | .regions = { | 1385 | .regions = { |
| 1498 | ERASEINFO(0x01000,256), | 1386 | ERASEINFO(0x01000,256), |
| 1499 | } | 1387 | } |
| 1500 | }, { | 1388 | }, { |
| 1501 | .mfr_id = MANUFACTURER_SST, /* should be CFI */ | 1389 | .mfr_id = MANUFACTURER_SST, /* should be CFI */ |
| 1502 | .dev_id = SST39LF160, | 1390 | .dev_id = SST39LF160, |
| 1503 | .name = "SST 39LF160", | 1391 | .name = "SST 39LF160", |
| 1504 | .uaddr = { | 1392 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1505 | [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ | 1393 | .uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */ |
| 1506 | [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ | 1394 | .dev_size = SIZE_2MiB, |
| 1507 | }, | 1395 | .cmd_set = P_ID_AMD_STD, |
| 1508 | .DevSize = SIZE_2MiB, | 1396 | .nr_regions = 2, |
| 1509 | .CmdSet = P_ID_AMD_STD, | 1397 | .regions = { |
| 1510 | .NumEraseRegions= 2, | 1398 | ERASEINFO(0x1000,256), |
| 1511 | .regions = { | 1399 | ERASEINFO(0x1000,256) |
| 1512 | ERASEINFO(0x1000,256), | 1400 | } |
| 1513 | ERASEINFO(0x1000,256) | 1401 | }, { |
| 1514 | } | 1402 | .mfr_id = MANUFACTURER_SST, /* should be CFI */ |
| 1515 | }, { | 1403 | .dev_id = SST39VF1601, |
| 1516 | .mfr_id = MANUFACTURER_SST, /* should be CFI */ | 1404 | .name = "SST 39VF1601", |
| 1517 | .dev_id = SST39VF1601, | 1405 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1518 | .name = "SST 39VF1601", | 1406 | .uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */ |
| 1519 | .uaddr = { | 1407 | .dev_size = SIZE_2MiB, |
| 1520 | [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ | 1408 | .cmd_set = P_ID_AMD_STD, |
| 1521 | [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ | 1409 | .nr_regions = 2, |
| 1522 | }, | 1410 | .regions = { |
| 1523 | .DevSize = SIZE_2MiB, | 1411 | ERASEINFO(0x1000,256), |
| 1524 | .CmdSet = P_ID_AMD_STD, | 1412 | ERASEINFO(0x1000,256) |
| 1525 | .NumEraseRegions= 2, | 1413 | } |
| 1526 | .regions = { | ||
| 1527 | ERASEINFO(0x1000,256), | ||
| 1528 | ERASEINFO(0x1000,256) | ||
| 1529 | } | ||
| 1530 | |||
| 1531 | }, { | 1414 | }, { |
| 1532 | .mfr_id = MANUFACTURER_ST, | 1415 | .mfr_id = MANUFACTURER_ST, |
| 1533 | .dev_id = M29F800AB, | 1416 | .dev_id = M29F800AB, |
| 1534 | .name = "ST M29F800AB", | 1417 | .name = "ST M29F800AB", |
| 1535 | .uaddr = { | 1418 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1536 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1419 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1537 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 1420 | .dev_size = SIZE_1MiB, |
| 1538 | }, | 1421 | .cmd_set = P_ID_AMD_STD, |
| 1539 | .DevSize = SIZE_1MiB, | 1422 | .nr_regions = 4, |
| 1540 | .CmdSet = P_ID_AMD_STD, | ||
| 1541 | .NumEraseRegions= 4, | ||
| 1542 | .regions = { | 1423 | .regions = { |
| 1543 | ERASEINFO(0x04000,1), | 1424 | ERASEINFO(0x04000,1), |
| 1544 | ERASEINFO(0x02000,2), | 1425 | ERASEINFO(0x02000,2), |
| @@ -1549,13 +1430,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1549 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ | 1430 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ |
| 1550 | .dev_id = M29W800DT, | 1431 | .dev_id = M29W800DT, |
| 1551 | .name = "ST M29W800DT", | 1432 | .name = "ST M29W800DT", |
| 1552 | .uaddr = { | 1433 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1553 | [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ | 1434 | .uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */ |
| 1554 | [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ | 1435 | .dev_size = SIZE_1MiB, |
| 1555 | }, | 1436 | .cmd_set = P_ID_AMD_STD, |
| 1556 | .DevSize = SIZE_1MiB, | 1437 | .nr_regions = 4, |
| 1557 | .CmdSet = P_ID_AMD_STD, | ||
| 1558 | .NumEraseRegions= 4, | ||
| 1559 | .regions = { | 1438 | .regions = { |
| 1560 | ERASEINFO(0x10000,15), | 1439 | ERASEINFO(0x10000,15), |
| 1561 | ERASEINFO(0x08000,1), | 1440 | ERASEINFO(0x08000,1), |
| @@ -1566,13 +1445,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1566 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ | 1445 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ |
| 1567 | .dev_id = M29W800DB, | 1446 | .dev_id = M29W800DB, |
| 1568 | .name = "ST M29W800DB", | 1447 | .name = "ST M29W800DB", |
| 1569 | .uaddr = { | 1448 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1570 | [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ | 1449 | .uaddr = MTD_UADDR_0x5555_0x2AAA, /* ???? */ |
| 1571 | [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ | 1450 | .dev_size = SIZE_1MiB, |
| 1572 | }, | 1451 | .cmd_set = P_ID_AMD_STD, |
| 1573 | .DevSize = SIZE_1MiB, | 1452 | .nr_regions = 4, |
| 1574 | .CmdSet = P_ID_AMD_STD, | ||
| 1575 | .NumEraseRegions= 4, | ||
| 1576 | .regions = { | 1453 | .regions = { |
| 1577 | ERASEINFO(0x04000,1), | 1454 | ERASEINFO(0x04000,1), |
| 1578 | ERASEINFO(0x02000,2), | 1455 | ERASEINFO(0x02000,2), |
| @@ -1583,13 +1460,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1583 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ | 1460 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ |
| 1584 | .dev_id = M29W160DT, | 1461 | .dev_id = M29W160DT, |
| 1585 | .name = "ST M29W160DT", | 1462 | .name = "ST M29W160DT", |
| 1586 | .uaddr = { | 1463 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1587 | [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ | 1464 | .uaddr = MTD_UADDR_0x0555_0x02AA, /* ???? */ |
| 1588 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 1465 | .dev_size = SIZE_2MiB, |
| 1589 | }, | 1466 | .cmd_set = P_ID_AMD_STD, |
| 1590 | .DevSize = SIZE_2MiB, | 1467 | .nr_regions = 4, |
| 1591 | .CmdSet = P_ID_AMD_STD, | ||
| 1592 | .NumEraseRegions= 4, | ||
| 1593 | .regions = { | 1468 | .regions = { |
| 1594 | ERASEINFO(0x10000,31), | 1469 | ERASEINFO(0x10000,31), |
| 1595 | ERASEINFO(0x08000,1), | 1470 | ERASEINFO(0x08000,1), |
| @@ -1600,13 +1475,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1600 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ | 1475 | .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ |
| 1601 | .dev_id = M29W160DB, | 1476 | .dev_id = M29W160DB, |
| 1602 | .name = "ST M29W160DB", | 1477 | .name = "ST M29W160DB", |
| 1603 | .uaddr = { | 1478 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1604 | [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ | 1479 | .uaddr = MTD_UADDR_0x0555_0x02AA, /* ???? */ |
| 1605 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 1480 | .dev_size = SIZE_2MiB, |
| 1606 | }, | 1481 | .cmd_set = P_ID_AMD_STD, |
| 1607 | .DevSize = SIZE_2MiB, | 1482 | .nr_regions = 4, |
| 1608 | .CmdSet = P_ID_AMD_STD, | ||
| 1609 | .NumEraseRegions= 4, | ||
| 1610 | .regions = { | 1483 | .regions = { |
| 1611 | ERASEINFO(0x04000,1), | 1484 | ERASEINFO(0x04000,1), |
| 1612 | ERASEINFO(0x02000,2), | 1485 | ERASEINFO(0x02000,2), |
| @@ -1617,12 +1490,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1617 | .mfr_id = MANUFACTURER_ST, | 1490 | .mfr_id = MANUFACTURER_ST, |
| 1618 | .dev_id = M29W040B, | 1491 | .dev_id = M29W040B, |
| 1619 | .name = "ST M29W040B", | 1492 | .name = "ST M29W040B", |
| 1620 | .uaddr = { | 1493 | .devtypes = CFI_DEVICETYPE_X8, |
| 1621 | [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ | 1494 | .uaddr = MTD_UADDR_0x0555_0x02AA, |
| 1622 | }, | 1495 | .dev_size = SIZE_512KiB, |
| 1623 | .DevSize = SIZE_512KiB, | 1496 | .cmd_set = P_ID_AMD_STD, |
| 1624 | .CmdSet = P_ID_AMD_STD, | 1497 | .nr_regions = 1, |
| 1625 | .NumEraseRegions= 1, | ||
| 1626 | .regions = { | 1498 | .regions = { |
| 1627 | ERASEINFO(0x10000,8), | 1499 | ERASEINFO(0x10000,8), |
| 1628 | } | 1500 | } |
| @@ -1630,12 +1502,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1630 | .mfr_id = MANUFACTURER_ST, | 1502 | .mfr_id = MANUFACTURER_ST, |
| 1631 | .dev_id = M50FW040, | 1503 | .dev_id = M50FW040, |
| 1632 | .name = "ST M50FW040", | 1504 | .name = "ST M50FW040", |
| 1633 | .uaddr = { | 1505 | .devtypes = CFI_DEVICETYPE_X8, |
| 1634 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 1506 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1635 | }, | 1507 | .dev_size = SIZE_512KiB, |
| 1636 | .DevSize = SIZE_512KiB, | 1508 | .cmd_set = P_ID_INTEL_EXT, |
| 1637 | .CmdSet = P_ID_INTEL_EXT, | 1509 | .nr_regions = 1, |
| 1638 | .NumEraseRegions= 1, | ||
| 1639 | .regions = { | 1510 | .regions = { |
| 1640 | ERASEINFO(0x10000,8), | 1511 | ERASEINFO(0x10000,8), |
| 1641 | } | 1512 | } |
| @@ -1643,12 +1514,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1643 | .mfr_id = MANUFACTURER_ST, | 1514 | .mfr_id = MANUFACTURER_ST, |
| 1644 | .dev_id = M50FW080, | 1515 | .dev_id = M50FW080, |
| 1645 | .name = "ST M50FW080", | 1516 | .name = "ST M50FW080", |
| 1646 | .uaddr = { | 1517 | .devtypes = CFI_DEVICETYPE_X8, |
| 1647 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 1518 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1648 | }, | 1519 | .dev_size = SIZE_1MiB, |
| 1649 | .DevSize = SIZE_1MiB, | 1520 | .cmd_set = P_ID_INTEL_EXT, |
| 1650 | .CmdSet = P_ID_INTEL_EXT, | 1521 | .nr_regions = 1, |
| 1651 | .NumEraseRegions= 1, | ||
| 1652 | .regions = { | 1522 | .regions = { |
| 1653 | ERASEINFO(0x10000,16), | 1523 | ERASEINFO(0x10000,16), |
| 1654 | } | 1524 | } |
| @@ -1656,12 +1526,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1656 | .mfr_id = MANUFACTURER_ST, | 1526 | .mfr_id = MANUFACTURER_ST, |
| 1657 | .dev_id = M50FW016, | 1527 | .dev_id = M50FW016, |
| 1658 | .name = "ST M50FW016", | 1528 | .name = "ST M50FW016", |
| 1659 | .uaddr = { | 1529 | .devtypes = CFI_DEVICETYPE_X8, |
| 1660 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 1530 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1661 | }, | 1531 | .dev_size = SIZE_2MiB, |
| 1662 | .DevSize = SIZE_2MiB, | 1532 | .cmd_set = P_ID_INTEL_EXT, |
| 1663 | .CmdSet = P_ID_INTEL_EXT, | 1533 | .nr_regions = 1, |
| 1664 | .NumEraseRegions= 1, | ||
| 1665 | .regions = { | 1534 | .regions = { |
| 1666 | ERASEINFO(0x10000,32), | 1535 | ERASEINFO(0x10000,32), |
| 1667 | } | 1536 | } |
| @@ -1669,12 +1538,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1669 | .mfr_id = MANUFACTURER_ST, | 1538 | .mfr_id = MANUFACTURER_ST, |
| 1670 | .dev_id = M50LPW080, | 1539 | .dev_id = M50LPW080, |
| 1671 | .name = "ST M50LPW080", | 1540 | .name = "ST M50LPW080", |
| 1672 | .uaddr = { | 1541 | .devtypes = CFI_DEVICETYPE_X8, |
| 1673 | [0] = MTD_UADDR_UNNECESSARY, /* x8 */ | 1542 | .uaddr = MTD_UADDR_UNNECESSARY, |
| 1674 | }, | 1543 | .dev_size = SIZE_1MiB, |
| 1675 | .DevSize = SIZE_1MiB, | 1544 | .cmd_set = P_ID_INTEL_EXT, |
| 1676 | .CmdSet = P_ID_INTEL_EXT, | 1545 | .nr_regions = 1, |
| 1677 | .NumEraseRegions= 1, | ||
| 1678 | .regions = { | 1546 | .regions = { |
| 1679 | ERASEINFO(0x10000,16), | 1547 | ERASEINFO(0x10000,16), |
| 1680 | } | 1548 | } |
| @@ -1682,13 +1550,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1682 | .mfr_id = MANUFACTURER_TOSHIBA, | 1550 | .mfr_id = MANUFACTURER_TOSHIBA, |
| 1683 | .dev_id = TC58FVT160, | 1551 | .dev_id = TC58FVT160, |
| 1684 | .name = "Toshiba TC58FVT160", | 1552 | .name = "Toshiba TC58FVT160", |
| 1685 | .uaddr = { | 1553 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1686 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1554 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1687 | [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ | 1555 | .dev_size = SIZE_2MiB, |
| 1688 | }, | 1556 | .cmd_set = P_ID_AMD_STD, |
| 1689 | .DevSize = SIZE_2MiB, | 1557 | .nr_regions = 4, |
| 1690 | .CmdSet = P_ID_AMD_STD, | ||
| 1691 | .NumEraseRegions= 4, | ||
| 1692 | .regions = { | 1558 | .regions = { |
| 1693 | ERASEINFO(0x10000,31), | 1559 | ERASEINFO(0x10000,31), |
| 1694 | ERASEINFO(0x08000,1), | 1560 | ERASEINFO(0x08000,1), |
| @@ -1699,13 +1565,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1699 | .mfr_id = MANUFACTURER_TOSHIBA, | 1565 | .mfr_id = MANUFACTURER_TOSHIBA, |
| 1700 | .dev_id = TC58FVB160, | 1566 | .dev_id = TC58FVB160, |
| 1701 | .name = "Toshiba TC58FVB160", | 1567 | .name = "Toshiba TC58FVB160", |
| 1702 | .uaddr = { | 1568 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1703 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1569 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1704 | [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ | 1570 | .dev_size = SIZE_2MiB, |
| 1705 | }, | 1571 | .cmd_set = P_ID_AMD_STD, |
| 1706 | .DevSize = SIZE_2MiB, | 1572 | .nr_regions = 4, |
| 1707 | .CmdSet = P_ID_AMD_STD, | ||
| 1708 | .NumEraseRegions= 4, | ||
| 1709 | .regions = { | 1573 | .regions = { |
| 1710 | ERASEINFO(0x04000,1), | 1574 | ERASEINFO(0x04000,1), |
| 1711 | ERASEINFO(0x02000,2), | 1575 | ERASEINFO(0x02000,2), |
| @@ -1716,13 +1580,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1716 | .mfr_id = MANUFACTURER_TOSHIBA, | 1580 | .mfr_id = MANUFACTURER_TOSHIBA, |
| 1717 | .dev_id = TC58FVB321, | 1581 | .dev_id = TC58FVB321, |
| 1718 | .name = "Toshiba TC58FVB321", | 1582 | .name = "Toshiba TC58FVB321", |
| 1719 | .uaddr = { | 1583 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1720 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1584 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1721 | [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ | 1585 | .dev_size = SIZE_4MiB, |
| 1722 | }, | 1586 | .cmd_set = P_ID_AMD_STD, |
| 1723 | .DevSize = SIZE_4MiB, | 1587 | .nr_regions = 2, |
| 1724 | .CmdSet = P_ID_AMD_STD, | ||
| 1725 | .NumEraseRegions= 2, | ||
| 1726 | .regions = { | 1588 | .regions = { |
| 1727 | ERASEINFO(0x02000,8), | 1589 | ERASEINFO(0x02000,8), |
| 1728 | ERASEINFO(0x10000,63) | 1590 | ERASEINFO(0x10000,63) |
| @@ -1731,13 +1593,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1731 | .mfr_id = MANUFACTURER_TOSHIBA, | 1593 | .mfr_id = MANUFACTURER_TOSHIBA, |
| 1732 | .dev_id = TC58FVT321, | 1594 | .dev_id = TC58FVT321, |
| 1733 | .name = "Toshiba TC58FVT321", | 1595 | .name = "Toshiba TC58FVT321", |
| 1734 | .uaddr = { | 1596 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1735 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1597 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1736 | [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ | 1598 | .dev_size = SIZE_4MiB, |
| 1737 | }, | 1599 | .cmd_set = P_ID_AMD_STD, |
| 1738 | .DevSize = SIZE_4MiB, | 1600 | .nr_regions = 2, |
| 1739 | .CmdSet = P_ID_AMD_STD, | ||
| 1740 | .NumEraseRegions= 2, | ||
| 1741 | .regions = { | 1601 | .regions = { |
| 1742 | ERASEINFO(0x10000,63), | 1602 | ERASEINFO(0x10000,63), |
| 1743 | ERASEINFO(0x02000,8) | 1603 | ERASEINFO(0x02000,8) |
| @@ -1746,13 +1606,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1746 | .mfr_id = MANUFACTURER_TOSHIBA, | 1606 | .mfr_id = MANUFACTURER_TOSHIBA, |
| 1747 | .dev_id = TC58FVB641, | 1607 | .dev_id = TC58FVB641, |
| 1748 | .name = "Toshiba TC58FVB641", | 1608 | .name = "Toshiba TC58FVB641", |
| 1749 | .uaddr = { | 1609 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1750 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1610 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1751 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 1611 | .dev_size = SIZE_8MiB, |
| 1752 | }, | 1612 | .cmd_set = P_ID_AMD_STD, |
| 1753 | .DevSize = SIZE_8MiB, | 1613 | .nr_regions = 2, |
| 1754 | .CmdSet = P_ID_AMD_STD, | ||
| 1755 | .NumEraseRegions= 2, | ||
| 1756 | .regions = { | 1614 | .regions = { |
| 1757 | ERASEINFO(0x02000,8), | 1615 | ERASEINFO(0x02000,8), |
| 1758 | ERASEINFO(0x10000,127) | 1616 | ERASEINFO(0x10000,127) |
| @@ -1761,13 +1619,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1761 | .mfr_id = MANUFACTURER_TOSHIBA, | 1619 | .mfr_id = MANUFACTURER_TOSHIBA, |
| 1762 | .dev_id = TC58FVT641, | 1620 | .dev_id = TC58FVT641, |
| 1763 | .name = "Toshiba TC58FVT641", | 1621 | .name = "Toshiba TC58FVT641", |
| 1764 | .uaddr = { | 1622 | .devtypes = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8, |
| 1765 | [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ | 1623 | .uaddr = MTD_UADDR_0x0AAA_0x0555, |
| 1766 | [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ | 1624 | .dev_size = SIZE_8MiB, |
| 1767 | }, | 1625 | .cmd_set = P_ID_AMD_STD, |
| 1768 | .DevSize = SIZE_8MiB, | 1626 | .nr_regions = 2, |
| 1769 | .CmdSet = P_ID_AMD_STD, | ||
| 1770 | .NumEraseRegions= 2, | ||
| 1771 | .regions = { | 1627 | .regions = { |
| 1772 | ERASEINFO(0x10000,127), | 1628 | ERASEINFO(0x10000,127), |
| 1773 | ERASEINFO(0x02000,8) | 1629 | ERASEINFO(0x02000,8) |
| @@ -1776,12 +1632,11 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1776 | .mfr_id = MANUFACTURER_WINBOND, | 1632 | .mfr_id = MANUFACTURER_WINBOND, |
| 1777 | .dev_id = W49V002A, | 1633 | .dev_id = W49V002A, |
| 1778 | .name = "Winbond W49V002A", | 1634 | .name = "Winbond W49V002A", |
| 1779 | .uaddr = { | 1635 | .devtypes = CFI_DEVICETYPE_X8, |
| 1780 | [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ | 1636 | .uaddr = MTD_UADDR_0x5555_0x2AAA, |
| 1781 | }, | 1637 | .dev_size = SIZE_256KiB, |
| 1782 | .DevSize = SIZE_256KiB, | 1638 | .cmd_set = P_ID_AMD_STD, |
| 1783 | .CmdSet = P_ID_AMD_STD, | 1639 | .nr_regions = 4, |
| 1784 | .NumEraseRegions= 4, | ||
| 1785 | .regions = { | 1640 | .regions = { |
| 1786 | ERASEINFO(0x10000, 3), | 1641 | ERASEINFO(0x10000, 3), |
| 1787 | ERASEINFO(0x08000, 1), | 1642 | ERASEINFO(0x08000, 1), |
| @@ -1791,15 +1646,7 @@ static const struct amd_flash_info jedec_table[] = { | |||
| 1791 | } | 1646 | } |
| 1792 | }; | 1647 | }; |
| 1793 | 1648 | ||
| 1794 | 1649 | static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base, | |
| 1795 | static int cfi_jedec_setup(struct cfi_private *p_cfi, int index); | ||
| 1796 | |||
| 1797 | static int jedec_probe_chip(struct map_info *map, __u32 base, | ||
| 1798 | unsigned long *chip_map, struct cfi_private *cfi); | ||
| 1799 | |||
| 1800 | static struct mtd_info *jedec_probe(struct map_info *map); | ||
| 1801 | |||
| 1802 | static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, | ||
| 1803 | struct cfi_private *cfi) | 1650 | struct cfi_private *cfi) |
| 1804 | { | 1651 | { |
| 1805 | map_word result; | 1652 | map_word result; |
| @@ -1810,7 +1657,7 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, | |||
| 1810 | return result.x[0] & mask; | 1657 | return result.x[0] & mask; |
| 1811 | } | 1658 | } |
| 1812 | 1659 | ||
| 1813 | static inline u32 jedec_read_id(struct map_info *map, __u32 base, | 1660 | static inline u32 jedec_read_id(struct map_info *map, uint32_t base, |
| 1814 | struct cfi_private *cfi) | 1661 | struct cfi_private *cfi) |
| 1815 | { | 1662 | { |
| 1816 | map_word result; | 1663 | map_word result; |
| @@ -1821,8 +1668,7 @@ static inline u32 jedec_read_id(struct map_info *map, __u32 base, | |||
| 1821 | return result.x[0] & mask; | 1668 | return result.x[0] & mask; |
| 1822 | } | 1669 | } |
| 1823 | 1670 | ||
| 1824 | static inline void jedec_reset(u32 base, struct map_info *map, | 1671 | static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi) |
| 1825 | struct cfi_private *cfi) | ||
| 1826 | { | 1672 | { |
| 1827 | /* Reset */ | 1673 | /* Reset */ |
| 1828 | 1674 | ||
| @@ -1832,7 +1678,7 @@ static inline void jedec_reset(u32 base, struct map_info *map, | |||
| 1832 | * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips | 1678 | * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips |
| 1833 | * as they will ignore the writes and dont care what address | 1679 | * as they will ignore the writes and dont care what address |
| 1834 | * the F0 is written to */ | 1680 | * the F0 is written to */ |
| 1835 | if(cfi->addr_unlock1) { | 1681 | if (cfi->addr_unlock1) { |
| 1836 | DEBUG( MTD_DEBUG_LEVEL3, | 1682 | DEBUG( MTD_DEBUG_LEVEL3, |
| 1837 | "reset unlock called %x %x \n", | 1683 | "reset unlock called %x %x \n", |
| 1838 | cfi->addr_unlock1,cfi->addr_unlock2); | 1684 | cfi->addr_unlock1,cfi->addr_unlock2); |
| @@ -1841,7 +1687,7 @@ static inline void jedec_reset(u32 base, struct map_info *map, | |||
| 1841 | } | 1687 | } |
| 1842 | 1688 | ||
| 1843 | cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); | 1689 | cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); |
| 1844 | /* Some misdesigned intel chips do not respond for 0xF0 for a reset, | 1690 | /* Some misdesigned Intel chips do not respond for 0xF0 for a reset, |
| 1845 | * so ensure we're in read mode. Send both the Intel and the AMD command | 1691 | * so ensure we're in read mode. Send both the Intel and the AMD command |
| 1846 | * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so | 1692 | * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so |
| 1847 | * this should be safe. | 1693 | * this should be safe. |
| @@ -1851,42 +1697,20 @@ static inline void jedec_reset(u32 base, struct map_info *map, | |||
| 1851 | } | 1697 | } |
| 1852 | 1698 | ||
| 1853 | 1699 | ||
| 1854 | static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type) | ||
| 1855 | { | ||
| 1856 | int uaddr_idx; | ||
| 1857 | __u8 uaddr = MTD_UADDR_NOT_SUPPORTED; | ||
| 1858 | |||
| 1859 | switch ( device_type ) { | ||
| 1860 | case CFI_DEVICETYPE_X8: uaddr_idx = 0; break; | ||
| 1861 | case CFI_DEVICETYPE_X16: uaddr_idx = 1; break; | ||
| 1862 | case CFI_DEVICETYPE_X32: uaddr_idx = 2; break; | ||
| 1863 | default: | ||
| 1864 | printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n", | ||
| 1865 | __func__, device_type); | ||
| 1866 | goto uaddr_done; | ||
| 1867 | } | ||
| 1868 | |||
| 1869 | uaddr = finfo->uaddr[uaddr_idx]; | ||
| 1870 | |||
| 1871 | if (uaddr != MTD_UADDR_NOT_SUPPORTED ) { | ||
| 1872 | /* ASSERT("The unlock addresses for non-8-bit mode | ||
| 1873 | are bollocks. We don't really need an array."); */ | ||
| 1874 | uaddr = finfo->uaddr[0]; | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | uaddr_done: | ||
| 1878 | return uaddr; | ||
| 1879 | } | ||
| 1880 | |||
| 1881 | |||
| 1882 | static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) | 1700 | static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) |
| 1883 | { | 1701 | { |
| 1884 | int i,num_erase_regions; | 1702 | int i,num_erase_regions; |
| 1885 | __u8 uaddr; | 1703 | uint8_t uaddr; |
| 1886 | 1704 | ||
| 1887 | printk("Found: %s\n",jedec_table[index].name); | 1705 | if (! (jedec_table[index].devtypes & p_cfi->device_type)) { |
| 1706 | DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n", | ||
| 1707 | jedec_table[index].name, 4 * (1<<p_cfi->device_type)); | ||
| 1708 | return 0; | ||
| 1709 | } | ||
| 1710 | |||
| 1711 | printk(KERN_INFO "Found: %s\n",jedec_table[index].name); | ||
| 1888 | 1712 | ||
| 1889 | num_erase_regions = jedec_table[index].NumEraseRegions; | 1713 | num_erase_regions = jedec_table[index].nr_regions; |
| 1890 | 1714 | ||
| 1891 | p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); | 1715 | p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL); |
| 1892 | if (!p_cfi->cfiq) { | 1716 | if (!p_cfi->cfiq) { |
| @@ -1896,9 +1720,9 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) | |||
| 1896 | 1720 | ||
| 1897 | memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); | 1721 | memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); |
| 1898 | 1722 | ||
| 1899 | p_cfi->cfiq->P_ID = jedec_table[index].CmdSet; | 1723 | p_cfi->cfiq->P_ID = jedec_table[index].cmd_set; |
| 1900 | p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions; | 1724 | p_cfi->cfiq->NumEraseRegions = jedec_table[index].nr_regions; |
| 1901 | p_cfi->cfiq->DevSize = jedec_table[index].DevSize; | 1725 | p_cfi->cfiq->DevSize = jedec_table[index].dev_size; |
| 1902 | p_cfi->cfi_mode = CFI_MODE_JEDEC; | 1726 | p_cfi->cfi_mode = CFI_MODE_JEDEC; |
| 1903 | 1727 | ||
| 1904 | for (i=0; i<num_erase_regions; i++){ | 1728 | for (i=0; i<num_erase_regions; i++){ |
| @@ -1910,14 +1734,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) | |||
| 1910 | p_cfi->mfr = jedec_table[index].mfr_id; | 1734 | p_cfi->mfr = jedec_table[index].mfr_id; |
| 1911 | p_cfi->id = jedec_table[index].dev_id; | 1735 | p_cfi->id = jedec_table[index].dev_id; |
| 1912 | 1736 | ||
| 1913 | uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type); | 1737 | uaddr = jedec_table[index].uaddr; |
| 1914 | if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) { | ||
| 1915 | kfree( p_cfi->cfiq ); | ||
| 1916 | return 0; | ||
| 1917 | } | ||
| 1918 | 1738 | ||
| 1919 | p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1; | 1739 | /* The table has unlock addresses in _bytes_, and we try not to let |
| 1920 | p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2; | 1740 | our brains explode when we see the datasheets talking about address |
| 1741 | lines numbered from A-1 to A18. The CFI table has unlock addresses | ||
| 1742 | in device-words according to the mode the device is connected in */ | ||
| 1743 | p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 / p_cfi->device_type; | ||
| 1744 | p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 / p_cfi->device_type; | ||
| 1921 | 1745 | ||
| 1922 | return 1; /* ok */ | 1746 | return 1; /* ok */ |
| 1923 | } | 1747 | } |
| @@ -1930,14 +1754,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) | |||
| 1930 | * be perfect - consequently there should be some module parameters that | 1754 | * be perfect - consequently there should be some module parameters that |
| 1931 | * could be manually specified to force the chip info. | 1755 | * could be manually specified to force the chip info. |
| 1932 | */ | 1756 | */ |
| 1933 | static inline int jedec_match( __u32 base, | 1757 | static inline int jedec_match( uint32_t base, |
| 1934 | struct map_info *map, | 1758 | struct map_info *map, |
| 1935 | struct cfi_private *cfi, | 1759 | struct cfi_private *cfi, |
| 1936 | const struct amd_flash_info *finfo ) | 1760 | const struct amd_flash_info *finfo ) |
| 1937 | { | 1761 | { |
| 1938 | int rc = 0; /* failure until all tests pass */ | 1762 | int rc = 0; /* failure until all tests pass */ |
| 1939 | u32 mfr, id; | 1763 | u32 mfr, id; |
| 1940 | __u8 uaddr; | 1764 | uint8_t uaddr; |
| 1941 | 1765 | ||
| 1942 | /* | 1766 | /* |
| 1943 | * The IDs must match. For X16 and X32 devices operating in | 1767 | * The IDs must match. For X16 and X32 devices operating in |
| @@ -1950,8 +1774,8 @@ static inline int jedec_match( __u32 base, | |||
| 1950 | */ | 1774 | */ |
| 1951 | switch (cfi->device_type) { | 1775 | switch (cfi->device_type) { |
| 1952 | case CFI_DEVICETYPE_X8: | 1776 | case CFI_DEVICETYPE_X8: |
| 1953 | mfr = (__u8)finfo->mfr_id; | 1777 | mfr = (uint8_t)finfo->mfr_id; |
| 1954 | id = (__u8)finfo->dev_id; | 1778 | id = (uint8_t)finfo->dev_id; |
| 1955 | 1779 | ||
| 1956 | /* bjd: it seems that if we do this, we can end up | 1780 | /* bjd: it seems that if we do this, we can end up |
| 1957 | * detecting 16bit flashes as an 8bit device, even though | 1781 | * detecting 16bit flashes as an 8bit device, even though |
| @@ -1964,12 +1788,12 @@ static inline int jedec_match( __u32 base, | |||
| 1964 | } | 1788 | } |
| 1965 | break; | 1789 | break; |
| 1966 | case CFI_DEVICETYPE_X16: | 1790 | case CFI_DEVICETYPE_X16: |
| 1967 | mfr = (__u16)finfo->mfr_id; | 1791 | mfr = (uint16_t)finfo->mfr_id; |
| 1968 | id = (__u16)finfo->dev_id; | 1792 | id = (uint16_t)finfo->dev_id; |
| 1969 | break; | 1793 | break; |
| 1970 | case CFI_DEVICETYPE_X32: | 1794 | case CFI_DEVICETYPE_X32: |
| 1971 | mfr = (__u16)finfo->mfr_id; | 1795 | mfr = (uint16_t)finfo->mfr_id; |
| 1972 | id = (__u32)finfo->dev_id; | 1796 | id = (uint32_t)finfo->dev_id; |
| 1973 | break; | 1797 | break; |
| 1974 | default: | 1798 | default: |
| 1975 | printk(KERN_WARNING | 1799 | printk(KERN_WARNING |
| @@ -1984,25 +1808,25 @@ static inline int jedec_match( __u32 base, | |||
| 1984 | /* the part size must fit in the memory window */ | 1808 | /* the part size must fit in the memory window */ |
| 1985 | DEBUG( MTD_DEBUG_LEVEL3, | 1809 | DEBUG( MTD_DEBUG_LEVEL3, |
| 1986 | "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", | 1810 | "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", |
| 1987 | __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) ); | 1811 | __func__, base, 1 << finfo->dev_size, base + (1 << finfo->dev_size) ); |
| 1988 | if ( base + cfi_interleave(cfi) * ( 1 << finfo->DevSize ) > map->size ) { | 1812 | if ( base + cfi_interleave(cfi) * ( 1 << finfo->dev_size ) > map->size ) { |
| 1989 | DEBUG( MTD_DEBUG_LEVEL3, | 1813 | DEBUG( MTD_DEBUG_LEVEL3, |
| 1990 | "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", | 1814 | "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", |
| 1991 | __func__, finfo->mfr_id, finfo->dev_id, | 1815 | __func__, finfo->mfr_id, finfo->dev_id, |
| 1992 | 1 << finfo->DevSize ); | 1816 | 1 << finfo->dev_size ); |
| 1993 | goto match_done; | 1817 | goto match_done; |
| 1994 | } | 1818 | } |
| 1995 | 1819 | ||
| 1996 | uaddr = finfo_uaddr(finfo, cfi->device_type); | 1820 | if (! (finfo->devtypes & cfi->device_type)) |
| 1997 | if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) { | ||
| 1998 | goto match_done; | 1821 | goto match_done; |
| 1999 | } | 1822 | |
| 1823 | uaddr = finfo->uaddr; | ||
| 2000 | 1824 | ||
| 2001 | DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", | 1825 | DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", |
| 2002 | __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); | 1826 | __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); |
| 2003 | if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr | 1827 | if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr |
| 2004 | && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1 || | 1828 | && ( unlock_addrs[uaddr].addr1 / cfi->device_type != cfi->addr_unlock1 || |
| 2005 | unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) { | 1829 | unlock_addrs[uaddr].addr2 / cfi->device_type != cfi->addr_unlock2 ) ) { |
| 2006 | DEBUG( MTD_DEBUG_LEVEL3, | 1830 | DEBUG( MTD_DEBUG_LEVEL3, |
| 2007 | "MTD %s(): 0x%.4x 0x%.4x did not match\n", | 1831 | "MTD %s(): 0x%.4x 0x%.4x did not match\n", |
| 2008 | __func__, | 1832 | __func__, |
| @@ -2042,7 +1866,7 @@ static inline int jedec_match( __u32 base, | |||
| 2042 | * were truly frobbing a real device. | 1866 | * were truly frobbing a real device. |
| 2043 | */ | 1867 | */ |
| 2044 | DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); | 1868 | DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); |
| 2045 | if(cfi->addr_unlock1) { | 1869 | if (cfi->addr_unlock1) { |
| 2046 | cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); | 1870 | cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); |
| 2047 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); | 1871 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); |
| 2048 | } | 1872 | } |
| @@ -2068,8 +1892,8 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
| 2068 | if (MTD_UADDR_UNNECESSARY == uaddr_idx) | 1892 | if (MTD_UADDR_UNNECESSARY == uaddr_idx) |
| 2069 | return 0; | 1893 | return 0; |
| 2070 | 1894 | ||
| 2071 | cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1; | 1895 | cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 / cfi->device_type; |
| 2072 | cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2; | 1896 | cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 / cfi->device_type; |
| 2073 | } | 1897 | } |
| 2074 | 1898 | ||
| 2075 | /* Make certain we aren't probing past the end of map */ | 1899 | /* Make certain we aren't probing past the end of map */ |
| @@ -2081,19 +1905,11 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
| 2081 | 1905 | ||
| 2082 | } | 1906 | } |
| 2083 | /* Ensure the unlock addresses we try stay inside the map */ | 1907 | /* Ensure the unlock addresses we try stay inside the map */ |
| 2084 | probe_offset1 = cfi_build_cmd_addr( | 1908 | probe_offset1 = cfi_build_cmd_addr(cfi->addr_unlock1, cfi_interleave(cfi), cfi->device_type); |
| 2085 | cfi->addr_unlock1, | 1909 | probe_offset2 = cfi_build_cmd_addr(cfi->addr_unlock2, cfi_interleave(cfi), cfi->device_type); |
| 2086 | cfi_interleave(cfi), | ||
| 2087 | cfi->device_type); | ||
| 2088 | probe_offset2 = cfi_build_cmd_addr( | ||
| 2089 | cfi->addr_unlock1, | ||
| 2090 | cfi_interleave(cfi), | ||
| 2091 | cfi->device_type); | ||
| 2092 | if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || | 1910 | if ( ((base + probe_offset1 + map_bankwidth(map)) >= map->size) || |
| 2093 | ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) | 1911 | ((base + probe_offset2 + map_bankwidth(map)) >= map->size)) |
| 2094 | { | ||
| 2095 | goto retry; | 1912 | goto retry; |
| 2096 | } | ||
| 2097 | 1913 | ||
| 2098 | /* Reset */ | 1914 | /* Reset */ |
| 2099 | jedec_reset(base, map, cfi); | 1915 | jedec_reset(base, map, cfi); |
| @@ -2128,8 +1944,8 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, | |||
| 2128 | } | 1944 | } |
| 2129 | goto retry; | 1945 | goto retry; |
| 2130 | } else { | 1946 | } else { |
| 2131 | __u16 mfr; | 1947 | uint16_t mfr; |
| 2132 | __u16 id; | 1948 | uint16_t id; |
| 2133 | 1949 | ||
| 2134 | /* Make sure it is a chip of the same manufacturer and id */ | 1950 | /* Make sure it is a chip of the same manufacturer and id */ |
| 2135 | mfr = jedec_read_mfr(map, base, cfi); | 1951 | mfr = jedec_read_mfr(map, base, cfi); |
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 23fab14f1637..b44292abd9f7 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | * | 9 | * |
| 10 | * mtdparts=<mtddef>[;<mtddef] | 10 | * mtdparts=<mtddef>[;<mtddef] |
| 11 | * <mtddef> := <mtd-id>:<partdef>[,<partdef>] | 11 | * <mtddef> := <mtd-id>:<partdef>[,<partdef>] |
| 12 | * <partdef> := <size>[@offset][<name>][ro] | 12 | * <partdef> := <size>[@offset][<name>][ro][lk] |
| 13 | * <mtd-id> := unique name used in mapping driver/device (mtd->name) | 13 | * <mtd-id> := unique name used in mapping driver/device (mtd->name) |
| 14 | * <size> := standard linux memsize OR "-" to denote all remaining space | 14 | * <size> := standard linux memsize OR "-" to denote all remaining space |
| 15 | * <name> := '(' NAME ')' | 15 | * <name> := '(' NAME ')' |
| @@ -143,6 +143,13 @@ static struct mtd_partition * newpart(char *s, | |||
| 143 | s += 2; | 143 | s += 2; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | /* if lk is found do NOT unlock the MTD partition*/ | ||
| 147 | if (strncmp(s, "lk", 2) == 0) | ||
| 148 | { | ||
| 149 | mask_flags |= MTD_POWERUP_LOCK; | ||
| 150 | s += 2; | ||
| 151 | } | ||
| 152 | |||
| 146 | /* test if more partitions are following */ | 153 | /* test if more partitions are following */ |
| 147 | if (*s == ',') | 154 | if (*s == ',') |
| 148 | { | 155 | { |
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index 90acf57c19bd..846989f292e3 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c | |||
| @@ -632,7 +632,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 632 | len = ((from | 0x1ff) + 1) - from; | 632 | len = ((from | 0x1ff) + 1) - from; |
| 633 | 633 | ||
| 634 | /* The ECC will not be calculated correctly if less than 512 is read */ | 634 | /* The ECC will not be calculated correctly if less than 512 is read */ |
| 635 | if (len != 0x200 && eccbuf) | 635 | if (len != 0x200) |
| 636 | printk(KERN_WARNING | 636 | printk(KERN_WARNING |
| 637 | "ECC needs a full sector read (adr: %lx size %lx)\n", | 637 | "ECC needs a full sector read (adr: %lx size %lx)\n", |
| 638 | (long) from, (long) len); | 638 | (long) from, (long) len); |
| @@ -896,7 +896,7 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 896 | /* Let the caller know we completed it */ | 896 | /* Let the caller know we completed it */ |
| 897 | *retlen += len; | 897 | *retlen += len; |
| 898 | 898 | ||
| 899 | if (eccbuf) { | 899 | { |
| 900 | unsigned char x[8]; | 900 | unsigned char x[8]; |
| 901 | size_t dummy; | 901 | size_t dummy; |
| 902 | int ret; | 902 | int ret; |
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 2b30b587c6e8..83be3461658f 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c | |||
| @@ -748,7 +748,7 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 748 | WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd); | 748 | WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd); |
| 749 | 749 | ||
| 750 | /* On interleaved devices the flags for 2nd half 512 are before data */ | 750 | /* On interleaved devices the flags for 2nd half 512 are before data */ |
| 751 | if (eccbuf && before) | 751 | if (before) |
| 752 | fto -= 2; | 752 | fto -= 2; |
| 753 | 753 | ||
| 754 | /* issue the Serial Data In command to initial the Page Program process */ | 754 | /* issue the Serial Data In command to initial the Page Program process */ |
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 4ea50a1dda85..99fd210feaec 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c | |||
| @@ -323,7 +323,7 @@ static int flash_probe (void) | |||
| 323 | /* put the flash back into command mode */ | 323 | /* put the flash back into command mode */ |
| 324 | write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000); | 324 | write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000); |
| 325 | 325 | ||
| 326 | return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || FLASH_DEVICE_16mbit_BOTTOM)); | 326 | return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || devtype == FLASH_DEVICE_16mbit_BOTTOM)); |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | /* | 329 | /* |
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index a5ed6d232c35..b35e4813a3a5 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c | |||
| @@ -420,7 +420,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 420 | status = dataflash_waitready(priv->spi); | 420 | status = dataflash_waitready(priv->spi); |
| 421 | 421 | ||
| 422 | /* Check result of the compare operation */ | 422 | /* Check result of the compare operation */ |
| 423 | if ((status & (1 << 6)) == 1) { | 423 | if (status & (1 << 6)) { |
| 424 | printk(KERN_ERR "%s: compare page %u, err %d\n", | 424 | printk(KERN_ERR "%s: compare page %u, err %d\n", |
| 425 | spi->dev.bus_id, pageaddr, status); | 425 | spi->dev.bus_id, pageaddr, status); |
| 426 | remaining = 0; | 426 | remaining = 0; |
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index a592fc04cf78..12c253664eb2 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig | |||
| @@ -110,13 +110,6 @@ config MTD_SUN_UFLASH | |||
| 110 | Sun Microsystems boardsets. This driver will require CFI support | 110 | Sun Microsystems boardsets. This driver will require CFI support |
| 111 | in the kernel, so if you did not enable CFI previously, do that now. | 111 | in the kernel, so if you did not enable CFI previously, do that now. |
| 112 | 112 | ||
| 113 | config MTD_PNC2000 | ||
| 114 | tristate "CFI Flash device mapped on Photron PNC-2000" | ||
| 115 | depends on X86 && MTD_CFI && MTD_PARTITIONS | ||
| 116 | help | ||
| 117 | PNC-2000 is the name of Network Camera product from PHOTRON | ||
| 118 | Ltd. in Japan. It uses CFI-compliant flash. | ||
| 119 | |||
| 120 | config MTD_SC520CDP | 113 | config MTD_SC520CDP |
| 121 | tristate "CFI Flash device mapped on AMD SC520 CDP" | 114 | tristate "CFI Flash device mapped on AMD SC520 CDP" |
| 122 | depends on X86 && MTD_CFI && MTD_CONCAT | 115 | depends on X86 && MTD_CFI && MTD_CONCAT |
| @@ -576,7 +569,7 @@ config MTD_BAST_MAXSIZE | |||
| 576 | default "4" | 569 | default "4" |
| 577 | 570 | ||
| 578 | config MTD_SHARP_SL | 571 | config MTD_SHARP_SL |
| 579 | bool "ROM mapped on Sharp SL Series" | 572 | tristate "ROM mapped on Sharp SL Series" |
| 580 | depends on ARCH_PXA | 573 | depends on ARCH_PXA |
| 581 | help | 574 | help |
| 582 | This enables access to the flash chip on the Sharp SL Series of PDAs. | 575 | This enables access to the flash chip on the Sharp SL Series of PDAs. |
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 316382a1401b..a9cbe80f99a0 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile | |||
| @@ -28,7 +28,6 @@ obj-$(CONFIG_MTD_PHYSMAP) += physmap.o | |||
| 28 | obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o | 28 | obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o |
| 29 | obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o | 29 | obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o |
| 30 | obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o | 30 | obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o |
| 31 | obj-$(CONFIG_MTD_PNC2000) += pnc2000.o | ||
| 32 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o | 31 | obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o |
| 33 | obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o | 32 | obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o |
| 34 | obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o | 33 | obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o |
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 28c5ffd75233..f00e04efbe28 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c | |||
| @@ -20,11 +20,15 @@ | |||
| 20 | #include <linux/mtd/map.h> | 20 | #include <linux/mtd/map.h> |
| 21 | #include <linux/mtd/partitions.h> | 21 | #include <linux/mtd/partitions.h> |
| 22 | #include <linux/mtd/physmap.h> | 22 | #include <linux/mtd/physmap.h> |
| 23 | #include <linux/mtd/concat.h> | ||
| 23 | #include <asm/io.h> | 24 | #include <asm/io.h> |
| 24 | 25 | ||
| 26 | #define MAX_RESOURCES 4 | ||
| 27 | |||
| 25 | struct physmap_flash_info { | 28 | struct physmap_flash_info { |
| 26 | struct mtd_info *mtd; | 29 | struct mtd_info *mtd[MAX_RESOURCES]; |
| 27 | struct map_info map; | 30 | struct mtd_info *cmtd; |
| 31 | struct map_info map[MAX_RESOURCES]; | ||
| 28 | struct resource *res; | 32 | struct resource *res; |
| 29 | #ifdef CONFIG_MTD_PARTITIONS | 33 | #ifdef CONFIG_MTD_PARTITIONS |
| 30 | int nr_parts; | 34 | int nr_parts; |
| @@ -32,11 +36,11 @@ struct physmap_flash_info { | |||
| 32 | #endif | 36 | #endif |
| 33 | }; | 37 | }; |
| 34 | 38 | ||
| 35 | |||
| 36 | static int physmap_flash_remove(struct platform_device *dev) | 39 | static int physmap_flash_remove(struct platform_device *dev) |
| 37 | { | 40 | { |
| 38 | struct physmap_flash_info *info; | 41 | struct physmap_flash_info *info; |
| 39 | struct physmap_flash_data *physmap_data; | 42 | struct physmap_flash_data *physmap_data; |
| 43 | int i; | ||
| 40 | 44 | ||
| 41 | info = platform_get_drvdata(dev); | 45 | info = platform_get_drvdata(dev); |
| 42 | if (info == NULL) | 46 | if (info == NULL) |
| @@ -45,24 +49,33 @@ static int physmap_flash_remove(struct platform_device *dev) | |||
| 45 | 49 | ||
| 46 | physmap_data = dev->dev.platform_data; | 50 | physmap_data = dev->dev.platform_data; |
| 47 | 51 | ||
| 48 | if (info->mtd != NULL) { | 52 | #ifdef CONFIG_MTD_CONCAT |
| 53 | if (info->cmtd != info->mtd[0]) { | ||
| 54 | del_mtd_device(info->cmtd); | ||
| 55 | mtd_concat_destroy(info->cmtd); | ||
| 56 | } | ||
| 57 | #endif | ||
| 58 | |||
| 59 | for (i = 0; i < MAX_RESOURCES; i++) { | ||
| 60 | if (info->mtd[i] != NULL) { | ||
| 49 | #ifdef CONFIG_MTD_PARTITIONS | 61 | #ifdef CONFIG_MTD_PARTITIONS |
| 50 | if (info->nr_parts) { | 62 | if (info->nr_parts) { |
| 51 | del_mtd_partitions(info->mtd); | 63 | del_mtd_partitions(info->mtd[i]); |
| 52 | kfree(info->parts); | 64 | kfree(info->parts); |
| 53 | } else if (physmap_data->nr_parts) { | 65 | } else if (physmap_data->nr_parts) { |
| 54 | del_mtd_partitions(info->mtd); | 66 | del_mtd_partitions(info->mtd[i]); |
| 55 | } else { | 67 | } else { |
| 56 | del_mtd_device(info->mtd); | 68 | del_mtd_device(info->mtd[i]); |
| 57 | } | 69 | } |
| 58 | #else | 70 | #else |
| 59 | del_mtd_device(info->mtd); | 71 | del_mtd_device(info->mtd[i]); |
| 60 | #endif | 72 | #endif |
| 61 | map_destroy(info->mtd); | 73 | map_destroy(info->mtd[i]); |
| 62 | } | 74 | } |
| 63 | 75 | ||
| 64 | if (info->map.virt != NULL) | 76 | if (info->map[i].virt != NULL) |
| 65 | iounmap(info->map.virt); | 77 | iounmap(info->map[i].virt); |
| 78 | } | ||
| 66 | 79 | ||
| 67 | if (info->res != NULL) { | 80 | if (info->res != NULL) { |
| 68 | release_resource(info->res); | 81 | release_resource(info->res); |
| @@ -82,16 +95,14 @@ static int physmap_flash_probe(struct platform_device *dev) | |||
| 82 | struct physmap_flash_data *physmap_data; | 95 | struct physmap_flash_data *physmap_data; |
| 83 | struct physmap_flash_info *info; | 96 | struct physmap_flash_info *info; |
| 84 | const char **probe_type; | 97 | const char **probe_type; |
| 85 | int err; | 98 | int err = 0; |
| 99 | int i; | ||
| 100 | int devices_found = 0; | ||
| 86 | 101 | ||
| 87 | physmap_data = dev->dev.platform_data; | 102 | physmap_data = dev->dev.platform_data; |
| 88 | if (physmap_data == NULL) | 103 | if (physmap_data == NULL) |
| 89 | return -ENODEV; | 104 | return -ENODEV; |
| 90 | 105 | ||
| 91 | printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n", | ||
| 92 | (unsigned long long)(dev->resource->end - dev->resource->start + 1), | ||
| 93 | (unsigned long long)dev->resource->start); | ||
| 94 | |||
| 95 | info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); | 106 | info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL); |
| 96 | if (info == NULL) { | 107 | if (info == NULL) { |
| 97 | err = -ENOMEM; | 108 | err = -ENOMEM; |
| @@ -100,56 +111,83 @@ static int physmap_flash_probe(struct platform_device *dev) | |||
| 100 | 111 | ||
| 101 | platform_set_drvdata(dev, info); | 112 | platform_set_drvdata(dev, info); |
| 102 | 113 | ||
| 103 | info->res = request_mem_region(dev->resource->start, | 114 | for (i = 0; i < dev->num_resources; i++) { |
| 104 | dev->resource->end - dev->resource->start + 1, | 115 | printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n", |
| 105 | dev->dev.bus_id); | 116 | (unsigned long long)(dev->resource[i].end - dev->resource[i].start + 1), |
| 106 | if (info->res == NULL) { | 117 | (unsigned long long)dev->resource[i].start); |
| 107 | dev_err(&dev->dev, "Could not reserve memory region\n"); | 118 | |
| 108 | err = -ENOMEM; | 119 | info->res = request_mem_region(dev->resource[i].start, |
| 109 | goto err_out; | 120 | dev->resource[i].end - dev->resource[i].start + 1, |
| 110 | } | 121 | dev->dev.bus_id); |
| 122 | if (info->res == NULL) { | ||
| 123 | dev_err(&dev->dev, "Could not reserve memory region\n"); | ||
| 124 | err = -ENOMEM; | ||
| 125 | goto err_out; | ||
| 126 | } | ||
| 111 | 127 | ||
| 112 | info->map.name = dev->dev.bus_id; | 128 | info->map[i].name = dev->dev.bus_id; |
| 113 | info->map.phys = dev->resource->start; | 129 | info->map[i].phys = dev->resource[i].start; |
| 114 | info->map.size = dev->resource->end - dev->resource->start + 1; | 130 | info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1; |
| 115 | info->map.bankwidth = physmap_data->width; | 131 | info->map[i].bankwidth = physmap_data->width; |
| 116 | info->map.set_vpp = physmap_data->set_vpp; | 132 | info->map[i].set_vpp = physmap_data->set_vpp; |
| 133 | |||
| 134 | info->map[i].virt = ioremap(info->map[i].phys, info->map[i].size); | ||
| 135 | if (info->map[i].virt == NULL) { | ||
| 136 | dev_err(&dev->dev, "Failed to ioremap flash region\n"); | ||
| 137 | err = EIO; | ||
| 138 | goto err_out; | ||
| 139 | } | ||
| 117 | 140 | ||
| 118 | info->map.virt = ioremap(info->map.phys, info->map.size); | 141 | simple_map_init(&info->map[i]); |
| 119 | if (info->map.virt == NULL) { | ||
| 120 | dev_err(&dev->dev, "Failed to ioremap flash region\n"); | ||
| 121 | err = EIO; | ||
| 122 | goto err_out; | ||
| 123 | } | ||
| 124 | 142 | ||
| 125 | simple_map_init(&info->map); | 143 | probe_type = rom_probe_types; |
| 144 | for (; info->mtd[i] == NULL && *probe_type != NULL; probe_type++) | ||
| 145 | info->mtd[i] = do_map_probe(*probe_type, &info->map[i]); | ||
| 146 | if (info->mtd[i] == NULL) { | ||
| 147 | dev_err(&dev->dev, "map_probe failed\n"); | ||
| 148 | err = -ENXIO; | ||
| 149 | goto err_out; | ||
| 150 | } else { | ||
| 151 | devices_found++; | ||
| 152 | } | ||
| 153 | info->mtd[i]->owner = THIS_MODULE; | ||
| 154 | } | ||
| 126 | 155 | ||
| 127 | probe_type = rom_probe_types; | 156 | if (devices_found == 1) { |
| 128 | for (; info->mtd == NULL && *probe_type != NULL; probe_type++) | 157 | info->cmtd = info->mtd[0]; |
| 129 | info->mtd = do_map_probe(*probe_type, &info->map); | 158 | } else if (devices_found > 1) { |
| 130 | if (info->mtd == NULL) { | 159 | /* |
| 131 | dev_err(&dev->dev, "map_probe failed\n"); | 160 | * We detected multiple devices. Concatenate them together. |
| 161 | */ | ||
| 162 | #ifdef CONFIG_MTD_CONCAT | ||
| 163 | info->cmtd = mtd_concat_create(info->mtd, devices_found, dev->dev.bus_id); | ||
| 164 | if (info->cmtd == NULL) | ||
| 165 | err = -ENXIO; | ||
| 166 | #else | ||
| 167 | printk(KERN_ERR "physmap-flash: multiple devices " | ||
| 168 | "found but MTD concat support disabled.\n"); | ||
| 132 | err = -ENXIO; | 169 | err = -ENXIO; |
| 133 | goto err_out; | 170 | #endif |
| 134 | } | 171 | } |
| 135 | info->mtd->owner = THIS_MODULE; | 172 | if (err) |
| 173 | goto err_out; | ||
| 136 | 174 | ||
| 137 | #ifdef CONFIG_MTD_PARTITIONS | 175 | #ifdef CONFIG_MTD_PARTITIONS |
| 138 | err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0); | 176 | err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0); |
| 139 | if (err > 0) { | 177 | if (err > 0) { |
| 140 | add_mtd_partitions(info->mtd, info->parts, err); | 178 | add_mtd_partitions(info->cmtd, info->parts, err); |
| 141 | return 0; | 179 | return 0; |
| 142 | } | 180 | } |
| 143 | 181 | ||
| 144 | if (physmap_data->nr_parts) { | 182 | if (physmap_data->nr_parts) { |
| 145 | printk(KERN_NOTICE "Using physmap partition information\n"); | 183 | printk(KERN_NOTICE "Using physmap partition information\n"); |
| 146 | add_mtd_partitions(info->mtd, physmap_data->parts, | 184 | add_mtd_partitions(info->cmtd, physmap_data->parts, |
| 147 | physmap_data->nr_parts); | 185 | physmap_data->nr_parts); |
| 148 | return 0; | 186 | return 0; |
| 149 | } | 187 | } |
| 150 | #endif | 188 | #endif |
| 151 | 189 | ||
| 152 | add_mtd_device(info->mtd); | 190 | add_mtd_device(info->cmtd); |
| 153 | return 0; | 191 | return 0; |
| 154 | 192 | ||
| 155 | err_out: | 193 | err_out: |
| @@ -162,9 +200,11 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state | |||
| 162 | { | 200 | { |
| 163 | struct physmap_flash_info *info = platform_get_drvdata(dev); | 201 | struct physmap_flash_info *info = platform_get_drvdata(dev); |
| 164 | int ret = 0; | 202 | int ret = 0; |
| 203 | int i; | ||
| 165 | 204 | ||
| 166 | if (info) | 205 | if (info) |
| 167 | ret = info->mtd->suspend(info->mtd); | 206 | for (i = 0; i < MAX_RESOURCES; i++) |
| 207 | ret |= info->mtd[i]->suspend(info->mtd[i]); | ||
| 168 | 208 | ||
| 169 | return ret; | 209 | return ret; |
| 170 | } | 210 | } |
| @@ -172,27 +212,35 @@ static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state | |||
| 172 | static int physmap_flash_resume(struct platform_device *dev) | 212 | static int physmap_flash_resume(struct platform_device *dev) |
| 173 | { | 213 | { |
| 174 | struct physmap_flash_info *info = platform_get_drvdata(dev); | 214 | struct physmap_flash_info *info = platform_get_drvdata(dev); |
| 215 | int i; | ||
| 216 | |||
| 175 | if (info) | 217 | if (info) |
| 176 | info->mtd->resume(info->mtd); | 218 | for (i = 0; i < MAX_RESOURCES; i++) |
| 219 | info->mtd[i]->resume(info->mtd[i]); | ||
| 177 | return 0; | 220 | return 0; |
| 178 | } | 221 | } |
| 179 | 222 | ||
| 180 | static void physmap_flash_shutdown(struct platform_device *dev) | 223 | static void physmap_flash_shutdown(struct platform_device *dev) |
| 181 | { | 224 | { |
| 182 | struct physmap_flash_info *info = platform_get_drvdata(dev); | 225 | struct physmap_flash_info *info = platform_get_drvdata(dev); |
| 183 | if (info && info->mtd->suspend(info->mtd) == 0) | 226 | int i; |
| 184 | info->mtd->resume(info->mtd); | 227 | |
| 228 | for (i = 0; i < MAX_RESOURCES; i++) | ||
| 229 | if (info && info->mtd[i]->suspend(info->mtd[i]) == 0) | ||
| 230 | info->mtd[i]->resume(info->mtd[i]); | ||
| 185 | } | 231 | } |
| 232 | #else | ||
| 233 | #define physmap_flash_suspend NULL | ||
| 234 | #define physmap_flash_resume NULL | ||
| 235 | #define physmap_flash_shutdown NULL | ||
| 186 | #endif | 236 | #endif |
| 187 | 237 | ||
| 188 | static struct platform_driver physmap_flash_driver = { | 238 | static struct platform_driver physmap_flash_driver = { |
| 189 | .probe = physmap_flash_probe, | 239 | .probe = physmap_flash_probe, |
| 190 | .remove = physmap_flash_remove, | 240 | .remove = physmap_flash_remove, |
| 191 | #ifdef CONFIG_PM | ||
| 192 | .suspend = physmap_flash_suspend, | 241 | .suspend = physmap_flash_suspend, |
| 193 | .resume = physmap_flash_resume, | 242 | .resume = physmap_flash_resume, |
| 194 | .shutdown = physmap_flash_shutdown, | 243 | .shutdown = physmap_flash_shutdown, |
| 195 | #endif | ||
| 196 | .driver = { | 244 | .driver = { |
| 197 | .name = "physmap-flash", | 245 | .name = "physmap-flash", |
| 198 | }, | 246 | }, |
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index aeed9ea79714..49acd4171893 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c | |||
| @@ -80,64 +80,6 @@ static int parse_obsolete_partitions(struct of_device *dev, | |||
| 80 | 80 | ||
| 81 | return nr_parts; | 81 | return nr_parts; |
| 82 | } | 82 | } |
| 83 | |||
| 84 | static int __devinit parse_partitions(struct of_flash *info, | ||
| 85 | struct of_device *dev) | ||
| 86 | { | ||
| 87 | const char *partname; | ||
| 88 | static const char *part_probe_types[] | ||
| 89 | = { "cmdlinepart", "RedBoot", NULL }; | ||
| 90 | struct device_node *dp = dev->node, *pp; | ||
| 91 | int nr_parts, i; | ||
| 92 | |||
| 93 | /* First look for RedBoot table or partitions on the command | ||
| 94 | * line, these take precedence over device tree information */ | ||
| 95 | nr_parts = parse_mtd_partitions(info->mtd, part_probe_types, | ||
| 96 | &info->parts, 0); | ||
| 97 | if (nr_parts > 0) { | ||
| 98 | add_mtd_partitions(info->mtd, info->parts, nr_parts); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* First count the subnodes */ | ||
| 103 | nr_parts = 0; | ||
| 104 | for (pp = dp->child; pp; pp = pp->sibling) | ||
| 105 | nr_parts++; | ||
| 106 | |||
| 107 | if (nr_parts == 0) | ||
| 108 | return parse_obsolete_partitions(dev, info, dp); | ||
| 109 | |||
| 110 | info->parts = kzalloc(nr_parts * sizeof(*info->parts), | ||
| 111 | GFP_KERNEL); | ||
| 112 | if (!info->parts) | ||
| 113 | return -ENOMEM; | ||
| 114 | |||
| 115 | for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) { | ||
| 116 | const u32 *reg; | ||
| 117 | int len; | ||
| 118 | |||
| 119 | reg = of_get_property(pp, "reg", &len); | ||
| 120 | if (!reg || (len != 2*sizeof(u32))) { | ||
| 121 | dev_err(&dev->dev, "Invalid 'reg' on %s\n", | ||
| 122 | dp->full_name); | ||
| 123 | kfree(info->parts); | ||
| 124 | info->parts = NULL; | ||
| 125 | return -EINVAL; | ||
| 126 | } | ||
| 127 | info->parts[i].offset = reg[0]; | ||
| 128 | info->parts[i].size = reg[1]; | ||
| 129 | |||
| 130 | partname = of_get_property(pp, "label", &len); | ||
| 131 | if (!partname) | ||
| 132 | partname = of_get_property(pp, "name", &len); | ||
| 133 | info->parts[i].name = (char *)partname; | ||
| 134 | |||
| 135 | if (of_get_property(pp, "read-only", &len)) | ||
| 136 | info->parts[i].mask_flags = MTD_WRITEABLE; | ||
| 137 | } | ||
| 138 | |||
| 139 | return nr_parts; | ||
| 140 | } | ||
| 141 | #else /* MTD_PARTITIONS */ | 83 | #else /* MTD_PARTITIONS */ |
| 142 | #define OF_FLASH_PARTS(info) (0) | 84 | #define OF_FLASH_PARTS(info) (0) |
| 143 | #define parse_partitions(info, dev) (0) | 85 | #define parse_partitions(info, dev) (0) |
| @@ -212,6 +154,10 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev, | |||
| 212 | static int __devinit of_flash_probe(struct of_device *dev, | 154 | static int __devinit of_flash_probe(struct of_device *dev, |
| 213 | const struct of_device_id *match) | 155 | const struct of_device_id *match) |
| 214 | { | 156 | { |
| 157 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 158 | static const char *part_probe_types[] | ||
| 159 | = { "cmdlinepart", "RedBoot", NULL }; | ||
| 160 | #endif | ||
| 215 | struct device_node *dp = dev->node; | 161 | struct device_node *dp = dev->node; |
| 216 | struct resource res; | 162 | struct resource res; |
| 217 | struct of_flash *info; | 163 | struct of_flash *info; |
| @@ -274,13 +220,33 @@ static int __devinit of_flash_probe(struct of_device *dev, | |||
| 274 | } | 220 | } |
| 275 | info->mtd->owner = THIS_MODULE; | 221 | info->mtd->owner = THIS_MODULE; |
| 276 | 222 | ||
| 277 | err = parse_partitions(info, dev); | 223 | #ifdef CONFIG_MTD_PARTITIONS |
| 224 | /* First look for RedBoot table or partitions on the command | ||
| 225 | * line, these take precedence over device tree information */ | ||
| 226 | err = parse_mtd_partitions(info->mtd, part_probe_types, | ||
| 227 | &info->parts, 0); | ||
| 278 | if (err < 0) | 228 | if (err < 0) |
| 279 | goto err_out; | 229 | return err; |
| 230 | |||
| 231 | #ifdef CONFIG_MTD_OF_PARTS | ||
| 232 | if (err == 0) { | ||
| 233 | err = of_mtd_parse_partitions(&dev->dev, info->mtd, | ||
| 234 | dp, &info->parts); | ||
| 235 | if (err < 0) | ||
| 236 | return err; | ||
| 237 | } | ||
| 238 | #endif | ||
| 239 | |||
| 240 | if (err == 0) { | ||
| 241 | err = parse_obsolete_partitions(dev, info, dp); | ||
| 242 | if (err < 0) | ||
| 243 | return err; | ||
| 244 | } | ||
| 280 | 245 | ||
| 281 | if (err > 0) | 246 | if (err > 0) |
| 282 | add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err); | 247 | add_mtd_partitions(info->mtd, info->parts, err); |
| 283 | else | 248 | else |
| 249 | #endif | ||
| 284 | add_mtd_device(info->mtd); | 250 | add_mtd_device(info->mtd); |
| 285 | 251 | ||
| 286 | return 0; | 252 | return 0; |
diff --git a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c deleted file mode 100644 index d7e16c2d5c44..000000000000 --- a/drivers/mtd/maps/pnc2000.c +++ /dev/null | |||
| @@ -1,93 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * pnc2000.c - mapper for Photron PNC-2000 board. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp> | ||
| 5 | * | ||
| 6 | * This code is GPL | ||
| 7 | * | ||
| 8 | * $Id: pnc2000.c,v 1.18 2005/11/07 11:14:28 gleixner Exp $ | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/types.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | |||
| 16 | #include <linux/mtd/mtd.h> | ||
| 17 | #include <linux/mtd/map.h> | ||
| 18 | #include <linux/mtd/partitions.h> | ||
| 19 | |||
| 20 | |||
| 21 | #define WINDOW_ADDR 0xbf000000 | ||
| 22 | #define WINDOW_SIZE 0x00400000 | ||
| 23 | |||
| 24 | /* | ||
| 25 | * MAP DRIVER STUFF | ||
| 26 | */ | ||
| 27 | |||
| 28 | |||
| 29 | static struct map_info pnc_map = { | ||
| 30 | .name = "PNC-2000", | ||
| 31 | .size = WINDOW_SIZE, | ||
| 32 | .bankwidth = 4, | ||
| 33 | .phys = 0xFFFFFFFF, | ||
| 34 | .virt = (void __iomem *)WINDOW_ADDR, | ||
| 35 | }; | ||
| 36 | |||
| 37 | |||
| 38 | /* | ||
| 39 | * MTD 'PARTITIONING' STUFF | ||
| 40 | */ | ||
| 41 | static struct mtd_partition pnc_partitions[3] = { | ||
| 42 | { | ||
| 43 | .name = "PNC-2000 boot firmware", | ||
| 44 | .size = 0x20000, | ||
| 45 | .offset = 0 | ||
| 46 | }, | ||
| 47 | { | ||
| 48 | .name = "PNC-2000 kernel", | ||
| 49 | .size = 0x1a0000, | ||
| 50 | .offset = 0x20000 | ||
| 51 | }, | ||
| 52 | { | ||
| 53 | .name = "PNC-2000 filesystem", | ||
| 54 | .size = 0x240000, | ||
| 55 | .offset = 0x1c0000 | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | |||
| 59 | /* | ||
| 60 | * This is the master MTD device for which all the others are just | ||
| 61 | * auto-relocating aliases. | ||
| 62 | */ | ||
| 63 | static struct mtd_info *mymtd; | ||
| 64 | |||
| 65 | static int __init init_pnc2000(void) | ||
| 66 | { | ||
| 67 | printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); | ||
| 68 | |||
| 69 | simple_map_init(&pnc_map); | ||
| 70 | |||
| 71 | mymtd = do_map_probe("cfi_probe", &pnc_map); | ||
| 72 | if (mymtd) { | ||
| 73 | mymtd->owner = THIS_MODULE; | ||
| 74 | return add_mtd_partitions(mymtd, pnc_partitions, 3); | ||
| 75 | } | ||
| 76 | |||
| 77 | return -ENXIO; | ||
| 78 | } | ||
| 79 | |||
| 80 | static void __exit cleanup_pnc2000(void) | ||
| 81 | { | ||
| 82 | if (mymtd) { | ||
| 83 | del_mtd_partitions(mymtd); | ||
| 84 | map_destroy(mymtd); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | module_init(init_pnc2000); | ||
| 89 | module_exit(cleanup_pnc2000); | ||
| 90 | |||
| 91 | MODULE_LICENSE("GPL"); | ||
| 92 | MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp>"); | ||
| 93 | MODULE_DESCRIPTION("MTD map driver for Photron PNC-2000 board"); | ||
diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index dcfb85840d1e..0fc5584324e3 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c | |||
| @@ -79,7 +79,7 @@ scb2_fixup_mtd(struct mtd_info *mtd) | |||
| 79 | struct cfi_private *cfi = map->fldrv_priv; | 79 | struct cfi_private *cfi = map->fldrv_priv; |
| 80 | 80 | ||
| 81 | /* barf if this doesn't look right */ | 81 | /* barf if this doesn't look right */ |
| 82 | if (cfi->cfiq->InterfaceDesc != 1) { | 82 | if (cfi->cfiq->InterfaceDesc != CFI_INTERFACE_X16_ASYNC) { |
| 83 | printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n", | 83 | printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n", |
| 84 | cfi->cfiq->InterfaceDesc); | 84 | cfi->cfiq->InterfaceDesc); |
| 85 | return -1; | 85 | return -1; |
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 74d9d30edabd..839eed8430a2 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c | |||
| @@ -248,9 +248,9 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) | |||
| 248 | return -EBUSY; | 248 | return -EBUSY; |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | mutex_init(&new->lock); | ||
| 252 | list_add_tail(&new->list, &tr->devs); | 251 | list_add_tail(&new->list, &tr->devs); |
| 253 | added: | 252 | added: |
| 253 | mutex_init(&new->lock); | ||
| 254 | if (!tr->writesect) | 254 | if (!tr->writesect) |
| 255 | new->readonly = 1; | 255 | new->readonly = 1; |
| 256 | 256 | ||
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index a0cee86464ca..5d3ac512ce16 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
| @@ -481,6 +481,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
| 481 | { | 481 | { |
| 482 | struct mtd_oob_buf buf; | 482 | struct mtd_oob_buf buf; |
| 483 | struct mtd_oob_ops ops; | 483 | struct mtd_oob_ops ops; |
| 484 | uint32_t retlen; | ||
| 484 | 485 | ||
| 485 | if(!(file->f_mode & 2)) | 486 | if(!(file->f_mode & 2)) |
| 486 | return -EPERM; | 487 | return -EPERM; |
| @@ -520,8 +521,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
| 520 | buf.start &= ~(mtd->oobsize - 1); | 521 | buf.start &= ~(mtd->oobsize - 1); |
| 521 | ret = mtd->write_oob(mtd, buf.start, &ops); | 522 | ret = mtd->write_oob(mtd, buf.start, &ops); |
| 522 | 523 | ||
| 523 | if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen, | 524 | if (ops.oobretlen > 0xFFFFFFFFU) |
| 524 | sizeof(uint32_t))) | 525 | ret = -EOVERFLOW; |
| 526 | retlen = ops.oobretlen; | ||
| 527 | if (copy_to_user(&((struct mtd_oob_buf *)argp)->length, | ||
| 528 | &retlen, sizeof(buf.length))) | ||
| 525 | ret = -EFAULT; | 529 | ret = -EFAULT; |
| 526 | 530 | ||
| 527 | kfree(ops.oobbuf); | 531 | kfree(ops.oobbuf); |
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 6c2645e28371..f7e7890e5bc6 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c | |||
| @@ -61,7 +61,7 @@ int add_mtd_device(struct mtd_info *mtd) | |||
| 61 | 61 | ||
| 62 | /* Some chips always power up locked. Unlock them now */ | 62 | /* Some chips always power up locked. Unlock them now */ |
| 63 | if ((mtd->flags & MTD_WRITEABLE) | 63 | if ((mtd->flags & MTD_WRITEABLE) |
| 64 | && (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) { | 64 | && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) { |
| 65 | if (mtd->unlock(mtd, 0, mtd->size)) | 65 | if (mtd->unlock(mtd, 0, mtd->size)) |
| 66 | printk(KERN_WARNING | 66 | printk(KERN_WARNING |
| 67 | "%s: unlock failed, " | 67 | "%s: unlock failed, " |
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index f8af627f0b98..d3cf05012b46 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c | |||
| @@ -28,19 +28,26 @@ | |||
| 28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
| 29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
| 30 | #include <linux/wait.h> | 30 | #include <linux/wait.h> |
| 31 | #include <linux/delay.h> | ||
| 32 | #include <linux/spinlock.h> | ||
| 33 | #include <linux/interrupt.h> | ||
| 31 | #include <linux/mtd/mtd.h> | 34 | #include <linux/mtd/mtd.h> |
| 32 | 35 | ||
| 33 | #define OOPS_PAGE_SIZE 4096 | 36 | #define OOPS_PAGE_SIZE 4096 |
| 34 | 37 | ||
| 35 | static struct mtdoops_context { | 38 | struct mtdoops_context { |
| 36 | int mtd_index; | 39 | int mtd_index; |
| 37 | struct work_struct work; | 40 | struct work_struct work_erase; |
| 41 | struct work_struct work_write; | ||
| 38 | struct mtd_info *mtd; | 42 | struct mtd_info *mtd; |
| 39 | int oops_pages; | 43 | int oops_pages; |
| 40 | int nextpage; | 44 | int nextpage; |
| 41 | int nextcount; | 45 | int nextcount; |
| 42 | 46 | ||
| 43 | void *oops_buf; | 47 | void *oops_buf; |
| 48 | |||
| 49 | /* writecount and disabling ready are spin lock protected */ | ||
| 50 | spinlock_t writecount_lock; | ||
| 44 | int ready; | 51 | int ready; |
| 45 | int writecount; | 52 | int writecount; |
| 46 | } oops_cxt; | 53 | } oops_cxt; |
| @@ -62,10 +69,7 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset) | |||
| 62 | erase.mtd = mtd; | 69 | erase.mtd = mtd; |
| 63 | erase.callback = mtdoops_erase_callback; | 70 | erase.callback = mtdoops_erase_callback; |
| 64 | erase.addr = offset; | 71 | erase.addr = offset; |
| 65 | if (mtd->erasesize < OOPS_PAGE_SIZE) | 72 | erase.len = mtd->erasesize; |
| 66 | erase.len = OOPS_PAGE_SIZE; | ||
| 67 | else | ||
| 68 | erase.len = mtd->erasesize; | ||
| 69 | erase.priv = (u_long)&wait_q; | 73 | erase.priv = (u_long)&wait_q; |
| 70 | 74 | ||
| 71 | set_current_state(TASK_INTERRUPTIBLE); | 75 | set_current_state(TASK_INTERRUPTIBLE); |
| @@ -87,7 +91,7 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset) | |||
| 87 | return 0; | 91 | return 0; |
| 88 | } | 92 | } |
| 89 | 93 | ||
| 90 | static int mtdoops_inc_counter(struct mtdoops_context *cxt) | 94 | static void mtdoops_inc_counter(struct mtdoops_context *cxt) |
| 91 | { | 95 | { |
| 92 | struct mtd_info *mtd = cxt->mtd; | 96 | struct mtd_info *mtd = cxt->mtd; |
| 93 | size_t retlen; | 97 | size_t retlen; |
| @@ -103,25 +107,30 @@ static int mtdoops_inc_counter(struct mtdoops_context *cxt) | |||
| 103 | 107 | ||
| 104 | ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4, | 108 | ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4, |
| 105 | &retlen, (u_char *) &count); | 109 | &retlen, (u_char *) &count); |
| 106 | if ((retlen != 4) || (ret < 0)) { | 110 | if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) { |
| 107 | printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)" | 111 | printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)" |
| 108 | ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE, | 112 | ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE, |
| 109 | retlen, ret); | 113 | retlen, ret); |
| 110 | return 1; | 114 | schedule_work(&cxt->work_erase); |
| 115 | return; | ||
| 111 | } | 116 | } |
| 112 | 117 | ||
| 113 | /* See if we need to erase the next block */ | 118 | /* See if we need to erase the next block */ |
| 114 | if (count != 0xffffffff) | 119 | if (count != 0xffffffff) { |
| 115 | return 1; | 120 | schedule_work(&cxt->work_erase); |
| 121 | return; | ||
| 122 | } | ||
| 116 | 123 | ||
| 117 | printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n", | 124 | printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n", |
| 118 | cxt->nextpage, cxt->nextcount); | 125 | cxt->nextpage, cxt->nextcount); |
| 119 | cxt->ready = 1; | 126 | cxt->ready = 1; |
| 120 | return 0; | ||
| 121 | } | 127 | } |
| 122 | 128 | ||
| 123 | static void mtdoops_prepare(struct mtdoops_context *cxt) | 129 | /* Scheduled work - when we can't proceed without erasing a block */ |
| 130 | static void mtdoops_workfunc_erase(struct work_struct *work) | ||
| 124 | { | 131 | { |
| 132 | struct mtdoops_context *cxt = | ||
| 133 | container_of(work, struct mtdoops_context, work_erase); | ||
| 125 | struct mtd_info *mtd = cxt->mtd; | 134 | struct mtd_info *mtd = cxt->mtd; |
| 126 | int i = 0, j, ret, mod; | 135 | int i = 0, j, ret, mod; |
| 127 | 136 | ||
| @@ -136,8 +145,14 @@ static void mtdoops_prepare(struct mtdoops_context *cxt) | |||
| 136 | cxt->nextpage = 0; | 145 | cxt->nextpage = 0; |
| 137 | } | 146 | } |
| 138 | 147 | ||
| 139 | while (mtd->block_isbad && | 148 | while (mtd->block_isbad) { |
| 140 | mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) { | 149 | ret = mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE); |
| 150 | if (!ret) | ||
| 151 | break; | ||
| 152 | if (ret < 0) { | ||
| 153 | printk(KERN_ERR "mtdoops: block_isbad failed, aborting.\n"); | ||
| 154 | return; | ||
| 155 | } | ||
| 141 | badblock: | 156 | badblock: |
| 142 | printk(KERN_WARNING "mtdoops: Bad block at %08x\n", | 157 | printk(KERN_WARNING "mtdoops: Bad block at %08x\n", |
| 143 | cxt->nextpage * OOPS_PAGE_SIZE); | 158 | cxt->nextpage * OOPS_PAGE_SIZE); |
| @@ -154,34 +169,72 @@ badblock: | |||
| 154 | for (j = 0, ret = -1; (j < 3) && (ret < 0); j++) | 169 | for (j = 0, ret = -1; (j < 3) && (ret < 0); j++) |
| 155 | ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE); | 170 | ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE); |
| 156 | 171 | ||
| 157 | if (ret < 0) { | 172 | if (ret >= 0) { |
| 158 | if (mtd->block_markbad) | 173 | printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount); |
| 159 | mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE); | 174 | cxt->ready = 1; |
| 160 | goto badblock; | 175 | return; |
| 161 | } | 176 | } |
| 162 | 177 | ||
| 163 | printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount); | 178 | if (mtd->block_markbad && (ret == -EIO)) { |
| 179 | ret = mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE); | ||
| 180 | if (ret < 0) { | ||
| 181 | printk(KERN_ERR "mtdoops: block_markbad failed, aborting.\n"); | ||
| 182 | return; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | goto badblock; | ||
| 186 | } | ||
| 164 | 187 | ||
| 165 | cxt->ready = 1; | 188 | static void mtdoops_write(struct mtdoops_context *cxt, int panic) |
| 189 | { | ||
| 190 | struct mtd_info *mtd = cxt->mtd; | ||
| 191 | size_t retlen; | ||
| 192 | int ret; | ||
| 193 | |||
| 194 | if (cxt->writecount < OOPS_PAGE_SIZE) | ||
| 195 | memset(cxt->oops_buf + cxt->writecount, 0xff, | ||
| 196 | OOPS_PAGE_SIZE - cxt->writecount); | ||
| 197 | |||
| 198 | if (panic) | ||
| 199 | ret = mtd->panic_write(mtd, cxt->nextpage * OOPS_PAGE_SIZE, | ||
| 200 | OOPS_PAGE_SIZE, &retlen, cxt->oops_buf); | ||
| 201 | else | ||
| 202 | ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE, | ||
| 203 | OOPS_PAGE_SIZE, &retlen, cxt->oops_buf); | ||
| 204 | |||
| 205 | cxt->writecount = 0; | ||
| 206 | |||
| 207 | if ((retlen != OOPS_PAGE_SIZE) || (ret < 0)) | ||
| 208 | printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n", | ||
| 209 | cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret); | ||
| 210 | |||
| 211 | mtdoops_inc_counter(cxt); | ||
| 166 | } | 212 | } |
| 167 | 213 | ||
| 168 | static void mtdoops_workfunc(struct work_struct *work) | 214 | |
| 215 | static void mtdoops_workfunc_write(struct work_struct *work) | ||
| 169 | { | 216 | { |
| 170 | struct mtdoops_context *cxt = | 217 | struct mtdoops_context *cxt = |
| 171 | container_of(work, struct mtdoops_context, work); | 218 | container_of(work, struct mtdoops_context, work_write); |
| 172 | 219 | ||
| 173 | mtdoops_prepare(cxt); | 220 | mtdoops_write(cxt, 0); |
| 174 | } | 221 | } |
| 175 | 222 | ||
| 176 | static int find_next_position(struct mtdoops_context *cxt) | 223 | static void find_next_position(struct mtdoops_context *cxt) |
| 177 | { | 224 | { |
| 178 | struct mtd_info *mtd = cxt->mtd; | 225 | struct mtd_info *mtd = cxt->mtd; |
| 179 | int page, maxpos = 0; | 226 | int ret, page, maxpos = 0; |
| 180 | u32 count, maxcount = 0xffffffff; | 227 | u32 count, maxcount = 0xffffffff; |
| 181 | size_t retlen; | 228 | size_t retlen; |
| 182 | 229 | ||
| 183 | for (page = 0; page < cxt->oops_pages; page++) { | 230 | for (page = 0; page < cxt->oops_pages; page++) { |
| 184 | mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count); | 231 | ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count); |
| 232 | if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) { | ||
| 233 | printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)" | ||
| 234 | ", err %d.\n", page * OOPS_PAGE_SIZE, retlen, ret); | ||
| 235 | continue; | ||
| 236 | } | ||
| 237 | |||
| 185 | if (count == 0xffffffff) | 238 | if (count == 0xffffffff) |
| 186 | continue; | 239 | continue; |
| 187 | if (maxcount == 0xffffffff) { | 240 | if (maxcount == 0xffffffff) { |
| @@ -205,20 +258,19 @@ static int find_next_position(struct mtdoops_context *cxt) | |||
| 205 | cxt->ready = 1; | 258 | cxt->ready = 1; |
| 206 | printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n", | 259 | printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n", |
| 207 | cxt->nextpage, cxt->nextcount); | 260 | cxt->nextpage, cxt->nextcount); |
| 208 | return 0; | 261 | return; |
| 209 | } | 262 | } |
| 210 | 263 | ||
| 211 | cxt->nextpage = maxpos; | 264 | cxt->nextpage = maxpos; |
| 212 | cxt->nextcount = maxcount; | 265 | cxt->nextcount = maxcount; |
| 213 | 266 | ||
| 214 | return mtdoops_inc_counter(cxt); | 267 | mtdoops_inc_counter(cxt); |
| 215 | } | 268 | } |
| 216 | 269 | ||
| 217 | 270 | ||
| 218 | static void mtdoops_notify_add(struct mtd_info *mtd) | 271 | static void mtdoops_notify_add(struct mtd_info *mtd) |
| 219 | { | 272 | { |
| 220 | struct mtdoops_context *cxt = &oops_cxt; | 273 | struct mtdoops_context *cxt = &oops_cxt; |
| 221 | int ret; | ||
| 222 | 274 | ||
| 223 | if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0) | 275 | if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0) |
| 224 | return; | 276 | return; |
| @@ -229,14 +281,18 @@ static void mtdoops_notify_add(struct mtd_info *mtd) | |||
| 229 | return; | 281 | return; |
| 230 | } | 282 | } |
| 231 | 283 | ||
| 284 | if (mtd->erasesize < OOPS_PAGE_SIZE) { | ||
| 285 | printk(KERN_ERR "Eraseblock size of MTD partition %d too small\n", | ||
| 286 | mtd->index); | ||
| 287 | return; | ||
| 288 | } | ||
| 289 | |||
| 232 | cxt->mtd = mtd; | 290 | cxt->mtd = mtd; |
| 233 | cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE; | 291 | cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE; |
| 234 | 292 | ||
| 235 | ret = find_next_position(cxt); | 293 | find_next_position(cxt); |
| 236 | if (ret == 1) | ||
| 237 | mtdoops_prepare(cxt); | ||
| 238 | 294 | ||
| 239 | printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index); | 295 | printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index); |
| 240 | } | 296 | } |
| 241 | 297 | ||
| 242 | static void mtdoops_notify_remove(struct mtd_info *mtd) | 298 | static void mtdoops_notify_remove(struct mtd_info *mtd) |
| @@ -254,31 +310,28 @@ static void mtdoops_console_sync(void) | |||
| 254 | { | 310 | { |
| 255 | struct mtdoops_context *cxt = &oops_cxt; | 311 | struct mtdoops_context *cxt = &oops_cxt; |
| 256 | struct mtd_info *mtd = cxt->mtd; | 312 | struct mtd_info *mtd = cxt->mtd; |
| 257 | size_t retlen; | 313 | unsigned long flags; |
| 258 | int ret; | ||
| 259 | 314 | ||
| 260 | if (!cxt->ready || !mtd) | 315 | if (!cxt->ready || !mtd || cxt->writecount == 0) |
| 261 | return; | 316 | return; |
| 262 | 317 | ||
| 263 | if (cxt->writecount == 0) | 318 | /* |
| 319 | * Once ready is 0 and we've held the lock no further writes to the | ||
| 320 | * buffer will happen | ||
| 321 | */ | ||
| 322 | spin_lock_irqsave(&cxt->writecount_lock, flags); | ||
| 323 | if (!cxt->ready) { | ||
| 324 | spin_unlock_irqrestore(&cxt->writecount_lock, flags); | ||
| 264 | return; | 325 | return; |
| 265 | 326 | } | |
| 266 | if (cxt->writecount < OOPS_PAGE_SIZE) | ||
| 267 | memset(cxt->oops_buf + cxt->writecount, 0xff, | ||
| 268 | OOPS_PAGE_SIZE - cxt->writecount); | ||
| 269 | |||
| 270 | ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE, | ||
| 271 | OOPS_PAGE_SIZE, &retlen, cxt->oops_buf); | ||
| 272 | cxt->ready = 0; | 327 | cxt->ready = 0; |
| 273 | cxt->writecount = 0; | 328 | spin_unlock_irqrestore(&cxt->writecount_lock, flags); |
| 274 | |||
| 275 | if ((retlen != OOPS_PAGE_SIZE) || (ret < 0)) | ||
| 276 | printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n", | ||
| 277 | cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret); | ||
| 278 | 329 | ||
| 279 | ret = mtdoops_inc_counter(cxt); | 330 | if (mtd->panic_write && in_interrupt()) |
| 280 | if (ret == 1) | 331 | /* Interrupt context, we're going to panic so try and log */ |
| 281 | schedule_work(&cxt->work); | 332 | mtdoops_write(cxt, 1); |
| 333 | else | ||
| 334 | schedule_work(&cxt->work_write); | ||
| 282 | } | 335 | } |
| 283 | 336 | ||
| 284 | static void | 337 | static void |
| @@ -286,7 +339,7 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count) | |||
| 286 | { | 339 | { |
| 287 | struct mtdoops_context *cxt = co->data; | 340 | struct mtdoops_context *cxt = co->data; |
| 288 | struct mtd_info *mtd = cxt->mtd; | 341 | struct mtd_info *mtd = cxt->mtd; |
| 289 | int i; | 342 | unsigned long flags; |
| 290 | 343 | ||
| 291 | if (!oops_in_progress) { | 344 | if (!oops_in_progress) { |
| 292 | mtdoops_console_sync(); | 345 | mtdoops_console_sync(); |
| @@ -296,6 +349,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count) | |||
| 296 | if (!cxt->ready || !mtd) | 349 | if (!cxt->ready || !mtd) |
| 297 | return; | 350 | return; |
| 298 | 351 | ||
| 352 | /* Locking on writecount ensures sequential writes to the buffer */ | ||
| 353 | spin_lock_irqsave(&cxt->writecount_lock, flags); | ||
| 354 | |||
| 355 | /* Check ready status didn't change whilst waiting for the lock */ | ||
| 356 | if (!cxt->ready) | ||
| 357 | return; | ||
| 358 | |||
| 299 | if (cxt->writecount == 0) { | 359 | if (cxt->writecount == 0) { |
| 300 | u32 *stamp = cxt->oops_buf; | 360 | u32 *stamp = cxt->oops_buf; |
| 301 | *stamp = cxt->nextcount; | 361 | *stamp = cxt->nextcount; |
| @@ -305,10 +365,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count) | |||
| 305 | if ((count + cxt->writecount) > OOPS_PAGE_SIZE) | 365 | if ((count + cxt->writecount) > OOPS_PAGE_SIZE) |
| 306 | count = OOPS_PAGE_SIZE - cxt->writecount; | 366 | count = OOPS_PAGE_SIZE - cxt->writecount; |
| 307 | 367 | ||
| 308 | for (i = 0; i < count; i++, s++) | 368 | memcpy(cxt->oops_buf + cxt->writecount, s, count); |
| 309 | *((char *)(cxt->oops_buf) + cxt->writecount + i) = *s; | 369 | cxt->writecount += count; |
| 310 | 370 | ||
| 311 | cxt->writecount = cxt->writecount + count; | 371 | spin_unlock_irqrestore(&cxt->writecount_lock, flags); |
| 372 | |||
| 373 | if (cxt->writecount == OOPS_PAGE_SIZE) | ||
| 374 | mtdoops_console_sync(); | ||
| 312 | } | 375 | } |
| 313 | 376 | ||
| 314 | static int __init mtdoops_console_setup(struct console *co, char *options) | 377 | static int __init mtdoops_console_setup(struct console *co, char *options) |
| @@ -334,7 +397,6 @@ static struct console mtdoops_console = { | |||
| 334 | .write = mtdoops_console_write, | 397 | .write = mtdoops_console_write, |
| 335 | .setup = mtdoops_console_setup, | 398 | .setup = mtdoops_console_setup, |
| 336 | .unblank = mtdoops_console_sync, | 399 | .unblank = mtdoops_console_sync, |
| 337 | .flags = CON_PRINTBUFFER, | ||
| 338 | .index = -1, | 400 | .index = -1, |
| 339 | .data = &oops_cxt, | 401 | .data = &oops_cxt, |
| 340 | }; | 402 | }; |
| @@ -347,11 +409,12 @@ static int __init mtdoops_console_init(void) | |||
| 347 | cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE); | 409 | cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE); |
| 348 | 410 | ||
| 349 | if (!cxt->oops_buf) { | 411 | if (!cxt->oops_buf) { |
| 350 | printk(KERN_ERR "Failed to allocate oops buffer workspace\n"); | 412 | printk(KERN_ERR "Failed to allocate mtdoops buffer workspace\n"); |
| 351 | return -ENOMEM; | 413 | return -ENOMEM; |
| 352 | } | 414 | } |
| 353 | 415 | ||
| 354 | INIT_WORK(&cxt->work, mtdoops_workfunc); | 416 | INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase); |
| 417 | INIT_WORK(&cxt->work_write, mtdoops_workfunc_write); | ||
| 355 | 418 | ||
| 356 | register_console(&mtdoops_console); | 419 | register_console(&mtdoops_console); |
| 357 | register_mtd_user(&mtdoops_notifier); | 420 | register_mtd_user(&mtdoops_notifier); |
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 6174a97d7902..c66902df3171 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c | |||
| @@ -151,6 +151,20 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len, | |||
| 151 | len, retlen, buf); | 151 | len, retlen, buf); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | static int part_panic_write (struct mtd_info *mtd, loff_t to, size_t len, | ||
| 155 | size_t *retlen, const u_char *buf) | ||
| 156 | { | ||
| 157 | struct mtd_part *part = PART(mtd); | ||
| 158 | if (!(mtd->flags & MTD_WRITEABLE)) | ||
| 159 | return -EROFS; | ||
| 160 | if (to >= mtd->size) | ||
| 161 | len = 0; | ||
| 162 | else if (to + len > mtd->size) | ||
| 163 | len = mtd->size - to; | ||
| 164 | return part->master->panic_write (part->master, to + part->offset, | ||
| 165 | len, retlen, buf); | ||
| 166 | } | ||
| 167 | |||
| 154 | static int part_write_oob(struct mtd_info *mtd, loff_t to, | 168 | static int part_write_oob(struct mtd_info *mtd, loff_t to, |
| 155 | struct mtd_oob_ops *ops) | 169 | struct mtd_oob_ops *ops) |
| 156 | { | 170 | { |
| @@ -352,6 +366,9 @@ int add_mtd_partitions(struct mtd_info *master, | |||
| 352 | slave->mtd.read = part_read; | 366 | slave->mtd.read = part_read; |
| 353 | slave->mtd.write = part_write; | 367 | slave->mtd.write = part_write; |
| 354 | 368 | ||
| 369 | if (master->panic_write) | ||
| 370 | slave->mtd.panic_write = part_panic_write; | ||
| 371 | |||
| 355 | if(master->point && master->unpoint){ | 372 | if(master->point && master->unpoint){ |
| 356 | slave->mtd.point = part_point; | 373 | slave->mtd.point = part_point; |
| 357 | slave->mtd.unpoint = part_unpoint; | 374 | slave->mtd.unpoint = part_unpoint; |
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 246d4512f64b..4a3c6759492b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
| @@ -93,7 +93,7 @@ config MTD_NAND_AU1550 | |||
| 93 | 93 | ||
| 94 | config MTD_NAND_BF5XX | 94 | config MTD_NAND_BF5XX |
| 95 | tristate "Blackfin on-chip NAND Flash Controller driver" | 95 | tristate "Blackfin on-chip NAND Flash Controller driver" |
| 96 | depends on BF54x && MTD_NAND | 96 | depends on (BF54x || BF52x) && MTD_NAND |
| 97 | help | 97 | help |
| 98 | This enables the Blackfin on-chip NAND flash controller | 98 | This enables the Blackfin on-chip NAND flash controller |
| 99 | 99 | ||
| @@ -283,6 +283,12 @@ config MTD_NAND_CM_X270 | |||
| 283 | tristate "Support for NAND Flash on CM-X270 modules" | 283 | tristate "Support for NAND Flash on CM-X270 modules" |
| 284 | depends on MTD_NAND && MACH_ARMCORE | 284 | depends on MTD_NAND && MACH_ARMCORE |
| 285 | 285 | ||
| 286 | config MTD_NAND_PASEMI | ||
| 287 | tristate "NAND support for PA Semi PWRficient" | ||
| 288 | depends on MTD_NAND && PPC_PASEMI | ||
| 289 | help | ||
| 290 | Enables support for NAND Flash interface on PA Semi PWRficient | ||
| 291 | based boards | ||
| 286 | 292 | ||
| 287 | config MTD_NAND_NANDSIM | 293 | config MTD_NAND_NANDSIM |
| 288 | tristate "Support for NAND Flash Simulator" | 294 | tristate "Support for NAND Flash Simulator" |
| @@ -306,4 +312,22 @@ config MTD_ALAUDA | |||
| 306 | These two (and possibly other) Alauda-based cardreaders for | 312 | These two (and possibly other) Alauda-based cardreaders for |
| 307 | SmartMedia and xD allow raw flash access. | 313 | SmartMedia and xD allow raw flash access. |
| 308 | 314 | ||
| 315 | config MTD_NAND_ORION | ||
| 316 | tristate "NAND Flash support for Marvell Orion SoC" | ||
| 317 | depends on ARCH_ORION && MTD_NAND | ||
| 318 | help | ||
| 319 | This enables the NAND flash controller on Orion machines. | ||
| 320 | |||
| 321 | No board specific support is done by this driver, each board | ||
| 322 | must advertise a platform_device for the driver to attach. | ||
| 323 | |||
| 324 | config MTD_NAND_FSL_ELBC | ||
| 325 | tristate "NAND support for Freescale eLBC controllers" | ||
| 326 | depends on MTD_NAND && PPC_OF | ||
| 327 | help | ||
| 328 | Various Freescale chips, including the 8313, include a NAND Flash | ||
| 329 | Controller Module with built-in hardware ECC capabilities. | ||
| 330 | Enabling this option will enable you to use this to control | ||
| 331 | external NAND devices. | ||
| 332 | |||
| 309 | endif # MTD_NAND | 333 | endif # MTD_NAND |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 3ad6c0165da3..80d575eeee96 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
| @@ -29,5 +29,8 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o | |||
| 29 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o | 29 | obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o |
| 30 | obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o | 30 | obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o |
| 31 | obj-$(CONFIG_MTD_ALAUDA) += alauda.o | 31 | obj-$(CONFIG_MTD_ALAUDA) += alauda.o |
| 32 | obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o | ||
| 33 | obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o | ||
| 34 | obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o | ||
| 32 | 35 | ||
| 33 | nand-objs := nand_base.o nand_bbt.o | 36 | nand-objs := nand_base.o nand_bbt.o |
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c index b2a5672df6e0..c9fb2acf4056 100644 --- a/drivers/mtd/nand/at91_nand.c +++ b/drivers/mtd/nand/at91_nand.c | |||
| @@ -156,14 +156,14 @@ static int __init at91_nand_probe(struct platform_device *pdev) | |||
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | #ifdef CONFIG_MTD_PARTITIONS | 158 | #ifdef CONFIG_MTD_PARTITIONS |
| 159 | if (host->board->partition_info) | ||
| 160 | partitions = host->board->partition_info(mtd->size, &num_partitions); | ||
| 161 | #ifdef CONFIG_MTD_CMDLINE_PARTS | 159 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
| 162 | else { | 160 | mtd->name = "at91_nand"; |
| 163 | mtd->name = "at91_nand"; | 161 | num_partitions = parse_mtd_partitions(mtd, part_probes, |
| 164 | num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0); | 162 | &partitions, 0); |
| 165 | } | ||
| 166 | #endif | 163 | #endif |
| 164 | if (num_partitions <= 0 && host->board->partition_info) | ||
| 165 | partitions = host->board->partition_info(mtd->size, | ||
| 166 | &num_partitions); | ||
| 167 | 167 | ||
| 168 | if ((!partitions) || (num_partitions == 0)) { | 168 | if ((!partitions) || (num_partitions == 0)) { |
| 169 | printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); | 169 | printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); |
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c index a52f3a737c39..747042ab094a 100644 --- a/drivers/mtd/nand/bf5xx_nand.c +++ b/drivers/mtd/nand/bf5xx_nand.c | |||
| @@ -74,7 +74,22 @@ static int hardware_ecc = 1; | |||
| 74 | static int hardware_ecc; | 74 | static int hardware_ecc; |
| 75 | #endif | 75 | #endif |
| 76 | 76 | ||
| 77 | static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0}; | 77 | static unsigned short bfin_nfc_pin_req[] = |
| 78 | {P_NAND_CE, | ||
| 79 | P_NAND_RB, | ||
| 80 | P_NAND_D0, | ||
| 81 | P_NAND_D1, | ||
| 82 | P_NAND_D2, | ||
| 83 | P_NAND_D3, | ||
| 84 | P_NAND_D4, | ||
| 85 | P_NAND_D5, | ||
| 86 | P_NAND_D6, | ||
| 87 | P_NAND_D7, | ||
| 88 | P_NAND_WE, | ||
| 89 | P_NAND_RE, | ||
| 90 | P_NAND_CLE, | ||
| 91 | P_NAND_ALE, | ||
| 92 | 0}; | ||
| 78 | 93 | ||
| 79 | /* | 94 | /* |
| 80 | * Data structures for bf5xx nand flash controller driver | 95 | * Data structures for bf5xx nand flash controller driver |
| @@ -278,7 +293,6 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, | |||
| 278 | u16 ecc0, ecc1; | 293 | u16 ecc0, ecc1; |
| 279 | u32 code[2]; | 294 | u32 code[2]; |
| 280 | u8 *p; | 295 | u8 *p; |
| 281 | int bytes = 3, i; | ||
| 282 | 296 | ||
| 283 | /* first 4 bytes ECC code for 256 page size */ | 297 | /* first 4 bytes ECC code for 256 page size */ |
| 284 | ecc0 = bfin_read_NFC_ECC0(); | 298 | ecc0 = bfin_read_NFC_ECC0(); |
| @@ -288,19 +302,24 @@ static int bf5xx_nand_calculate_ecc(struct mtd_info *mtd, | |||
| 288 | 302 | ||
| 289 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); | 303 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[0]); |
| 290 | 304 | ||
| 305 | /* first 3 bytes in ecc_code for 256 page size */ | ||
| 306 | p = (u8 *) code; | ||
| 307 | memcpy(ecc_code, p, 3); | ||
| 308 | |||
| 291 | /* second 4 bytes ECC code for 512 page size */ | 309 | /* second 4 bytes ECC code for 512 page size */ |
| 292 | if (page_size == 512) { | 310 | if (page_size == 512) { |
| 293 | ecc0 = bfin_read_NFC_ECC2(); | 311 | ecc0 = bfin_read_NFC_ECC2(); |
| 294 | ecc1 = bfin_read_NFC_ECC3(); | 312 | ecc1 = bfin_read_NFC_ECC3(); |
| 295 | code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); | 313 | code[1] = (ecc0 & 0x3FF) | ((ecc1 & 0x3FF) << 11); |
| 296 | bytes = 6; | 314 | |
| 315 | /* second 3 bytes in ecc_code for second 256 | ||
| 316 | * bytes of 512 page size | ||
| 317 | */ | ||
| 318 | p = (u8 *) (code + 1); | ||
| 319 | memcpy((ecc_code + 3), p, 3); | ||
| 297 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]); | 320 | dev_dbg(info->device, "returning ecc 0x%08x\n", code[1]); |
| 298 | } | 321 | } |
| 299 | 322 | ||
| 300 | p = (u8 *)code; | ||
| 301 | for (i = 0; i < bytes; i++) | ||
| 302 | ecc_code[i] = p[i]; | ||
| 303 | |||
| 304 | return 0; | 323 | return 0; |
| 305 | } | 324 | } |
| 306 | 325 | ||
| @@ -507,12 +526,13 @@ static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info) | |||
| 507 | 526 | ||
| 508 | init_completion(&info->dma_completion); | 527 | init_completion(&info->dma_completion); |
| 509 | 528 | ||
| 529 | #ifdef CONFIG_BF54x | ||
| 510 | /* Setup DMAC1 channel mux for NFC which shared with SDH */ | 530 | /* Setup DMAC1 channel mux for NFC which shared with SDH */ |
| 511 | val = bfin_read_DMAC1_PERIMUX(); | 531 | val = bfin_read_DMAC1_PERIMUX(); |
| 512 | val &= 0xFFFE; | 532 | val &= 0xFFFE; |
| 513 | bfin_write_DMAC1_PERIMUX(val); | 533 | bfin_write_DMAC1_PERIMUX(val); |
| 514 | SSYNC(); | 534 | SSYNC(); |
| 515 | 535 | #endif | |
| 516 | /* Request NFC DMA channel */ | 536 | /* Request NFC DMA channel */ |
| 517 | ret = request_dma(CH_NFC, "BF5XX NFC driver"); | 537 | ret = request_dma(CH_NFC, "BF5XX NFC driver"); |
| 518 | if (ret < 0) { | 538 | if (ret < 0) { |
| @@ -744,9 +764,6 @@ static int bf5xx_nand_resume(struct platform_device *dev) | |||
| 744 | { | 764 | { |
| 745 | struct bf5xx_nand_info *info = platform_get_drvdata(dev); | 765 | struct bf5xx_nand_info *info = platform_get_drvdata(dev); |
| 746 | 766 | ||
| 747 | if (info) | ||
| 748 | bf5xx_nand_hw_init(info); | ||
| 749 | |||
| 750 | return 0; | 767 | return 0; |
| 751 | } | 768 | } |
| 752 | 769 | ||
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 1e811715211a..da6ceaa80ba1 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #undef DEBUG | 11 | #undef DEBUG |
| 12 | #include <linux/mtd/mtd.h> | 12 | #include <linux/mtd/mtd.h> |
| 13 | #include <linux/mtd/nand.h> | 13 | #include <linux/mtd/nand.h> |
| 14 | #include <linux/mtd/partitions.h> | ||
| 14 | #include <linux/rslib.h> | 15 | #include <linux/rslib.h> |
| 15 | #include <linux/pci.h> | 16 | #include <linux/pci.h> |
| 16 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| @@ -52,6 +53,7 @@ | |||
| 52 | 53 | ||
| 53 | struct cafe_priv { | 54 | struct cafe_priv { |
| 54 | struct nand_chip nand; | 55 | struct nand_chip nand; |
| 56 | struct mtd_partition *parts; | ||
| 55 | struct pci_dev *pdev; | 57 | struct pci_dev *pdev; |
| 56 | void __iomem *mmio; | 58 | void __iomem *mmio; |
| 57 | struct rs_control *rs; | 59 | struct rs_control *rs; |
| @@ -84,6 +86,10 @@ static unsigned int numtimings; | |||
| 84 | static int timing[3]; | 86 | static int timing[3]; |
| 85 | module_param_array(timing, int, &numtimings, 0644); | 87 | module_param_array(timing, int, &numtimings, 0644); |
| 86 | 88 | ||
| 89 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 90 | static const char *part_probes[] = { "RedBoot", NULL }; | ||
| 91 | #endif | ||
| 92 | |||
| 87 | /* Hrm. Why isn't this already conditional on something in the struct device? */ | 93 | /* Hrm. Why isn't this already conditional on something in the struct device? */ |
| 88 | #define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0) | 94 | #define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0) |
| 89 | 95 | ||
| @@ -620,7 +626,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
| 620 | { | 626 | { |
| 621 | struct mtd_info *mtd; | 627 | struct mtd_info *mtd; |
| 622 | struct cafe_priv *cafe; | 628 | struct cafe_priv *cafe; |
| 629 | struct mtd_partition *parts; | ||
| 623 | uint32_t ctrl; | 630 | uint32_t ctrl; |
| 631 | int nr_parts; | ||
| 624 | int err = 0; | 632 | int err = 0; |
| 625 | 633 | ||
| 626 | /* Very old versions shared the same PCI ident for all three | 634 | /* Very old versions shared the same PCI ident for all three |
| @@ -787,7 +795,18 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, | |||
| 787 | goto out_irq; | 795 | goto out_irq; |
| 788 | 796 | ||
| 789 | pci_set_drvdata(pdev, mtd); | 797 | pci_set_drvdata(pdev, mtd); |
| 798 | |||
| 799 | /* We register the whole device first, separate from the partitions */ | ||
| 790 | add_mtd_device(mtd); | 800 | add_mtd_device(mtd); |
| 801 | |||
| 802 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 803 | nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0); | ||
| 804 | if (nr_parts > 0) { | ||
| 805 | cafe->parts = parts; | ||
| 806 | dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts); | ||
| 807 | add_mtd_partitions(mtd, parts, nr_parts); | ||
| 808 | } | ||
| 809 | #endif | ||
| 791 | goto out; | 810 | goto out; |
| 792 | 811 | ||
| 793 | out_irq: | 812 | out_irq: |
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c new file mode 100644 index 000000000000..b025dfe0b274 --- /dev/null +++ b/drivers/mtd/nand/fsl_elbc_nand.c | |||
| @@ -0,0 +1,1244 @@ | |||
| 1 | /* Freescale Enhanced Local Bus Controller NAND driver | ||
| 2 | * | ||
| 3 | * Copyright (c) 2006-2007 Freescale Semiconductor | ||
| 4 | * | ||
| 5 | * Authors: Nick Spence <nick.spence@freescale.com>, | ||
| 6 | * Scott Wood <scottwood@freescale.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/types.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/string.h> | ||
| 28 | #include <linux/ioport.h> | ||
| 29 | #include <linux/of_platform.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | #include <linux/interrupt.h> | ||
| 32 | |||
| 33 | #include <linux/mtd/mtd.h> | ||
| 34 | #include <linux/mtd/nand.h> | ||
| 35 | #include <linux/mtd/nand_ecc.h> | ||
| 36 | #include <linux/mtd/partitions.h> | ||
| 37 | |||
| 38 | #include <asm/io.h> | ||
| 39 | |||
| 40 | |||
| 41 | #define MAX_BANKS 8 | ||
| 42 | #define ERR_BYTE 0xFF /* Value returned for read bytes when read failed */ | ||
| 43 | #define FCM_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait for FCM */ | ||
| 44 | |||
| 45 | struct elbc_bank { | ||
| 46 | __be32 br; /**< Base Register */ | ||
| 47 | #define BR_BA 0xFFFF8000 | ||
| 48 | #define BR_BA_SHIFT 15 | ||
| 49 | #define BR_PS 0x00001800 | ||
| 50 | #define BR_PS_SHIFT 11 | ||
| 51 | #define BR_PS_8 0x00000800 /* Port Size 8 bit */ | ||
| 52 | #define BR_PS_16 0x00001000 /* Port Size 16 bit */ | ||
| 53 | #define BR_PS_32 0x00001800 /* Port Size 32 bit */ | ||
| 54 | #define BR_DECC 0x00000600 | ||
| 55 | #define BR_DECC_SHIFT 9 | ||
| 56 | #define BR_DECC_OFF 0x00000000 /* HW ECC checking and generation off */ | ||
| 57 | #define BR_DECC_CHK 0x00000200 /* HW ECC checking on, generation off */ | ||
| 58 | #define BR_DECC_CHK_GEN 0x00000400 /* HW ECC checking and generation on */ | ||
| 59 | #define BR_WP 0x00000100 | ||
| 60 | #define BR_WP_SHIFT 8 | ||
| 61 | #define BR_MSEL 0x000000E0 | ||
| 62 | #define BR_MSEL_SHIFT 5 | ||
| 63 | #define BR_MS_GPCM 0x00000000 /* GPCM */ | ||
| 64 | #define BR_MS_FCM 0x00000020 /* FCM */ | ||
| 65 | #define BR_MS_SDRAM 0x00000060 /* SDRAM */ | ||
| 66 | #define BR_MS_UPMA 0x00000080 /* UPMA */ | ||
| 67 | #define BR_MS_UPMB 0x000000A0 /* UPMB */ | ||
| 68 | #define BR_MS_UPMC 0x000000C0 /* UPMC */ | ||
| 69 | #define BR_V 0x00000001 | ||
| 70 | #define BR_V_SHIFT 0 | ||
| 71 | #define BR_RES ~(BR_BA|BR_PS|BR_DECC|BR_WP|BR_MSEL|BR_V) | ||
| 72 | |||
| 73 | __be32 or; /**< Base Register */ | ||
| 74 | #define OR0 0x5004 | ||
| 75 | #define OR1 0x500C | ||
| 76 | #define OR2 0x5014 | ||
| 77 | #define OR3 0x501C | ||
| 78 | #define OR4 0x5024 | ||
| 79 | #define OR5 0x502C | ||
| 80 | #define OR6 0x5034 | ||
| 81 | #define OR7 0x503C | ||
| 82 | |||
| 83 | #define OR_FCM_AM 0xFFFF8000 | ||
| 84 | #define OR_FCM_AM_SHIFT 15 | ||
| 85 | #define OR_FCM_BCTLD 0x00001000 | ||
| 86 | #define OR_FCM_BCTLD_SHIFT 12 | ||
| 87 | #define OR_FCM_PGS 0x00000400 | ||
| 88 | #define OR_FCM_PGS_SHIFT 10 | ||
| 89 | #define OR_FCM_CSCT 0x00000200 | ||
| 90 | #define OR_FCM_CSCT_SHIFT 9 | ||
| 91 | #define OR_FCM_CST 0x00000100 | ||
| 92 | #define OR_FCM_CST_SHIFT 8 | ||
| 93 | #define OR_FCM_CHT 0x00000080 | ||
| 94 | #define OR_FCM_CHT_SHIFT 7 | ||
| 95 | #define OR_FCM_SCY 0x00000070 | ||
| 96 | #define OR_FCM_SCY_SHIFT 4 | ||
| 97 | #define OR_FCM_SCY_1 0x00000010 | ||
| 98 | #define OR_FCM_SCY_2 0x00000020 | ||
| 99 | #define OR_FCM_SCY_3 0x00000030 | ||
| 100 | #define OR_FCM_SCY_4 0x00000040 | ||
| 101 | #define OR_FCM_SCY_5 0x00000050 | ||
| 102 | #define OR_FCM_SCY_6 0x00000060 | ||
| 103 | #define OR_FCM_SCY_7 0x00000070 | ||
| 104 | #define OR_FCM_RST 0x00000008 | ||
| 105 | #define OR_FCM_RST_SHIFT 3 | ||
| 106 | #define OR_FCM_TRLX 0x00000004 | ||
| 107 | #define OR_FCM_TRLX_SHIFT 2 | ||
| 108 | #define OR_FCM_EHTR 0x00000002 | ||
| 109 | #define OR_FCM_EHTR_SHIFT 1 | ||
| 110 | }; | ||
| 111 | |||
| 112 | struct elbc_regs { | ||
| 113 | struct elbc_bank bank[8]; | ||
| 114 | u8 res0[0x28]; | ||
| 115 | __be32 mar; /**< UPM Address Register */ | ||
| 116 | u8 res1[0x4]; | ||
| 117 | __be32 mamr; /**< UPMA Mode Register */ | ||
| 118 | __be32 mbmr; /**< UPMB Mode Register */ | ||
| 119 | __be32 mcmr; /**< UPMC Mode Register */ | ||
| 120 | u8 res2[0x8]; | ||
| 121 | __be32 mrtpr; /**< Memory Refresh Timer Prescaler Register */ | ||
| 122 | __be32 mdr; /**< UPM Data Register */ | ||
| 123 | u8 res3[0x4]; | ||
| 124 | __be32 lsor; /**< Special Operation Initiation Register */ | ||
| 125 | __be32 lsdmr; /**< SDRAM Mode Register */ | ||
| 126 | u8 res4[0x8]; | ||
| 127 | __be32 lurt; /**< UPM Refresh Timer */ | ||
| 128 | __be32 lsrt; /**< SDRAM Refresh Timer */ | ||
| 129 | u8 res5[0x8]; | ||
| 130 | __be32 ltesr; /**< Transfer Error Status Register */ | ||
| 131 | #define LTESR_BM 0x80000000 | ||
| 132 | #define LTESR_FCT 0x40000000 | ||
| 133 | #define LTESR_PAR 0x20000000 | ||
| 134 | #define LTESR_WP 0x04000000 | ||
| 135 | #define LTESR_ATMW 0x00800000 | ||
| 136 | #define LTESR_ATMR 0x00400000 | ||
| 137 | #define LTESR_CS 0x00080000 | ||
| 138 | #define LTESR_CC 0x00000001 | ||
| 139 | #define LTESR_NAND_MASK (LTESR_FCT | LTESR_PAR | LTESR_CC) | ||
| 140 | __be32 ltedr; /**< Transfer Error Disable Register */ | ||
| 141 | __be32 lteir; /**< Transfer Error Interrupt Register */ | ||
| 142 | __be32 lteatr; /**< Transfer Error Attributes Register */ | ||
| 143 | __be32 ltear; /**< Transfer Error Address Register */ | ||
| 144 | u8 res6[0xC]; | ||
| 145 | __be32 lbcr; /**< Configuration Register */ | ||
| 146 | #define LBCR_LDIS 0x80000000 | ||
| 147 | #define LBCR_LDIS_SHIFT 31 | ||
| 148 | #define LBCR_BCTLC 0x00C00000 | ||
| 149 | #define LBCR_BCTLC_SHIFT 22 | ||
| 150 | #define LBCR_AHD 0x00200000 | ||
| 151 | #define LBCR_LPBSE 0x00020000 | ||
| 152 | #define LBCR_LPBSE_SHIFT 17 | ||
| 153 | #define LBCR_EPAR 0x00010000 | ||
| 154 | #define LBCR_EPAR_SHIFT 16 | ||
| 155 | #define LBCR_BMT 0x0000FF00 | ||
| 156 | #define LBCR_BMT_SHIFT 8 | ||
| 157 | #define LBCR_INIT 0x00040000 | ||
| 158 | __be32 lcrr; /**< Clock Ratio Register */ | ||
| 159 | #define LCRR_DBYP 0x80000000 | ||
| 160 | #define LCRR_DBYP_SHIFT 31 | ||
| 161 | #define LCRR_BUFCMDC 0x30000000 | ||
| 162 | #define LCRR_BUFCMDC_SHIFT 28 | ||
| 163 | #define LCRR_ECL 0x03000000 | ||
| 164 | #define LCRR_ECL_SHIFT 24 | ||
| 165 | #define LCRR_EADC 0x00030000 | ||
| 166 | #define LCRR_EADC_SHIFT 16 | ||
| 167 | #define LCRR_CLKDIV 0x0000000F | ||
| 168 | #define LCRR_CLKDIV_SHIFT 0 | ||
| 169 | u8 res7[0x8]; | ||
| 170 | __be32 fmr; /**< Flash Mode Register */ | ||
| 171 | #define FMR_CWTO 0x0000F000 | ||
| 172 | #define FMR_CWTO_SHIFT 12 | ||
| 173 | #define FMR_BOOT 0x00000800 | ||
| 174 | #define FMR_ECCM 0x00000100 | ||
| 175 | #define FMR_AL 0x00000030 | ||
| 176 | #define FMR_AL_SHIFT 4 | ||
| 177 | #define FMR_OP 0x00000003 | ||
| 178 | #define FMR_OP_SHIFT 0 | ||
| 179 | __be32 fir; /**< Flash Instruction Register */ | ||
| 180 | #define FIR_OP0 0xF0000000 | ||
| 181 | #define FIR_OP0_SHIFT 28 | ||
| 182 | #define FIR_OP1 0x0F000000 | ||
| 183 | #define FIR_OP1_SHIFT 24 | ||
| 184 | #define FIR_OP2 0x00F00000 | ||
| 185 | #define FIR_OP2_SHIFT 20 | ||
| 186 | #define FIR_OP3 0x000F0000 | ||
| 187 | #define FIR_OP3_SHIFT 16 | ||
| 188 | #define FIR_OP4 0x0000F000 | ||
| 189 | #define FIR_OP4_SHIFT 12 | ||
| 190 | #define FIR_OP5 0x00000F00 | ||
| 191 | #define FIR_OP5_SHIFT 8 | ||
| 192 | #define FIR_OP6 0x000000F0 | ||
| 193 | #define FIR_OP6_SHIFT 4 | ||
| 194 | #define FIR_OP7 0x0000000F | ||
| 195 | #define FIR_OP7_SHIFT 0 | ||
| 196 | #define FIR_OP_NOP 0x0 /* No operation and end of sequence */ | ||
| 197 | #define FIR_OP_CA 0x1 /* Issue current column address */ | ||
| 198 | #define FIR_OP_PA 0x2 /* Issue current block+page address */ | ||
| 199 | #define FIR_OP_UA 0x3 /* Issue user defined address */ | ||
| 200 | #define FIR_OP_CM0 0x4 /* Issue command from FCR[CMD0] */ | ||
| 201 | #define FIR_OP_CM1 0x5 /* Issue command from FCR[CMD1] */ | ||
| 202 | #define FIR_OP_CM2 0x6 /* Issue command from FCR[CMD2] */ | ||
| 203 | #define FIR_OP_CM3 0x7 /* Issue command from FCR[CMD3] */ | ||
| 204 | #define FIR_OP_WB 0x8 /* Write FBCR bytes from FCM buffer */ | ||
| 205 | #define FIR_OP_WS 0x9 /* Write 1 or 2 bytes from MDR[AS] */ | ||
| 206 | #define FIR_OP_RB 0xA /* Read FBCR bytes to FCM buffer */ | ||
| 207 | #define FIR_OP_RS 0xB /* Read 1 or 2 bytes to MDR[AS] */ | ||
| 208 | #define FIR_OP_CW0 0xC /* Wait then issue FCR[CMD0] */ | ||
| 209 | #define FIR_OP_CW1 0xD /* Wait then issue FCR[CMD1] */ | ||
| 210 | #define FIR_OP_RBW 0xE /* Wait then read FBCR bytes */ | ||
| 211 | #define FIR_OP_RSW 0xE /* Wait then read 1 or 2 bytes */ | ||
| 212 | __be32 fcr; /**< Flash Command Register */ | ||
| 213 | #define FCR_CMD0 0xFF000000 | ||
| 214 | #define FCR_CMD0_SHIFT 24 | ||
| 215 | #define FCR_CMD1 0x00FF0000 | ||
| 216 | #define FCR_CMD1_SHIFT 16 | ||
| 217 | #define FCR_CMD2 0x0000FF00 | ||
| 218 | #define FCR_CMD2_SHIFT 8 | ||
| 219 | #define FCR_CMD3 0x000000FF | ||
| 220 | #define FCR_CMD3_SHIFT 0 | ||
| 221 | __be32 fbar; /**< Flash Block Address Register */ | ||
| 222 | #define FBAR_BLK 0x00FFFFFF | ||
| 223 | __be32 fpar; /**< Flash Page Address Register */ | ||
| 224 | #define FPAR_SP_PI 0x00007C00 | ||
| 225 | #define FPAR_SP_PI_SHIFT 10 | ||
| 226 | #define FPAR_SP_MS 0x00000200 | ||
| 227 | #define FPAR_SP_CI 0x000001FF | ||
| 228 | #define FPAR_SP_CI_SHIFT 0 | ||
| 229 | #define FPAR_LP_PI 0x0003F000 | ||
| 230 | #define FPAR_LP_PI_SHIFT 12 | ||
| 231 | #define FPAR_LP_MS 0x00000800 | ||
| 232 | #define FPAR_LP_CI 0x000007FF | ||
| 233 | #define FPAR_LP_CI_SHIFT 0 | ||
| 234 | __be32 fbcr; /**< Flash Byte Count Register */ | ||
| 235 | #define FBCR_BC 0x00000FFF | ||
| 236 | u8 res11[0x8]; | ||
| 237 | u8 res8[0xF00]; | ||
| 238 | }; | ||
| 239 | |||
| 240 | struct fsl_elbc_ctrl; | ||
| 241 | |||
| 242 | /* mtd information per set */ | ||
| 243 | |||
| 244 | struct fsl_elbc_mtd { | ||
| 245 | struct mtd_info mtd; | ||
| 246 | struct nand_chip chip; | ||
| 247 | struct fsl_elbc_ctrl *ctrl; | ||
| 248 | |||
| 249 | struct device *dev; | ||
| 250 | int bank; /* Chip select bank number */ | ||
| 251 | u8 __iomem *vbase; /* Chip select base virtual address */ | ||
| 252 | int page_size; /* NAND page size (0=512, 1=2048) */ | ||
| 253 | unsigned int fmr; /* FCM Flash Mode Register value */ | ||
| 254 | }; | ||
| 255 | |||
| 256 | /* overview of the fsl elbc controller */ | ||
| 257 | |||
| 258 | struct fsl_elbc_ctrl { | ||
| 259 | struct nand_hw_control controller; | ||
| 260 | struct fsl_elbc_mtd *chips[MAX_BANKS]; | ||
| 261 | |||
| 262 | /* device info */ | ||
| 263 | struct device *dev; | ||
| 264 | struct elbc_regs __iomem *regs; | ||
| 265 | int irq; | ||
| 266 | wait_queue_head_t irq_wait; | ||
| 267 | unsigned int irq_status; /* status read from LTESR by irq handler */ | ||
| 268 | u8 __iomem *addr; /* Address of assigned FCM buffer */ | ||
| 269 | unsigned int page; /* Last page written to / read from */ | ||
| 270 | unsigned int read_bytes; /* Number of bytes read during command */ | ||
| 271 | unsigned int column; /* Saved column from SEQIN */ | ||
| 272 | unsigned int index; /* Pointer to next byte to 'read' */ | ||
| 273 | unsigned int status; /* status read from LTESR after last op */ | ||
| 274 | unsigned int mdr; /* UPM/FCM Data Register value */ | ||
| 275 | unsigned int use_mdr; /* Non zero if the MDR is to be set */ | ||
| 276 | unsigned int oob; /* Non zero if operating on OOB data */ | ||
| 277 | char *oob_poi; /* Place to write ECC after read back */ | ||
| 278 | }; | ||
| 279 | |||
| 280 | /* These map to the positions used by the FCM hardware ECC generator */ | ||
| 281 | |||
| 282 | /* Small Page FLASH with FMR[ECCM] = 0 */ | ||
| 283 | static struct nand_ecclayout fsl_elbc_oob_sp_eccm0 = { | ||
| 284 | .eccbytes = 3, | ||
| 285 | .eccpos = {6, 7, 8}, | ||
| 286 | .oobfree = { {0, 5}, {9, 7} }, | ||
| 287 | .oobavail = 12, | ||
| 288 | }; | ||
| 289 | |||
| 290 | /* Small Page FLASH with FMR[ECCM] = 1 */ | ||
| 291 | static struct nand_ecclayout fsl_elbc_oob_sp_eccm1 = { | ||
| 292 | .eccbytes = 3, | ||
| 293 | .eccpos = {8, 9, 10}, | ||
| 294 | .oobfree = { {0, 5}, {6, 2}, {11, 5} }, | ||
| 295 | .oobavail = 12, | ||
| 296 | }; | ||
| 297 | |||
| 298 | /* Large Page FLASH with FMR[ECCM] = 0 */ | ||
| 299 | static struct nand_ecclayout fsl_elbc_oob_lp_eccm0 = { | ||
| 300 | .eccbytes = 12, | ||
| 301 | .eccpos = {6, 7, 8, 22, 23, 24, 38, 39, 40, 54, 55, 56}, | ||
| 302 | .oobfree = { {1, 5}, {9, 13}, {25, 13}, {41, 13}, {57, 7} }, | ||
| 303 | .oobavail = 48, | ||
| 304 | }; | ||
| 305 | |||
| 306 | /* Large Page FLASH with FMR[ECCM] = 1 */ | ||
| 307 | static struct nand_ecclayout fsl_elbc_oob_lp_eccm1 = { | ||
| 308 | .eccbytes = 12, | ||
| 309 | .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, | ||
| 310 | .oobfree = { {1, 7}, {11, 13}, {27, 13}, {43, 13}, {59, 5} }, | ||
| 311 | .oobavail = 48, | ||
| 312 | }; | ||
| 313 | |||
| 314 | /*=================================*/ | ||
| 315 | |||
| 316 | /* | ||
| 317 | * Set up the FCM hardware block and page address fields, and the fcm | ||
| 318 | * structure addr field to point to the correct FCM buffer in memory | ||
| 319 | */ | ||
| 320 | static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) | ||
| 321 | { | ||
| 322 | struct nand_chip *chip = mtd->priv; | ||
| 323 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 324 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 325 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 326 | int buf_num; | ||
| 327 | |||
| 328 | ctrl->page = page_addr; | ||
| 329 | |||
| 330 | out_be32(&lbc->fbar, | ||
| 331 | page_addr >> (chip->phys_erase_shift - chip->page_shift)); | ||
| 332 | |||
| 333 | if (priv->page_size) { | ||
| 334 | out_be32(&lbc->fpar, | ||
| 335 | ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) | | ||
| 336 | (oob ? FPAR_LP_MS : 0) | column); | ||
| 337 | buf_num = (page_addr & 1) << 2; | ||
| 338 | } else { | ||
| 339 | out_be32(&lbc->fpar, | ||
| 340 | ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) | | ||
| 341 | (oob ? FPAR_SP_MS : 0) | column); | ||
| 342 | buf_num = page_addr & 7; | ||
| 343 | } | ||
| 344 | |||
| 345 | ctrl->addr = priv->vbase + buf_num * 1024; | ||
| 346 | ctrl->index = column; | ||
| 347 | |||
| 348 | /* for OOB data point to the second half of the buffer */ | ||
| 349 | if (oob) | ||
| 350 | ctrl->index += priv->page_size ? 2048 : 512; | ||
| 351 | |||
| 352 | dev_vdbg(ctrl->dev, "set_addr: bank=%d, ctrl->addr=0x%p (0x%p), " | ||
| 353 | "index %x, pes %d ps %d\n", | ||
| 354 | buf_num, ctrl->addr, priv->vbase, ctrl->index, | ||
| 355 | chip->phys_erase_shift, chip->page_shift); | ||
| 356 | } | ||
| 357 | |||
| 358 | /* | ||
| 359 | * execute FCM command and wait for it to complete | ||
| 360 | */ | ||
| 361 | static int fsl_elbc_run_command(struct mtd_info *mtd) | ||
| 362 | { | ||
| 363 | struct nand_chip *chip = mtd->priv; | ||
| 364 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 365 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 366 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 367 | |||
| 368 | /* Setup the FMR[OP] to execute without write protection */ | ||
| 369 | out_be32(&lbc->fmr, priv->fmr | 3); | ||
| 370 | if (ctrl->use_mdr) | ||
| 371 | out_be32(&lbc->mdr, ctrl->mdr); | ||
| 372 | |||
| 373 | dev_vdbg(ctrl->dev, | ||
| 374 | "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n", | ||
| 375 | in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr)); | ||
| 376 | dev_vdbg(ctrl->dev, | ||
| 377 | "fsl_elbc_run_command: fbar=%08x fpar=%08x " | ||
| 378 | "fbcr=%08x bank=%d\n", | ||
| 379 | in_be32(&lbc->fbar), in_be32(&lbc->fpar), | ||
| 380 | in_be32(&lbc->fbcr), priv->bank); | ||
| 381 | |||
| 382 | /* execute special operation */ | ||
| 383 | out_be32(&lbc->lsor, priv->bank); | ||
| 384 | |||
| 385 | /* wait for FCM complete flag or timeout */ | ||
| 386 | ctrl->irq_status = 0; | ||
| 387 | wait_event_timeout(ctrl->irq_wait, ctrl->irq_status, | ||
| 388 | FCM_TIMEOUT_MSECS * HZ/1000); | ||
| 389 | ctrl->status = ctrl->irq_status; | ||
| 390 | |||
| 391 | /* store mdr value in case it was needed */ | ||
| 392 | if (ctrl->use_mdr) | ||
| 393 | ctrl->mdr = in_be32(&lbc->mdr); | ||
| 394 | |||
| 395 | ctrl->use_mdr = 0; | ||
| 396 | |||
| 397 | dev_vdbg(ctrl->dev, | ||
| 398 | "fsl_elbc_run_command: stat=%08x mdr=%08x fmr=%08x\n", | ||
| 399 | ctrl->status, ctrl->mdr, in_be32(&lbc->fmr)); | ||
| 400 | |||
| 401 | /* returns 0 on success otherwise non-zero) */ | ||
| 402 | return ctrl->status == LTESR_CC ? 0 : -EIO; | ||
| 403 | } | ||
| 404 | |||
| 405 | static void fsl_elbc_do_read(struct nand_chip *chip, int oob) | ||
| 406 | { | ||
| 407 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 408 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 409 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 410 | |||
| 411 | if (priv->page_size) { | ||
| 412 | out_be32(&lbc->fir, | ||
| 413 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | | ||
| 414 | (FIR_OP_CA << FIR_OP1_SHIFT) | | ||
| 415 | (FIR_OP_PA << FIR_OP2_SHIFT) | | ||
| 416 | (FIR_OP_CW1 << FIR_OP3_SHIFT) | | ||
| 417 | (FIR_OP_RBW << FIR_OP4_SHIFT)); | ||
| 418 | |||
| 419 | out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) | | ||
| 420 | (NAND_CMD_READSTART << FCR_CMD1_SHIFT)); | ||
| 421 | } else { | ||
| 422 | out_be32(&lbc->fir, | ||
| 423 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | | ||
| 424 | (FIR_OP_CA << FIR_OP1_SHIFT) | | ||
| 425 | (FIR_OP_PA << FIR_OP2_SHIFT) | | ||
| 426 | (FIR_OP_RBW << FIR_OP3_SHIFT)); | ||
| 427 | |||
| 428 | if (oob) | ||
| 429 | out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT); | ||
| 430 | else | ||
| 431 | out_be32(&lbc->fcr, NAND_CMD_READ0 << FCR_CMD0_SHIFT); | ||
| 432 | } | ||
| 433 | } | ||
| 434 | |||
| 435 | /* cmdfunc send commands to the FCM */ | ||
| 436 | static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, | ||
| 437 | int column, int page_addr) | ||
| 438 | { | ||
| 439 | struct nand_chip *chip = mtd->priv; | ||
| 440 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 441 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 442 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 443 | |||
| 444 | ctrl->use_mdr = 0; | ||
| 445 | |||
| 446 | /* clear the read buffer */ | ||
| 447 | ctrl->read_bytes = 0; | ||
| 448 | if (command != NAND_CMD_PAGEPROG) | ||
| 449 | ctrl->index = 0; | ||
| 450 | |||
| 451 | switch (command) { | ||
| 452 | /* READ0 and READ1 read the entire buffer to use hardware ECC. */ | ||
| 453 | case NAND_CMD_READ1: | ||
| 454 | column += 256; | ||
| 455 | |||
| 456 | /* fall-through */ | ||
| 457 | case NAND_CMD_READ0: | ||
| 458 | dev_dbg(ctrl->dev, | ||
| 459 | "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:" | ||
| 460 | " 0x%x, column: 0x%x.\n", page_addr, column); | ||
| 461 | |||
| 462 | |||
| 463 | out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */ | ||
| 464 | set_addr(mtd, 0, page_addr, 0); | ||
| 465 | |||
| 466 | ctrl->read_bytes = mtd->writesize + mtd->oobsize; | ||
| 467 | ctrl->index += column; | ||
| 468 | |||
| 469 | fsl_elbc_do_read(chip, 0); | ||
| 470 | fsl_elbc_run_command(mtd); | ||
| 471 | return; | ||
| 472 | |||
| 473 | /* READOOB reads only the OOB because no ECC is performed. */ | ||
| 474 | case NAND_CMD_READOOB: | ||
| 475 | dev_vdbg(ctrl->dev, | ||
| 476 | "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:" | ||
| 477 | " 0x%x, column: 0x%x.\n", page_addr, column); | ||
| 478 | |||
| 479 | out_be32(&lbc->fbcr, mtd->oobsize - column); | ||
| 480 | set_addr(mtd, column, page_addr, 1); | ||
| 481 | |||
| 482 | ctrl->read_bytes = mtd->writesize + mtd->oobsize; | ||
| 483 | |||
| 484 | fsl_elbc_do_read(chip, 1); | ||
| 485 | fsl_elbc_run_command(mtd); | ||
| 486 | return; | ||
| 487 | |||
| 488 | /* READID must read all 5 possible bytes while CEB is active */ | ||
| 489 | case NAND_CMD_READID: | ||
| 490 | dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); | ||
| 491 | |||
| 492 | out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) | | ||
| 493 | (FIR_OP_UA << FIR_OP1_SHIFT) | | ||
| 494 | (FIR_OP_RBW << FIR_OP2_SHIFT)); | ||
| 495 | out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT); | ||
| 496 | /* 5 bytes for manuf, device and exts */ | ||
| 497 | out_be32(&lbc->fbcr, 5); | ||
| 498 | ctrl->read_bytes = 5; | ||
| 499 | ctrl->use_mdr = 1; | ||
| 500 | ctrl->mdr = 0; | ||
| 501 | |||
| 502 | set_addr(mtd, 0, 0, 0); | ||
| 503 | fsl_elbc_run_command(mtd); | ||
| 504 | return; | ||
| 505 | |||
| 506 | /* ERASE1 stores the block and page address */ | ||
| 507 | case NAND_CMD_ERASE1: | ||
| 508 | dev_vdbg(ctrl->dev, | ||
| 509 | "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, " | ||
| 510 | "page_addr: 0x%x.\n", page_addr); | ||
| 511 | set_addr(mtd, 0, page_addr, 0); | ||
| 512 | return; | ||
| 513 | |||
| 514 | /* ERASE2 uses the block and page address from ERASE1 */ | ||
| 515 | case NAND_CMD_ERASE2: | ||
| 516 | dev_vdbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n"); | ||
| 517 | |||
| 518 | out_be32(&lbc->fir, | ||
| 519 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | | ||
| 520 | (FIR_OP_PA << FIR_OP1_SHIFT) | | ||
| 521 | (FIR_OP_CM1 << FIR_OP2_SHIFT)); | ||
| 522 | |||
| 523 | out_be32(&lbc->fcr, | ||
| 524 | (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) | | ||
| 525 | (NAND_CMD_ERASE2 << FCR_CMD1_SHIFT)); | ||
| 526 | |||
| 527 | out_be32(&lbc->fbcr, 0); | ||
| 528 | ctrl->read_bytes = 0; | ||
| 529 | |||
| 530 | fsl_elbc_run_command(mtd); | ||
| 531 | return; | ||
| 532 | |||
| 533 | /* SEQIN sets up the addr buffer and all registers except the length */ | ||
| 534 | case NAND_CMD_SEQIN: { | ||
| 535 | __be32 fcr; | ||
| 536 | dev_vdbg(ctrl->dev, | ||
| 537 | "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, " | ||
| 538 | "page_addr: 0x%x, column: 0x%x.\n", | ||
| 539 | page_addr, column); | ||
| 540 | |||
| 541 | ctrl->column = column; | ||
| 542 | ctrl->oob = 0; | ||
| 543 | |||
| 544 | fcr = (NAND_CMD_PAGEPROG << FCR_CMD1_SHIFT) | | ||
| 545 | (NAND_CMD_SEQIN << FCR_CMD2_SHIFT); | ||
| 546 | |||
| 547 | if (priv->page_size) { | ||
| 548 | out_be32(&lbc->fir, | ||
| 549 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | | ||
| 550 | (FIR_OP_CA << FIR_OP1_SHIFT) | | ||
| 551 | (FIR_OP_PA << FIR_OP2_SHIFT) | | ||
| 552 | (FIR_OP_WB << FIR_OP3_SHIFT) | | ||
| 553 | (FIR_OP_CW1 << FIR_OP4_SHIFT)); | ||
| 554 | |||
| 555 | fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT; | ||
| 556 | } else { | ||
| 557 | out_be32(&lbc->fir, | ||
| 558 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | | ||
| 559 | (FIR_OP_CM2 << FIR_OP1_SHIFT) | | ||
| 560 | (FIR_OP_CA << FIR_OP2_SHIFT) | | ||
| 561 | (FIR_OP_PA << FIR_OP3_SHIFT) | | ||
| 562 | (FIR_OP_WB << FIR_OP4_SHIFT) | | ||
| 563 | (FIR_OP_CW1 << FIR_OP5_SHIFT)); | ||
| 564 | |||
| 565 | if (column >= mtd->writesize) { | ||
| 566 | /* OOB area --> READOOB */ | ||
| 567 | column -= mtd->writesize; | ||
| 568 | fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT; | ||
| 569 | ctrl->oob = 1; | ||
| 570 | } else if (column < 256) { | ||
| 571 | /* First 256 bytes --> READ0 */ | ||
| 572 | fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT; | ||
| 573 | } else { | ||
| 574 | /* Second 256 bytes --> READ1 */ | ||
| 575 | fcr |= NAND_CMD_READ1 << FCR_CMD0_SHIFT; | ||
| 576 | } | ||
| 577 | } | ||
| 578 | |||
| 579 | out_be32(&lbc->fcr, fcr); | ||
| 580 | set_addr(mtd, column, page_addr, ctrl->oob); | ||
| 581 | return; | ||
| 582 | } | ||
| 583 | |||
| 584 | /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ | ||
| 585 | case NAND_CMD_PAGEPROG: { | ||
| 586 | int full_page; | ||
| 587 | dev_vdbg(ctrl->dev, | ||
| 588 | "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " | ||
| 589 | "writing %d bytes.\n", ctrl->index); | ||
| 590 | |||
| 591 | /* if the write did not start at 0 or is not a full page | ||
| 592 | * then set the exact length, otherwise use a full page | ||
| 593 | * write so the HW generates the ECC. | ||
| 594 | */ | ||
| 595 | if (ctrl->oob || ctrl->column != 0 || | ||
| 596 | ctrl->index != mtd->writesize + mtd->oobsize) { | ||
| 597 | out_be32(&lbc->fbcr, ctrl->index); | ||
| 598 | full_page = 0; | ||
| 599 | } else { | ||
| 600 | out_be32(&lbc->fbcr, 0); | ||
| 601 | full_page = 1; | ||
| 602 | } | ||
| 603 | |||
| 604 | fsl_elbc_run_command(mtd); | ||
| 605 | |||
| 606 | /* Read back the page in order to fill in the ECC for the | ||
| 607 | * caller. Is this really needed? | ||
| 608 | */ | ||
| 609 | if (full_page && ctrl->oob_poi) { | ||
| 610 | out_be32(&lbc->fbcr, 3); | ||
| 611 | set_addr(mtd, 6, page_addr, 1); | ||
| 612 | |||
| 613 | ctrl->read_bytes = mtd->writesize + 9; | ||
| 614 | |||
| 615 | fsl_elbc_do_read(chip, 1); | ||
| 616 | fsl_elbc_run_command(mtd); | ||
| 617 | |||
| 618 | memcpy_fromio(ctrl->oob_poi + 6, | ||
| 619 | &ctrl->addr[ctrl->index], 3); | ||
| 620 | ctrl->index += 3; | ||
| 621 | } | ||
| 622 | |||
| 623 | ctrl->oob_poi = NULL; | ||
| 624 | return; | ||
| 625 | } | ||
| 626 | |||
| 627 | /* CMD_STATUS must read the status byte while CEB is active */ | ||
| 628 | /* Note - it does not wait for the ready line */ | ||
| 629 | case NAND_CMD_STATUS: | ||
| 630 | out_be32(&lbc->fir, | ||
| 631 | (FIR_OP_CM0 << FIR_OP0_SHIFT) | | ||
| 632 | (FIR_OP_RBW << FIR_OP1_SHIFT)); | ||
| 633 | out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); | ||
| 634 | out_be32(&lbc->fbcr, 1); | ||
| 635 | set_addr(mtd, 0, 0, 0); | ||
| 636 | ctrl->read_bytes = 1; | ||
| 637 | |||
| 638 | fsl_elbc_run_command(mtd); | ||
| 639 | |||
| 640 | /* The chip always seems to report that it is | ||
| 641 | * write-protected, even when it is not. | ||
| 642 | */ | ||
| 643 | setbits8(ctrl->addr, NAND_STATUS_WP); | ||
| 644 | return; | ||
| 645 | |||
| 646 | /* RESET without waiting for the ready line */ | ||
| 647 | case NAND_CMD_RESET: | ||
| 648 | dev_dbg(ctrl->dev, "fsl_elbc_cmdfunc: NAND_CMD_RESET.\n"); | ||
| 649 | out_be32(&lbc->fir, FIR_OP_CM0 << FIR_OP0_SHIFT); | ||
| 650 | out_be32(&lbc->fcr, NAND_CMD_RESET << FCR_CMD0_SHIFT); | ||
| 651 | fsl_elbc_run_command(mtd); | ||
| 652 | return; | ||
| 653 | |||
| 654 | default: | ||
| 655 | dev_err(ctrl->dev, | ||
| 656 | "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n", | ||
| 657 | command); | ||
| 658 | } | ||
| 659 | } | ||
| 660 | |||
| 661 | static void fsl_elbc_select_chip(struct mtd_info *mtd, int chip) | ||
| 662 | { | ||
| 663 | /* The hardware does not seem to support multiple | ||
| 664 | * chips per bank. | ||
| 665 | */ | ||
| 666 | } | ||
| 667 | |||
| 668 | /* | ||
| 669 | * Write buf to the FCM Controller Data Buffer | ||
| 670 | */ | ||
| 671 | static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | ||
| 672 | { | ||
| 673 | struct nand_chip *chip = mtd->priv; | ||
| 674 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 675 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 676 | unsigned int bufsize = mtd->writesize + mtd->oobsize; | ||
| 677 | |||
| 678 | if (len < 0) { | ||
| 679 | dev_err(ctrl->dev, "write_buf of %d bytes", len); | ||
| 680 | ctrl->status = 0; | ||
| 681 | return; | ||
| 682 | } | ||
| 683 | |||
| 684 | if ((unsigned int)len > bufsize - ctrl->index) { | ||
| 685 | dev_err(ctrl->dev, | ||
| 686 | "write_buf beyond end of buffer " | ||
| 687 | "(%d requested, %u available)\n", | ||
| 688 | len, bufsize - ctrl->index); | ||
| 689 | len = bufsize - ctrl->index; | ||
| 690 | } | ||
| 691 | |||
| 692 | memcpy_toio(&ctrl->addr[ctrl->index], buf, len); | ||
| 693 | ctrl->index += len; | ||
| 694 | } | ||
| 695 | |||
| 696 | /* | ||
| 697 | * read a byte from either the FCM hardware buffer if it has any data left | ||
| 698 | * otherwise issue a command to read a single byte. | ||
| 699 | */ | ||
| 700 | static u8 fsl_elbc_read_byte(struct mtd_info *mtd) | ||
| 701 | { | ||
| 702 | struct nand_chip *chip = mtd->priv; | ||
| 703 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 704 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 705 | |||
| 706 | /* If there are still bytes in the FCM, then use the next byte. */ | ||
| 707 | if (ctrl->index < ctrl->read_bytes) | ||
| 708 | return in_8(&ctrl->addr[ctrl->index++]); | ||
| 709 | |||
| 710 | dev_err(ctrl->dev, "read_byte beyond end of buffer\n"); | ||
| 711 | return ERR_BYTE; | ||
| 712 | } | ||
| 713 | |||
| 714 | /* | ||
| 715 | * Read from the FCM Controller Data Buffer | ||
| 716 | */ | ||
| 717 | static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len) | ||
| 718 | { | ||
| 719 | struct nand_chip *chip = mtd->priv; | ||
| 720 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 721 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 722 | int avail; | ||
| 723 | |||
| 724 | if (len < 0) | ||
| 725 | return; | ||
| 726 | |||
| 727 | avail = min((unsigned int)len, ctrl->read_bytes - ctrl->index); | ||
| 728 | memcpy_fromio(buf, &ctrl->addr[ctrl->index], avail); | ||
| 729 | ctrl->index += avail; | ||
| 730 | |||
| 731 | if (len > avail) | ||
| 732 | dev_err(ctrl->dev, | ||
| 733 | "read_buf beyond end of buffer " | ||
| 734 | "(%d requested, %d available)\n", | ||
| 735 | len, avail); | ||
| 736 | } | ||
| 737 | |||
| 738 | /* | ||
| 739 | * Verify buffer against the FCM Controller Data Buffer | ||
| 740 | */ | ||
| 741 | static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
| 742 | { | ||
| 743 | struct nand_chip *chip = mtd->priv; | ||
| 744 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 745 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 746 | int i; | ||
| 747 | |||
| 748 | if (len < 0) { | ||
| 749 | dev_err(ctrl->dev, "write_buf of %d bytes", len); | ||
| 750 | return -EINVAL; | ||
| 751 | } | ||
| 752 | |||
| 753 | if ((unsigned int)len > ctrl->read_bytes - ctrl->index) { | ||
| 754 | dev_err(ctrl->dev, | ||
| 755 | "verify_buf beyond end of buffer " | ||
| 756 | "(%d requested, %u available)\n", | ||
| 757 | len, ctrl->read_bytes - ctrl->index); | ||
| 758 | |||
| 759 | ctrl->index = ctrl->read_bytes; | ||
| 760 | return -EINVAL; | ||
| 761 | } | ||
| 762 | |||
| 763 | for (i = 0; i < len; i++) | ||
| 764 | if (in_8(&ctrl->addr[ctrl->index + i]) != buf[i]) | ||
| 765 | break; | ||
| 766 | |||
| 767 | ctrl->index += len; | ||
| 768 | return i == len && ctrl->status == LTESR_CC ? 0 : -EIO; | ||
| 769 | } | ||
| 770 | |||
| 771 | /* This function is called after Program and Erase Operations to | ||
| 772 | * check for success or failure. | ||
| 773 | */ | ||
| 774 | static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) | ||
| 775 | { | ||
| 776 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 777 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 778 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 779 | |||
| 780 | if (ctrl->status != LTESR_CC) | ||
| 781 | return NAND_STATUS_FAIL; | ||
| 782 | |||
| 783 | /* Use READ_STATUS command, but wait for the device to be ready */ | ||
| 784 | ctrl->use_mdr = 0; | ||
| 785 | out_be32(&lbc->fir, | ||
| 786 | (FIR_OP_CW0 << FIR_OP0_SHIFT) | | ||
| 787 | (FIR_OP_RBW << FIR_OP1_SHIFT)); | ||
| 788 | out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT); | ||
| 789 | out_be32(&lbc->fbcr, 1); | ||
| 790 | set_addr(mtd, 0, 0, 0); | ||
| 791 | ctrl->read_bytes = 1; | ||
| 792 | |||
| 793 | fsl_elbc_run_command(mtd); | ||
| 794 | |||
| 795 | if (ctrl->status != LTESR_CC) | ||
| 796 | return NAND_STATUS_FAIL; | ||
| 797 | |||
| 798 | /* The chip always seems to report that it is | ||
| 799 | * write-protected, even when it is not. | ||
| 800 | */ | ||
| 801 | setbits8(ctrl->addr, NAND_STATUS_WP); | ||
| 802 | return fsl_elbc_read_byte(mtd); | ||
| 803 | } | ||
| 804 | |||
| 805 | static int fsl_elbc_chip_init_tail(struct mtd_info *mtd) | ||
| 806 | { | ||
| 807 | struct nand_chip *chip = mtd->priv; | ||
| 808 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 809 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 810 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 811 | unsigned int al; | ||
| 812 | |||
| 813 | /* calculate FMR Address Length field */ | ||
| 814 | al = 0; | ||
| 815 | if (chip->pagemask & 0xffff0000) | ||
| 816 | al++; | ||
| 817 | if (chip->pagemask & 0xff000000) | ||
| 818 | al++; | ||
| 819 | |||
| 820 | /* add to ECCM mode set in fsl_elbc_init */ | ||
| 821 | priv->fmr |= (12 << FMR_CWTO_SHIFT) | /* Timeout > 12 ms */ | ||
| 822 | (al << FMR_AL_SHIFT); | ||
| 823 | |||
| 824 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->numchips = %d\n", | ||
| 825 | chip->numchips); | ||
| 826 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chipsize = %ld\n", | ||
| 827 | chip->chipsize); | ||
| 828 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->pagemask = %8x\n", | ||
| 829 | chip->pagemask); | ||
| 830 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_delay = %d\n", | ||
| 831 | chip->chip_delay); | ||
| 832 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->badblockpos = %d\n", | ||
| 833 | chip->badblockpos); | ||
| 834 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->chip_shift = %d\n", | ||
| 835 | chip->chip_shift); | ||
| 836 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->page_shift = %d\n", | ||
| 837 | chip->page_shift); | ||
| 838 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n", | ||
| 839 | chip->phys_erase_shift); | ||
| 840 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecclayout = %p\n", | ||
| 841 | chip->ecclayout); | ||
| 842 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.mode = %d\n", | ||
| 843 | chip->ecc.mode); | ||
| 844 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.steps = %d\n", | ||
| 845 | chip->ecc.steps); | ||
| 846 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n", | ||
| 847 | chip->ecc.bytes); | ||
| 848 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.total = %d\n", | ||
| 849 | chip->ecc.total); | ||
| 850 | dev_dbg(ctrl->dev, "fsl_elbc_init: nand->ecc.layout = %p\n", | ||
| 851 | chip->ecc.layout); | ||
| 852 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags); | ||
| 853 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->size = %d\n", mtd->size); | ||
| 854 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->erasesize = %d\n", | ||
| 855 | mtd->erasesize); | ||
| 856 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->writesize = %d\n", | ||
| 857 | mtd->writesize); | ||
| 858 | dev_dbg(ctrl->dev, "fsl_elbc_init: mtd->oobsize = %d\n", | ||
| 859 | mtd->oobsize); | ||
| 860 | |||
| 861 | /* adjust Option Register and ECC to match Flash page size */ | ||
| 862 | if (mtd->writesize == 512) { | ||
| 863 | priv->page_size = 0; | ||
| 864 | clrbits32(&lbc->bank[priv->bank].or, ~OR_FCM_PGS); | ||
| 865 | } else if (mtd->writesize == 2048) { | ||
| 866 | priv->page_size = 1; | ||
| 867 | setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS); | ||
| 868 | /* adjust ecc setup if needed */ | ||
| 869 | if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) == | ||
| 870 | BR_DECC_CHK_GEN) { | ||
| 871 | chip->ecc.size = 512; | ||
| 872 | chip->ecc.layout = (priv->fmr & FMR_ECCM) ? | ||
| 873 | &fsl_elbc_oob_lp_eccm1 : | ||
| 874 | &fsl_elbc_oob_lp_eccm0; | ||
| 875 | mtd->ecclayout = chip->ecc.layout; | ||
| 876 | mtd->oobavail = chip->ecc.layout->oobavail; | ||
| 877 | } | ||
| 878 | } else { | ||
| 879 | dev_err(ctrl->dev, | ||
| 880 | "fsl_elbc_init: page size %d is not supported\n", | ||
| 881 | mtd->writesize); | ||
| 882 | return -1; | ||
| 883 | } | ||
| 884 | |||
| 885 | /* The default u-boot configuration on MPC8313ERDB causes errors; | ||
| 886 | * more delay is needed. This should be safe for other boards | ||
| 887 | * as well. | ||
| 888 | */ | ||
| 889 | setbits32(&lbc->bank[priv->bank].or, 0x70); | ||
| 890 | return 0; | ||
| 891 | } | ||
| 892 | |||
| 893 | static int fsl_elbc_read_page(struct mtd_info *mtd, | ||
| 894 | struct nand_chip *chip, | ||
| 895 | uint8_t *buf) | ||
| 896 | { | ||
| 897 | fsl_elbc_read_buf(mtd, buf, mtd->writesize); | ||
| 898 | fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
| 899 | |||
| 900 | if (fsl_elbc_wait(mtd, chip) & NAND_STATUS_FAIL) | ||
| 901 | mtd->ecc_stats.failed++; | ||
| 902 | |||
| 903 | return 0; | ||
| 904 | } | ||
| 905 | |||
| 906 | /* ECC will be calculated automatically, and errors will be detected in | ||
| 907 | * waitfunc. | ||
| 908 | */ | ||
| 909 | static void fsl_elbc_write_page(struct mtd_info *mtd, | ||
| 910 | struct nand_chip *chip, | ||
| 911 | const uint8_t *buf) | ||
| 912 | { | ||
| 913 | struct fsl_elbc_mtd *priv = chip->priv; | ||
| 914 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 915 | |||
| 916 | fsl_elbc_write_buf(mtd, buf, mtd->writesize); | ||
| 917 | fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
| 918 | |||
| 919 | ctrl->oob_poi = chip->oob_poi; | ||
| 920 | } | ||
| 921 | |||
| 922 | static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) | ||
| 923 | { | ||
| 924 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 925 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 926 | struct nand_chip *chip = &priv->chip; | ||
| 927 | |||
| 928 | dev_dbg(priv->dev, "eLBC Set Information for bank %d\n", priv->bank); | ||
| 929 | |||
| 930 | /* Fill in fsl_elbc_mtd structure */ | ||
| 931 | priv->mtd.priv = chip; | ||
| 932 | priv->mtd.owner = THIS_MODULE; | ||
| 933 | priv->fmr = 0; /* rest filled in later */ | ||
| 934 | |||
| 935 | /* fill in nand_chip structure */ | ||
| 936 | /* set up function call table */ | ||
| 937 | chip->read_byte = fsl_elbc_read_byte; | ||
| 938 | chip->write_buf = fsl_elbc_write_buf; | ||
| 939 | chip->read_buf = fsl_elbc_read_buf; | ||
| 940 | chip->verify_buf = fsl_elbc_verify_buf; | ||
| 941 | chip->select_chip = fsl_elbc_select_chip; | ||
| 942 | chip->cmdfunc = fsl_elbc_cmdfunc; | ||
| 943 | chip->waitfunc = fsl_elbc_wait; | ||
| 944 | |||
| 945 | /* set up nand options */ | ||
| 946 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; | ||
| 947 | |||
| 948 | chip->controller = &ctrl->controller; | ||
| 949 | chip->priv = priv; | ||
| 950 | |||
| 951 | chip->ecc.read_page = fsl_elbc_read_page; | ||
| 952 | chip->ecc.write_page = fsl_elbc_write_page; | ||
| 953 | |||
| 954 | /* If CS Base Register selects full hardware ECC then use it */ | ||
| 955 | if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) == | ||
| 956 | BR_DECC_CHK_GEN) { | ||
| 957 | chip->ecc.mode = NAND_ECC_HW; | ||
| 958 | /* put in small page settings and adjust later if needed */ | ||
| 959 | chip->ecc.layout = (priv->fmr & FMR_ECCM) ? | ||
| 960 | &fsl_elbc_oob_sp_eccm1 : &fsl_elbc_oob_sp_eccm0; | ||
| 961 | chip->ecc.size = 512; | ||
| 962 | chip->ecc.bytes = 3; | ||
| 963 | } else { | ||
| 964 | /* otherwise fall back to default software ECC */ | ||
| 965 | chip->ecc.mode = NAND_ECC_SOFT; | ||
| 966 | } | ||
| 967 | |||
| 968 | return 0; | ||
| 969 | } | ||
| 970 | |||
| 971 | static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) | ||
| 972 | { | ||
| 973 | struct fsl_elbc_ctrl *ctrl = priv->ctrl; | ||
| 974 | |||
| 975 | nand_release(&priv->mtd); | ||
| 976 | |||
| 977 | if (priv->vbase) | ||
| 978 | iounmap(priv->vbase); | ||
| 979 | |||
| 980 | ctrl->chips[priv->bank] = NULL; | ||
| 981 | kfree(priv); | ||
| 982 | |||
| 983 | return 0; | ||
| 984 | } | ||
| 985 | |||
| 986 | static int fsl_elbc_chip_probe(struct fsl_elbc_ctrl *ctrl, | ||
| 987 | struct device_node *node) | ||
| 988 | { | ||
| 989 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 990 | struct fsl_elbc_mtd *priv; | ||
| 991 | struct resource res; | ||
| 992 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 993 | static const char *part_probe_types[] | ||
| 994 | = { "cmdlinepart", "RedBoot", NULL }; | ||
| 995 | struct mtd_partition *parts; | ||
| 996 | #endif | ||
| 997 | int ret; | ||
| 998 | int bank; | ||
| 999 | |||
| 1000 | /* get, allocate and map the memory resource */ | ||
| 1001 | ret = of_address_to_resource(node, 0, &res); | ||
| 1002 | if (ret) { | ||
| 1003 | dev_err(ctrl->dev, "failed to get resource\n"); | ||
| 1004 | return ret; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | /* find which chip select it is connected to */ | ||
| 1008 | for (bank = 0; bank < MAX_BANKS; bank++) | ||
| 1009 | if ((in_be32(&lbc->bank[bank].br) & BR_V) && | ||
| 1010 | (in_be32(&lbc->bank[bank].br) & BR_MSEL) == BR_MS_FCM && | ||
| 1011 | (in_be32(&lbc->bank[bank].br) & | ||
| 1012 | in_be32(&lbc->bank[bank].or) & BR_BA) | ||
| 1013 | == res.start) | ||
| 1014 | break; | ||
| 1015 | |||
| 1016 | if (bank >= MAX_BANKS) { | ||
| 1017 | dev_err(ctrl->dev, "address did not match any chip selects\n"); | ||
| 1018 | return -ENODEV; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
| 1022 | if (!priv) | ||
| 1023 | return -ENOMEM; | ||
| 1024 | |||
| 1025 | ctrl->chips[bank] = priv; | ||
| 1026 | priv->bank = bank; | ||
| 1027 | priv->ctrl = ctrl; | ||
| 1028 | priv->dev = ctrl->dev; | ||
| 1029 | |||
| 1030 | priv->vbase = ioremap(res.start, res.end - res.start + 1); | ||
| 1031 | if (!priv->vbase) { | ||
| 1032 | dev_err(ctrl->dev, "failed to map chip region\n"); | ||
| 1033 | ret = -ENOMEM; | ||
| 1034 | goto err; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | ret = fsl_elbc_chip_init(priv); | ||
| 1038 | if (ret) | ||
| 1039 | goto err; | ||
| 1040 | |||
| 1041 | ret = nand_scan_ident(&priv->mtd, 1); | ||
| 1042 | if (ret) | ||
| 1043 | goto err; | ||
| 1044 | |||
| 1045 | ret = fsl_elbc_chip_init_tail(&priv->mtd); | ||
| 1046 | if (ret) | ||
| 1047 | goto err; | ||
| 1048 | |||
| 1049 | ret = nand_scan_tail(&priv->mtd); | ||
| 1050 | if (ret) | ||
| 1051 | goto err; | ||
| 1052 | |||
| 1053 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 1054 | /* First look for RedBoot table or partitions on the command | ||
| 1055 | * line, these take precedence over device tree information */ | ||
| 1056 | ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, 0); | ||
| 1057 | if (ret < 0) | ||
| 1058 | goto err; | ||
| 1059 | |||
| 1060 | #ifdef CONFIG_MTD_OF_PARTS | ||
| 1061 | if (ret == 0) { | ||
| 1062 | ret = of_mtd_parse_partitions(priv->dev, &priv->mtd, | ||
| 1063 | node, &parts); | ||
| 1064 | if (ret < 0) | ||
| 1065 | goto err; | ||
| 1066 | } | ||
| 1067 | #endif | ||
| 1068 | |||
| 1069 | if (ret > 0) | ||
| 1070 | add_mtd_partitions(&priv->mtd, parts, ret); | ||
| 1071 | else | ||
| 1072 | #endif | ||
| 1073 | add_mtd_device(&priv->mtd); | ||
| 1074 | |||
| 1075 | printk(KERN_INFO "eLBC NAND device at 0x%zx, bank %d\n", | ||
| 1076 | res.start, priv->bank); | ||
| 1077 | return 0; | ||
| 1078 | |||
| 1079 | err: | ||
| 1080 | fsl_elbc_chip_remove(priv); | ||
| 1081 | return ret; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | static int __devinit fsl_elbc_ctrl_init(struct fsl_elbc_ctrl *ctrl) | ||
| 1085 | { | ||
| 1086 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 1087 | |||
| 1088 | /* clear event registers */ | ||
| 1089 | setbits32(&lbc->ltesr, LTESR_NAND_MASK); | ||
| 1090 | out_be32(&lbc->lteatr, 0); | ||
| 1091 | |||
| 1092 | /* Enable interrupts for any detected events */ | ||
| 1093 | out_be32(&lbc->lteir, LTESR_NAND_MASK); | ||
| 1094 | |||
| 1095 | ctrl->read_bytes = 0; | ||
| 1096 | ctrl->index = 0; | ||
| 1097 | ctrl->addr = NULL; | ||
| 1098 | |||
| 1099 | return 0; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | static int __devexit fsl_elbc_ctrl_remove(struct of_device *ofdev) | ||
| 1103 | { | ||
| 1104 | struct fsl_elbc_ctrl *ctrl = dev_get_drvdata(&ofdev->dev); | ||
| 1105 | int i; | ||
| 1106 | |||
| 1107 | for (i = 0; i < MAX_BANKS; i++) | ||
| 1108 | if (ctrl->chips[i]) | ||
| 1109 | fsl_elbc_chip_remove(ctrl->chips[i]); | ||
| 1110 | |||
| 1111 | if (ctrl->irq) | ||
| 1112 | free_irq(ctrl->irq, ctrl); | ||
| 1113 | |||
| 1114 | if (ctrl->regs) | ||
| 1115 | iounmap(ctrl->regs); | ||
| 1116 | |||
| 1117 | dev_set_drvdata(&ofdev->dev, NULL); | ||
| 1118 | kfree(ctrl); | ||
| 1119 | return 0; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | /* NOTE: This interrupt is also used to report other localbus events, | ||
| 1123 | * such as transaction errors on other chipselects. If we want to | ||
| 1124 | * capture those, we'll need to move the IRQ code into a shared | ||
| 1125 | * LBC driver. | ||
| 1126 | */ | ||
| 1127 | |||
| 1128 | static irqreturn_t fsl_elbc_ctrl_irq(int irqno, void *data) | ||
| 1129 | { | ||
| 1130 | struct fsl_elbc_ctrl *ctrl = data; | ||
| 1131 | struct elbc_regs __iomem *lbc = ctrl->regs; | ||
| 1132 | __be32 status = in_be32(&lbc->ltesr) & LTESR_NAND_MASK; | ||
| 1133 | |||
| 1134 | if (status) { | ||
| 1135 | out_be32(&lbc->ltesr, status); | ||
| 1136 | out_be32(&lbc->lteatr, 0); | ||
| 1137 | |||
| 1138 | ctrl->irq_status = status; | ||
| 1139 | smp_wmb(); | ||
| 1140 | wake_up(&ctrl->irq_wait); | ||
| 1141 | |||
| 1142 | return IRQ_HANDLED; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | return IRQ_NONE; | ||
| 1146 | } | ||
| 1147 | |||
| 1148 | /* fsl_elbc_ctrl_probe | ||
| 1149 | * | ||
| 1150 | * called by device layer when it finds a device matching | ||
| 1151 | * one our driver can handled. This code allocates all of | ||
| 1152 | * the resources needed for the controller only. The | ||
| 1153 | * resources for the NAND banks themselves are allocated | ||
| 1154 | * in the chip probe function. | ||
| 1155 | */ | ||
| 1156 | |||
| 1157 | static int __devinit fsl_elbc_ctrl_probe(struct of_device *ofdev, | ||
| 1158 | const struct of_device_id *match) | ||
| 1159 | { | ||
| 1160 | struct device_node *child; | ||
| 1161 | struct fsl_elbc_ctrl *ctrl; | ||
| 1162 | int ret; | ||
| 1163 | |||
| 1164 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | ||
| 1165 | if (!ctrl) | ||
| 1166 | return -ENOMEM; | ||
| 1167 | |||
| 1168 | dev_set_drvdata(&ofdev->dev, ctrl); | ||
| 1169 | |||
| 1170 | spin_lock_init(&ctrl->controller.lock); | ||
| 1171 | init_waitqueue_head(&ctrl->controller.wq); | ||
| 1172 | init_waitqueue_head(&ctrl->irq_wait); | ||
| 1173 | |||
| 1174 | ctrl->regs = of_iomap(ofdev->node, 0); | ||
| 1175 | if (!ctrl->regs) { | ||
| 1176 | dev_err(&ofdev->dev, "failed to get memory region\n"); | ||
| 1177 | ret = -ENODEV; | ||
| 1178 | goto err; | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | ctrl->irq = of_irq_to_resource(ofdev->node, 0, NULL); | ||
| 1182 | if (ctrl->irq == NO_IRQ) { | ||
| 1183 | dev_err(&ofdev->dev, "failed to get irq resource\n"); | ||
| 1184 | ret = -ENODEV; | ||
| 1185 | goto err; | ||
| 1186 | } | ||
| 1187 | |||
| 1188 | ctrl->dev = &ofdev->dev; | ||
| 1189 | |||
| 1190 | ret = fsl_elbc_ctrl_init(ctrl); | ||
| 1191 | if (ret < 0) | ||
| 1192 | goto err; | ||
| 1193 | |||
| 1194 | ret = request_irq(ctrl->irq, fsl_elbc_ctrl_irq, 0, "fsl-elbc", ctrl); | ||
| 1195 | if (ret != 0) { | ||
| 1196 | dev_err(&ofdev->dev, "failed to install irq (%d)\n", | ||
| 1197 | ctrl->irq); | ||
| 1198 | ret = ctrl->irq; | ||
| 1199 | goto err; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | for_each_child_of_node(ofdev->node, child) | ||
| 1203 | if (of_device_is_compatible(child, "fsl,elbc-fcm-nand")) | ||
| 1204 | fsl_elbc_chip_probe(ctrl, child); | ||
| 1205 | |||
| 1206 | return 0; | ||
| 1207 | |||
| 1208 | err: | ||
| 1209 | fsl_elbc_ctrl_remove(ofdev); | ||
| 1210 | return ret; | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | static const struct of_device_id fsl_elbc_match[] = { | ||
| 1214 | { | ||
| 1215 | .compatible = "fsl,elbc", | ||
| 1216 | }, | ||
| 1217 | {} | ||
| 1218 | }; | ||
| 1219 | |||
| 1220 | static struct of_platform_driver fsl_elbc_ctrl_driver = { | ||
| 1221 | .driver = { | ||
| 1222 | .name = "fsl-elbc", | ||
| 1223 | }, | ||
| 1224 | .match_table = fsl_elbc_match, | ||
| 1225 | .probe = fsl_elbc_ctrl_probe, | ||
| 1226 | .remove = __devexit_p(fsl_elbc_ctrl_remove), | ||
| 1227 | }; | ||
| 1228 | |||
| 1229 | static int __init fsl_elbc_init(void) | ||
| 1230 | { | ||
| 1231 | return of_register_platform_driver(&fsl_elbc_ctrl_driver); | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | static void __exit fsl_elbc_exit(void) | ||
| 1235 | { | ||
| 1236 | of_unregister_platform_driver(&fsl_elbc_ctrl_driver); | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | module_init(fsl_elbc_init); | ||
| 1240 | module_exit(fsl_elbc_exit); | ||
| 1241 | |||
| 1242 | MODULE_LICENSE("GPL"); | ||
| 1243 | MODULE_AUTHOR("Freescale"); | ||
| 1244 | MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller MTD NAND driver"); | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ddd4fc019042..7acb1a0e7409 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
| @@ -2469,8 +2469,12 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
| 2469 | chip->ecc.write_oob = nand_write_oob_std; | 2469 | chip->ecc.write_oob = nand_write_oob_std; |
| 2470 | 2470 | ||
| 2471 | case NAND_ECC_HW_SYNDROME: | 2471 | case NAND_ECC_HW_SYNDROME: |
| 2472 | if (!chip->ecc.calculate || !chip->ecc.correct || | 2472 | if ((!chip->ecc.calculate || !chip->ecc.correct || |
| 2473 | !chip->ecc.hwctl) { | 2473 | !chip->ecc.hwctl) && |
| 2474 | (!chip->ecc.read_page || | ||
| 2475 | chip->ecc.read_page == nand_read_page_hwecc || | ||
| 2476 | !chip->ecc.write_page || | ||
| 2477 | chip->ecc.write_page == nand_write_page_hwecc)) { | ||
| 2474 | printk(KERN_WARNING "No ECC functions supplied, " | 2478 | printk(KERN_WARNING "No ECC functions supplied, " |
| 2475 | "Hardware ECC not possible\n"); | 2479 | "Hardware ECC not possible\n"); |
| 2476 | BUG(); | 2480 | BUG(); |
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c new file mode 100644 index 000000000000..9162cca0182b --- /dev/null +++ b/drivers/mtd/nand/orion_nand.c | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | /* | ||
| 2 | * drivers/mtd/nand/orion_nand.c | ||
| 3 | * | ||
| 4 | * NAND support for Marvell Orion SoC platforms | ||
| 5 | * | ||
| 6 | * Tzachi Perelstein <tzachi@marvell.com> | ||
| 7 | * | ||
| 8 | * This file is licensed under the terms of the GNU General Public | ||
| 9 | * License version 2. This program is licensed "as is" without any | ||
| 10 | * warranty of any kind, whether express or implied. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/mtd/mtd.h> | ||
| 17 | #include <linux/mtd/nand.h> | ||
| 18 | #include <linux/mtd/partitions.h> | ||
| 19 | #include <asm/io.h> | ||
| 20 | #include <asm/sizes.h> | ||
| 21 | #include <asm/arch/platform.h> | ||
| 22 | #include <asm/arch/hardware.h> | ||
| 23 | |||
| 24 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
| 25 | static const char *part_probes[] = { "cmdlinepart", NULL }; | ||
| 26 | #endif | ||
| 27 | |||
| 28 | static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | ||
| 29 | { | ||
| 30 | struct nand_chip *nc = mtd->priv; | ||
| 31 | struct orion_nand_data *board = nc->priv; | ||
| 32 | u32 offs; | ||
| 33 | |||
| 34 | if (cmd == NAND_CMD_NONE) | ||
| 35 | return; | ||
| 36 | |||
| 37 | if (ctrl & NAND_CLE) | ||
| 38 | offs = (1 << board->cle); | ||
| 39 | else if (ctrl & NAND_ALE) | ||
| 40 | offs = (1 << board->ale); | ||
| 41 | else | ||
| 42 | return; | ||
| 43 | |||
| 44 | if (nc->options & NAND_BUSWIDTH_16) | ||
| 45 | offs <<= 1; | ||
| 46 | |||
| 47 | writeb(cmd, nc->IO_ADDR_W + offs); | ||
| 48 | } | ||
| 49 | |||
| 50 | static int __init orion_nand_probe(struct platform_device *pdev) | ||
| 51 | { | ||
| 52 | struct mtd_info *mtd; | ||
| 53 | struct nand_chip *nc; | ||
| 54 | struct orion_nand_data *board; | ||
| 55 | void __iomem *io_base; | ||
| 56 | int ret = 0; | ||
| 57 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 58 | struct mtd_partition *partitions = NULL; | ||
| 59 | int num_part = 0; | ||
| 60 | #endif | ||
| 61 | |||
| 62 | nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL); | ||
| 63 | if (!nc) { | ||
| 64 | printk(KERN_ERR "orion_nand: failed to allocate device structure.\n"); | ||
| 65 | ret = -ENOMEM; | ||
| 66 | goto no_res; | ||
| 67 | } | ||
| 68 | mtd = (struct mtd_info *)(nc + 1); | ||
| 69 | |||
| 70 | io_base = ioremap(pdev->resource[0].start, | ||
| 71 | pdev->resource[0].end - pdev->resource[0].start + 1); | ||
| 72 | if (!io_base) { | ||
| 73 | printk(KERN_ERR "orion_nand: ioremap failed\n"); | ||
| 74 | ret = -EIO; | ||
| 75 | goto no_res; | ||
| 76 | } | ||
| 77 | |||
| 78 | board = pdev->dev.platform_data; | ||
| 79 | |||
| 80 | mtd->priv = nc; | ||
| 81 | mtd->owner = THIS_MODULE; | ||
| 82 | |||
| 83 | nc->priv = board; | ||
| 84 | nc->IO_ADDR_R = nc->IO_ADDR_W = io_base; | ||
| 85 | nc->cmd_ctrl = orion_nand_cmd_ctrl; | ||
| 86 | nc->ecc.mode = NAND_ECC_SOFT; | ||
| 87 | |||
| 88 | if (board->width == 16) | ||
| 89 | nc->options |= NAND_BUSWIDTH_16; | ||
| 90 | |||
| 91 | platform_set_drvdata(pdev, mtd); | ||
| 92 | |||
| 93 | if (nand_scan(mtd, 1)) { | ||
| 94 | ret = -ENXIO; | ||
| 95 | goto no_dev; | ||
| 96 | } | ||
| 97 | |||
| 98 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 99 | #ifdef CONFIG_MTD_CMDLINE_PARTS | ||
| 100 | mtd->name = "orion_nand"; | ||
| 101 | num_part = parse_mtd_partitions(mtd, part_probes, &partitions, 0); | ||
| 102 | #endif | ||
| 103 | /* If cmdline partitions have been passed, let them be used */ | ||
| 104 | if (num_part <= 0) { | ||
| 105 | num_part = board->nr_parts; | ||
| 106 | partitions = board->parts; | ||
| 107 | } | ||
| 108 | |||
| 109 | if (partitions && num_part > 0) | ||
| 110 | ret = add_mtd_partitions(mtd, partitions, num_part); | ||
| 111 | else | ||
| 112 | ret = add_mtd_device(mtd); | ||
| 113 | #else | ||
| 114 | ret = add_mtd_device(mtd); | ||
| 115 | #endif | ||
| 116 | |||
| 117 | if (ret) { | ||
| 118 | nand_release(mtd); | ||
| 119 | goto no_dev; | ||
| 120 | } | ||
| 121 | |||
| 122 | return 0; | ||
| 123 | |||
| 124 | no_dev: | ||
| 125 | platform_set_drvdata(pdev, NULL); | ||
| 126 | iounmap(io_base); | ||
| 127 | no_res: | ||
| 128 | kfree(nc); | ||
| 129 | |||
| 130 | return ret; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int __devexit orion_nand_remove(struct platform_device *pdev) | ||
| 134 | { | ||
| 135 | struct mtd_info *mtd = platform_get_drvdata(pdev); | ||
| 136 | struct nand_chip *nc = mtd->priv; | ||
| 137 | |||
| 138 | nand_release(mtd); | ||
| 139 | |||
| 140 | iounmap(nc->IO_ADDR_W); | ||
| 141 | |||
| 142 | kfree(nc); | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | static struct platform_driver orion_nand_driver = { | ||
| 148 | .probe = orion_nand_probe, | ||
| 149 | .remove = orion_nand_remove, | ||
| 150 | .driver = { | ||
| 151 | .name = "orion_nand", | ||
| 152 | .owner = THIS_MODULE, | ||
| 153 | }, | ||
| 154 | }; | ||
| 155 | |||
| 156 | static int __init orion_nand_init(void) | ||
| 157 | { | ||
| 158 | return platform_driver_register(&orion_nand_driver); | ||
| 159 | } | ||
| 160 | |||
| 161 | static void __exit orion_nand_exit(void) | ||
| 162 | { | ||
| 163 | platform_driver_unregister(&orion_nand_driver); | ||
| 164 | } | ||
| 165 | |||
| 166 | module_init(orion_nand_init); | ||
| 167 | module_exit(orion_nand_exit); | ||
| 168 | |||
| 169 | MODULE_LICENSE("GPL"); | ||
| 170 | MODULE_AUTHOR("Tzachi Perelstein"); | ||
| 171 | MODULE_DESCRIPTION("NAND glue for Orion platforms"); | ||
diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c new file mode 100644 index 000000000000..75c899039023 --- /dev/null +++ b/drivers/mtd/nand/pasemi_nand.c | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2006-2007 PA Semi, Inc | ||
| 3 | * | ||
| 4 | * Author: Egor Martovetsky <egor@pasemi.com> | ||
| 5 | * Maintained by: Olof Johansson <olof@lixom.net> | ||
| 6 | * | ||
| 7 | * Driver for the PWRficient onchip NAND flash interface | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | #undef DEBUG | ||
| 24 | |||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/init.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/mtd/mtd.h> | ||
| 29 | #include <linux/mtd/nand.h> | ||
| 30 | #include <linux/mtd/nand_ecc.h> | ||
| 31 | #include <linux/of_platform.h> | ||
| 32 | #include <linux/platform_device.h> | ||
| 33 | #include <linux/pci.h> | ||
| 34 | |||
| 35 | #include <asm/io.h> | ||
| 36 | |||
| 37 | #define LBICTRL_LPCCTL_NR 0x00004000 | ||
| 38 | #define CLE_PIN_CTL 15 | ||
| 39 | #define ALE_PIN_CTL 14 | ||
| 40 | |||
| 41 | static unsigned int lpcctl; | ||
| 42 | static struct mtd_info *pasemi_nand_mtd; | ||
| 43 | static const char driver_name[] = "pasemi-nand"; | ||
| 44 | |||
| 45 | static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len) | ||
| 46 | { | ||
| 47 | struct nand_chip *chip = mtd->priv; | ||
| 48 | |||
| 49 | while (len > 0x800) { | ||
| 50 | memcpy_fromio(buf, chip->IO_ADDR_R, 0x800); | ||
| 51 | buf += 0x800; | ||
| 52 | len -= 0x800; | ||
| 53 | } | ||
| 54 | memcpy_fromio(buf, chip->IO_ADDR_R, len); | ||
| 55 | } | ||
| 56 | |||
| 57 | static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | ||
| 58 | { | ||
| 59 | struct nand_chip *chip = mtd->priv; | ||
| 60 | |||
| 61 | while (len > 0x800) { | ||
| 62 | memcpy_toio(chip->IO_ADDR_R, buf, 0x800); | ||
| 63 | buf += 0x800; | ||
| 64 | len -= 0x800; | ||
| 65 | } | ||
| 66 | memcpy_toio(chip->IO_ADDR_R, buf, len); | ||
| 67 | } | ||
| 68 | |||
| 69 | static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd, | ||
| 70 | unsigned int ctrl) | ||
| 71 | { | ||
| 72 | struct nand_chip *chip = mtd->priv; | ||
| 73 | |||
| 74 | if (cmd == NAND_CMD_NONE) | ||
| 75 | return; | ||
| 76 | |||
| 77 | if (ctrl & NAND_CLE) | ||
| 78 | out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd); | ||
| 79 | else | ||
| 80 | out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd); | ||
| 81 | |||
| 82 | /* Push out posted writes */ | ||
| 83 | eieio(); | ||
| 84 | inl(lpcctl); | ||
| 85 | } | ||
| 86 | |||
| 87 | int pasemi_device_ready(struct mtd_info *mtd) | ||
| 88 | { | ||
| 89 | return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR); | ||
| 90 | } | ||
| 91 | |||
| 92 | static int __devinit pasemi_nand_probe(struct of_device *ofdev, | ||
| 93 | const struct of_device_id *match) | ||
| 94 | { | ||
| 95 | struct pci_dev *pdev; | ||
| 96 | struct device_node *np = ofdev->node; | ||
| 97 | struct resource res; | ||
| 98 | struct nand_chip *chip; | ||
| 99 | int err = 0; | ||
| 100 | |||
| 101 | err = of_address_to_resource(np, 0, &res); | ||
| 102 | |||
| 103 | if (err) | ||
| 104 | return -EINVAL; | ||
| 105 | |||
| 106 | /* We only support one device at the moment */ | ||
| 107 | if (pasemi_nand_mtd) | ||
| 108 | return -ENODEV; | ||
| 109 | |||
| 110 | pr_debug("pasemi_nand at %lx-%lx\n", res.start, res.end); | ||
| 111 | |||
| 112 | /* Allocate memory for MTD device structure and private data */ | ||
| 113 | pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) + | ||
| 114 | sizeof(struct nand_chip), GFP_KERNEL); | ||
| 115 | if (!pasemi_nand_mtd) { | ||
| 116 | printk(KERN_WARNING | ||
| 117 | "Unable to allocate PASEMI NAND MTD device structure\n"); | ||
| 118 | err = -ENOMEM; | ||
| 119 | goto out; | ||
| 120 | } | ||
| 121 | |||
| 122 | /* Get pointer to private data */ | ||
| 123 | chip = (struct nand_chip *)&pasemi_nand_mtd[1]; | ||
| 124 | |||
| 125 | /* Link the private data with the MTD structure */ | ||
| 126 | pasemi_nand_mtd->priv = chip; | ||
| 127 | pasemi_nand_mtd->owner = THIS_MODULE; | ||
| 128 | |||
| 129 | chip->IO_ADDR_R = of_iomap(np, 0); | ||
| 130 | chip->IO_ADDR_W = chip->IO_ADDR_R; | ||
| 131 | |||
| 132 | if (!chip->IO_ADDR_R) { | ||
| 133 | err = -EIO; | ||
| 134 | goto out_mtd; | ||
| 135 | } | ||
| 136 | |||
| 137 | pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa008, NULL); | ||
| 138 | if (!pdev) { | ||
| 139 | err = -ENODEV; | ||
| 140 | goto out_ior; | ||
| 141 | } | ||
| 142 | |||
| 143 | lpcctl = pci_resource_start(pdev, 0); | ||
| 144 | |||
| 145 | if (!request_region(lpcctl, 4, driver_name)) { | ||
| 146 | err = -EBUSY; | ||
| 147 | goto out_ior; | ||
| 148 | } | ||
| 149 | |||
| 150 | chip->cmd_ctrl = pasemi_hwcontrol; | ||
| 151 | chip->dev_ready = pasemi_device_ready; | ||
| 152 | chip->read_buf = pasemi_read_buf; | ||
| 153 | chip->write_buf = pasemi_write_buf; | ||
| 154 | chip->chip_delay = 0; | ||
| 155 | chip->ecc.mode = NAND_ECC_SOFT; | ||
| 156 | |||
| 157 | /* Enable the following for a flash based bad block table */ | ||
| 158 | chip->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; | ||
| 159 | |||
| 160 | /* Scan to find existance of the device */ | ||
| 161 | if (nand_scan(pasemi_nand_mtd, 1)) { | ||
| 162 | err = -ENXIO; | ||
| 163 | goto out_lpc; | ||
| 164 | } | ||
| 165 | |||
| 166 | if (add_mtd_device(pasemi_nand_mtd)) { | ||
| 167 | printk(KERN_ERR "pasemi_nand: Unable to register MTD device\n"); | ||
| 168 | err = -ENODEV; | ||
| 169 | goto out_lpc; | ||
| 170 | } | ||
| 171 | |||
| 172 | printk(KERN_INFO "PA Semi NAND flash at %08lx, control at I/O %x\n", | ||
| 173 | res.start, lpcctl); | ||
| 174 | |||
| 175 | return 0; | ||
| 176 | |||
| 177 | out_lpc: | ||
| 178 | release_region(lpcctl, 4); | ||
| 179 | out_ior: | ||
| 180 | iounmap(chip->IO_ADDR_R); | ||
| 181 | out_mtd: | ||
| 182 | kfree(pasemi_nand_mtd); | ||
| 183 | out: | ||
| 184 | return err; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int __devexit pasemi_nand_remove(struct of_device *ofdev) | ||
| 188 | { | ||
| 189 | struct nand_chip *chip; | ||
| 190 | |||
| 191 | if (!pasemi_nand_mtd) | ||
| 192 | return 0; | ||
| 193 | |||
| 194 | chip = pasemi_nand_mtd->priv; | ||
| 195 | |||
| 196 | /* Release resources, unregister device */ | ||
| 197 | nand_release(pasemi_nand_mtd); | ||
| 198 | |||
| 199 | release_region(lpcctl, 4); | ||
| 200 | |||
| 201 | iounmap(chip->IO_ADDR_R); | ||
| 202 | |||
| 203 | /* Free the MTD device structure */ | ||
| 204 | kfree(pasemi_nand_mtd); | ||
| 205 | |||
| 206 | pasemi_nand_mtd = NULL; | ||
| 207 | |||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | static struct of_device_id pasemi_nand_match[] = | ||
| 212 | { | ||
| 213 | { | ||
| 214 | .compatible = "pasemi,localbus-nand", | ||
| 215 | }, | ||
| 216 | {}, | ||
| 217 | }; | ||
| 218 | |||
| 219 | MODULE_DEVICE_TABLE(of, pasemi_nand_match); | ||
| 220 | |||
| 221 | static struct of_platform_driver pasemi_nand_driver = | ||
| 222 | { | ||
| 223 | .name = (char*)driver_name, | ||
| 224 | .match_table = pasemi_nand_match, | ||
| 225 | .probe = pasemi_nand_probe, | ||
| 226 | .remove = pasemi_nand_remove, | ||
| 227 | }; | ||
| 228 | |||
| 229 | static int __init pasemi_nand_init(void) | ||
| 230 | { | ||
| 231 | return of_register_platform_driver(&pasemi_nand_driver); | ||
| 232 | } | ||
| 233 | module_init(pasemi_nand_init); | ||
| 234 | |||
| 235 | static void __exit pasemi_nand_exit(void) | ||
| 236 | { | ||
| 237 | of_unregister_platform_driver(&pasemi_nand_driver); | ||
| 238 | } | ||
| 239 | module_exit(pasemi_nand_exit); | ||
| 240 | |||
| 241 | MODULE_LICENSE("GPL"); | ||
| 242 | MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>"); | ||
| 243 | MODULE_DESCRIPTION("NAND flash interface driver for PA Semi PWRficient"); | ||
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index cd725fc5e813..f6d5c2adc4fd 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c | |||
| @@ -110,7 +110,9 @@ out: | |||
| 110 | static int __devexit plat_nand_remove(struct platform_device *pdev) | 110 | static int __devexit plat_nand_remove(struct platform_device *pdev) |
| 111 | { | 111 | { |
| 112 | struct plat_nand_data *data = platform_get_drvdata(pdev); | 112 | struct plat_nand_data *data = platform_get_drvdata(pdev); |
| 113 | #ifdef CONFIG_MTD_PARTITIONS | ||
| 113 | struct platform_nand_data *pdata = pdev->dev.platform_data; | 114 | struct platform_nand_data *pdata = pdev->dev.platform_data; |
| 115 | #endif | ||
| 114 | 116 | ||
| 115 | nand_release(&data->mtd); | 117 | nand_release(&data->mtd); |
| 116 | #ifdef CONFIG_MTD_PARTITIONS | 118 | #ifdef CONFIG_MTD_PARTITIONS |
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 2bd0737572c6..9260ad947524 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
| @@ -120,6 +120,8 @@ struct s3c2410_nand_info { | |||
| 120 | int sel_bit; | 120 | int sel_bit; |
| 121 | int mtd_count; | 121 | int mtd_count; |
| 122 | 122 | ||
| 123 | unsigned long save_nfconf; | ||
| 124 | |||
| 123 | enum s3c_cpu_type cpu_type; | 125 | enum s3c_cpu_type cpu_type; |
| 124 | }; | 126 | }; |
| 125 | 127 | ||
| @@ -364,23 +366,21 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
| 364 | ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) { | 366 | ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) { |
| 365 | /* calculate the bit position of the error */ | 367 | /* calculate the bit position of the error */ |
| 366 | 368 | ||
| 367 | bit = (diff2 >> 2) & 1; | 369 | bit = ((diff2 >> 3) & 1) | |
| 368 | bit |= (diff2 >> 3) & 2; | 370 | ((diff2 >> 4) & 2) | |
| 369 | bit |= (diff2 >> 4) & 4; | 371 | ((diff2 >> 5) & 4); |
| 370 | 372 | ||
| 371 | /* calculate the byte position of the error */ | 373 | /* calculate the byte position of the error */ |
| 372 | 374 | ||
| 373 | byte = (diff1 << 1) & 0x80; | 375 | byte = ((diff2 << 7) & 0x100) | |
| 374 | byte |= (diff1 << 2) & 0x40; | 376 | ((diff1 << 0) & 0x80) | |
| 375 | byte |= (diff1 << 3) & 0x20; | 377 | ((diff1 << 1) & 0x40) | |
| 376 | byte |= (diff1 << 4) & 0x10; | 378 | ((diff1 << 2) & 0x20) | |
| 377 | 379 | ((diff1 << 3) & 0x10) | | |
| 378 | byte |= (diff0 >> 3) & 0x08; | 380 | ((diff0 >> 4) & 0x08) | |
| 379 | byte |= (diff0 >> 2) & 0x04; | 381 | ((diff0 >> 3) & 0x04) | |
| 380 | byte |= (diff0 >> 1) & 0x02; | 382 | ((diff0 >> 2) & 0x02) | |
| 381 | byte |= (diff0 >> 0) & 0x01; | 383 | ((diff0 >> 1) & 0x01); |
| 382 | |||
| 383 | byte |= (diff2 << 8) & 0x100; | ||
| 384 | 384 | ||
| 385 | dev_dbg(info->device, "correcting error bit %d, byte %d\n", | 385 | dev_dbg(info->device, "correcting error bit %d, byte %d\n", |
| 386 | bit, byte); | 386 | bit, byte); |
| @@ -399,7 +399,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, | |||
| 399 | if ((diff0 & ~(1<<fls(diff0))) == 0) | 399 | if ((diff0 & ~(1<<fls(diff0))) == 0) |
| 400 | return 1; | 400 | return 1; |
| 401 | 401 | ||
| 402 | return 0; | 402 | return -1; |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | /* ECC functions | 405 | /* ECC functions |
| @@ -810,6 +810,16 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) | |||
| 810 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); | 810 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); |
| 811 | 811 | ||
| 812 | if (info) { | 812 | if (info) { |
| 813 | info->save_nfconf = readl(info->regs + S3C2410_NFCONF); | ||
| 814 | |||
| 815 | /* For the moment, we must ensure nFCE is high during | ||
| 816 | * the time we are suspended. This really should be | ||
| 817 | * handled by suspending the MTDs we are using, but | ||
| 818 | * that is currently not the case. */ | ||
| 819 | |||
| 820 | writel(info->save_nfconf | info->sel_bit, | ||
| 821 | info->regs + S3C2410_NFCONF); | ||
| 822 | |||
| 813 | if (!allow_clk_stop(info)) | 823 | if (!allow_clk_stop(info)) |
| 814 | clk_disable(info->clk); | 824 | clk_disable(info->clk); |
| 815 | } | 825 | } |
| @@ -820,11 +830,19 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) | |||
| 820 | static int s3c24xx_nand_resume(struct platform_device *dev) | 830 | static int s3c24xx_nand_resume(struct platform_device *dev) |
| 821 | { | 831 | { |
| 822 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); | 832 | struct s3c2410_nand_info *info = platform_get_drvdata(dev); |
| 833 | unsigned long nfconf; | ||
| 823 | 834 | ||
| 824 | if (info) { | 835 | if (info) { |
| 825 | clk_enable(info->clk); | 836 | clk_enable(info->clk); |
| 826 | s3c2410_nand_inithw(info, dev); | 837 | s3c2410_nand_inithw(info, dev); |
| 827 | 838 | ||
| 839 | /* Restore the state of the nFCE line. */ | ||
| 840 | |||
| 841 | nfconf = readl(info->regs + S3C2410_NFCONF); | ||
| 842 | nfconf &= ~info->sel_bit; | ||
| 843 | nfconf |= info->save_nfconf & info->sel_bit; | ||
| 844 | writel(nfconf, info->regs + S3C2410_NFCONF); | ||
| 845 | |||
| 828 | if (allow_clk_stop(info)) | 846 | if (allow_clk_stop(info)) |
| 829 | clk_disable(info->clk); | 847 | clk_disable(info->clk); |
| 830 | } | 848 | } |
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c new file mode 100644 index 000000000000..f86e06934cd8 --- /dev/null +++ b/drivers/mtd/ofpart.c | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | /* | ||
| 2 | * Flash partitions described by the OF (or flattened) device tree | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 MontaVista Software Inc. | ||
| 5 | * Author: Vitaly Wool <vwool@ru.mvista.com> | ||
| 6 | * | ||
| 7 | * Revised to handle newer style flash binding by: | ||
| 8 | * Copyright (C) 2007 David Gibson, IBM Corporation. | ||
| 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 | |||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/mtd/mtd.h> | ||
| 20 | #include <linux/mtd/partitions.h> | ||
| 21 | |||
| 22 | int __devinit of_mtd_parse_partitions(struct device *dev, | ||
| 23 | struct mtd_info *mtd, | ||
| 24 | struct device_node *node, | ||
| 25 | struct mtd_partition **pparts) | ||
| 26 | { | ||
| 27 | const char *partname; | ||
| 28 | struct device_node *pp; | ||
| 29 | int nr_parts, i; | ||
| 30 | |||
| 31 | /* First count the subnodes */ | ||
| 32 | pp = NULL; | ||
| 33 | nr_parts = 0; | ||
| 34 | while ((pp = of_get_next_child(node, pp))) | ||
| 35 | nr_parts++; | ||
| 36 | |||
| 37 | if (nr_parts == 0) | ||
| 38 | return 0; | ||
| 39 | |||
| 40 | *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL); | ||
| 41 | if (!*pparts) | ||
| 42 | return -ENOMEM; | ||
| 43 | |||
| 44 | pp = NULL; | ||
| 45 | i = 0; | ||
| 46 | while ((pp = of_get_next_child(node, pp))) { | ||
| 47 | const u32 *reg; | ||
| 48 | int len; | ||
| 49 | |||
| 50 | reg = of_get_property(pp, "reg", &len); | ||
| 51 | if (!reg || (len != 2 * sizeof(u32))) { | ||
| 52 | of_node_put(pp); | ||
| 53 | dev_err(dev, "Invalid 'reg' on %s\n", node->full_name); | ||
| 54 | kfree(*pparts); | ||
| 55 | *pparts = NULL; | ||
| 56 | return -EINVAL; | ||
| 57 | } | ||
| 58 | (*pparts)[i].offset = reg[0]; | ||
| 59 | (*pparts)[i].size = reg[1]; | ||
| 60 | |||
| 61 | partname = of_get_property(pp, "label", &len); | ||
| 62 | if (!partname) | ||
| 63 | partname = of_get_property(pp, "name", &len); | ||
| 64 | (*pparts)[i].name = (char *)partname; | ||
| 65 | |||
| 66 | if (of_get_property(pp, "read-only", &len)) | ||
| 67 | (*pparts)[i].mask_flags = MTD_WRITEABLE; | ||
| 68 | |||
| 69 | i++; | ||
| 70 | } | ||
| 71 | |||
| 72 | return nr_parts; | ||
| 73 | } | ||
| 74 | EXPORT_SYMBOL(of_mtd_parse_partitions); | ||
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 1b0b32011415..8d7d21be1541 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
| 21 | #include <linux/delay.h> | ||
| 21 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
| 22 | #include <linux/jiffies.h> | 23 | #include <linux/jiffies.h> |
| 23 | #include <linux/mtd/mtd.h> | 24 | #include <linux/mtd/mtd.h> |
| @@ -170,6 +171,18 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) | |||
| 170 | } | 171 | } |
| 171 | 172 | ||
| 172 | /** | 173 | /** |
| 174 | * onenand_get_density - [DEFAULT] Get OneNAND density | ||
| 175 | * @param dev_id OneNAND device ID | ||
| 176 | * | ||
| 177 | * Get OneNAND density from device ID | ||
| 178 | */ | ||
| 179 | static inline int onenand_get_density(int dev_id) | ||
| 180 | { | ||
| 181 | int density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | ||
| 182 | return (density & ONENAND_DEVICE_DENSITY_MASK); | ||
| 183 | } | ||
| 184 | |||
| 185 | /** | ||
| 173 | * onenand_command - [DEFAULT] Send command to OneNAND device | 186 | * onenand_command - [DEFAULT] Send command to OneNAND device |
| 174 | * @param mtd MTD device structure | 187 | * @param mtd MTD device structure |
| 175 | * @param cmd the command to be sent | 188 | * @param cmd the command to be sent |
| @@ -182,8 +195,7 @@ static int onenand_buffer_address(int dataram1, int sectors, int count) | |||
| 182 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) | 195 | static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len) |
| 183 | { | 196 | { |
| 184 | struct onenand_chip *this = mtd->priv; | 197 | struct onenand_chip *this = mtd->priv; |
| 185 | int value, readcmd = 0, block_cmd = 0; | 198 | int value, block, page; |
| 186 | int block, page; | ||
| 187 | 199 | ||
| 188 | /* Address translation */ | 200 | /* Address translation */ |
| 189 | switch (cmd) { | 201 | switch (cmd) { |
| @@ -198,7 +210,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
| 198 | case ONENAND_CMD_ERASE: | 210 | case ONENAND_CMD_ERASE: |
| 199 | case ONENAND_CMD_BUFFERRAM: | 211 | case ONENAND_CMD_BUFFERRAM: |
| 200 | case ONENAND_CMD_OTP_ACCESS: | 212 | case ONENAND_CMD_OTP_ACCESS: |
| 201 | block_cmd = 1; | ||
| 202 | block = (int) (addr >> this->erase_shift); | 213 | block = (int) (addr >> this->erase_shift); |
| 203 | page = -1; | 214 | page = -1; |
| 204 | break; | 215 | break; |
| @@ -240,11 +251,9 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
| 240 | value = onenand_block_address(this, block); | 251 | value = onenand_block_address(this, block); |
| 241 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); | 252 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1); |
| 242 | 253 | ||
| 243 | if (block_cmd) { | 254 | /* Select DataRAM for DDP */ |
| 244 | /* Select DataRAM for DDP */ | 255 | value = onenand_bufferram_address(this, block); |
| 245 | value = onenand_bufferram_address(this, block); | 256 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); |
| 246 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
| 247 | } | ||
| 248 | } | 257 | } |
| 249 | 258 | ||
| 250 | if (page != -1) { | 259 | if (page != -1) { |
| @@ -256,7 +265,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
| 256 | case ONENAND_CMD_READ: | 265 | case ONENAND_CMD_READ: |
| 257 | case ONENAND_CMD_READOOB: | 266 | case ONENAND_CMD_READOOB: |
| 258 | dataram = ONENAND_SET_NEXT_BUFFERRAM(this); | 267 | dataram = ONENAND_SET_NEXT_BUFFERRAM(this); |
| 259 | readcmd = 1; | ||
| 260 | break; | 268 | break; |
| 261 | 269 | ||
| 262 | default: | 270 | default: |
| @@ -273,12 +281,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le | |||
| 273 | /* Write 'BSA, BSC' of DataRAM */ | 281 | /* Write 'BSA, BSC' of DataRAM */ |
| 274 | value = onenand_buffer_address(dataram, sectors, count); | 282 | value = onenand_buffer_address(dataram, sectors, count); |
| 275 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); | 283 | this->write_word(value, this->base + ONENAND_REG_START_BUFFER); |
| 276 | |||
| 277 | if (readcmd) { | ||
| 278 | /* Select DataRAM for DDP */ | ||
| 279 | value = onenand_bufferram_address(this, block); | ||
| 280 | this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2); | ||
| 281 | } | ||
| 282 | } | 284 | } |
| 283 | 285 | ||
| 284 | /* Interrupt clear */ | 286 | /* Interrupt clear */ |
| @@ -855,6 +857,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
| 855 | this->command(mtd, ONENAND_CMD_READ, from, writesize); | 857 | this->command(mtd, ONENAND_CMD_READ, from, writesize); |
| 856 | ret = this->wait(mtd, FL_READING); | 858 | ret = this->wait(mtd, FL_READING); |
| 857 | onenand_update_bufferram(mtd, from, !ret); | 859 | onenand_update_bufferram(mtd, from, !ret); |
| 860 | if (ret == -EBADMSG) | ||
| 861 | ret = 0; | ||
| 858 | } | 862 | } |
| 859 | } | 863 | } |
| 860 | 864 | ||
| @@ -913,6 +917,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
| 913 | /* Now wait for load */ | 917 | /* Now wait for load */ |
| 914 | ret = this->wait(mtd, FL_READING); | 918 | ret = this->wait(mtd, FL_READING); |
| 915 | onenand_update_bufferram(mtd, from, !ret); | 919 | onenand_update_bufferram(mtd, from, !ret); |
| 920 | if (ret == -EBADMSG) | ||
| 921 | ret = 0; | ||
| 916 | } | 922 | } |
| 917 | 923 | ||
| 918 | /* | 924 | /* |
| @@ -923,12 +929,12 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, | |||
| 923 | ops->retlen = read; | 929 | ops->retlen = read; |
| 924 | ops->oobretlen = oobread; | 930 | ops->oobretlen = oobread; |
| 925 | 931 | ||
| 926 | if (mtd->ecc_stats.failed - stats.failed) | ||
| 927 | return -EBADMSG; | ||
| 928 | |||
| 929 | if (ret) | 932 | if (ret) |
| 930 | return ret; | 933 | return ret; |
| 931 | 934 | ||
| 935 | if (mtd->ecc_stats.failed - stats.failed) | ||
| 936 | return -EBADMSG; | ||
| 937 | |||
| 932 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; | 938 | return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; |
| 933 | } | 939 | } |
| 934 | 940 | ||
| @@ -944,6 +950,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
| 944 | struct mtd_oob_ops *ops) | 950 | struct mtd_oob_ops *ops) |
| 945 | { | 951 | { |
| 946 | struct onenand_chip *this = mtd->priv; | 952 | struct onenand_chip *this = mtd->priv; |
| 953 | struct mtd_ecc_stats stats; | ||
| 947 | int read = 0, thislen, column, oobsize; | 954 | int read = 0, thislen, column, oobsize; |
| 948 | size_t len = ops->ooblen; | 955 | size_t len = ops->ooblen; |
| 949 | mtd_oob_mode_t mode = ops->mode; | 956 | mtd_oob_mode_t mode = ops->mode; |
| @@ -977,6 +984,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
| 977 | return -EINVAL; | 984 | return -EINVAL; |
| 978 | } | 985 | } |
| 979 | 986 | ||
| 987 | stats = mtd->ecc_stats; | ||
| 988 | |||
| 980 | while (read < len) { | 989 | while (read < len) { |
| 981 | cond_resched(); | 990 | cond_resched(); |
| 982 | 991 | ||
| @@ -988,18 +997,16 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
| 988 | onenand_update_bufferram(mtd, from, 0); | 997 | onenand_update_bufferram(mtd, from, 0); |
| 989 | 998 | ||
| 990 | ret = this->wait(mtd, FL_READING); | 999 | ret = this->wait(mtd, FL_READING); |
| 991 | /* First copy data and check return value for ECC handling */ | 1000 | if (ret && ret != -EBADMSG) { |
| 1001 | printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret); | ||
| 1002 | break; | ||
| 1003 | } | ||
| 992 | 1004 | ||
| 993 | if (mode == MTD_OOB_AUTO) | 1005 | if (mode == MTD_OOB_AUTO) |
| 994 | onenand_transfer_auto_oob(mtd, buf, column, thislen); | 1006 | onenand_transfer_auto_oob(mtd, buf, column, thislen); |
| 995 | else | 1007 | else |
| 996 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); | 1008 | this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); |
| 997 | 1009 | ||
| 998 | if (ret) { | ||
| 999 | printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret); | ||
| 1000 | break; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | read += thislen; | 1010 | read += thislen; |
| 1004 | 1011 | ||
| 1005 | if (read == len) | 1012 | if (read == len) |
| @@ -1016,7 +1023,14 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, | |||
| 1016 | } | 1023 | } |
| 1017 | 1024 | ||
| 1018 | ops->oobretlen = read; | 1025 | ops->oobretlen = read; |
| 1019 | return ret; | 1026 | |
| 1027 | if (ret) | ||
| 1028 | return ret; | ||
| 1029 | |||
| 1030 | if (mtd->ecc_stats.failed - stats.failed) | ||
| 1031 | return -EBADMSG; | ||
| 1032 | |||
| 1033 | return 0; | ||
| 1020 | } | 1034 | } |
| 1021 | 1035 | ||
| 1022 | /** | 1036 | /** |
| @@ -1106,12 +1120,10 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) | |||
| 1106 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | 1120 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); |
| 1107 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); | 1121 | ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS); |
| 1108 | 1122 | ||
| 1123 | /* Initial bad block case: 0x2400 or 0x0400 */ | ||
| 1109 | if (ctrl & ONENAND_CTRL_ERROR) { | 1124 | if (ctrl & ONENAND_CTRL_ERROR) { |
| 1110 | printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); | 1125 | printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl); |
| 1111 | /* Initial bad block case */ | 1126 | return ONENAND_BBT_READ_ERROR; |
| 1112 | if (ctrl & ONENAND_CTRL_LOAD) | ||
| 1113 | return ONENAND_BBT_READ_ERROR; | ||
| 1114 | return ONENAND_BBT_READ_FATAL_ERROR; | ||
| 1115 | } | 1127 | } |
| 1116 | 1128 | ||
| 1117 | if (interrupt & ONENAND_INT_READ) { | 1129 | if (interrupt & ONENAND_INT_READ) { |
| @@ -1206,7 +1218,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, | |||
| 1206 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) | 1218 | static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) |
| 1207 | { | 1219 | { |
| 1208 | struct onenand_chip *this = mtd->priv; | 1220 | struct onenand_chip *this = mtd->priv; |
| 1209 | char oobbuf[64]; | 1221 | u_char *oob_buf = this->oob_buf; |
| 1210 | int status, i; | 1222 | int status, i; |
| 1211 | 1223 | ||
| 1212 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); | 1224 | this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); |
| @@ -1215,9 +1227,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to | |||
| 1215 | if (status) | 1227 | if (status) |
| 1216 | return status; | 1228 | return status; |
| 1217 | 1229 | ||
| 1218 | this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); | 1230 | this->read_bufferram(mtd, ONENAND_SPARERAM, oob_buf, 0, mtd->oobsize); |
| 1219 | for (i = 0; i < mtd->oobsize; i++) | 1231 | for (i = 0; i < mtd->oobsize; i++) |
| 1220 | if (buf[i] != 0xFF && buf[i] != oobbuf[i]) | 1232 | if (buf[i] != 0xFF && buf[i] != oob_buf[i]) |
| 1221 | return -EBADMSG; | 1233 | return -EBADMSG; |
| 1222 | 1234 | ||
| 1223 | return 0; | 1235 | return 0; |
| @@ -1273,6 +1285,112 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, | |||
| 1273 | 1285 | ||
| 1274 | #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) | 1286 | #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) |
| 1275 | 1287 | ||
| 1288 | static void onenand_panic_wait(struct mtd_info *mtd) | ||
| 1289 | { | ||
| 1290 | struct onenand_chip *this = mtd->priv; | ||
| 1291 | unsigned int interrupt; | ||
| 1292 | int i; | ||
| 1293 | |||
| 1294 | for (i = 0; i < 2000; i++) { | ||
| 1295 | interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT); | ||
| 1296 | if (interrupt & ONENAND_INT_MASTER) | ||
| 1297 | break; | ||
| 1298 | udelay(10); | ||
| 1299 | } | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | /** | ||
| 1303 | * onenand_panic_write - [MTD Interface] write buffer to FLASH in a panic context | ||
| 1304 | * @param mtd MTD device structure | ||
| 1305 | * @param to offset to write to | ||
| 1306 | * @param len number of bytes to write | ||
| 1307 | * @param retlen pointer to variable to store the number of written bytes | ||
| 1308 | * @param buf the data to write | ||
| 1309 | * | ||
| 1310 | * Write with ECC | ||
| 1311 | */ | ||
| 1312 | static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
| 1313 | size_t *retlen, const u_char *buf) | ||
| 1314 | { | ||
| 1315 | struct onenand_chip *this = mtd->priv; | ||
| 1316 | int column, subpage; | ||
| 1317 | int written = 0; | ||
| 1318 | int ret = 0; | ||
| 1319 | |||
| 1320 | if (this->state == FL_PM_SUSPENDED) | ||
| 1321 | return -EBUSY; | ||
| 1322 | |||
| 1323 | /* Wait for any existing operation to clear */ | ||
| 1324 | onenand_panic_wait(mtd); | ||
| 1325 | |||
| 1326 | DEBUG(MTD_DEBUG_LEVEL3, "onenand_panic_write: to = 0x%08x, len = %i\n", | ||
| 1327 | (unsigned int) to, (int) len); | ||
| 1328 | |||
| 1329 | /* Initialize retlen, in case of early exit */ | ||
| 1330 | *retlen = 0; | ||
| 1331 | |||
| 1332 | /* Do not allow writes past end of device */ | ||
| 1333 | if (unlikely((to + len) > mtd->size)) { | ||
| 1334 | printk(KERN_ERR "onenand_panic_write: Attempt write to past end of device\n"); | ||
| 1335 | return -EINVAL; | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | /* Reject writes, which are not page aligned */ | ||
| 1339 | if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) { | ||
| 1340 | printk(KERN_ERR "onenand_panic_write: Attempt to write not page aligned data\n"); | ||
| 1341 | return -EINVAL; | ||
| 1342 | } | ||
| 1343 | |||
| 1344 | column = to & (mtd->writesize - 1); | ||
| 1345 | |||
| 1346 | /* Loop until all data write */ | ||
| 1347 | while (written < len) { | ||
| 1348 | int thislen = min_t(int, mtd->writesize - column, len - written); | ||
| 1349 | u_char *wbuf = (u_char *) buf; | ||
| 1350 | |||
| 1351 | this->command(mtd, ONENAND_CMD_BUFFERRAM, to, thislen); | ||
| 1352 | |||
| 1353 | /* Partial page write */ | ||
| 1354 | subpage = thislen < mtd->writesize; | ||
| 1355 | if (subpage) { | ||
| 1356 | memset(this->page_buf, 0xff, mtd->writesize); | ||
| 1357 | memcpy(this->page_buf + column, buf, thislen); | ||
| 1358 | wbuf = this->page_buf; | ||
| 1359 | } | ||
| 1360 | |||
| 1361 | this->write_bufferram(mtd, ONENAND_DATARAM, wbuf, 0, mtd->writesize); | ||
| 1362 | this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize); | ||
| 1363 | |||
| 1364 | this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize); | ||
| 1365 | |||
| 1366 | onenand_panic_wait(mtd); | ||
| 1367 | |||
| 1368 | /* In partial page write we don't update bufferram */ | ||
| 1369 | onenand_update_bufferram(mtd, to, !ret && !subpage); | ||
| 1370 | if (ONENAND_IS_2PLANE(this)) { | ||
| 1371 | ONENAND_SET_BUFFERRAM1(this); | ||
| 1372 | onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); | ||
| 1373 | } | ||
| 1374 | |||
| 1375 | if (ret) { | ||
| 1376 | printk(KERN_ERR "onenand_panic_write: write failed %d\n", ret); | ||
| 1377 | break; | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | written += thislen; | ||
| 1381 | |||
| 1382 | if (written == len) | ||
| 1383 | break; | ||
| 1384 | |||
| 1385 | column = 0; | ||
| 1386 | to += thislen; | ||
| 1387 | buf += thislen; | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | *retlen = written; | ||
| 1391 | return ret; | ||
| 1392 | } | ||
| 1393 | |||
| 1276 | /** | 1394 | /** |
| 1277 | * onenand_fill_auto_oob - [Internal] oob auto-placement transfer | 1395 | * onenand_fill_auto_oob - [Internal] oob auto-placement transfer |
| 1278 | * @param mtd MTD device structure | 1396 | * @param mtd MTD device structure |
| @@ -1419,7 +1537,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
| 1419 | } | 1537 | } |
| 1420 | 1538 | ||
| 1421 | /* Only check verify write turn on */ | 1539 | /* Only check verify write turn on */ |
| 1422 | ret = onenand_verify(mtd, (u_char *) wbuf, to, thislen); | 1540 | ret = onenand_verify(mtd, buf, to, thislen); |
| 1423 | if (ret) { | 1541 | if (ret) { |
| 1424 | printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); | 1542 | printk(KERN_ERR "onenand_write_ops_nolock: verify failed %d\n", ret); |
| 1425 | break; | 1543 | break; |
| @@ -1435,9 +1553,6 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, | |||
| 1435 | buf += thislen; | 1553 | buf += thislen; |
| 1436 | } | 1554 | } |
| 1437 | 1555 | ||
| 1438 | /* Deselect and wake up anyone waiting on the device */ | ||
| 1439 | onenand_release_device(mtd); | ||
| 1440 | |||
| 1441 | ops->retlen = written; | 1556 | ops->retlen = written; |
| 1442 | 1557 | ||
| 1443 | return ret; | 1558 | return ret; |
| @@ -2148,7 +2263,7 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 2148 | 2263 | ||
| 2149 | *retlen = 0; | 2264 | *retlen = 0; |
| 2150 | 2265 | ||
| 2151 | density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2266 | density = onenand_get_density(this->device_id); |
| 2152 | if (density < ONENAND_DEVICE_DENSITY_512Mb) | 2267 | if (density < ONENAND_DEVICE_DENSITY_512Mb) |
| 2153 | otp_pages = 20; | 2268 | otp_pages = 20; |
| 2154 | else | 2269 | else |
| @@ -2299,7 +2414,8 @@ static int onenand_write_user_prot_reg(struct mtd_info *mtd, loff_t from, | |||
| 2299 | static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, | 2414 | static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, |
| 2300 | size_t len) | 2415 | size_t len) |
| 2301 | { | 2416 | { |
| 2302 | unsigned char oob_buf[64]; | 2417 | struct onenand_chip *this = mtd->priv; |
| 2418 | u_char *oob_buf = this->oob_buf; | ||
| 2303 | size_t retlen; | 2419 | size_t retlen; |
| 2304 | int ret; | 2420 | int ret; |
| 2305 | 2421 | ||
| @@ -2339,7 +2455,7 @@ static void onenand_check_features(struct mtd_info *mtd) | |||
| 2339 | unsigned int density, process; | 2455 | unsigned int density, process; |
| 2340 | 2456 | ||
| 2341 | /* Lock scheme depends on density and process */ | 2457 | /* Lock scheme depends on density and process */ |
| 2342 | density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2458 | density = onenand_get_density(this->device_id); |
| 2343 | process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; | 2459 | process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT; |
| 2344 | 2460 | ||
| 2345 | /* Lock scheme */ | 2461 | /* Lock scheme */ |
| @@ -2388,7 +2504,7 @@ static void onenand_print_device_info(int device, int version) | |||
| 2388 | vcc = device & ONENAND_DEVICE_VCC_MASK; | 2504 | vcc = device & ONENAND_DEVICE_VCC_MASK; |
| 2389 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; | 2505 | demuxed = device & ONENAND_DEVICE_IS_DEMUX; |
| 2390 | ddp = device & ONENAND_DEVICE_IS_DDP; | 2506 | ddp = device & ONENAND_DEVICE_IS_DDP; |
| 2391 | density = device >> ONENAND_DEVICE_DENSITY_SHIFT; | 2507 | density = onenand_get_density(device); |
| 2392 | printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", | 2508 | printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n", |
| 2393 | demuxed ? "" : "Muxed ", | 2509 | demuxed ? "" : "Muxed ", |
| 2394 | ddp ? "(DDP)" : "", | 2510 | ddp ? "(DDP)" : "", |
| @@ -2480,7 +2596,7 @@ static int onenand_probe(struct mtd_info *mtd) | |||
| 2480 | this->device_id = dev_id; | 2596 | this->device_id = dev_id; |
| 2481 | this->version_id = ver_id; | 2597 | this->version_id = ver_id; |
| 2482 | 2598 | ||
| 2483 | density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT; | 2599 | density = onenand_get_density(dev_id); |
| 2484 | this->chipsize = (16 << density) << 20; | 2600 | this->chipsize = (16 << density) << 20; |
| 2485 | /* Set density mask. it is used for DDP */ | 2601 | /* Set density mask. it is used for DDP */ |
| 2486 | if (ONENAND_IS_DDP(this)) | 2602 | if (ONENAND_IS_DDP(this)) |
| @@ -2664,6 +2780,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) | |||
| 2664 | mtd->write = onenand_write; | 2780 | mtd->write = onenand_write; |
| 2665 | mtd->read_oob = onenand_read_oob; | 2781 | mtd->read_oob = onenand_read_oob; |
| 2666 | mtd->write_oob = onenand_write_oob; | 2782 | mtd->write_oob = onenand_write_oob; |
| 2783 | mtd->panic_write = onenand_panic_write; | ||
| 2667 | #ifdef CONFIG_MTD_ONENAND_OTP | 2784 | #ifdef CONFIG_MTD_ONENAND_OTP |
| 2668 | mtd->get_fact_prot_info = onenand_get_fact_prot_info; | 2785 | mtd->get_fact_prot_info = onenand_get_fact_prot_info; |
| 2669 | mtd->read_fact_prot_reg = onenand_read_fact_prot_reg; | 2786 | mtd->read_fact_prot_reg = onenand_read_fact_prot_reg; |
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index a61351f88ec0..47474903263c 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c | |||
| @@ -59,16 +59,31 @@ static int parse_redboot_partitions(struct mtd_info *master, | |||
| 59 | static char nullstring[] = "unallocated"; | 59 | static char nullstring[] = "unallocated"; |
| 60 | #endif | 60 | #endif |
| 61 | 61 | ||
| 62 | if ( directory < 0 ) { | ||
| 63 | offset = master->size + directory * master->erasesize; | ||
| 64 | while (master->block_isbad && | ||
| 65 | master->block_isbad(master, offset)) { | ||
| 66 | if (!offset) { | ||
| 67 | nogood: | ||
| 68 | printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n"); | ||
| 69 | return -EIO; | ||
| 70 | } | ||
| 71 | offset -= master->erasesize; | ||
| 72 | } | ||
| 73 | } else { | ||
| 74 | offset = directory * master->erasesize; | ||
| 75 | while (master->block_isbad && | ||
| 76 | master->block_isbad(master, offset)) { | ||
| 77 | offset += master->erasesize; | ||
| 78 | if (offset == master->size) | ||
| 79 | goto nogood; | ||
| 80 | } | ||
| 81 | } | ||
| 62 | buf = vmalloc(master->erasesize); | 82 | buf = vmalloc(master->erasesize); |
| 63 | 83 | ||
| 64 | if (!buf) | 84 | if (!buf) |
| 65 | return -ENOMEM; | 85 | return -ENOMEM; |
| 66 | 86 | ||
| 67 | if ( directory < 0 ) | ||
| 68 | offset = master->size + directory*master->erasesize; | ||
| 69 | else | ||
| 70 | offset = directory*master->erasesize; | ||
| 71 | |||
| 72 | printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n", | 87 | printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n", |
| 73 | master->name, offset); | 88 | master->name, offset); |
| 74 | 89 | ||
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 023653977a1a..6ac81e35355c 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
| @@ -21,11 +21,16 @@ | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | /* | 23 | /* |
| 24 | * This file includes UBI initialization and building of UBI devices. At the | 24 | * This file includes UBI initialization and building of UBI devices. |
| 25 | * moment UBI devices may only be added while UBI is initialized, but dynamic | 25 | * |
| 26 | * device add/remove functionality is planned. Also, at the moment we only | 26 | * When UBI is initialized, it attaches all the MTD devices specified as the |
| 27 | * attach UBI devices by scanning, which will become a bottleneck when flashes | 27 | * module load parameters or the kernel boot parameters. If MTD devices were |
| 28 | * reach certain large size. Then one may improve UBI and add other methods. | 28 | * specified, UBI does not attach any MTD device, but it is possible to do |
| 29 | * later using the "UBI control device". | ||
| 30 | * | ||
| 31 | * At the moment we only attach UBI devices by scanning, which will become a | ||
| 32 | * bottleneck when flashes reach certain large size. Then one may improve UBI | ||
| 33 | * and add other methods, although it does not seem to be easy to do. | ||
| 29 | */ | 34 | */ |
| 30 | 35 | ||
| 31 | #include <linux/err.h> | 36 | #include <linux/err.h> |
| @@ -33,7 +38,9 @@ | |||
| 33 | #include <linux/moduleparam.h> | 38 | #include <linux/moduleparam.h> |
| 34 | #include <linux/stringify.h> | 39 | #include <linux/stringify.h> |
| 35 | #include <linux/stat.h> | 40 | #include <linux/stat.h> |
| 41 | #include <linux/miscdevice.h> | ||
| 36 | #include <linux/log2.h> | 42 | #include <linux/log2.h> |
| 43 | #include <linux/kthread.h> | ||
| 37 | #include "ubi.h" | 44 | #include "ubi.h" |
| 38 | 45 | ||
| 39 | /* Maximum length of the 'mtd=' parameter */ | 46 | /* Maximum length of the 'mtd=' parameter */ |
| @@ -43,13 +50,11 @@ | |||
| 43 | * struct mtd_dev_param - MTD device parameter description data structure. | 50 | * struct mtd_dev_param - MTD device parameter description data structure. |
| 44 | * @name: MTD device name or number string | 51 | * @name: MTD device name or number string |
| 45 | * @vid_hdr_offs: VID header offset | 52 | * @vid_hdr_offs: VID header offset |
| 46 | * @data_offs: data offset | ||
| 47 | */ | 53 | */ |
| 48 | struct mtd_dev_param | 54 | struct mtd_dev_param |
| 49 | { | 55 | { |
| 50 | char name[MTD_PARAM_LEN_MAX]; | 56 | char name[MTD_PARAM_LEN_MAX]; |
| 51 | int vid_hdr_offs; | 57 | int vid_hdr_offs; |
| 52 | int data_offs; | ||
| 53 | }; | 58 | }; |
| 54 | 59 | ||
| 55 | /* Numbers of elements set in the @mtd_dev_param array */ | 60 | /* Numbers of elements set in the @mtd_dev_param array */ |
| @@ -58,14 +63,27 @@ static int mtd_devs = 0; | |||
| 58 | /* MTD devices specification parameters */ | 63 | /* MTD devices specification parameters */ |
| 59 | static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; | 64 | static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; |
| 60 | 65 | ||
| 61 | /* Number of UBI devices in system */ | 66 | /* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */ |
| 62 | int ubi_devices_cnt; | 67 | struct class *ubi_class; |
| 68 | |||
| 69 | /* Slab cache for wear-leveling entries */ | ||
| 70 | struct kmem_cache *ubi_wl_entry_slab; | ||
| 71 | |||
| 72 | /* UBI control character device */ | ||
| 73 | static struct miscdevice ubi_ctrl_cdev = { | ||
| 74 | .minor = MISC_DYNAMIC_MINOR, | ||
| 75 | .name = "ubi_ctrl", | ||
| 76 | .fops = &ubi_ctrl_cdev_operations, | ||
| 77 | }; | ||
| 63 | 78 | ||
| 64 | /* All UBI devices in system */ | 79 | /* All UBI devices in system */ |
| 65 | struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; | 80 | static struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; |
| 66 | 81 | ||
| 67 | /* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */ | 82 | /* Serializes UBI devices creations and removals */ |
| 68 | struct class *ubi_class; | 83 | DEFINE_MUTEX(ubi_devices_mutex); |
| 84 | |||
| 85 | /* Protects @ubi_devices and @ubi->ref_count */ | ||
| 86 | static DEFINE_SPINLOCK(ubi_devices_lock); | ||
| 69 | 87 | ||
| 70 | /* "Show" method for files in '/<sysfs>/class/ubi/' */ | 88 | /* "Show" method for files in '/<sysfs>/class/ubi/' */ |
| 71 | static ssize_t ubi_version_show(struct class *class, char *buf) | 89 | static ssize_t ubi_version_show(struct class *class, char *buf) |
| @@ -101,38 +119,150 @@ static struct device_attribute dev_min_io_size = | |||
| 101 | __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL); | 119 | __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL); |
| 102 | static struct device_attribute dev_bgt_enabled = | 120 | static struct device_attribute dev_bgt_enabled = |
| 103 | __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); | 121 | __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); |
| 122 | static struct device_attribute dev_mtd_num = | ||
| 123 | __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); | ||
| 124 | |||
| 125 | /** | ||
| 126 | * ubi_get_device - get UBI device. | ||
| 127 | * @ubi_num: UBI device number | ||
| 128 | * | ||
| 129 | * This function returns UBI device description object for UBI device number | ||
| 130 | * @ubi_num, or %NULL if the device does not exist. This function increases the | ||
| 131 | * device reference count to prevent removal of the device. In other words, the | ||
| 132 | * device cannot be removed if its reference count is not zero. | ||
| 133 | */ | ||
| 134 | struct ubi_device *ubi_get_device(int ubi_num) | ||
| 135 | { | ||
| 136 | struct ubi_device *ubi; | ||
| 137 | |||
| 138 | spin_lock(&ubi_devices_lock); | ||
| 139 | ubi = ubi_devices[ubi_num]; | ||
| 140 | if (ubi) { | ||
| 141 | ubi_assert(ubi->ref_count >= 0); | ||
| 142 | ubi->ref_count += 1; | ||
| 143 | get_device(&ubi->dev); | ||
| 144 | } | ||
| 145 | spin_unlock(&ubi_devices_lock); | ||
| 146 | |||
| 147 | return ubi; | ||
| 148 | } | ||
| 149 | |||
| 150 | /** | ||
| 151 | * ubi_put_device - drop an UBI device reference. | ||
| 152 | * @ubi: UBI device description object | ||
| 153 | */ | ||
| 154 | void ubi_put_device(struct ubi_device *ubi) | ||
| 155 | { | ||
| 156 | spin_lock(&ubi_devices_lock); | ||
| 157 | ubi->ref_count -= 1; | ||
| 158 | put_device(&ubi->dev); | ||
| 159 | spin_unlock(&ubi_devices_lock); | ||
| 160 | } | ||
| 161 | |||
| 162 | /** | ||
| 163 | * ubi_get_by_major - get UBI device description object by character device | ||
| 164 | * major number. | ||
| 165 | * @major: major number | ||
| 166 | * | ||
| 167 | * This function is similar to 'ubi_get_device()', but it searches the device | ||
| 168 | * by its major number. | ||
| 169 | */ | ||
| 170 | struct ubi_device *ubi_get_by_major(int major) | ||
| 171 | { | ||
| 172 | int i; | ||
| 173 | struct ubi_device *ubi; | ||
| 174 | |||
| 175 | spin_lock(&ubi_devices_lock); | ||
| 176 | for (i = 0; i < UBI_MAX_DEVICES; i++) { | ||
| 177 | ubi = ubi_devices[i]; | ||
| 178 | if (ubi && MAJOR(ubi->cdev.dev) == major) { | ||
| 179 | ubi_assert(ubi->ref_count >= 0); | ||
| 180 | ubi->ref_count += 1; | ||
| 181 | get_device(&ubi->dev); | ||
| 182 | spin_unlock(&ubi_devices_lock); | ||
| 183 | return ubi; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | spin_unlock(&ubi_devices_lock); | ||
| 187 | |||
| 188 | return NULL; | ||
| 189 | } | ||
| 190 | |||
| 191 | /** | ||
| 192 | * ubi_major2num - get UBI device number by character device major number. | ||
| 193 | * @major: major number | ||
| 194 | * | ||
| 195 | * This function searches UBI device number object by its major number. If UBI | ||
| 196 | * device was not found, this function returns -ENODEV, otherwise the UBI device | ||
| 197 | * number is returned. | ||
| 198 | */ | ||
| 199 | int ubi_major2num(int major) | ||
| 200 | { | ||
| 201 | int i, ubi_num = -ENODEV; | ||
| 202 | |||
| 203 | spin_lock(&ubi_devices_lock); | ||
| 204 | for (i = 0; i < UBI_MAX_DEVICES; i++) { | ||
| 205 | struct ubi_device *ubi = ubi_devices[i]; | ||
| 206 | |||
| 207 | if (ubi && MAJOR(ubi->cdev.dev) == major) { | ||
| 208 | ubi_num = ubi->ubi_num; | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | spin_unlock(&ubi_devices_lock); | ||
| 213 | |||
| 214 | return ubi_num; | ||
| 215 | } | ||
| 104 | 216 | ||
| 105 | /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */ | 217 | /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */ |
| 106 | static ssize_t dev_attribute_show(struct device *dev, | 218 | static ssize_t dev_attribute_show(struct device *dev, |
| 107 | struct device_attribute *attr, char *buf) | 219 | struct device_attribute *attr, char *buf) |
| 108 | { | 220 | { |
| 109 | const struct ubi_device *ubi; | 221 | ssize_t ret; |
| 222 | struct ubi_device *ubi; | ||
| 110 | 223 | ||
| 224 | /* | ||
| 225 | * The below code looks weird, but it actually makes sense. We get the | ||
| 226 | * UBI device reference from the contained 'struct ubi_device'. But it | ||
| 227 | * is unclear if the device was removed or not yet. Indeed, if the | ||
| 228 | * device was removed before we increased its reference count, | ||
| 229 | * 'ubi_get_device()' will return -ENODEV and we fail. | ||
| 230 | * | ||
| 231 | * Remember, 'struct ubi_device' is freed in the release function, so | ||
| 232 | * we still can use 'ubi->ubi_num'. | ||
| 233 | */ | ||
| 111 | ubi = container_of(dev, struct ubi_device, dev); | 234 | ubi = container_of(dev, struct ubi_device, dev); |
| 235 | ubi = ubi_get_device(ubi->ubi_num); | ||
| 236 | if (!ubi) | ||
| 237 | return -ENODEV; | ||
| 238 | |||
| 112 | if (attr == &dev_eraseblock_size) | 239 | if (attr == &dev_eraseblock_size) |
| 113 | return sprintf(buf, "%d\n", ubi->leb_size); | 240 | ret = sprintf(buf, "%d\n", ubi->leb_size); |
| 114 | else if (attr == &dev_avail_eraseblocks) | 241 | else if (attr == &dev_avail_eraseblocks) |
| 115 | return sprintf(buf, "%d\n", ubi->avail_pebs); | 242 | ret = sprintf(buf, "%d\n", ubi->avail_pebs); |
| 116 | else if (attr == &dev_total_eraseblocks) | 243 | else if (attr == &dev_total_eraseblocks) |
| 117 | return sprintf(buf, "%d\n", ubi->good_peb_count); | 244 | ret = sprintf(buf, "%d\n", ubi->good_peb_count); |
| 118 | else if (attr == &dev_volumes_count) | 245 | else if (attr == &dev_volumes_count) |
| 119 | return sprintf(buf, "%d\n", ubi->vol_count); | 246 | ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); |
| 120 | else if (attr == &dev_max_ec) | 247 | else if (attr == &dev_max_ec) |
| 121 | return sprintf(buf, "%d\n", ubi->max_ec); | 248 | ret = sprintf(buf, "%d\n", ubi->max_ec); |
| 122 | else if (attr == &dev_reserved_for_bad) | 249 | else if (attr == &dev_reserved_for_bad) |
| 123 | return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); | 250 | ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); |
| 124 | else if (attr == &dev_bad_peb_count) | 251 | else if (attr == &dev_bad_peb_count) |
| 125 | return sprintf(buf, "%d\n", ubi->bad_peb_count); | 252 | ret = sprintf(buf, "%d\n", ubi->bad_peb_count); |
| 126 | else if (attr == &dev_max_vol_count) | 253 | else if (attr == &dev_max_vol_count) |
| 127 | return sprintf(buf, "%d\n", ubi->vtbl_slots); | 254 | ret = sprintf(buf, "%d\n", ubi->vtbl_slots); |
| 128 | else if (attr == &dev_min_io_size) | 255 | else if (attr == &dev_min_io_size) |
| 129 | return sprintf(buf, "%d\n", ubi->min_io_size); | 256 | ret = sprintf(buf, "%d\n", ubi->min_io_size); |
| 130 | else if (attr == &dev_bgt_enabled) | 257 | else if (attr == &dev_bgt_enabled) |
| 131 | return sprintf(buf, "%d\n", ubi->thread_enabled); | 258 | ret = sprintf(buf, "%d\n", ubi->thread_enabled); |
| 259 | else if (attr == &dev_mtd_num) | ||
| 260 | ret = sprintf(buf, "%d\n", ubi->mtd->index); | ||
| 132 | else | 261 | else |
| 133 | BUG(); | 262 | ret = -EINVAL; |
| 134 | 263 | ||
| 135 | return 0; | 264 | ubi_put_device(ubi); |
| 265 | return ret; | ||
| 136 | } | 266 | } |
| 137 | 267 | ||
| 138 | /* Fake "release" method for UBI devices */ | 268 | /* Fake "release" method for UBI devices */ |
| @@ -150,68 +280,44 @@ static int ubi_sysfs_init(struct ubi_device *ubi) | |||
| 150 | int err; | 280 | int err; |
| 151 | 281 | ||
| 152 | ubi->dev.release = dev_release; | 282 | ubi->dev.release = dev_release; |
| 153 | ubi->dev.devt = MKDEV(ubi->major, 0); | 283 | ubi->dev.devt = ubi->cdev.dev; |
| 154 | ubi->dev.class = ubi_class; | 284 | ubi->dev.class = ubi_class; |
| 155 | sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); | 285 | sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); |
| 156 | err = device_register(&ubi->dev); | 286 | err = device_register(&ubi->dev); |
| 157 | if (err) | 287 | if (err) |
| 158 | goto out; | 288 | return err; |
| 159 | 289 | ||
| 160 | err = device_create_file(&ubi->dev, &dev_eraseblock_size); | 290 | err = device_create_file(&ubi->dev, &dev_eraseblock_size); |
| 161 | if (err) | 291 | if (err) |
| 162 | goto out_unregister; | 292 | return err; |
| 163 | err = device_create_file(&ubi->dev, &dev_avail_eraseblocks); | 293 | err = device_create_file(&ubi->dev, &dev_avail_eraseblocks); |
| 164 | if (err) | 294 | if (err) |
| 165 | goto out_eraseblock_size; | 295 | return err; |
| 166 | err = device_create_file(&ubi->dev, &dev_total_eraseblocks); | 296 | err = device_create_file(&ubi->dev, &dev_total_eraseblocks); |
| 167 | if (err) | 297 | if (err) |
| 168 | goto out_avail_eraseblocks; | 298 | return err; |
| 169 | err = device_create_file(&ubi->dev, &dev_volumes_count); | 299 | err = device_create_file(&ubi->dev, &dev_volumes_count); |
| 170 | if (err) | 300 | if (err) |
| 171 | goto out_total_eraseblocks; | 301 | return err; |
| 172 | err = device_create_file(&ubi->dev, &dev_max_ec); | 302 | err = device_create_file(&ubi->dev, &dev_max_ec); |
| 173 | if (err) | 303 | if (err) |
| 174 | goto out_volumes_count; | 304 | return err; |
| 175 | err = device_create_file(&ubi->dev, &dev_reserved_for_bad); | 305 | err = device_create_file(&ubi->dev, &dev_reserved_for_bad); |
| 176 | if (err) | 306 | if (err) |
| 177 | goto out_volumes_max_ec; | 307 | return err; |
| 178 | err = device_create_file(&ubi->dev, &dev_bad_peb_count); | 308 | err = device_create_file(&ubi->dev, &dev_bad_peb_count); |
| 179 | if (err) | 309 | if (err) |
| 180 | goto out_reserved_for_bad; | 310 | return err; |
| 181 | err = device_create_file(&ubi->dev, &dev_max_vol_count); | 311 | err = device_create_file(&ubi->dev, &dev_max_vol_count); |
| 182 | if (err) | 312 | if (err) |
| 183 | goto out_bad_peb_count; | 313 | return err; |
| 184 | err = device_create_file(&ubi->dev, &dev_min_io_size); | 314 | err = device_create_file(&ubi->dev, &dev_min_io_size); |
| 185 | if (err) | 315 | if (err) |
| 186 | goto out_max_vol_count; | 316 | return err; |
| 187 | err = device_create_file(&ubi->dev, &dev_bgt_enabled); | 317 | err = device_create_file(&ubi->dev, &dev_bgt_enabled); |
| 188 | if (err) | 318 | if (err) |
| 189 | goto out_min_io_size; | 319 | return err; |
| 190 | 320 | err = device_create_file(&ubi->dev, &dev_mtd_num); | |
| 191 | return 0; | ||
| 192 | |||
| 193 | out_min_io_size: | ||
| 194 | device_remove_file(&ubi->dev, &dev_min_io_size); | ||
| 195 | out_max_vol_count: | ||
| 196 | device_remove_file(&ubi->dev, &dev_max_vol_count); | ||
| 197 | out_bad_peb_count: | ||
| 198 | device_remove_file(&ubi->dev, &dev_bad_peb_count); | ||
| 199 | out_reserved_for_bad: | ||
| 200 | device_remove_file(&ubi->dev, &dev_reserved_for_bad); | ||
| 201 | out_volumes_max_ec: | ||
| 202 | device_remove_file(&ubi->dev, &dev_max_ec); | ||
| 203 | out_volumes_count: | ||
| 204 | device_remove_file(&ubi->dev, &dev_volumes_count); | ||
| 205 | out_total_eraseblocks: | ||
| 206 | device_remove_file(&ubi->dev, &dev_total_eraseblocks); | ||
| 207 | out_avail_eraseblocks: | ||
| 208 | device_remove_file(&ubi->dev, &dev_avail_eraseblocks); | ||
| 209 | out_eraseblock_size: | ||
| 210 | device_remove_file(&ubi->dev, &dev_eraseblock_size); | ||
| 211 | out_unregister: | ||
| 212 | device_unregister(&ubi->dev); | ||
| 213 | out: | ||
| 214 | ubi_err("failed to initialize sysfs for %s", ubi->ubi_name); | ||
| 215 | return err; | 321 | return err; |
| 216 | } | 322 | } |
| 217 | 323 | ||
| @@ -221,6 +327,7 @@ out: | |||
| 221 | */ | 327 | */ |
| 222 | static void ubi_sysfs_close(struct ubi_device *ubi) | 328 | static void ubi_sysfs_close(struct ubi_device *ubi) |
| 223 | { | 329 | { |
| 330 | device_remove_file(&ubi->dev, &dev_mtd_num); | ||
| 224 | device_remove_file(&ubi->dev, &dev_bgt_enabled); | 331 | device_remove_file(&ubi->dev, &dev_bgt_enabled); |
| 225 | device_remove_file(&ubi->dev, &dev_min_io_size); | 332 | device_remove_file(&ubi->dev, &dev_min_io_size); |
| 226 | device_remove_file(&ubi->dev, &dev_max_vol_count); | 333 | device_remove_file(&ubi->dev, &dev_max_vol_count); |
| @@ -244,7 +351,7 @@ static void kill_volumes(struct ubi_device *ubi) | |||
| 244 | 351 | ||
| 245 | for (i = 0; i < ubi->vtbl_slots; i++) | 352 | for (i = 0; i < ubi->vtbl_slots; i++) |
| 246 | if (ubi->volumes[i]) | 353 | if (ubi->volumes[i]) |
| 247 | ubi_free_volume(ubi, i); | 354 | ubi_free_volume(ubi, ubi->volumes[i]); |
| 248 | } | 355 | } |
| 249 | 356 | ||
| 250 | /** | 357 | /** |
| @@ -259,9 +366,6 @@ static int uif_init(struct ubi_device *ubi) | |||
| 259 | int i, err; | 366 | int i, err; |
| 260 | dev_t dev; | 367 | dev_t dev; |
| 261 | 368 | ||
| 262 | mutex_init(&ubi->vtbl_mutex); | ||
| 263 | spin_lock_init(&ubi->volumes_lock); | ||
| 264 | |||
| 265 | sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); | 369 | sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); |
| 266 | 370 | ||
| 267 | /* | 371 | /* |
| @@ -278,39 +382,40 @@ static int uif_init(struct ubi_device *ubi) | |||
| 278 | return err; | 382 | return err; |
| 279 | } | 383 | } |
| 280 | 384 | ||
| 385 | ubi_assert(MINOR(dev) == 0); | ||
| 281 | cdev_init(&ubi->cdev, &ubi_cdev_operations); | 386 | cdev_init(&ubi->cdev, &ubi_cdev_operations); |
| 282 | ubi->major = MAJOR(dev); | 387 | dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev)); |
| 283 | dbg_msg("%s major is %u", ubi->ubi_name, ubi->major); | ||
| 284 | ubi->cdev.owner = THIS_MODULE; | 388 | ubi->cdev.owner = THIS_MODULE; |
| 285 | 389 | ||
| 286 | dev = MKDEV(ubi->major, 0); | ||
| 287 | err = cdev_add(&ubi->cdev, dev, 1); | 390 | err = cdev_add(&ubi->cdev, dev, 1); |
| 288 | if (err) { | 391 | if (err) { |
| 289 | ubi_err("cannot add character device %s", ubi->ubi_name); | 392 | ubi_err("cannot add character device"); |
| 290 | goto out_unreg; | 393 | goto out_unreg; |
| 291 | } | 394 | } |
| 292 | 395 | ||
| 293 | err = ubi_sysfs_init(ubi); | 396 | err = ubi_sysfs_init(ubi); |
| 294 | if (err) | 397 | if (err) |
| 295 | goto out_cdev; | 398 | goto out_sysfs; |
| 296 | 399 | ||
| 297 | for (i = 0; i < ubi->vtbl_slots; i++) | 400 | for (i = 0; i < ubi->vtbl_slots; i++) |
| 298 | if (ubi->volumes[i]) { | 401 | if (ubi->volumes[i]) { |
| 299 | err = ubi_add_volume(ubi, i); | 402 | err = ubi_add_volume(ubi, ubi->volumes[i]); |
| 300 | if (err) | 403 | if (err) { |
| 404 | ubi_err("cannot add volume %d", i); | ||
| 301 | goto out_volumes; | 405 | goto out_volumes; |
| 406 | } | ||
| 302 | } | 407 | } |
| 303 | 408 | ||
| 304 | return 0; | 409 | return 0; |
| 305 | 410 | ||
| 306 | out_volumes: | 411 | out_volumes: |
| 307 | kill_volumes(ubi); | 412 | kill_volumes(ubi); |
| 413 | out_sysfs: | ||
| 308 | ubi_sysfs_close(ubi); | 414 | ubi_sysfs_close(ubi); |
| 309 | out_cdev: | ||
| 310 | cdev_del(&ubi->cdev); | 415 | cdev_del(&ubi->cdev); |
| 311 | out_unreg: | 416 | out_unreg: |
| 312 | unregister_chrdev_region(MKDEV(ubi->major, 0), | 417 | unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); |
| 313 | ubi->vtbl_slots + 1); | 418 | ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); |
| 314 | return err; | 419 | return err; |
| 315 | } | 420 | } |
| 316 | 421 | ||
| @@ -323,7 +428,7 @@ static void uif_close(struct ubi_device *ubi) | |||
| 323 | kill_volumes(ubi); | 428 | kill_volumes(ubi); |
| 324 | ubi_sysfs_close(ubi); | 429 | ubi_sysfs_close(ubi); |
| 325 | cdev_del(&ubi->cdev); | 430 | cdev_del(&ubi->cdev); |
| 326 | unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1); | 431 | unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); |
| 327 | } | 432 | } |
| 328 | 433 | ||
| 329 | /** | 434 | /** |
| @@ -384,9 +489,9 @@ out_si: | |||
| 384 | * assumed: | 489 | * assumed: |
| 385 | * o EC header is always at offset zero - this cannot be changed; | 490 | * o EC header is always at offset zero - this cannot be changed; |
| 386 | * o VID header starts just after the EC header at the closest address | 491 | * o VID header starts just after the EC header at the closest address |
| 387 | * aligned to @io->@hdrs_min_io_size; | 492 | * aligned to @io->hdrs_min_io_size; |
| 388 | * o data starts just after the VID header at the closest address aligned to | 493 | * o data starts just after the VID header at the closest address aligned to |
| 389 | * @io->@min_io_size | 494 | * @io->min_io_size |
| 390 | * | 495 | * |
| 391 | * This function returns zero in case of success and a negative error code in | 496 | * This function returns zero in case of success and a negative error code in |
| 392 | * case of failure. | 497 | * case of failure. |
| @@ -407,6 +512,9 @@ static int io_init(struct ubi_device *ubi) | |||
| 407 | return -EINVAL; | 512 | return -EINVAL; |
| 408 | } | 513 | } |
| 409 | 514 | ||
| 515 | if (ubi->vid_hdr_offset < 0) | ||
| 516 | return -EINVAL; | ||
| 517 | |||
| 410 | /* | 518 | /* |
| 411 | * Note, in this implementation we support MTD devices with 0x7FFFFFFF | 519 | * Note, in this implementation we support MTD devices with 0x7FFFFFFF |
| 412 | * physical eraseblocks maximum. | 520 | * physical eraseblocks maximum. |
| @@ -424,7 +532,8 @@ static int io_init(struct ubi_device *ubi) | |||
| 424 | 532 | ||
| 425 | /* Make sure minimal I/O unit is power of 2 */ | 533 | /* Make sure minimal I/O unit is power of 2 */ |
| 426 | if (!is_power_of_2(ubi->min_io_size)) { | 534 | if (!is_power_of_2(ubi->min_io_size)) { |
| 427 | ubi_err("bad min. I/O unit"); | 535 | ubi_err("min. I/O unit (%d) is not power of 2", |
| 536 | ubi->min_io_size); | ||
| 428 | return -EINVAL; | 537 | return -EINVAL; |
| 429 | } | 538 | } |
| 430 | 539 | ||
| @@ -453,10 +562,8 @@ static int io_init(struct ubi_device *ubi) | |||
| 453 | } | 562 | } |
| 454 | 563 | ||
| 455 | /* Similar for the data offset */ | 564 | /* Similar for the data offset */ |
| 456 | if (ubi->leb_start == 0) { | 565 | ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE; |
| 457 | ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize; | 566 | ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); |
| 458 | ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); | ||
| 459 | } | ||
| 460 | 567 | ||
| 461 | dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); | 568 | dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); |
| 462 | dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset); | 569 | dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset); |
| @@ -514,76 +621,147 @@ static int io_init(struct ubi_device *ubi) | |||
| 514 | } | 621 | } |
| 515 | 622 | ||
| 516 | /** | 623 | /** |
| 517 | * attach_mtd_dev - attach an MTD device. | 624 | * autoresize - re-size the volume which has the "auto-resize" flag set. |
| 518 | * @mtd_dev: MTD device name or number string | 625 | * @ubi: UBI device description object |
| 519 | * @vid_hdr_offset: VID header offset | 626 | * @vol_id: ID of the volume to re-size |
| 520 | * @data_offset: data offset | ||
| 521 | * | 627 | * |
| 522 | * This function attaches an MTD device to UBI. It first treats @mtd_dev as the | 628 | * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in |
| 523 | * MTD device name, and tries to open it by this name. If it is unable to open, | 629 | * the volume table to the largest possible size. See comments in ubi-header.h |
| 524 | * it tries to convert @mtd_dev to an integer and open the MTD device by its | 630 | * for more description of the flag. Returns zero in case of success and a |
| 525 | * number. Returns zero in case of success and a negative error code in case of | 631 | * negative error code in case of failure. |
| 526 | * failure. | ||
| 527 | */ | 632 | */ |
| 528 | static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, | 633 | static int autoresize(struct ubi_device *ubi, int vol_id) |
| 529 | int data_offset) | ||
| 530 | { | 634 | { |
| 531 | struct ubi_device *ubi; | 635 | struct ubi_volume_desc desc; |
| 532 | struct mtd_info *mtd; | 636 | struct ubi_volume *vol = ubi->volumes[vol_id]; |
| 533 | int i, err; | 637 | int err, old_reserved_pebs = vol->reserved_pebs; |
| 534 | 638 | ||
| 535 | mtd = get_mtd_device_nm(mtd_dev); | 639 | /* |
| 536 | if (IS_ERR(mtd)) { | 640 | * Clear the auto-resize flag in the volume in-memory copy of the |
| 537 | int mtd_num; | 641 | * volume table, and 'ubi_resize_volume()' will propogate this change |
| 538 | char *endp; | 642 | * to the flash. |
| 643 | */ | ||
| 644 | ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; | ||
| 539 | 645 | ||
| 540 | if (PTR_ERR(mtd) != -ENODEV) | 646 | if (ubi->avail_pebs == 0) { |
| 541 | return PTR_ERR(mtd); | 647 | struct ubi_vtbl_record vtbl_rec; |
| 542 | 648 | ||
| 543 | /* | 649 | /* |
| 544 | * Probably this is not MTD device name but MTD device number - | 650 | * No avalilable PEBs to re-size the volume, clear the flag on |
| 545 | * check this out. | 651 | * flash and exit. |
| 546 | */ | 652 | */ |
| 547 | mtd_num = simple_strtoul(mtd_dev, &endp, 0); | 653 | memcpy(&vtbl_rec, &ubi->vtbl[vol_id], |
| 548 | if (*endp != '\0' || mtd_dev == endp) { | 654 | sizeof(struct ubi_vtbl_record)); |
| 549 | ubi_err("incorrect MTD device: \"%s\"", mtd_dev); | 655 | err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); |
| 550 | return -ENODEV; | 656 | if (err) |
| 551 | } | 657 | ubi_err("cannot clean auto-resize flag for volume %d", |
| 552 | 658 | vol_id); | |
| 553 | mtd = get_mtd_device(NULL, mtd_num); | 659 | } else { |
| 554 | if (IS_ERR(mtd)) | 660 | desc.vol = vol; |
| 555 | return PTR_ERR(mtd); | 661 | err = ubi_resize_volume(&desc, |
| 662 | old_reserved_pebs + ubi->avail_pebs); | ||
| 663 | if (err) | ||
| 664 | ubi_err("cannot auto-resize volume %d", vol_id); | ||
| 556 | } | 665 | } |
| 557 | 666 | ||
| 558 | /* Check if we already have the same MTD device attached */ | 667 | if (err) |
| 559 | for (i = 0; i < ubi_devices_cnt; i++) | 668 | return err; |
| 560 | if (ubi_devices[i]->mtd->index == mtd->index) { | 669 | |
| 561 | ubi_err("mtd%d is already attached to ubi%d", | 670 | ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, |
| 671 | vol->name, old_reserved_pebs, vol->reserved_pebs); | ||
| 672 | return 0; | ||
| 673 | } | ||
| 674 | |||
| 675 | /** | ||
| 676 | * ubi_attach_mtd_dev - attach an MTD device. | ||
| 677 | * @mtd_dev: MTD device description object | ||
| 678 | * @ubi_num: number to assign to the new UBI device | ||
| 679 | * @vid_hdr_offset: VID header offset | ||
| 680 | * | ||
| 681 | * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number | ||
| 682 | * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in | ||
| 683 | * which case this function finds a vacant device nubert and assings it | ||
| 684 | * automatically. Returns the new UBI device number in case of success and a | ||
| 685 | * negative error code in case of failure. | ||
| 686 | * | ||
| 687 | * Note, the invocations of this function has to be serialized by the | ||
| 688 | * @ubi_devices_mutex. | ||
| 689 | */ | ||
| 690 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | ||
| 691 | { | ||
| 692 | struct ubi_device *ubi; | ||
| 693 | int i, err; | ||
| 694 | |||
| 695 | /* | ||
| 696 | * Check if we already have the same MTD device attached. | ||
| 697 | * | ||
| 698 | * Note, this function assumes that UBI devices creations and deletions | ||
| 699 | * are serialized, so it does not take the &ubi_devices_lock. | ||
| 700 | */ | ||
| 701 | for (i = 0; i < UBI_MAX_DEVICES; i++) { | ||
| 702 | ubi = ubi_devices[i]; | ||
| 703 | if (ubi && mtd->index == ubi->mtd->index) { | ||
| 704 | dbg_err("mtd%d is already attached to ubi%d", | ||
| 562 | mtd->index, i); | 705 | mtd->index, i); |
| 563 | err = -EINVAL; | 706 | return -EEXIST; |
| 564 | goto out_mtd; | ||
| 565 | } | 707 | } |
| 708 | } | ||
| 566 | 709 | ||
| 567 | ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device), | 710 | /* |
| 568 | GFP_KERNEL); | 711 | * Make sure this MTD device is not emulated on top of an UBI volume |
| 569 | if (!ubi) { | 712 | * already. Well, generally this recursion works fine, but there are |
| 570 | err = -ENOMEM; | 713 | * different problems like the UBI module takes a reference to itself |
| 571 | goto out_mtd; | 714 | * by attaching (and thus, opening) the emulated MTD device. This |
| 715 | * results in inability to unload the module. And in general it makes | ||
| 716 | * no sense to attach emulated MTD devices, so we prohibit this. | ||
| 717 | */ | ||
| 718 | if (mtd->type == MTD_UBIVOLUME) { | ||
| 719 | ubi_err("refuse attaching mtd%d - it is already emulated on " | ||
| 720 | "top of UBI", mtd->index); | ||
| 721 | return -EINVAL; | ||
| 572 | } | 722 | } |
| 573 | 723 | ||
| 574 | ubi->ubi_num = ubi_devices_cnt; | 724 | if (ubi_num == UBI_DEV_NUM_AUTO) { |
| 575 | ubi->mtd = mtd; | 725 | /* Search for an empty slot in the @ubi_devices array */ |
| 726 | for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) | ||
| 727 | if (!ubi_devices[ubi_num]) | ||
| 728 | break; | ||
| 729 | if (ubi_num == UBI_MAX_DEVICES) { | ||
| 730 | dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES); | ||
| 731 | return -ENFILE; | ||
| 732 | } | ||
| 733 | } else { | ||
| 734 | if (ubi_num >= UBI_MAX_DEVICES) | ||
| 735 | return -EINVAL; | ||
| 736 | |||
| 737 | /* Make sure ubi_num is not busy */ | ||
| 738 | if (ubi_devices[ubi_num]) { | ||
| 739 | dbg_err("ubi%d already exists", ubi_num); | ||
| 740 | return -EEXIST; | ||
| 741 | } | ||
| 742 | } | ||
| 576 | 743 | ||
| 577 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d", | 744 | ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); |
| 578 | ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_offset); | 745 | if (!ubi) |
| 746 | return -ENOMEM; | ||
| 579 | 747 | ||
| 748 | ubi->mtd = mtd; | ||
| 749 | ubi->ubi_num = ubi_num; | ||
| 580 | ubi->vid_hdr_offset = vid_hdr_offset; | 750 | ubi->vid_hdr_offset = vid_hdr_offset; |
| 581 | ubi->leb_start = data_offset; | 751 | ubi->autoresize_vol_id = -1; |
| 752 | |||
| 753 | mutex_init(&ubi->buf_mutex); | ||
| 754 | mutex_init(&ubi->ckvol_mutex); | ||
| 755 | mutex_init(&ubi->volumes_mutex); | ||
| 756 | spin_lock_init(&ubi->volumes_lock); | ||
| 757 | |||
| 758 | dbg_msg("attaching mtd%d to ubi%d: VID header offset %d", | ||
| 759 | mtd->index, ubi_num, vid_hdr_offset); | ||
| 760 | |||
| 582 | err = io_init(ubi); | 761 | err = io_init(ubi); |
| 583 | if (err) | 762 | if (err) |
| 584 | goto out_free; | 763 | goto out_free; |
| 585 | 764 | ||
| 586 | mutex_init(&ubi->buf_mutex); | ||
| 587 | ubi->peb_buf1 = vmalloc(ubi->peb_size); | 765 | ubi->peb_buf1 = vmalloc(ubi->peb_size); |
| 588 | if (!ubi->peb_buf1) | 766 | if (!ubi->peb_buf1) |
| 589 | goto out_free; | 767 | goto out_free; |
| @@ -605,12 +783,26 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, | |||
| 605 | goto out_free; | 783 | goto out_free; |
| 606 | } | 784 | } |
| 607 | 785 | ||
| 786 | if (ubi->autoresize_vol_id != -1) { | ||
| 787 | err = autoresize(ubi, ubi->autoresize_vol_id); | ||
| 788 | if (err) | ||
| 789 | goto out_detach; | ||
| 790 | } | ||
| 791 | |||
| 608 | err = uif_init(ubi); | 792 | err = uif_init(ubi); |
| 609 | if (err) | 793 | if (err) |
| 610 | goto out_detach; | 794 | goto out_detach; |
| 611 | 795 | ||
| 612 | ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt); | 796 | ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); |
| 613 | ubi_msg("MTD device name: \"%s\"", ubi->mtd->name); | 797 | if (IS_ERR(ubi->bgt_thread)) { |
| 798 | err = PTR_ERR(ubi->bgt_thread); | ||
| 799 | ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, | ||
| 800 | err); | ||
| 801 | goto out_uif; | ||
| 802 | } | ||
| 803 | |||
| 804 | ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); | ||
| 805 | ubi_msg("MTD device name: \"%s\"", mtd->name); | ||
| 614 | ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); | 806 | ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); |
| 615 | ubi_msg("physical eraseblock size: %d bytes (%d KiB)", | 807 | ubi_msg("physical eraseblock size: %d bytes (%d KiB)", |
| 616 | ubi->peb_size, ubi->peb_size >> 10); | 808 | ubi->peb_size, ubi->peb_size >> 10); |
| @@ -638,9 +830,11 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset, | |||
| 638 | wake_up_process(ubi->bgt_thread); | 830 | wake_up_process(ubi->bgt_thread); |
| 639 | } | 831 | } |
| 640 | 832 | ||
| 641 | ubi_devices_cnt += 1; | 833 | ubi_devices[ubi_num] = ubi; |
| 642 | return 0; | 834 | return ubi_num; |
| 643 | 835 | ||
| 836 | out_uif: | ||
| 837 | uif_close(ubi); | ||
| 644 | out_detach: | 838 | out_detach: |
| 645 | ubi_eba_close(ubi); | 839 | ubi_eba_close(ubi); |
| 646 | ubi_wl_close(ubi); | 840 | ubi_wl_close(ubi); |
| @@ -652,21 +846,58 @@ out_free: | |||
| 652 | vfree(ubi->dbg_peb_buf); | 846 | vfree(ubi->dbg_peb_buf); |
| 653 | #endif | 847 | #endif |
| 654 | kfree(ubi); | 848 | kfree(ubi); |
| 655 | out_mtd: | ||
| 656 | put_mtd_device(mtd); | ||
| 657 | ubi_devices[ubi_devices_cnt] = NULL; | ||
| 658 | return err; | 849 | return err; |
| 659 | } | 850 | } |
| 660 | 851 | ||
| 661 | /** | 852 | /** |
| 662 | * detach_mtd_dev - detach an MTD device. | 853 | * ubi_detach_mtd_dev - detach an MTD device. |
| 663 | * @ubi: UBI device description object | 854 | * @ubi_num: UBI device number to detach from |
| 855 | * @anyway: detach MTD even if device reference count is not zero | ||
| 856 | * | ||
| 857 | * This function destroys an UBI device number @ubi_num and detaches the | ||
| 858 | * underlying MTD device. Returns zero in case of success and %-EBUSY if the | ||
| 859 | * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not | ||
| 860 | * exist. | ||
| 861 | * | ||
| 862 | * Note, the invocations of this function has to be serialized by the | ||
| 863 | * @ubi_devices_mutex. | ||
| 664 | */ | 864 | */ |
| 665 | static void detach_mtd_dev(struct ubi_device *ubi) | 865 | int ubi_detach_mtd_dev(int ubi_num, int anyway) |
| 666 | { | 866 | { |
| 667 | int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index; | 867 | struct ubi_device *ubi; |
| 868 | |||
| 869 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) | ||
| 870 | return -EINVAL; | ||
| 871 | |||
| 872 | spin_lock(&ubi_devices_lock); | ||
| 873 | ubi = ubi_devices[ubi_num]; | ||
| 874 | if (!ubi) { | ||
| 875 | spin_unlock(&ubi_devices_lock); | ||
| 876 | return -EINVAL; | ||
| 877 | } | ||
| 878 | |||
| 879 | if (ubi->ref_count) { | ||
| 880 | if (!anyway) { | ||
| 881 | spin_unlock(&ubi_devices_lock); | ||
| 882 | return -EBUSY; | ||
| 883 | } | ||
| 884 | /* This may only happen if there is a bug */ | ||
| 885 | ubi_err("%s reference count %d, destroy anyway", | ||
| 886 | ubi->ubi_name, ubi->ref_count); | ||
| 887 | } | ||
| 888 | ubi_devices[ubi_num] = NULL; | ||
| 889 | spin_unlock(&ubi_devices_lock); | ||
| 668 | 890 | ||
| 891 | ubi_assert(ubi_num == ubi->ubi_num); | ||
| 669 | dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); | 892 | dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); |
| 893 | |||
| 894 | /* | ||
| 895 | * Before freeing anything, we have to stop the background thread to | ||
| 896 | * prevent it from doing anything on this device while we are freeing. | ||
| 897 | */ | ||
| 898 | if (ubi->bgt_thread) | ||
| 899 | kthread_stop(ubi->bgt_thread); | ||
| 900 | |||
| 670 | uif_close(ubi); | 901 | uif_close(ubi); |
| 671 | ubi_eba_close(ubi); | 902 | ubi_eba_close(ubi); |
| 672 | ubi_wl_close(ubi); | 903 | ubi_wl_close(ubi); |
| @@ -677,11 +908,37 @@ static void detach_mtd_dev(struct ubi_device *ubi) | |||
| 677 | #ifdef CONFIG_MTD_UBI_DEBUG | 908 | #ifdef CONFIG_MTD_UBI_DEBUG |
| 678 | vfree(ubi->dbg_peb_buf); | 909 | vfree(ubi->dbg_peb_buf); |
| 679 | #endif | 910 | #endif |
| 680 | kfree(ubi_devices[ubi_num]); | 911 | ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); |
| 681 | ubi_devices[ubi_num] = NULL; | 912 | kfree(ubi); |
| 682 | ubi_devices_cnt -= 1; | 913 | return 0; |
| 683 | ubi_assert(ubi_devices_cnt >= 0); | 914 | } |
| 684 | ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num); | 915 | |
| 916 | /** | ||
| 917 | * find_mtd_device - open an MTD device by its name or number. | ||
| 918 | * @mtd_dev: name or number of the device | ||
| 919 | * | ||
| 920 | * This function tries to open and MTD device described by @mtd_dev string, | ||
| 921 | * which is first treated as an ASCII number, and if it is not true, it is | ||
| 922 | * treated as MTD device name. Returns MTD device description object in case of | ||
| 923 | * success and a negative error code in case of failure. | ||
| 924 | */ | ||
| 925 | static struct mtd_info * __init open_mtd_device(const char *mtd_dev) | ||
| 926 | { | ||
| 927 | struct mtd_info *mtd; | ||
| 928 | int mtd_num; | ||
| 929 | char *endp; | ||
| 930 | |||
| 931 | mtd_num = simple_strtoul(mtd_dev, &endp, 0); | ||
| 932 | if (*endp != '\0' || mtd_dev == endp) { | ||
| 933 | /* | ||
| 934 | * This does not look like an ASCII integer, probably this is | ||
| 935 | * MTD device name. | ||
| 936 | */ | ||
| 937 | mtd = get_mtd_device_nm(mtd_dev); | ||
| 938 | } else | ||
| 939 | mtd = get_mtd_device(NULL, mtd_num); | ||
| 940 | |||
| 941 | return mtd; | ||
| 685 | } | 942 | } |
| 686 | 943 | ||
| 687 | static int __init ubi_init(void) | 944 | static int __init ubi_init(void) |
| @@ -693,47 +950,96 @@ static int __init ubi_init(void) | |||
| 693 | BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); | 950 | BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64); |
| 694 | 951 | ||
| 695 | if (mtd_devs > UBI_MAX_DEVICES) { | 952 | if (mtd_devs > UBI_MAX_DEVICES) { |
| 696 | printk("UBI error: too many MTD devices, maximum is %d\n", | 953 | printk(KERN_ERR "UBI error: too many MTD devices, " |
| 697 | UBI_MAX_DEVICES); | 954 | "maximum is %d\n", UBI_MAX_DEVICES); |
| 698 | return -EINVAL; | 955 | return -EINVAL; |
| 699 | } | 956 | } |
| 700 | 957 | ||
| 958 | /* Create base sysfs directory and sysfs files */ | ||
| 701 | ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); | 959 | ubi_class = class_create(THIS_MODULE, UBI_NAME_STR); |
| 702 | if (IS_ERR(ubi_class)) | 960 | if (IS_ERR(ubi_class)) { |
| 703 | return PTR_ERR(ubi_class); | 961 | err = PTR_ERR(ubi_class); |
| 962 | printk(KERN_ERR "UBI error: cannot create UBI class\n"); | ||
| 963 | goto out; | ||
| 964 | } | ||
| 704 | 965 | ||
| 705 | err = class_create_file(ubi_class, &ubi_version); | 966 | err = class_create_file(ubi_class, &ubi_version); |
| 706 | if (err) | 967 | if (err) { |
| 968 | printk(KERN_ERR "UBI error: cannot create sysfs file\n"); | ||
| 707 | goto out_class; | 969 | goto out_class; |
| 970 | } | ||
| 971 | |||
| 972 | err = misc_register(&ubi_ctrl_cdev); | ||
| 973 | if (err) { | ||
| 974 | printk(KERN_ERR "UBI error: cannot register device\n"); | ||
| 975 | goto out_version; | ||
| 976 | } | ||
| 977 | |||
| 978 | ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab", | ||
| 979 | sizeof(struct ubi_wl_entry), | ||
| 980 | 0, 0, NULL); | ||
| 981 | if (!ubi_wl_entry_slab) | ||
| 982 | goto out_dev_unreg; | ||
| 708 | 983 | ||
| 709 | /* Attach MTD devices */ | 984 | /* Attach MTD devices */ |
| 710 | for (i = 0; i < mtd_devs; i++) { | 985 | for (i = 0; i < mtd_devs; i++) { |
| 711 | struct mtd_dev_param *p = &mtd_dev_param[i]; | 986 | struct mtd_dev_param *p = &mtd_dev_param[i]; |
| 987 | struct mtd_info *mtd; | ||
| 712 | 988 | ||
| 713 | cond_resched(); | 989 | cond_resched(); |
| 714 | err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs); | 990 | |
| 715 | if (err) | 991 | mtd = open_mtd_device(p->name); |
| 992 | if (IS_ERR(mtd)) { | ||
| 993 | err = PTR_ERR(mtd); | ||
| 994 | goto out_detach; | ||
| 995 | } | ||
| 996 | |||
| 997 | mutex_lock(&ubi_devices_mutex); | ||
| 998 | err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, | ||
| 999 | p->vid_hdr_offs); | ||
| 1000 | mutex_unlock(&ubi_devices_mutex); | ||
| 1001 | if (err < 0) { | ||
| 1002 | put_mtd_device(mtd); | ||
| 1003 | printk(KERN_ERR "UBI error: cannot attach %s\n", | ||
| 1004 | p->name); | ||
| 716 | goto out_detach; | 1005 | goto out_detach; |
| 1006 | } | ||
| 717 | } | 1007 | } |
| 718 | 1008 | ||
| 719 | return 0; | 1009 | return 0; |
| 720 | 1010 | ||
| 721 | out_detach: | 1011 | out_detach: |
| 722 | for (k = 0; k < i; k++) | 1012 | for (k = 0; k < i; k++) |
| 723 | detach_mtd_dev(ubi_devices[k]); | 1013 | if (ubi_devices[k]) { |
| 1014 | mutex_lock(&ubi_devices_mutex); | ||
| 1015 | ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1); | ||
| 1016 | mutex_unlock(&ubi_devices_mutex); | ||
| 1017 | } | ||
| 1018 | kmem_cache_destroy(ubi_wl_entry_slab); | ||
| 1019 | out_dev_unreg: | ||
| 1020 | misc_deregister(&ubi_ctrl_cdev); | ||
| 1021 | out_version: | ||
| 724 | class_remove_file(ubi_class, &ubi_version); | 1022 | class_remove_file(ubi_class, &ubi_version); |
| 725 | out_class: | 1023 | out_class: |
| 726 | class_destroy(ubi_class); | 1024 | class_destroy(ubi_class); |
| 1025 | out: | ||
| 1026 | printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err); | ||
| 727 | return err; | 1027 | return err; |
| 728 | } | 1028 | } |
| 729 | module_init(ubi_init); | 1029 | module_init(ubi_init); |
| 730 | 1030 | ||
| 731 | static void __exit ubi_exit(void) | 1031 | static void __exit ubi_exit(void) |
| 732 | { | 1032 | { |
| 733 | int i, n = ubi_devices_cnt; | 1033 | int i; |
| 734 | 1034 | ||
| 735 | for (i = 0; i < n; i++) | 1035 | for (i = 0; i < UBI_MAX_DEVICES; i++) |
| 736 | detach_mtd_dev(ubi_devices[i]); | 1036 | if (ubi_devices[i]) { |
| 1037 | mutex_lock(&ubi_devices_mutex); | ||
| 1038 | ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1); | ||
| 1039 | mutex_unlock(&ubi_devices_mutex); | ||
| 1040 | } | ||
| 1041 | kmem_cache_destroy(ubi_wl_entry_slab); | ||
| 1042 | misc_deregister(&ubi_ctrl_cdev); | ||
| 737 | class_remove_file(ubi_class, &ubi_version); | 1043 | class_remove_file(ubi_class, &ubi_version); |
| 738 | class_destroy(ubi_class); | 1044 | class_destroy(ubi_class); |
| 739 | } | 1045 | } |
| @@ -754,7 +1060,8 @@ static int __init bytes_str_to_int(const char *str) | |||
| 754 | 1060 | ||
| 755 | result = simple_strtoul(str, &endp, 0); | 1061 | result = simple_strtoul(str, &endp, 0); |
| 756 | if (str == endp || result < 0) { | 1062 | if (str == endp || result < 0) { |
| 757 | printk("UBI error: incorrect bytes count: \"%s\"\n", str); | 1063 | printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", |
| 1064 | str); | ||
| 758 | return -EINVAL; | 1065 | return -EINVAL; |
| 759 | } | 1066 | } |
| 760 | 1067 | ||
| @@ -764,15 +1071,14 @@ static int __init bytes_str_to_int(const char *str) | |||
| 764 | case 'M': | 1071 | case 'M': |
| 765 | result *= 1024; | 1072 | result *= 1024; |
| 766 | case 'K': | 1073 | case 'K': |
| 767 | case 'k': | ||
| 768 | result *= 1024; | 1074 | result *= 1024; |
| 769 | if (endp[1] == 'i' && (endp[2] == '\0' || | 1075 | if (endp[1] == 'i' && endp[2] == 'B') |
| 770 | endp[2] == 'B' || endp[2] == 'b')) | ||
| 771 | endp += 2; | 1076 | endp += 2; |
| 772 | case '\0': | 1077 | case '\0': |
| 773 | break; | 1078 | break; |
| 774 | default: | 1079 | default: |
| 775 | printk("UBI error: incorrect bytes count: \"%s\"\n", str); | 1080 | printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", |
| 1081 | str); | ||
| 776 | return -EINVAL; | 1082 | return -EINVAL; |
| 777 | } | 1083 | } |
| 778 | 1084 | ||
| @@ -793,23 +1099,27 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) | |||
| 793 | struct mtd_dev_param *p; | 1099 | struct mtd_dev_param *p; |
| 794 | char buf[MTD_PARAM_LEN_MAX]; | 1100 | char buf[MTD_PARAM_LEN_MAX]; |
| 795 | char *pbuf = &buf[0]; | 1101 | char *pbuf = &buf[0]; |
| 796 | char *tokens[3] = {NULL, NULL, NULL}; | 1102 | char *tokens[2] = {NULL, NULL}; |
| 1103 | |||
| 1104 | if (!val) | ||
| 1105 | return -EINVAL; | ||
| 797 | 1106 | ||
| 798 | if (mtd_devs == UBI_MAX_DEVICES) { | 1107 | if (mtd_devs == UBI_MAX_DEVICES) { |
| 799 | printk("UBI error: too many parameters, max. is %d\n", | 1108 | printk(KERN_ERR "UBI error: too many parameters, max. is %d\n", |
| 800 | UBI_MAX_DEVICES); | 1109 | UBI_MAX_DEVICES); |
| 801 | return -EINVAL; | 1110 | return -EINVAL; |
| 802 | } | 1111 | } |
| 803 | 1112 | ||
| 804 | len = strnlen(val, MTD_PARAM_LEN_MAX); | 1113 | len = strnlen(val, MTD_PARAM_LEN_MAX); |
| 805 | if (len == MTD_PARAM_LEN_MAX) { | 1114 | if (len == MTD_PARAM_LEN_MAX) { |
| 806 | printk("UBI error: parameter \"%s\" is too long, max. is %d\n", | 1115 | printk(KERN_ERR "UBI error: parameter \"%s\" is too long, " |
| 807 | val, MTD_PARAM_LEN_MAX); | 1116 | "max. is %d\n", val, MTD_PARAM_LEN_MAX); |
| 808 | return -EINVAL; | 1117 | return -EINVAL; |
| 809 | } | 1118 | } |
| 810 | 1119 | ||
| 811 | if (len == 0) { | 1120 | if (len == 0) { |
| 812 | printk("UBI warning: empty 'mtd=' parameter - ignored\n"); | 1121 | printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - " |
| 1122 | "ignored\n"); | ||
| 813 | return 0; | 1123 | return 0; |
| 814 | } | 1124 | } |
| 815 | 1125 | ||
| @@ -819,11 +1129,12 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) | |||
| 819 | if (buf[len - 1] == '\n') | 1129 | if (buf[len - 1] == '\n') |
| 820 | buf[len - 1] = '\0'; | 1130 | buf[len - 1] = '\0'; |
| 821 | 1131 | ||
| 822 | for (i = 0; i < 3; i++) | 1132 | for (i = 0; i < 2; i++) |
| 823 | tokens[i] = strsep(&pbuf, ","); | 1133 | tokens[i] = strsep(&pbuf, ","); |
| 824 | 1134 | ||
| 825 | if (pbuf) { | 1135 | if (pbuf) { |
| 826 | printk("UBI error: too many arguments at \"%s\"\n", val); | 1136 | printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n", |
| 1137 | val); | ||
| 827 | return -EINVAL; | 1138 | return -EINVAL; |
| 828 | } | 1139 | } |
| 829 | 1140 | ||
| @@ -832,13 +1143,9 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) | |||
| 832 | 1143 | ||
| 833 | if (tokens[1]) | 1144 | if (tokens[1]) |
| 834 | p->vid_hdr_offs = bytes_str_to_int(tokens[1]); | 1145 | p->vid_hdr_offs = bytes_str_to_int(tokens[1]); |
| 835 | if (tokens[2]) | ||
| 836 | p->data_offs = bytes_str_to_int(tokens[2]); | ||
| 837 | 1146 | ||
| 838 | if (p->vid_hdr_offs < 0) | 1147 | if (p->vid_hdr_offs < 0) |
| 839 | return p->vid_hdr_offs; | 1148 | return p->vid_hdr_offs; |
| 840 | if (p->data_offs < 0) | ||
| 841 | return p->data_offs; | ||
| 842 | 1149 | ||
| 843 | mtd_devs += 1; | 1150 | mtd_devs += 1; |
| 844 | return 0; | 1151 | return 0; |
| @@ -846,16 +1153,15 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) | |||
| 846 | 1153 | ||
| 847 | module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000); | 1154 | module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000); |
| 848 | MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: " | 1155 | MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: " |
| 849 | "mtd=<name|num>[,<vid_hdr_offs>,<data_offs>]. " | 1156 | "mtd=<name|num>[,<vid_hdr_offs>].\n" |
| 850 | "Multiple \"mtd\" parameters may be specified.\n" | 1157 | "Multiple \"mtd\" parameters may be specified.\n" |
| 851 | "MTD devices may be specified by their number or name. " | 1158 | "MTD devices may be specified by their number or name.\n" |
| 852 | "Optional \"vid_hdr_offs\" and \"data_offs\" parameters " | 1159 | "Optional \"vid_hdr_offs\" parameter specifies UBI VID " |
| 853 | "specify UBI VID header position and data starting " | 1160 | "header position and data starting position to be used " |
| 854 | "position to be used by UBI.\n" | 1161 | "by UBI.\n" |
| 855 | "Example: mtd=content,1984,2048 mtd=4 - attach MTD device" | 1162 | "Example: mtd=content,1984 mtd=4 - attach MTD device" |
| 856 | "with name content using VID header offset 1984 and data " | 1163 | "with name \"content\" using VID header offset 1984, and " |
| 857 | "start 2048, and MTD device number 4 using default " | 1164 | "MTD device number 4 with default VID header offset."); |
| 858 | "offsets"); | ||
| 859 | 1165 | ||
| 860 | MODULE_VERSION(__stringify(UBI_VERSION)); | 1166 | MODULE_VERSION(__stringify(UBI_VERSION)); |
| 861 | MODULE_DESCRIPTION("UBI - Unsorted Block Images"); | 1167 | MODULE_DESCRIPTION("UBI - Unsorted Block Images"); |
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index fe4da1e96c52..9d6aae5449b6 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c | |||
| @@ -28,6 +28,11 @@ | |||
| 28 | * | 28 | * |
| 29 | * Major and minor numbers are assigned dynamically to both UBI and volume | 29 | * Major and minor numbers are assigned dynamically to both UBI and volume |
| 30 | * character devices. | 30 | * character devices. |
| 31 | * | ||
| 32 | * Well, there is the third kind of character devices - the UBI control | ||
| 33 | * character device, which allows to manipulate by UBI devices - create and | ||
| 34 | * delete them. In other words, it is used for attaching and detaching MTD | ||
| 35 | * devices. | ||
| 31 | */ | 36 | */ |
| 32 | 37 | ||
| 33 | #include <linux/module.h> | 38 | #include <linux/module.h> |
| @@ -39,34 +44,6 @@ | |||
| 39 | #include <asm/div64.h> | 44 | #include <asm/div64.h> |
| 40 | #include "ubi.h" | 45 | #include "ubi.h" |
| 41 | 46 | ||
| 42 | /* | ||
| 43 | * Maximum sequence numbers of UBI and volume character device IOCTLs (direct | ||
| 44 | * logical eraseblock erase is a debug-only feature). | ||
| 45 | */ | ||
| 46 | #define UBI_CDEV_IOC_MAX_SEQ 2 | ||
| 47 | #ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO | ||
| 48 | #define VOL_CDEV_IOC_MAX_SEQ 1 | ||
| 49 | #else | ||
| 50 | #define VOL_CDEV_IOC_MAX_SEQ 2 | ||
| 51 | #endif | ||
| 52 | |||
| 53 | /** | ||
| 54 | * major_to_device - get UBI device object by character device major number. | ||
| 55 | * @major: major number | ||
| 56 | * | ||
| 57 | * This function returns a pointer to the UBI device object. | ||
| 58 | */ | ||
| 59 | static struct ubi_device *major_to_device(int major) | ||
| 60 | { | ||
| 61 | int i; | ||
| 62 | |||
| 63 | for (i = 0; i < ubi_devices_cnt; i++) | ||
| 64 | if (ubi_devices[i] && ubi_devices[i]->major == major) | ||
| 65 | return ubi_devices[i]; | ||
| 66 | BUG(); | ||
| 67 | return NULL; | ||
| 68 | } | ||
| 69 | |||
| 70 | /** | 47 | /** |
| 71 | * get_exclusive - get exclusive access to an UBI volume. | 48 | * get_exclusive - get exclusive access to an UBI volume. |
| 72 | * @desc: volume descriptor | 49 | * @desc: volume descriptor |
| @@ -124,9 +101,11 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode) | |||
| 124 | static int vol_cdev_open(struct inode *inode, struct file *file) | 101 | static int vol_cdev_open(struct inode *inode, struct file *file) |
| 125 | { | 102 | { |
| 126 | struct ubi_volume_desc *desc; | 103 | struct ubi_volume_desc *desc; |
| 127 | const struct ubi_device *ubi = major_to_device(imajor(inode)); | 104 | int vol_id = iminor(inode) - 1, mode, ubi_num; |
| 128 | int vol_id = iminor(inode) - 1; | 105 | |
| 129 | int mode; | 106 | ubi_num = ubi_major2num(imajor(inode)); |
| 107 | if (ubi_num < 0) | ||
| 108 | return ubi_num; | ||
| 130 | 109 | ||
| 131 | if (file->f_mode & FMODE_WRITE) | 110 | if (file->f_mode & FMODE_WRITE) |
| 132 | mode = UBI_READWRITE; | 111 | mode = UBI_READWRITE; |
| @@ -135,7 +114,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file) | |||
| 135 | 114 | ||
| 136 | dbg_msg("open volume %d, mode %d", vol_id, mode); | 115 | dbg_msg("open volume %d, mode %d", vol_id, mode); |
| 137 | 116 | ||
| 138 | desc = ubi_open_volume(ubi->ubi_num, vol_id, mode); | 117 | desc = ubi_open_volume(ubi_num, vol_id, mode); |
| 139 | if (IS_ERR(desc)) | 118 | if (IS_ERR(desc)) |
| 140 | return PTR_ERR(desc); | 119 | return PTR_ERR(desc); |
| 141 | 120 | ||
| @@ -153,8 +132,15 @@ static int vol_cdev_release(struct inode *inode, struct file *file) | |||
| 153 | if (vol->updating) { | 132 | if (vol->updating) { |
| 154 | ubi_warn("update of volume %d not finished, volume is damaged", | 133 | ubi_warn("update of volume %d not finished, volume is damaged", |
| 155 | vol->vol_id); | 134 | vol->vol_id); |
| 135 | ubi_assert(!vol->changing_leb); | ||
| 156 | vol->updating = 0; | 136 | vol->updating = 0; |
| 157 | vfree(vol->upd_buf); | 137 | vfree(vol->upd_buf); |
| 138 | } else if (vol->changing_leb) { | ||
| 139 | dbg_msg("only %lld of %lld bytes received for atomic LEB change" | ||
| 140 | " for volume %d:%d, cancel", vol->upd_received, | ||
| 141 | vol->upd_bytes, vol->ubi->ubi_num, vol->vol_id); | ||
| 142 | vol->changing_leb = 0; | ||
| 143 | vfree(vol->upd_buf); | ||
| 158 | } | 144 | } |
| 159 | 145 | ||
| 160 | ubi_close_volume(desc); | 146 | ubi_close_volume(desc); |
| @@ -205,13 +191,13 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, | |||
| 205 | struct ubi_volume_desc *desc = file->private_data; | 191 | struct ubi_volume_desc *desc = file->private_data; |
| 206 | struct ubi_volume *vol = desc->vol; | 192 | struct ubi_volume *vol = desc->vol; |
| 207 | struct ubi_device *ubi = vol->ubi; | 193 | struct ubi_device *ubi = vol->ubi; |
| 208 | int err, lnum, off, len, vol_id = desc->vol->vol_id, tbuf_size; | 194 | int err, lnum, off, len, tbuf_size; |
| 209 | size_t count_save = count; | 195 | size_t count_save = count; |
| 210 | void *tbuf; | 196 | void *tbuf; |
| 211 | uint64_t tmp; | 197 | uint64_t tmp; |
| 212 | 198 | ||
| 213 | dbg_msg("read %zd bytes from offset %lld of volume %d", | 199 | dbg_msg("read %zd bytes from offset %lld of volume %d", |
| 214 | count, *offp, vol_id); | 200 | count, *offp, vol->vol_id); |
| 215 | 201 | ||
| 216 | if (vol->updating) { | 202 | if (vol->updating) { |
| 217 | dbg_err("updating"); | 203 | dbg_err("updating"); |
| @@ -225,7 +211,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, | |||
| 225 | return 0; | 211 | return 0; |
| 226 | 212 | ||
| 227 | if (vol->corrupted) | 213 | if (vol->corrupted) |
| 228 | dbg_msg("read from corrupted volume %d", vol_id); | 214 | dbg_msg("read from corrupted volume %d", vol->vol_id); |
| 229 | 215 | ||
| 230 | if (*offp + count > vol->used_bytes) | 216 | if (*offp + count > vol->used_bytes) |
| 231 | count_save = count = vol->used_bytes - *offp; | 217 | count_save = count = vol->used_bytes - *offp; |
| @@ -249,7 +235,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count, | |||
| 249 | if (off + len >= vol->usable_leb_size) | 235 | if (off + len >= vol->usable_leb_size) |
| 250 | len = vol->usable_leb_size - off; | 236 | len = vol->usable_leb_size - off; |
| 251 | 237 | ||
| 252 | err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0); | 238 | err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0); |
| 253 | if (err) | 239 | if (err) |
| 254 | break; | 240 | break; |
| 255 | 241 | ||
| @@ -289,13 +275,13 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, | |||
| 289 | struct ubi_volume_desc *desc = file->private_data; | 275 | struct ubi_volume_desc *desc = file->private_data; |
| 290 | struct ubi_volume *vol = desc->vol; | 276 | struct ubi_volume *vol = desc->vol; |
| 291 | struct ubi_device *ubi = vol->ubi; | 277 | struct ubi_device *ubi = vol->ubi; |
| 292 | int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0; | 278 | int lnum, off, len, tbuf_size, err = 0; |
| 293 | size_t count_save = count; | 279 | size_t count_save = count; |
| 294 | char *tbuf; | 280 | char *tbuf; |
| 295 | uint64_t tmp; | 281 | uint64_t tmp; |
| 296 | 282 | ||
| 297 | dbg_msg("requested: write %zd bytes to offset %lld of volume %u", | 283 | dbg_msg("requested: write %zd bytes to offset %lld of volume %u", |
| 298 | count, *offp, desc->vol->vol_id); | 284 | count, *offp, vol->vol_id); |
| 299 | 285 | ||
| 300 | if (vol->vol_type == UBI_STATIC_VOLUME) | 286 | if (vol->vol_type == UBI_STATIC_VOLUME) |
| 301 | return -EROFS; | 287 | return -EROFS; |
| @@ -339,7 +325,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf, | |||
| 339 | break; | 325 | break; |
| 340 | } | 326 | } |
| 341 | 327 | ||
| 342 | err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len, | 328 | err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len, |
| 343 | UBI_UNKNOWN); | 329 | UBI_UNKNOWN); |
| 344 | if (err) | 330 | if (err) |
| 345 | break; | 331 | break; |
| @@ -372,22 +358,32 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, | |||
| 372 | struct ubi_volume *vol = desc->vol; | 358 | struct ubi_volume *vol = desc->vol; |
| 373 | struct ubi_device *ubi = vol->ubi; | 359 | struct ubi_device *ubi = vol->ubi; |
| 374 | 360 | ||
| 375 | if (!vol->updating) | 361 | if (!vol->updating && !vol->changing_leb) |
| 376 | return vol_cdev_direct_write(file, buf, count, offp); | 362 | return vol_cdev_direct_write(file, buf, count, offp); |
| 377 | 363 | ||
| 378 | err = ubi_more_update_data(ubi, vol->vol_id, buf, count); | 364 | if (vol->updating) |
| 365 | err = ubi_more_update_data(ubi, vol, buf, count); | ||
| 366 | else | ||
| 367 | err = ubi_more_leb_change_data(ubi, vol, buf, count); | ||
| 368 | |||
| 379 | if (err < 0) { | 369 | if (err < 0) { |
| 380 | ubi_err("cannot write %zd bytes of update data", count); | 370 | ubi_err("cannot accept more %zd bytes of data, error %d", |
| 371 | count, err); | ||
| 381 | return err; | 372 | return err; |
| 382 | } | 373 | } |
| 383 | 374 | ||
| 384 | if (err) { | 375 | if (err) { |
| 385 | /* | 376 | /* |
| 386 | * Update is finished, @err contains number of actually written | 377 | * The operation is finished, @err contains number of actually |
| 387 | * bytes now. | 378 | * written bytes. |
| 388 | */ | 379 | */ |
| 389 | count = err; | 380 | count = err; |
| 390 | 381 | ||
| 382 | if (vol->changing_leb) { | ||
| 383 | revoke_exclusive(desc, UBI_READWRITE); | ||
| 384 | return count; | ||
| 385 | } | ||
| 386 | |||
| 391 | err = ubi_check_volume(ubi, vol->vol_id); | 387 | err = ubi_check_volume(ubi, vol->vol_id); |
| 392 | if (err < 0) | 388 | if (err < 0) |
| 393 | return err; | 389 | return err; |
| @@ -402,7 +398,6 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, | |||
| 402 | revoke_exclusive(desc, UBI_READWRITE); | 398 | revoke_exclusive(desc, UBI_READWRITE); |
| 403 | } | 399 | } |
| 404 | 400 | ||
| 405 | *offp += count; | ||
| 406 | return count; | 401 | return count; |
| 407 | } | 402 | } |
| 408 | 403 | ||
| @@ -447,11 +442,46 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 447 | if (err < 0) | 442 | if (err < 0) |
| 448 | break; | 443 | break; |
| 449 | 444 | ||
| 450 | err = ubi_start_update(ubi, vol->vol_id, bytes); | 445 | err = ubi_start_update(ubi, vol, bytes); |
| 451 | if (bytes == 0) | 446 | if (bytes == 0) |
| 452 | revoke_exclusive(desc, UBI_READWRITE); | 447 | revoke_exclusive(desc, UBI_READWRITE); |
| 448 | break; | ||
| 449 | } | ||
| 450 | |||
| 451 | /* Atomic logical eraseblock change command */ | ||
| 452 | case UBI_IOCEBCH: | ||
| 453 | { | ||
| 454 | struct ubi_leb_change_req req; | ||
| 455 | |||
| 456 | err = copy_from_user(&req, argp, | ||
| 457 | sizeof(struct ubi_leb_change_req)); | ||
| 458 | if (err) { | ||
| 459 | err = -EFAULT; | ||
| 460 | break; | ||
| 461 | } | ||
| 462 | |||
| 463 | if (desc->mode == UBI_READONLY || | ||
| 464 | vol->vol_type == UBI_STATIC_VOLUME) { | ||
| 465 | err = -EROFS; | ||
| 466 | break; | ||
| 467 | } | ||
| 468 | |||
| 469 | /* Validate the request */ | ||
| 470 | err = -EINVAL; | ||
| 471 | if (req.lnum < 0 || req.lnum >= vol->reserved_pebs || | ||
| 472 | req.bytes < 0 || req.lnum >= vol->usable_leb_size) | ||
| 473 | break; | ||
| 474 | if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM && | ||
| 475 | req.dtype != UBI_UNKNOWN) | ||
| 476 | break; | ||
| 477 | |||
| 478 | err = get_exclusive(desc); | ||
| 479 | if (err < 0) | ||
| 480 | break; | ||
| 453 | 481 | ||
| 454 | file->f_pos = 0; | 482 | err = ubi_start_leb_change(ubi, vol, &req); |
| 483 | if (req.bytes == 0) | ||
| 484 | revoke_exclusive(desc, UBI_READWRITE); | ||
| 455 | break; | 485 | break; |
| 456 | } | 486 | } |
| 457 | 487 | ||
| @@ -467,7 +497,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 467 | break; | 497 | break; |
| 468 | } | 498 | } |
| 469 | 499 | ||
| 470 | if (desc->mode == UBI_READONLY) { | 500 | if (desc->mode == UBI_READONLY || |
| 501 | vol->vol_type == UBI_STATIC_VOLUME) { | ||
| 471 | err = -EROFS; | 502 | err = -EROFS; |
| 472 | break; | 503 | break; |
| 473 | } | 504 | } |
| @@ -477,13 +508,8 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 477 | break; | 508 | break; |
| 478 | } | 509 | } |
| 479 | 510 | ||
| 480 | if (vol->vol_type != UBI_DYNAMIC_VOLUME) { | ||
| 481 | err = -EROFS; | ||
| 482 | break; | ||
| 483 | } | ||
| 484 | |||
| 485 | dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); | 511 | dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); |
| 486 | err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum); | 512 | err = ubi_eba_unmap_leb(ubi, vol, lnum); |
| 487 | if (err) | 513 | if (err) |
| 488 | break; | 514 | break; |
| 489 | 515 | ||
| @@ -580,9 +606,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 580 | if (!capable(CAP_SYS_RESOURCE)) | 606 | if (!capable(CAP_SYS_RESOURCE)) |
| 581 | return -EPERM; | 607 | return -EPERM; |
| 582 | 608 | ||
| 583 | ubi = major_to_device(imajor(inode)); | 609 | ubi = ubi_get_by_major(imajor(inode)); |
| 584 | if (IS_ERR(ubi)) | 610 | if (!ubi) |
| 585 | return PTR_ERR(ubi); | 611 | return -ENODEV; |
| 586 | 612 | ||
| 587 | switch (cmd) { | 613 | switch (cmd) { |
| 588 | /* Create volume command */ | 614 | /* Create volume command */ |
| @@ -591,8 +617,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 591 | struct ubi_mkvol_req req; | 617 | struct ubi_mkvol_req req; |
| 592 | 618 | ||
| 593 | dbg_msg("create volume"); | 619 | dbg_msg("create volume"); |
| 594 | err = copy_from_user(&req, argp, | 620 | err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req)); |
| 595 | sizeof(struct ubi_mkvol_req)); | ||
| 596 | if (err) { | 621 | if (err) { |
| 597 | err = -EFAULT; | 622 | err = -EFAULT; |
| 598 | break; | 623 | break; |
| @@ -604,7 +629,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 604 | 629 | ||
| 605 | req.name[req.name_len] = '\0'; | 630 | req.name[req.name_len] = '\0'; |
| 606 | 631 | ||
| 632 | mutex_lock(&ubi->volumes_mutex); | ||
| 607 | err = ubi_create_volume(ubi, &req); | 633 | err = ubi_create_volume(ubi, &req); |
| 634 | mutex_unlock(&ubi->volumes_mutex); | ||
| 608 | if (err) | 635 | if (err) |
| 609 | break; | 636 | break; |
| 610 | 637 | ||
| @@ -633,10 +660,16 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 633 | break; | 660 | break; |
| 634 | } | 661 | } |
| 635 | 662 | ||
| 663 | mutex_lock(&ubi->volumes_mutex); | ||
| 636 | err = ubi_remove_volume(desc); | 664 | err = ubi_remove_volume(desc); |
| 637 | if (err) | 665 | mutex_unlock(&ubi->volumes_mutex); |
| 638 | ubi_close_volume(desc); | ||
| 639 | 666 | ||
| 667 | /* | ||
| 668 | * The volume is deleted (unless an error occurred), and the | ||
| 669 | * 'struct ubi_volume' object will be freed when | ||
| 670 | * 'ubi_close_volume()' will call 'put_device()'. | ||
| 671 | */ | ||
| 672 | ubi_close_volume(desc); | ||
| 640 | break; | 673 | break; |
| 641 | } | 674 | } |
| 642 | 675 | ||
| @@ -648,8 +681,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 648 | struct ubi_rsvol_req req; | 681 | struct ubi_rsvol_req req; |
| 649 | 682 | ||
| 650 | dbg_msg("re-size volume"); | 683 | dbg_msg("re-size volume"); |
| 651 | err = copy_from_user(&req, argp, | 684 | err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req)); |
| 652 | sizeof(struct ubi_rsvol_req)); | ||
| 653 | if (err) { | 685 | if (err) { |
| 654 | err = -EFAULT; | 686 | err = -EFAULT; |
| 655 | break; | 687 | break; |
| @@ -669,7 +701,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 669 | pebs = !!do_div(tmp, desc->vol->usable_leb_size); | 701 | pebs = !!do_div(tmp, desc->vol->usable_leb_size); |
| 670 | pebs += tmp; | 702 | pebs += tmp; |
| 671 | 703 | ||
| 704 | mutex_lock(&ubi->volumes_mutex); | ||
| 672 | err = ubi_resize_volume(desc, pebs); | 705 | err = ubi_resize_volume(desc, pebs); |
| 706 | mutex_unlock(&ubi->volumes_mutex); | ||
| 673 | ubi_close_volume(desc); | 707 | ubi_close_volume(desc); |
| 674 | break; | 708 | break; |
| 675 | } | 709 | } |
| @@ -679,9 +713,93 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 679 | break; | 713 | break; |
| 680 | } | 714 | } |
| 681 | 715 | ||
| 716 | ubi_put_device(ubi); | ||
| 682 | return err; | 717 | return err; |
| 683 | } | 718 | } |
| 684 | 719 | ||
| 720 | static int ctrl_cdev_ioctl(struct inode *inode, struct file *file, | ||
| 721 | unsigned int cmd, unsigned long arg) | ||
| 722 | { | ||
| 723 | int err = 0; | ||
| 724 | void __user *argp = (void __user *)arg; | ||
| 725 | |||
| 726 | if (!capable(CAP_SYS_RESOURCE)) | ||
| 727 | return -EPERM; | ||
| 728 | |||
| 729 | switch (cmd) { | ||
| 730 | /* Attach an MTD device command */ | ||
| 731 | case UBI_IOCATT: | ||
| 732 | { | ||
| 733 | struct ubi_attach_req req; | ||
| 734 | struct mtd_info *mtd; | ||
| 735 | |||
| 736 | dbg_msg("attach MTD device"); | ||
| 737 | err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req)); | ||
| 738 | if (err) { | ||
| 739 | err = -EFAULT; | ||
| 740 | break; | ||
| 741 | } | ||
| 742 | |||
| 743 | if (req.mtd_num < 0 || | ||
| 744 | (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) { | ||
| 745 | err = -EINVAL; | ||
| 746 | break; | ||
| 747 | } | ||
| 748 | |||
| 749 | mtd = get_mtd_device(NULL, req.mtd_num); | ||
| 750 | if (IS_ERR(mtd)) { | ||
| 751 | err = PTR_ERR(mtd); | ||
| 752 | break; | ||
| 753 | } | ||
| 754 | |||
| 755 | /* | ||
| 756 | * Note, further request verification is done by | ||
| 757 | * 'ubi_attach_mtd_dev()'. | ||
| 758 | */ | ||
| 759 | mutex_lock(&ubi_devices_mutex); | ||
| 760 | err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset); | ||
| 761 | mutex_unlock(&ubi_devices_mutex); | ||
| 762 | if (err < 0) | ||
| 763 | put_mtd_device(mtd); | ||
| 764 | else | ||
| 765 | /* @err contains UBI device number */ | ||
| 766 | err = put_user(err, (__user int32_t *)argp); | ||
| 767 | |||
| 768 | break; | ||
| 769 | } | ||
| 770 | |||
| 771 | /* Detach an MTD device command */ | ||
| 772 | case UBI_IOCDET: | ||
| 773 | { | ||
| 774 | int ubi_num; | ||
| 775 | |||
| 776 | dbg_msg("dettach MTD device"); | ||
| 777 | err = get_user(ubi_num, (__user int32_t *)argp); | ||
| 778 | if (err) { | ||
| 779 | err = -EFAULT; | ||
| 780 | break; | ||
| 781 | } | ||
| 782 | |||
| 783 | mutex_lock(&ubi_devices_mutex); | ||
| 784 | err = ubi_detach_mtd_dev(ubi_num, 0); | ||
| 785 | mutex_unlock(&ubi_devices_mutex); | ||
| 786 | break; | ||
| 787 | } | ||
| 788 | |||
| 789 | default: | ||
| 790 | err = -ENOTTY; | ||
| 791 | break; | ||
| 792 | } | ||
| 793 | |||
| 794 | return err; | ||
| 795 | } | ||
| 796 | |||
| 797 | /* UBI control character device operations */ | ||
| 798 | struct file_operations ubi_ctrl_cdev_operations = { | ||
| 799 | .ioctl = ctrl_cdev_ioctl, | ||
| 800 | .owner = THIS_MODULE, | ||
| 801 | }; | ||
| 802 | |||
| 685 | /* UBI character device operations */ | 803 | /* UBI character device operations */ |
| 686 | struct file_operations ubi_cdev_operations = { | 804 | struct file_operations ubi_cdev_operations = { |
| 687 | .owner = THIS_MODULE, | 805 | .owner = THIS_MODULE, |
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 467722eb618b..51c40b17f1ec 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h | |||
| @@ -39,8 +39,9 @@ | |||
| 39 | 39 | ||
| 40 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG | 40 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG |
| 41 | /* Generic debugging message */ | 41 | /* Generic debugging message */ |
| 42 | #define dbg_msg(fmt, ...) \ | 42 | #define dbg_msg(fmt, ...) \ |
| 43 | printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__) | 43 | printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ |
| 44 | current->pid, __FUNCTION__, ##__VA_ARGS__) | ||
| 44 | 45 | ||
| 45 | #define ubi_dbg_dump_stack() dump_stack() | 46 | #define ubi_dbg_dump_stack() dump_stack() |
| 46 | 47 | ||
| @@ -76,36 +77,28 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); | |||
| 76 | 77 | ||
| 77 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA | 78 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA |
| 78 | /* Messages from the eraseblock association unit */ | 79 | /* Messages from the eraseblock association unit */ |
| 79 | #define dbg_eba(fmt, ...) \ | 80 | #define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) |
| 80 | printk(KERN_DEBUG "UBI DBG eba: %s: " fmt "\n", __FUNCTION__, \ | ||
| 81 | ##__VA_ARGS__) | ||
| 82 | #else | 81 | #else |
| 83 | #define dbg_eba(fmt, ...) ({}) | 82 | #define dbg_eba(fmt, ...) ({}) |
| 84 | #endif | 83 | #endif |
| 85 | 84 | ||
| 86 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL | 85 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL |
| 87 | /* Messages from the wear-leveling unit */ | 86 | /* Messages from the wear-leveling unit */ |
| 88 | #define dbg_wl(fmt, ...) \ | 87 | #define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) |
| 89 | printk(KERN_DEBUG "UBI DBG wl: %s: " fmt "\n", __FUNCTION__, \ | ||
| 90 | ##__VA_ARGS__) | ||
| 91 | #else | 88 | #else |
| 92 | #define dbg_wl(fmt, ...) ({}) | 89 | #define dbg_wl(fmt, ...) ({}) |
| 93 | #endif | 90 | #endif |
| 94 | 91 | ||
| 95 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO | 92 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO |
| 96 | /* Messages from the input/output unit */ | 93 | /* Messages from the input/output unit */ |
| 97 | #define dbg_io(fmt, ...) \ | 94 | #define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) |
| 98 | printk(KERN_DEBUG "UBI DBG io: %s: " fmt "\n", __FUNCTION__, \ | ||
| 99 | ##__VA_ARGS__) | ||
| 100 | #else | 95 | #else |
| 101 | #define dbg_io(fmt, ...) ({}) | 96 | #define dbg_io(fmt, ...) ({}) |
| 102 | #endif | 97 | #endif |
| 103 | 98 | ||
| 104 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD | 99 | #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD |
| 105 | /* Initialization and build messages */ | 100 | /* Initialization and build messages */ |
| 106 | #define dbg_bld(fmt, ...) \ | 101 | #define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) |
| 107 | printk(KERN_DEBUG "UBI DBG bld: %s: " fmt "\n", __FUNCTION__, \ | ||
| 108 | ##__VA_ARGS__) | ||
| 109 | #else | 102 | #else |
| 110 | #define dbg_bld(fmt, ...) ({}) | 103 | #define dbg_bld(fmt, ...) ({}) |
| 111 | #endif | 104 | #endif |
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 880fa3690352..7ce91ca742b1 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | * logical eraseblock it is locked for reading or writing. The per-logical | 31 | * logical eraseblock it is locked for reading or writing. The per-logical |
| 32 | * eraseblock locking is implemented by means of the lock tree. The lock tree | 32 | * eraseblock locking is implemented by means of the lock tree. The lock tree |
| 33 | * is an RB-tree which refers all the currently locked logical eraseblocks. The | 33 | * is an RB-tree which refers all the currently locked logical eraseblocks. The |
| 34 | * lock tree elements are &struct ltree_entry objects. They are indexed by | 34 | * lock tree elements are &struct ubi_ltree_entry objects. They are indexed by |
| 35 | * (@vol_id, @lnum) pairs. | 35 | * (@vol_id, @lnum) pairs. |
| 36 | * | 36 | * |
| 37 | * EBA also maintains the global sequence counter which is incremented each | 37 | * EBA also maintains the global sequence counter which is incremented each |
| @@ -50,29 +50,6 @@ | |||
| 50 | #define EBA_RESERVED_PEBS 1 | 50 | #define EBA_RESERVED_PEBS 1 |
| 51 | 51 | ||
| 52 | /** | 52 | /** |
| 53 | * struct ltree_entry - an entry in the lock tree. | ||
| 54 | * @rb: links RB-tree nodes | ||
| 55 | * @vol_id: volume ID of the locked logical eraseblock | ||
| 56 | * @lnum: locked logical eraseblock number | ||
| 57 | * @users: how many tasks are using this logical eraseblock or wait for it | ||
| 58 | * @mutex: read/write mutex to implement read/write access serialization to | ||
| 59 | * the (@vol_id, @lnum) logical eraseblock | ||
| 60 | * | ||
| 61 | * When a logical eraseblock is being locked - corresponding &struct ltree_entry | ||
| 62 | * object is inserted to the lock tree (@ubi->ltree). | ||
| 63 | */ | ||
| 64 | struct ltree_entry { | ||
| 65 | struct rb_node rb; | ||
| 66 | int vol_id; | ||
| 67 | int lnum; | ||
| 68 | int users; | ||
| 69 | struct rw_semaphore mutex; | ||
| 70 | }; | ||
| 71 | |||
| 72 | /* Slab cache for lock-tree entries */ | ||
| 73 | static struct kmem_cache *ltree_slab; | ||
| 74 | |||
| 75 | /** | ||
| 76 | * next_sqnum - get next sequence number. | 53 | * next_sqnum - get next sequence number. |
| 77 | * @ubi: UBI device description object | 54 | * @ubi: UBI device description object |
| 78 | * | 55 | * |
| @@ -101,7 +78,7 @@ static unsigned long long next_sqnum(struct ubi_device *ubi) | |||
| 101 | */ | 78 | */ |
| 102 | static int ubi_get_compat(const struct ubi_device *ubi, int vol_id) | 79 | static int ubi_get_compat(const struct ubi_device *ubi, int vol_id) |
| 103 | { | 80 | { |
| 104 | if (vol_id == UBI_LAYOUT_VOL_ID) | 81 | if (vol_id == UBI_LAYOUT_VOLUME_ID) |
| 105 | return UBI_LAYOUT_VOLUME_COMPAT; | 82 | return UBI_LAYOUT_VOLUME_COMPAT; |
| 106 | return 0; | 83 | return 0; |
| 107 | } | 84 | } |
| @@ -112,20 +89,20 @@ static int ubi_get_compat(const struct ubi_device *ubi, int vol_id) | |||
| 112 | * @vol_id: volume ID | 89 | * @vol_id: volume ID |
| 113 | * @lnum: logical eraseblock number | 90 | * @lnum: logical eraseblock number |
| 114 | * | 91 | * |
| 115 | * This function returns a pointer to the corresponding &struct ltree_entry | 92 | * This function returns a pointer to the corresponding &struct ubi_ltree_entry |
| 116 | * object if the logical eraseblock is locked and %NULL if it is not. | 93 | * object if the logical eraseblock is locked and %NULL if it is not. |
| 117 | * @ubi->ltree_lock has to be locked. | 94 | * @ubi->ltree_lock has to be locked. |
| 118 | */ | 95 | */ |
| 119 | static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, | 96 | static struct ubi_ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, |
| 120 | int lnum) | 97 | int lnum) |
| 121 | { | 98 | { |
| 122 | struct rb_node *p; | 99 | struct rb_node *p; |
| 123 | 100 | ||
| 124 | p = ubi->ltree.rb_node; | 101 | p = ubi->ltree.rb_node; |
| 125 | while (p) { | 102 | while (p) { |
| 126 | struct ltree_entry *le; | 103 | struct ubi_ltree_entry *le; |
| 127 | 104 | ||
| 128 | le = rb_entry(p, struct ltree_entry, rb); | 105 | le = rb_entry(p, struct ubi_ltree_entry, rb); |
| 129 | 106 | ||
| 130 | if (vol_id < le->vol_id) | 107 | if (vol_id < le->vol_id) |
| 131 | p = p->rb_left; | 108 | p = p->rb_left; |
| @@ -155,15 +132,17 @@ static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, | |||
| 155 | * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation | 132 | * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation |
| 156 | * failed. | 133 | * failed. |
| 157 | */ | 134 | */ |
| 158 | static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, | 135 | static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi, |
| 159 | int lnum) | 136 | int vol_id, int lnum) |
| 160 | { | 137 | { |
| 161 | struct ltree_entry *le, *le1, *le_free; | 138 | struct ubi_ltree_entry *le, *le1, *le_free; |
| 162 | 139 | ||
| 163 | le = kmem_cache_alloc(ltree_slab, GFP_NOFS); | 140 | le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS); |
| 164 | if (!le) | 141 | if (!le) |
| 165 | return ERR_PTR(-ENOMEM); | 142 | return ERR_PTR(-ENOMEM); |
| 166 | 143 | ||
| 144 | le->users = 0; | ||
| 145 | init_rwsem(&le->mutex); | ||
| 167 | le->vol_id = vol_id; | 146 | le->vol_id = vol_id; |
| 168 | le->lnum = lnum; | 147 | le->lnum = lnum; |
| 169 | 148 | ||
| @@ -189,7 +168,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, | |||
| 189 | p = &ubi->ltree.rb_node; | 168 | p = &ubi->ltree.rb_node; |
| 190 | while (*p) { | 169 | while (*p) { |
| 191 | parent = *p; | 170 | parent = *p; |
| 192 | le1 = rb_entry(parent, struct ltree_entry, rb); | 171 | le1 = rb_entry(parent, struct ubi_ltree_entry, rb); |
| 193 | 172 | ||
| 194 | if (vol_id < le1->vol_id) | 173 | if (vol_id < le1->vol_id) |
| 195 | p = &(*p)->rb_left; | 174 | p = &(*p)->rb_left; |
| @@ -211,7 +190,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, | |||
| 211 | spin_unlock(&ubi->ltree_lock); | 190 | spin_unlock(&ubi->ltree_lock); |
| 212 | 191 | ||
| 213 | if (le_free) | 192 | if (le_free) |
| 214 | kmem_cache_free(ltree_slab, le_free); | 193 | kfree(le_free); |
| 215 | 194 | ||
| 216 | return le; | 195 | return le; |
| 217 | } | 196 | } |
| @@ -227,7 +206,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id, | |||
| 227 | */ | 206 | */ |
| 228 | static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum) | 207 | static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum) |
| 229 | { | 208 | { |
| 230 | struct ltree_entry *le; | 209 | struct ubi_ltree_entry *le; |
| 231 | 210 | ||
| 232 | le = ltree_add_entry(ubi, vol_id, lnum); | 211 | le = ltree_add_entry(ubi, vol_id, lnum); |
| 233 | if (IS_ERR(le)) | 212 | if (IS_ERR(le)) |
| @@ -245,7 +224,7 @@ static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum) | |||
| 245 | static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) | 224 | static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) |
| 246 | { | 225 | { |
| 247 | int free = 0; | 226 | int free = 0; |
| 248 | struct ltree_entry *le; | 227 | struct ubi_ltree_entry *le; |
| 249 | 228 | ||
| 250 | spin_lock(&ubi->ltree_lock); | 229 | spin_lock(&ubi->ltree_lock); |
| 251 | le = ltree_lookup(ubi, vol_id, lnum); | 230 | le = ltree_lookup(ubi, vol_id, lnum); |
| @@ -259,7 +238,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) | |||
| 259 | 238 | ||
| 260 | up_read(&le->mutex); | 239 | up_read(&le->mutex); |
| 261 | if (free) | 240 | if (free) |
| 262 | kmem_cache_free(ltree_slab, le); | 241 | kfree(le); |
| 263 | } | 242 | } |
| 264 | 243 | ||
| 265 | /** | 244 | /** |
| @@ -273,7 +252,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) | |||
| 273 | */ | 252 | */ |
| 274 | static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) | 253 | static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) |
| 275 | { | 254 | { |
| 276 | struct ltree_entry *le; | 255 | struct ubi_ltree_entry *le; |
| 277 | 256 | ||
| 278 | le = ltree_add_entry(ubi, vol_id, lnum); | 257 | le = ltree_add_entry(ubi, vol_id, lnum); |
| 279 | if (IS_ERR(le)) | 258 | if (IS_ERR(le)) |
| @@ -283,6 +262,44 @@ static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) | |||
| 283 | } | 262 | } |
| 284 | 263 | ||
| 285 | /** | 264 | /** |
| 265 | * leb_write_lock - lock logical eraseblock for writing. | ||
| 266 | * @ubi: UBI device description object | ||
| 267 | * @vol_id: volume ID | ||
| 268 | * @lnum: logical eraseblock number | ||
| 269 | * | ||
| 270 | * This function locks a logical eraseblock for writing if there is no | ||
| 271 | * contention and does nothing if there is contention. Returns %0 in case of | ||
| 272 | * success, %1 in case of contention, and and a negative error code in case of | ||
| 273 | * failure. | ||
| 274 | */ | ||
| 275 | static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum) | ||
| 276 | { | ||
| 277 | int free; | ||
| 278 | struct ubi_ltree_entry *le; | ||
| 279 | |||
| 280 | le = ltree_add_entry(ubi, vol_id, lnum); | ||
| 281 | if (IS_ERR(le)) | ||
| 282 | return PTR_ERR(le); | ||
| 283 | if (down_write_trylock(&le->mutex)) | ||
| 284 | return 0; | ||
| 285 | |||
| 286 | /* Contention, cancel */ | ||
| 287 | spin_lock(&ubi->ltree_lock); | ||
| 288 | le->users -= 1; | ||
| 289 | ubi_assert(le->users >= 0); | ||
| 290 | if (le->users == 0) { | ||
| 291 | rb_erase(&le->rb, &ubi->ltree); | ||
| 292 | free = 1; | ||
| 293 | } else | ||
| 294 | free = 0; | ||
| 295 | spin_unlock(&ubi->ltree_lock); | ||
| 296 | if (free) | ||
| 297 | kfree(le); | ||
| 298 | |||
| 299 | return 1; | ||
| 300 | } | ||
| 301 | |||
| 302 | /** | ||
| 286 | * leb_write_unlock - unlock logical eraseblock. | 303 | * leb_write_unlock - unlock logical eraseblock. |
| 287 | * @ubi: UBI device description object | 304 | * @ubi: UBI device description object |
| 288 | * @vol_id: volume ID | 305 | * @vol_id: volume ID |
| @@ -291,7 +308,7 @@ static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) | |||
| 291 | static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) | 308 | static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) |
| 292 | { | 309 | { |
| 293 | int free; | 310 | int free; |
| 294 | struct ltree_entry *le; | 311 | struct ubi_ltree_entry *le; |
| 295 | 312 | ||
| 296 | spin_lock(&ubi->ltree_lock); | 313 | spin_lock(&ubi->ltree_lock); |
| 297 | le = ltree_lookup(ubi, vol_id, lnum); | 314 | le = ltree_lookup(ubi, vol_id, lnum); |
| @@ -306,23 +323,23 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) | |||
| 306 | 323 | ||
| 307 | up_write(&le->mutex); | 324 | up_write(&le->mutex); |
| 308 | if (free) | 325 | if (free) |
| 309 | kmem_cache_free(ltree_slab, le); | 326 | kfree(le); |
| 310 | } | 327 | } |
| 311 | 328 | ||
| 312 | /** | 329 | /** |
| 313 | * ubi_eba_unmap_leb - un-map logical eraseblock. | 330 | * ubi_eba_unmap_leb - un-map logical eraseblock. |
| 314 | * @ubi: UBI device description object | 331 | * @ubi: UBI device description object |
| 315 | * @vol_id: volume ID | 332 | * @vol: volume description object |
| 316 | * @lnum: logical eraseblock number | 333 | * @lnum: logical eraseblock number |
| 317 | * | 334 | * |
| 318 | * This function un-maps logical eraseblock @lnum and schedules corresponding | 335 | * This function un-maps logical eraseblock @lnum and schedules corresponding |
| 319 | * physical eraseblock for erasure. Returns zero in case of success and a | 336 | * physical eraseblock for erasure. Returns zero in case of success and a |
| 320 | * negative error code in case of failure. | 337 | * negative error code in case of failure. |
| 321 | */ | 338 | */ |
| 322 | int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum) | 339 | int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, |
| 340 | int lnum) | ||
| 323 | { | 341 | { |
| 324 | int idx = vol_id2idx(ubi, vol_id), err, pnum; | 342 | int err, pnum, vol_id = vol->vol_id; |
| 325 | struct ubi_volume *vol = ubi->volumes[idx]; | ||
| 326 | 343 | ||
| 327 | if (ubi->ro_mode) | 344 | if (ubi->ro_mode) |
| 328 | return -EROFS; | 345 | return -EROFS; |
| @@ -349,7 +366,7 @@ out_unlock: | |||
| 349 | /** | 366 | /** |
| 350 | * ubi_eba_read_leb - read data. | 367 | * ubi_eba_read_leb - read data. |
| 351 | * @ubi: UBI device description object | 368 | * @ubi: UBI device description object |
| 352 | * @vol_id: volume ID | 369 | * @vol: volume description object |
| 353 | * @lnum: logical eraseblock number | 370 | * @lnum: logical eraseblock number |
| 354 | * @buf: buffer to store the read data | 371 | * @buf: buffer to store the read data |
| 355 | * @offset: offset from where to read | 372 | * @offset: offset from where to read |
| @@ -365,12 +382,11 @@ out_unlock: | |||
| 365 | * returned for any volume type if an ECC error was detected by the MTD device | 382 | * returned for any volume type if an ECC error was detected by the MTD device |
| 366 | * driver. Other negative error cored may be returned in case of other errors. | 383 | * driver. Other negative error cored may be returned in case of other errors. |
| 367 | */ | 384 | */ |
| 368 | int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, | 385 | int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, |
| 369 | int offset, int len, int check) | 386 | void *buf, int offset, int len, int check) |
| 370 | { | 387 | { |
| 371 | int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id); | 388 | int err, pnum, scrub = 0, vol_id = vol->vol_id; |
| 372 | struct ubi_vid_hdr *vid_hdr; | 389 | struct ubi_vid_hdr *vid_hdr; |
| 373 | struct ubi_volume *vol = ubi->volumes[idx]; | ||
| 374 | uint32_t uninitialized_var(crc); | 390 | uint32_t uninitialized_var(crc); |
| 375 | 391 | ||
| 376 | err = leb_read_lock(ubi, vol_id, lnum); | 392 | err = leb_read_lock(ubi, vol_id, lnum); |
| @@ -578,7 +594,7 @@ write_error: | |||
| 578 | /** | 594 | /** |
| 579 | * ubi_eba_write_leb - write data to dynamic volume. | 595 | * ubi_eba_write_leb - write data to dynamic volume. |
| 580 | * @ubi: UBI device description object | 596 | * @ubi: UBI device description object |
| 581 | * @vol_id: volume ID | 597 | * @vol: volume description object |
| 582 | * @lnum: logical eraseblock number | 598 | * @lnum: logical eraseblock number |
| 583 | * @buf: the data to write | 599 | * @buf: the data to write |
| 584 | * @offset: offset within the logical eraseblock where to write | 600 | * @offset: offset within the logical eraseblock where to write |
| @@ -586,15 +602,14 @@ write_error: | |||
| 586 | * @dtype: data type | 602 | * @dtype: data type |
| 587 | * | 603 | * |
| 588 | * This function writes data to logical eraseblock @lnum of a dynamic volume | 604 | * This function writes data to logical eraseblock @lnum of a dynamic volume |
| 589 | * @vol_id. Returns zero in case of success and a negative error code in case | 605 | * @vol. Returns zero in case of success and a negative error code in case |
| 590 | * of failure. In case of error, it is possible that something was still | 606 | * of failure. In case of error, it is possible that something was still |
| 591 | * written to the flash media, but may be some garbage. | 607 | * written to the flash media, but may be some garbage. |
| 592 | */ | 608 | */ |
| 593 | int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, | 609 | int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, |
| 594 | const void *buf, int offset, int len, int dtype) | 610 | const void *buf, int offset, int len, int dtype) |
| 595 | { | 611 | { |
| 596 | int idx = vol_id2idx(ubi, vol_id), err, pnum, tries = 0; | 612 | int err, pnum, tries = 0, vol_id = vol->vol_id; |
| 597 | struct ubi_volume *vol = ubi->volumes[idx]; | ||
| 598 | struct ubi_vid_hdr *vid_hdr; | 613 | struct ubi_vid_hdr *vid_hdr; |
| 599 | 614 | ||
| 600 | if (ubi->ro_mode) | 615 | if (ubi->ro_mode) |
| @@ -613,7 +628,8 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, | |||
| 613 | if (err) { | 628 | if (err) { |
| 614 | ubi_warn("failed to write data to PEB %d", pnum); | 629 | ubi_warn("failed to write data to PEB %d", pnum); |
| 615 | if (err == -EIO && ubi->bad_allowed) | 630 | if (err == -EIO && ubi->bad_allowed) |
| 616 | err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len); | 631 | err = recover_peb(ubi, pnum, vol_id, lnum, buf, |
| 632 | offset, len); | ||
| 617 | if (err) | 633 | if (err) |
| 618 | ubi_ro_mode(ubi); | 634 | ubi_ro_mode(ubi); |
| 619 | } | 635 | } |
| @@ -656,11 +672,14 @@ retry: | |||
| 656 | goto write_error; | 672 | goto write_error; |
| 657 | } | 673 | } |
| 658 | 674 | ||
| 659 | err = ubi_io_write_data(ubi, buf, pnum, offset, len); | 675 | if (len) { |
| 660 | if (err) { | 676 | err = ubi_io_write_data(ubi, buf, pnum, offset, len); |
| 661 | ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, " | 677 | if (err) { |
| 662 | "PEB %d", len, offset, vol_id, lnum, pnum); | 678 | ubi_warn("failed to write %d bytes at offset %d of " |
| 663 | goto write_error; | 679 | "LEB %d:%d, PEB %d", len, offset, vol_id, |
| 680 | lnum, pnum); | ||
| 681 | goto write_error; | ||
| 682 | } | ||
| 664 | } | 683 | } |
| 665 | 684 | ||
| 666 | vol->eba_tbl[lnum] = pnum; | 685 | vol->eba_tbl[lnum] = pnum; |
| @@ -698,7 +717,7 @@ write_error: | |||
| 698 | /** | 717 | /** |
| 699 | * ubi_eba_write_leb_st - write data to static volume. | 718 | * ubi_eba_write_leb_st - write data to static volume. |
| 700 | * @ubi: UBI device description object | 719 | * @ubi: UBI device description object |
| 701 | * @vol_id: volume ID | 720 | * @vol: volume description object |
| 702 | * @lnum: logical eraseblock number | 721 | * @lnum: logical eraseblock number |
| 703 | * @buf: data to write | 722 | * @buf: data to write |
| 704 | * @len: how many bytes to write | 723 | * @len: how many bytes to write |
| @@ -706,7 +725,7 @@ write_error: | |||
| 706 | * @used_ebs: how many logical eraseblocks will this volume contain | 725 | * @used_ebs: how many logical eraseblocks will this volume contain |
| 707 | * | 726 | * |
| 708 | * This function writes data to logical eraseblock @lnum of static volume | 727 | * This function writes data to logical eraseblock @lnum of static volume |
| 709 | * @vol_id. The @used_ebs argument should contain total number of logical | 728 | * @vol. The @used_ebs argument should contain total number of logical |
| 710 | * eraseblock in this static volume. | 729 | * eraseblock in this static volume. |
| 711 | * | 730 | * |
| 712 | * When writing to the last logical eraseblock, the @len argument doesn't have | 731 | * When writing to the last logical eraseblock, the @len argument doesn't have |
| @@ -718,12 +737,11 @@ write_error: | |||
| 718 | * volumes. This function returns zero in case of success and a negative error | 737 | * volumes. This function returns zero in case of success and a negative error |
| 719 | * code in case of failure. | 738 | * code in case of failure. |
| 720 | */ | 739 | */ |
| 721 | int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, | 740 | int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, |
| 722 | const void *buf, int len, int dtype, int used_ebs) | 741 | int lnum, const void *buf, int len, int dtype, |
| 742 | int used_ebs) | ||
| 723 | { | 743 | { |
| 724 | int err, pnum, tries = 0, data_size = len; | 744 | int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id; |
| 725 | int idx = vol_id2idx(ubi, vol_id); | ||
| 726 | struct ubi_volume *vol = ubi->volumes[idx]; | ||
| 727 | struct ubi_vid_hdr *vid_hdr; | 745 | struct ubi_vid_hdr *vid_hdr; |
| 728 | uint32_t crc; | 746 | uint32_t crc; |
| 729 | 747 | ||
| @@ -819,7 +837,7 @@ write_error: | |||
| 819 | /* | 837 | /* |
| 820 | * ubi_eba_atomic_leb_change - change logical eraseblock atomically. | 838 | * ubi_eba_atomic_leb_change - change logical eraseblock atomically. |
| 821 | * @ubi: UBI device description object | 839 | * @ubi: UBI device description object |
| 822 | * @vol_id: volume ID | 840 | * @vol: volume description object |
| 823 | * @lnum: logical eraseblock number | 841 | * @lnum: logical eraseblock number |
| 824 | * @buf: data to write | 842 | * @buf: data to write |
| 825 | * @len: how many bytes to write | 843 | * @len: how many bytes to write |
| @@ -834,17 +852,27 @@ write_error: | |||
| 834 | * UBI reserves one LEB for the "atomic LEB change" operation, so only one | 852 | * UBI reserves one LEB for the "atomic LEB change" operation, so only one |
| 835 | * LEB change may be done at a time. This is ensured by @ubi->alc_mutex. | 853 | * LEB change may be done at a time. This is ensured by @ubi->alc_mutex. |
| 836 | */ | 854 | */ |
| 837 | int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, | 855 | int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, |
| 838 | const void *buf, int len, int dtype) | 856 | int lnum, const void *buf, int len, int dtype) |
| 839 | { | 857 | { |
| 840 | int err, pnum, tries = 0, idx = vol_id2idx(ubi, vol_id); | 858 | int err, pnum, tries = 0, vol_id = vol->vol_id; |
| 841 | struct ubi_volume *vol = ubi->volumes[idx]; | ||
| 842 | struct ubi_vid_hdr *vid_hdr; | 859 | struct ubi_vid_hdr *vid_hdr; |
| 843 | uint32_t crc; | 860 | uint32_t crc; |
| 844 | 861 | ||
| 845 | if (ubi->ro_mode) | 862 | if (ubi->ro_mode) |
| 846 | return -EROFS; | 863 | return -EROFS; |
| 847 | 864 | ||
| 865 | if (len == 0) { | ||
| 866 | /* | ||
| 867 | * Special case when data length is zero. In this case the LEB | ||
| 868 | * has to be unmapped and mapped somewhere else. | ||
| 869 | */ | ||
| 870 | err = ubi_eba_unmap_leb(ubi, vol, lnum); | ||
| 871 | if (err) | ||
| 872 | return err; | ||
| 873 | return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); | ||
| 874 | } | ||
| 875 | |||
| 848 | vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); | 876 | vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); |
| 849 | if (!vid_hdr) | 877 | if (!vid_hdr) |
| 850 | return -ENOMEM; | 878 | return -ENOMEM; |
| @@ -928,20 +956,6 @@ write_error: | |||
| 928 | } | 956 | } |
| 929 | 957 | ||
| 930 | /** | 958 | /** |
| 931 | * ltree_entry_ctor - lock tree entries slab cache constructor. | ||
| 932 | * @obj: the lock-tree entry to construct | ||
| 933 | * @cache: the lock tree entry slab cache | ||
| 934 | * @flags: constructor flags | ||
| 935 | */ | ||
| 936 | static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) | ||
| 937 | { | ||
| 938 | struct ltree_entry *le = obj; | ||
| 939 | |||
| 940 | le->users = 0; | ||
| 941 | init_rwsem(&le->mutex); | ||
| 942 | } | ||
| 943 | |||
| 944 | /** | ||
| 945 | * ubi_eba_copy_leb - copy logical eraseblock. | 959 | * ubi_eba_copy_leb - copy logical eraseblock. |
| 946 | * @ubi: UBI device description object | 960 | * @ubi: UBI device description object |
| 947 | * @from: physical eraseblock number from where to copy | 961 | * @from: physical eraseblock number from where to copy |
| @@ -950,14 +964,16 @@ static void ltree_entry_ctor(struct kmem_cache *cache, void *obj) | |||
| 950 | * | 964 | * |
| 951 | * This function copies logical eraseblock from physical eraseblock @from to | 965 | * This function copies logical eraseblock from physical eraseblock @from to |
| 952 | * physical eraseblock @to. The @vid_hdr buffer may be changed by this | 966 | * physical eraseblock @to. The @vid_hdr buffer may be changed by this |
| 953 | * function. Returns zero in case of success, %UBI_IO_BITFLIPS if the operation | 967 | * function. Returns: |
| 954 | * was canceled because bit-flips were detected at the target PEB, and a | 968 | * o %0 in case of success; |
| 955 | * negative error code in case of failure. | 969 | * o %1 if the operation was canceled and should be tried later (e.g., |
| 970 | * because a bit-flip was detected at the target PEB); | ||
| 971 | * o %2 if the volume is being deleted and this LEB should not be moved. | ||
| 956 | */ | 972 | */ |
| 957 | int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | 973 | int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, |
| 958 | struct ubi_vid_hdr *vid_hdr) | 974 | struct ubi_vid_hdr *vid_hdr) |
| 959 | { | 975 | { |
| 960 | int err, vol_id, lnum, data_size, aldata_size, pnum, idx; | 976 | int err, vol_id, lnum, data_size, aldata_size, idx; |
| 961 | struct ubi_volume *vol; | 977 | struct ubi_volume *vol; |
| 962 | uint32_t crc; | 978 | uint32_t crc; |
| 963 | 979 | ||
| @@ -973,51 +989,67 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
| 973 | data_size = aldata_size = | 989 | data_size = aldata_size = |
| 974 | ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); | 990 | ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); |
| 975 | 991 | ||
| 976 | /* | ||
| 977 | * We do not want anybody to write to this logical eraseblock while we | ||
| 978 | * are moving it, so we lock it. | ||
| 979 | */ | ||
| 980 | err = leb_write_lock(ubi, vol_id, lnum); | ||
| 981 | if (err) | ||
| 982 | return err; | ||
| 983 | |||
| 984 | mutex_lock(&ubi->buf_mutex); | ||
| 985 | |||
| 986 | /* | ||
| 987 | * But the logical eraseblock might have been put by this time. | ||
| 988 | * Cancel if it is true. | ||
| 989 | */ | ||
| 990 | idx = vol_id2idx(ubi, vol_id); | 992 | idx = vol_id2idx(ubi, vol_id); |
| 991 | 993 | spin_lock(&ubi->volumes_lock); | |
| 992 | /* | 994 | /* |
| 993 | * We may race with volume deletion/re-size, so we have to hold | 995 | * Note, we may race with volume deletion, which means that the volume |
| 994 | * @ubi->volumes_lock. | 996 | * this logical eraseblock belongs to might be being deleted. Since the |
| 997 | * volume deletion unmaps all the volume's logical eraseblocks, it will | ||
| 998 | * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish. | ||
| 995 | */ | 999 | */ |
| 996 | spin_lock(&ubi->volumes_lock); | ||
| 997 | vol = ubi->volumes[idx]; | 1000 | vol = ubi->volumes[idx]; |
| 998 | if (!vol) { | 1001 | if (!vol) { |
| 999 | dbg_eba("volume %d was removed meanwhile", vol_id); | 1002 | /* No need to do further work, cancel */ |
| 1003 | dbg_eba("volume %d is being removed, cancel", vol_id); | ||
| 1000 | spin_unlock(&ubi->volumes_lock); | 1004 | spin_unlock(&ubi->volumes_lock); |
| 1001 | goto out_unlock; | 1005 | return 2; |
| 1002 | } | 1006 | } |
| 1007 | spin_unlock(&ubi->volumes_lock); | ||
| 1003 | 1008 | ||
| 1004 | pnum = vol->eba_tbl[lnum]; | 1009 | /* |
| 1005 | if (pnum != from) { | 1010 | * We do not want anybody to write to this logical eraseblock while we |
| 1006 | dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " | 1011 | * are moving it, so lock it. |
| 1007 | "PEB %d, cancel", vol_id, lnum, from, pnum); | 1012 | * |
| 1008 | spin_unlock(&ubi->volumes_lock); | 1013 | * Note, we are using non-waiting locking here, because we cannot sleep |
| 1009 | goto out_unlock; | 1014 | * on the LEB, since it may cause deadlocks. Indeed, imagine a task is |
| 1015 | * unmapping the LEB which is mapped to the PEB we are going to move | ||
| 1016 | * (@from). This task locks the LEB and goes sleep in the | ||
| 1017 | * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are | ||
| 1018 | * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the | ||
| 1019 | * LEB is already locked, we just do not move it and return %1. | ||
| 1020 | */ | ||
| 1021 | err = leb_write_trylock(ubi, vol_id, lnum); | ||
| 1022 | if (err) { | ||
| 1023 | dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum); | ||
| 1024 | return err; | ||
| 1010 | } | 1025 | } |
| 1011 | spin_unlock(&ubi->volumes_lock); | ||
| 1012 | 1026 | ||
| 1013 | /* OK, now the LEB is locked and we can safely start moving it */ | 1027 | /* |
| 1028 | * The LEB might have been put meanwhile, and the task which put it is | ||
| 1029 | * probably waiting on @ubi->move_mutex. No need to continue the work, | ||
| 1030 | * cancel it. | ||
| 1031 | */ | ||
| 1032 | if (vol->eba_tbl[lnum] != from) { | ||
| 1033 | dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " | ||
| 1034 | "PEB %d, cancel", vol_id, lnum, from, | ||
| 1035 | vol->eba_tbl[lnum]); | ||
| 1036 | err = 1; | ||
| 1037 | goto out_unlock_leb; | ||
| 1038 | } | ||
| 1014 | 1039 | ||
| 1040 | /* | ||
| 1041 | * OK, now the LEB is locked and we can safely start moving iy. Since | ||
| 1042 | * this function utilizes thie @ubi->peb1_buf buffer which is shared | ||
| 1043 | * with some other functions, so lock the buffer by taking the | ||
| 1044 | * @ubi->buf_mutex. | ||
| 1045 | */ | ||
| 1046 | mutex_lock(&ubi->buf_mutex); | ||
| 1015 | dbg_eba("read %d bytes of data", aldata_size); | 1047 | dbg_eba("read %d bytes of data", aldata_size); |
| 1016 | err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); | 1048 | err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); |
| 1017 | if (err && err != UBI_IO_BITFLIPS) { | 1049 | if (err && err != UBI_IO_BITFLIPS) { |
| 1018 | ubi_warn("error %d while reading data from PEB %d", | 1050 | ubi_warn("error %d while reading data from PEB %d", |
| 1019 | err, from); | 1051 | err, from); |
| 1020 | goto out_unlock; | 1052 | goto out_unlock_buf; |
| 1021 | } | 1053 | } |
| 1022 | 1054 | ||
| 1023 | /* | 1055 | /* |
| @@ -1053,7 +1085,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
| 1053 | 1085 | ||
| 1054 | err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); | 1086 | err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); |
| 1055 | if (err) | 1087 | if (err) |
| 1056 | goto out_unlock; | 1088 | goto out_unlock_buf; |
| 1057 | 1089 | ||
| 1058 | cond_resched(); | 1090 | cond_resched(); |
| 1059 | 1091 | ||
| @@ -1062,13 +1094,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
| 1062 | if (err) { | 1094 | if (err) { |
| 1063 | if (err != UBI_IO_BITFLIPS) | 1095 | if (err != UBI_IO_BITFLIPS) |
| 1064 | ubi_warn("cannot read VID header back from PEB %d", to); | 1096 | ubi_warn("cannot read VID header back from PEB %d", to); |
| 1065 | goto out_unlock; | 1097 | else |
| 1098 | err = 1; | ||
| 1099 | goto out_unlock_buf; | ||
| 1066 | } | 1100 | } |
| 1067 | 1101 | ||
| 1068 | if (data_size > 0) { | 1102 | if (data_size > 0) { |
| 1069 | err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); | 1103 | err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); |
| 1070 | if (err) | 1104 | if (err) |
| 1071 | goto out_unlock; | 1105 | goto out_unlock_buf; |
| 1072 | 1106 | ||
| 1073 | cond_resched(); | 1107 | cond_resched(); |
| 1074 | 1108 | ||
| @@ -1082,7 +1116,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
| 1082 | if (err != UBI_IO_BITFLIPS) | 1116 | if (err != UBI_IO_BITFLIPS) |
| 1083 | ubi_warn("cannot read data back from PEB %d", | 1117 | ubi_warn("cannot read data back from PEB %d", |
| 1084 | to); | 1118 | to); |
| 1085 | goto out_unlock; | 1119 | else |
| 1120 | err = 1; | ||
| 1121 | goto out_unlock_buf; | ||
| 1086 | } | 1122 | } |
| 1087 | 1123 | ||
| 1088 | cond_resched(); | 1124 | cond_resched(); |
| @@ -1090,15 +1126,16 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | |||
| 1090 | if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { | 1126 | if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { |
| 1091 | ubi_warn("read data back from PEB %d - it is different", | 1127 | ubi_warn("read data back from PEB %d - it is different", |
| 1092 | to); | 1128 | to); |
| 1093 | goto out_unlock; | 1129 | goto out_unlock_buf; |
| 1094 | } | 1130 | } |
| 1095 | } | 1131 | } |
| 1096 | 1132 | ||
| 1097 | ubi_assert(vol->eba_tbl[lnum] == from); | 1133 | ubi_assert(vol->eba_tbl[lnum] == from); |
| 1098 | vol->eba_tbl[lnum] = to; | 1134 | vol->eba_tbl[lnum] = to; |
| 1099 | 1135 | ||
| 1100 | out_unlock: | 1136 | out_unlock_buf: |
| 1101 | mutex_unlock(&ubi->buf_mutex); | 1137 | mutex_unlock(&ubi->buf_mutex); |
| 1138 | out_unlock_leb: | ||
| 1102 | leb_write_unlock(ubi, vol_id, lnum); | 1139 | leb_write_unlock(ubi, vol_id, lnum); |
| 1103 | return err; | 1140 | return err; |
| 1104 | } | 1141 | } |
| @@ -1125,14 +1162,6 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1125 | mutex_init(&ubi->alc_mutex); | 1162 | mutex_init(&ubi->alc_mutex); |
| 1126 | ubi->ltree = RB_ROOT; | 1163 | ubi->ltree = RB_ROOT; |
| 1127 | 1164 | ||
| 1128 | if (ubi_devices_cnt == 0) { | ||
| 1129 | ltree_slab = kmem_cache_create("ubi_ltree_slab", | ||
| 1130 | sizeof(struct ltree_entry), 0, | ||
| 1131 | 0, <ree_entry_ctor); | ||
| 1132 | if (!ltree_slab) | ||
| 1133 | return -ENOMEM; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | ubi->global_sqnum = si->max_sqnum + 1; | 1165 | ubi->global_sqnum = si->max_sqnum + 1; |
| 1137 | num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; | 1166 | num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; |
| 1138 | 1167 | ||
| @@ -1168,6 +1197,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1168 | } | 1197 | } |
| 1169 | } | 1198 | } |
| 1170 | 1199 | ||
| 1200 | if (ubi->avail_pebs < EBA_RESERVED_PEBS) { | ||
| 1201 | ubi_err("no enough physical eraseblocks (%d, need %d)", | ||
| 1202 | ubi->avail_pebs, EBA_RESERVED_PEBS); | ||
| 1203 | err = -ENOSPC; | ||
| 1204 | goto out_free; | ||
| 1205 | } | ||
| 1206 | ubi->avail_pebs -= EBA_RESERVED_PEBS; | ||
| 1207 | ubi->rsvd_pebs += EBA_RESERVED_PEBS; | ||
| 1208 | |||
| 1171 | if (ubi->bad_allowed) { | 1209 | if (ubi->bad_allowed) { |
| 1172 | ubi_calculate_reserved(ubi); | 1210 | ubi_calculate_reserved(ubi); |
| 1173 | 1211 | ||
| @@ -1184,15 +1222,6 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1184 | ubi->rsvd_pebs += ubi->beb_rsvd_pebs; | 1222 | ubi->rsvd_pebs += ubi->beb_rsvd_pebs; |
| 1185 | } | 1223 | } |
| 1186 | 1224 | ||
| 1187 | if (ubi->avail_pebs < EBA_RESERVED_PEBS) { | ||
| 1188 | ubi_err("no enough physical eraseblocks (%d, need %d)", | ||
| 1189 | ubi->avail_pebs, EBA_RESERVED_PEBS); | ||
| 1190 | err = -ENOSPC; | ||
| 1191 | goto out_free; | ||
| 1192 | } | ||
| 1193 | ubi->avail_pebs -= EBA_RESERVED_PEBS; | ||
| 1194 | ubi->rsvd_pebs += EBA_RESERVED_PEBS; | ||
| 1195 | |||
| 1196 | dbg_eba("EBA unit is initialized"); | 1225 | dbg_eba("EBA unit is initialized"); |
| 1197 | return 0; | 1226 | return 0; |
| 1198 | 1227 | ||
| @@ -1202,8 +1231,6 @@ out_free: | |||
| 1202 | continue; | 1231 | continue; |
| 1203 | kfree(ubi->volumes[i]->eba_tbl); | 1232 | kfree(ubi->volumes[i]->eba_tbl); |
| 1204 | } | 1233 | } |
| 1205 | if (ubi_devices_cnt == 0) | ||
| 1206 | kmem_cache_destroy(ltree_slab); | ||
| 1207 | return err; | 1234 | return err; |
| 1208 | } | 1235 | } |
| 1209 | 1236 | ||
| @@ -1222,6 +1249,4 @@ void ubi_eba_close(const struct ubi_device *ubi) | |||
| 1222 | continue; | 1249 | continue; |
| 1223 | kfree(ubi->volumes[i]->eba_tbl); | 1250 | kfree(ubi->volumes[i]->eba_tbl); |
| 1224 | } | 1251 | } |
| 1225 | if (ubi_devices_cnt == 1) | ||
| 1226 | kmem_cache_destroy(ltree_slab); | ||
| 1227 | } | 1252 | } |
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index 41ff74c60e14..d397219238d3 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c | |||
| @@ -129,8 +129,7 @@ static int gluebi_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
| 129 | if (to_read > total_read) | 129 | if (to_read > total_read) |
| 130 | to_read = total_read; | 130 | to_read = total_read; |
| 131 | 131 | ||
| 132 | err = ubi_eba_read_leb(ubi, vol->vol_id, lnum, buf, offs, | 132 | err = ubi_eba_read_leb(ubi, vol, lnum, buf, offs, to_read, 0); |
| 133 | to_read, 0); | ||
| 134 | if (err) | 133 | if (err) |
| 135 | break; | 134 | break; |
| 136 | 135 | ||
| @@ -187,8 +186,8 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
| 187 | if (to_write > total_written) | 186 | if (to_write > total_written) |
| 188 | to_write = total_written; | 187 | to_write = total_written; |
| 189 | 188 | ||
| 190 | err = ubi_eba_write_leb(ubi, vol->vol_id, lnum, buf, offs, | 189 | err = ubi_eba_write_leb(ubi, vol, lnum, buf, offs, to_write, |
| 191 | to_write, UBI_UNKNOWN); | 190 | UBI_UNKNOWN); |
| 192 | if (err) | 191 | if (err) |
| 193 | break; | 192 | break; |
| 194 | 193 | ||
| @@ -237,7 +236,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) | |||
| 237 | return -EROFS; | 236 | return -EROFS; |
| 238 | 237 | ||
| 239 | for (i = 0; i < count; i++) { | 238 | for (i = 0; i < count; i++) { |
| 240 | err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum + i); | 239 | err = ubi_eba_unmap_leb(ubi, vol, lnum + i); |
| 241 | if (err) | 240 | if (err) |
| 242 | goto out_err; | 241 | goto out_err; |
| 243 | } | 242 | } |
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 7c304eec78b5..db3efdef2433 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c | |||
| @@ -173,6 +173,16 @@ retry: | |||
| 173 | ubi_err("error %d while reading %d bytes from PEB %d:%d, " | 173 | ubi_err("error %d while reading %d bytes from PEB %d:%d, " |
| 174 | "read %zd bytes", err, len, pnum, offset, read); | 174 | "read %zd bytes", err, len, pnum, offset, read); |
| 175 | ubi_dbg_dump_stack(); | 175 | ubi_dbg_dump_stack(); |
| 176 | |||
| 177 | /* | ||
| 178 | * The driver should never return -EBADMSG if it failed to read | ||
| 179 | * all the requested data. But some buggy drivers might do | ||
| 180 | * this, so we change it to -EIO. | ||
| 181 | */ | ||
| 182 | if (read != len && err == -EBADMSG) { | ||
| 183 | ubi_assert(0); | ||
| 184 | err = -EIO; | ||
| 185 | } | ||
| 176 | } else { | 186 | } else { |
| 177 | ubi_assert(len == read); | 187 | ubi_assert(len == read); |
| 178 | 188 | ||
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 03c774f41549..a70d58823f8d 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c | |||
| @@ -30,23 +30,27 @@ | |||
| 30 | * @ubi_num: UBI device number | 30 | * @ubi_num: UBI device number |
| 31 | * @di: the information is stored here | 31 | * @di: the information is stored here |
| 32 | * | 32 | * |
| 33 | * This function returns %0 in case of success and a %-ENODEV if there is no | 33 | * This function returns %0 in case of success, %-EINVAL if the UBI device |
| 34 | * such UBI device. | 34 | * number is invalid, and %-ENODEV if there is no such UBI device. |
| 35 | */ | 35 | */ |
| 36 | int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) | 36 | int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) |
| 37 | { | 37 | { |
| 38 | const struct ubi_device *ubi; | 38 | struct ubi_device *ubi; |
| 39 | |||
| 40 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) | ||
| 41 | return -EINVAL; | ||
| 39 | 42 | ||
| 40 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || | 43 | ubi = ubi_get_device(ubi_num); |
| 41 | !ubi_devices[ubi_num]) | 44 | if (!ubi) |
| 42 | return -ENODEV; | 45 | return -ENODEV; |
| 43 | 46 | ||
| 44 | ubi = ubi_devices[ubi_num]; | ||
| 45 | di->ubi_num = ubi->ubi_num; | 47 | di->ubi_num = ubi->ubi_num; |
| 46 | di->leb_size = ubi->leb_size; | 48 | di->leb_size = ubi->leb_size; |
| 47 | di->min_io_size = ubi->min_io_size; | 49 | di->min_io_size = ubi->min_io_size; |
| 48 | di->ro_mode = ubi->ro_mode; | 50 | di->ro_mode = ubi->ro_mode; |
| 49 | di->cdev = MKDEV(ubi->major, 0); | 51 | di->cdev = ubi->cdev.dev; |
| 52 | |||
| 53 | ubi_put_device(ubi); | ||
| 50 | return 0; | 54 | return 0; |
| 51 | } | 55 | } |
| 52 | EXPORT_SYMBOL_GPL(ubi_get_device_info); | 56 | EXPORT_SYMBOL_GPL(ubi_get_device_info); |
| @@ -73,7 +77,7 @@ void ubi_get_volume_info(struct ubi_volume_desc *desc, | |||
| 73 | vi->usable_leb_size = vol->usable_leb_size; | 77 | vi->usable_leb_size = vol->usable_leb_size; |
| 74 | vi->name_len = vol->name_len; | 78 | vi->name_len = vol->name_len; |
| 75 | vi->name = vol->name; | 79 | vi->name = vol->name; |
| 76 | vi->cdev = MKDEV(ubi->major, vi->vol_id + 1); | 80 | vi->cdev = vol->cdev.dev; |
| 77 | } | 81 | } |
| 78 | EXPORT_SYMBOL_GPL(ubi_get_volume_info); | 82 | EXPORT_SYMBOL_GPL(ubi_get_volume_info); |
| 79 | 83 | ||
| @@ -104,37 +108,39 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) | |||
| 104 | 108 | ||
| 105 | dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); | 109 | dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); |
| 106 | 110 | ||
| 107 | err = -ENODEV; | 111 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) |
| 108 | if (ubi_num < 0) | 112 | return ERR_PTR(-EINVAL); |
| 109 | return ERR_PTR(err); | ||
| 110 | |||
| 111 | ubi = ubi_devices[ubi_num]; | ||
| 112 | |||
| 113 | if (!try_module_get(THIS_MODULE)) | ||
| 114 | return ERR_PTR(err); | ||
| 115 | |||
| 116 | if (ubi_num >= UBI_MAX_DEVICES || !ubi) | ||
| 117 | goto out_put; | ||
| 118 | 113 | ||
| 119 | err = -EINVAL; | ||
| 120 | if (vol_id < 0 || vol_id >= ubi->vtbl_slots) | ||
| 121 | goto out_put; | ||
| 122 | if (mode != UBI_READONLY && mode != UBI_READWRITE && | 114 | if (mode != UBI_READONLY && mode != UBI_READWRITE && |
| 123 | mode != UBI_EXCLUSIVE) | 115 | mode != UBI_EXCLUSIVE) |
| 124 | goto out_put; | 116 | return ERR_PTR(-EINVAL); |
| 117 | |||
| 118 | /* | ||
| 119 | * First of all, we have to get the UBI device to prevent its removal. | ||
| 120 | */ | ||
| 121 | ubi = ubi_get_device(ubi_num); | ||
| 122 | if (!ubi) | ||
| 123 | return ERR_PTR(-ENODEV); | ||
| 124 | |||
| 125 | if (vol_id < 0 || vol_id >= ubi->vtbl_slots) { | ||
| 126 | err = -EINVAL; | ||
| 127 | goto out_put_ubi; | ||
| 128 | } | ||
| 125 | 129 | ||
| 126 | desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); | 130 | desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); |
| 127 | if (!desc) { | 131 | if (!desc) { |
| 128 | err = -ENOMEM; | 132 | err = -ENOMEM; |
| 129 | goto out_put; | 133 | goto out_put_ubi; |
| 130 | } | 134 | } |
| 131 | 135 | ||
| 136 | err = -ENODEV; | ||
| 137 | if (!try_module_get(THIS_MODULE)) | ||
| 138 | goto out_free; | ||
| 139 | |||
| 132 | spin_lock(&ubi->volumes_lock); | 140 | spin_lock(&ubi->volumes_lock); |
| 133 | vol = ubi->volumes[vol_id]; | 141 | vol = ubi->volumes[vol_id]; |
| 134 | if (!vol) { | 142 | if (!vol) |
| 135 | err = -ENODEV; | ||
| 136 | goto out_unlock; | 143 | goto out_unlock; |
| 137 | } | ||
| 138 | 144 | ||
| 139 | err = -EBUSY; | 145 | err = -EBUSY; |
| 140 | switch (mode) { | 146 | switch (mode) { |
| @@ -156,21 +162,19 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) | |||
| 156 | vol->exclusive = 1; | 162 | vol->exclusive = 1; |
| 157 | break; | 163 | break; |
| 158 | } | 164 | } |
| 165 | get_device(&vol->dev); | ||
| 166 | vol->ref_count += 1; | ||
| 159 | spin_unlock(&ubi->volumes_lock); | 167 | spin_unlock(&ubi->volumes_lock); |
| 160 | 168 | ||
| 161 | desc->vol = vol; | 169 | desc->vol = vol; |
| 162 | desc->mode = mode; | 170 | desc->mode = mode; |
| 163 | 171 | ||
| 164 | /* | 172 | mutex_lock(&ubi->ckvol_mutex); |
| 165 | * To prevent simultaneous checks of the same volume we use @vtbl_mutex, | ||
| 166 | * although it is not the purpose it was introduced for. | ||
| 167 | */ | ||
| 168 | mutex_lock(&ubi->vtbl_mutex); | ||
| 169 | if (!vol->checked) { | 173 | if (!vol->checked) { |
| 170 | /* This is the first open - check the volume */ | 174 | /* This is the first open - check the volume */ |
| 171 | err = ubi_check_volume(ubi, vol_id); | 175 | err = ubi_check_volume(ubi, vol_id); |
| 172 | if (err < 0) { | 176 | if (err < 0) { |
| 173 | mutex_unlock(&ubi->vtbl_mutex); | 177 | mutex_unlock(&ubi->ckvol_mutex); |
| 174 | ubi_close_volume(desc); | 178 | ubi_close_volume(desc); |
| 175 | return ERR_PTR(err); | 179 | return ERR_PTR(err); |
| 176 | } | 180 | } |
| @@ -181,14 +185,17 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) | |||
| 181 | } | 185 | } |
| 182 | vol->checked = 1; | 186 | vol->checked = 1; |
| 183 | } | 187 | } |
| 184 | mutex_unlock(&ubi->vtbl_mutex); | 188 | mutex_unlock(&ubi->ckvol_mutex); |
| 189 | |||
| 185 | return desc; | 190 | return desc; |
| 186 | 191 | ||
| 187 | out_unlock: | 192 | out_unlock: |
| 188 | spin_unlock(&ubi->volumes_lock); | 193 | spin_unlock(&ubi->volumes_lock); |
| 189 | kfree(desc); | ||
| 190 | out_put: | ||
| 191 | module_put(THIS_MODULE); | 194 | module_put(THIS_MODULE); |
| 195 | out_free: | ||
| 196 | kfree(desc); | ||
| 197 | out_put_ubi: | ||
| 198 | ubi_put_device(ubi); | ||
| 192 | return ERR_PTR(err); | 199 | return ERR_PTR(err); |
| 193 | } | 200 | } |
| 194 | EXPORT_SYMBOL_GPL(ubi_open_volume); | 201 | EXPORT_SYMBOL_GPL(ubi_open_volume); |
| @@ -205,8 +212,8 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, | |||
| 205 | int mode) | 212 | int mode) |
| 206 | { | 213 | { |
| 207 | int i, vol_id = -1, len; | 214 | int i, vol_id = -1, len; |
| 208 | struct ubi_volume_desc *ret; | ||
| 209 | struct ubi_device *ubi; | 215 | struct ubi_device *ubi; |
| 216 | struct ubi_volume_desc *ret; | ||
| 210 | 217 | ||
| 211 | dbg_msg("open volume %s, mode %d", name, mode); | 218 | dbg_msg("open volume %s, mode %d", name, mode); |
| 212 | 219 | ||
| @@ -217,14 +224,12 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, | |||
| 217 | if (len > UBI_VOL_NAME_MAX) | 224 | if (len > UBI_VOL_NAME_MAX) |
| 218 | return ERR_PTR(-EINVAL); | 225 | return ERR_PTR(-EINVAL); |
| 219 | 226 | ||
| 220 | ret = ERR_PTR(-ENODEV); | 227 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) |
| 221 | if (!try_module_get(THIS_MODULE)) | 228 | return ERR_PTR(-EINVAL); |
| 222 | return ret; | ||
| 223 | |||
| 224 | if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES || !ubi_devices[ubi_num]) | ||
| 225 | goto out_put; | ||
| 226 | 229 | ||
| 227 | ubi = ubi_devices[ubi_num]; | 230 | ubi = ubi_get_device(ubi_num); |
| 231 | if (!ubi) | ||
| 232 | return ERR_PTR(-ENODEV); | ||
| 228 | 233 | ||
| 229 | spin_lock(&ubi->volumes_lock); | 234 | spin_lock(&ubi->volumes_lock); |
| 230 | /* Walk all volumes of this UBI device */ | 235 | /* Walk all volumes of this UBI device */ |
| @@ -238,13 +243,16 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, | |||
| 238 | } | 243 | } |
| 239 | spin_unlock(&ubi->volumes_lock); | 244 | spin_unlock(&ubi->volumes_lock); |
| 240 | 245 | ||
| 241 | if (vol_id < 0) | 246 | if (vol_id >= 0) |
| 242 | goto out_put; | 247 | ret = ubi_open_volume(ubi_num, vol_id, mode); |
| 248 | else | ||
| 249 | ret = ERR_PTR(-ENODEV); | ||
| 243 | 250 | ||
| 244 | ret = ubi_open_volume(ubi_num, vol_id, mode); | 251 | /* |
| 245 | 252 | * We should put the UBI device even in case of success, because | |
| 246 | out_put: | 253 | * 'ubi_open_volume()' took a reference as well. |
| 247 | module_put(THIS_MODULE); | 254 | */ |
| 255 | ubi_put_device(ubi); | ||
| 248 | return ret; | 256 | return ret; |
| 249 | } | 257 | } |
| 250 | EXPORT_SYMBOL_GPL(ubi_open_volume_nm); | 258 | EXPORT_SYMBOL_GPL(ubi_open_volume_nm); |
| @@ -256,10 +264,11 @@ EXPORT_SYMBOL_GPL(ubi_open_volume_nm); | |||
| 256 | void ubi_close_volume(struct ubi_volume_desc *desc) | 264 | void ubi_close_volume(struct ubi_volume_desc *desc) |
| 257 | { | 265 | { |
| 258 | struct ubi_volume *vol = desc->vol; | 266 | struct ubi_volume *vol = desc->vol; |
| 267 | struct ubi_device *ubi = vol->ubi; | ||
| 259 | 268 | ||
| 260 | dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); | 269 | dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); |
| 261 | 270 | ||
| 262 | spin_lock(&vol->ubi->volumes_lock); | 271 | spin_lock(&ubi->volumes_lock); |
| 263 | switch (desc->mode) { | 272 | switch (desc->mode) { |
| 264 | case UBI_READONLY: | 273 | case UBI_READONLY: |
| 265 | vol->readers -= 1; | 274 | vol->readers -= 1; |
| @@ -270,9 +279,12 @@ void ubi_close_volume(struct ubi_volume_desc *desc) | |||
| 270 | case UBI_EXCLUSIVE: | 279 | case UBI_EXCLUSIVE: |
| 271 | vol->exclusive = 0; | 280 | vol->exclusive = 0; |
| 272 | } | 281 | } |
| 273 | spin_unlock(&vol->ubi->volumes_lock); | 282 | vol->ref_count -= 1; |
| 283 | spin_unlock(&ubi->volumes_lock); | ||
| 274 | 284 | ||
| 275 | kfree(desc); | 285 | kfree(desc); |
| 286 | put_device(&vol->dev); | ||
| 287 | ubi_put_device(ubi); | ||
| 276 | module_put(THIS_MODULE); | 288 | module_put(THIS_MODULE); |
| 277 | } | 289 | } |
| 278 | EXPORT_SYMBOL_GPL(ubi_close_volume); | 290 | EXPORT_SYMBOL_GPL(ubi_close_volume); |
| @@ -332,7 +344,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, | |||
| 332 | if (len == 0) | 344 | if (len == 0) |
| 333 | return 0; | 345 | return 0; |
| 334 | 346 | ||
| 335 | err = ubi_eba_read_leb(ubi, vol_id, lnum, buf, offset, len, check); | 347 | err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); |
| 336 | if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { | 348 | if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { |
| 337 | ubi_warn("mark volume %d as corrupted", vol_id); | 349 | ubi_warn("mark volume %d as corrupted", vol_id); |
| 338 | vol->corrupted = 1; | 350 | vol->corrupted = 1; |
| @@ -399,7 +411,7 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, | |||
| 399 | if (len == 0) | 411 | if (len == 0) |
| 400 | return 0; | 412 | return 0; |
| 401 | 413 | ||
| 402 | return ubi_eba_write_leb(ubi, vol_id, lnum, buf, offset, len, dtype); | 414 | return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype); |
| 403 | } | 415 | } |
| 404 | EXPORT_SYMBOL_GPL(ubi_leb_write); | 416 | EXPORT_SYMBOL_GPL(ubi_leb_write); |
| 405 | 417 | ||
| @@ -448,7 +460,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, | |||
| 448 | if (len == 0) | 460 | if (len == 0) |
| 449 | return 0; | 461 | return 0; |
| 450 | 462 | ||
| 451 | return ubi_eba_atomic_leb_change(ubi, vol_id, lnum, buf, len, dtype); | 463 | return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype); |
| 452 | } | 464 | } |
| 453 | EXPORT_SYMBOL_GPL(ubi_leb_change); | 465 | EXPORT_SYMBOL_GPL(ubi_leb_change); |
| 454 | 466 | ||
| @@ -468,9 +480,9 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum) | |||
| 468 | { | 480 | { |
| 469 | struct ubi_volume *vol = desc->vol; | 481 | struct ubi_volume *vol = desc->vol; |
| 470 | struct ubi_device *ubi = vol->ubi; | 482 | struct ubi_device *ubi = vol->ubi; |
| 471 | int err, vol_id = vol->vol_id; | 483 | int err; |
| 472 | 484 | ||
| 473 | dbg_msg("erase LEB %d:%d", vol_id, lnum); | 485 | dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); |
| 474 | 486 | ||
| 475 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) | 487 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) |
| 476 | return -EROFS; | 488 | return -EROFS; |
| @@ -481,7 +493,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum) | |||
| 481 | if (vol->upd_marker) | 493 | if (vol->upd_marker) |
| 482 | return -EBADF; | 494 | return -EBADF; |
| 483 | 495 | ||
| 484 | err = ubi_eba_unmap_leb(ubi, vol_id, lnum); | 496 | err = ubi_eba_unmap_leb(ubi, vol, lnum); |
| 485 | if (err) | 497 | if (err) |
| 486 | return err; | 498 | return err; |
| 487 | 499 | ||
| @@ -529,9 +541,8 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) | |||
| 529 | { | 541 | { |
| 530 | struct ubi_volume *vol = desc->vol; | 542 | struct ubi_volume *vol = desc->vol; |
| 531 | struct ubi_device *ubi = vol->ubi; | 543 | struct ubi_device *ubi = vol->ubi; |
| 532 | int vol_id = vol->vol_id; | ||
| 533 | 544 | ||
| 534 | dbg_msg("unmap LEB %d:%d", vol_id, lnum); | 545 | dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); |
| 535 | 546 | ||
| 536 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) | 547 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) |
| 537 | return -EROFS; | 548 | return -EROFS; |
| @@ -542,11 +553,55 @@ int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) | |||
| 542 | if (vol->upd_marker) | 553 | if (vol->upd_marker) |
| 543 | return -EBADF; | 554 | return -EBADF; |
| 544 | 555 | ||
| 545 | return ubi_eba_unmap_leb(ubi, vol_id, lnum); | 556 | return ubi_eba_unmap_leb(ubi, vol, lnum); |
| 546 | } | 557 | } |
| 547 | EXPORT_SYMBOL_GPL(ubi_leb_unmap); | 558 | EXPORT_SYMBOL_GPL(ubi_leb_unmap); |
| 548 | 559 | ||
| 549 | /** | 560 | /** |
| 561 | * ubi_leb_map - map logical erasblock to a physical eraseblock. | ||
| 562 | * @desc: volume descriptor | ||
| 563 | * @lnum: logical eraseblock number | ||
| 564 | * @dtype: expected data type | ||
| 565 | * | ||
| 566 | * This function maps an un-mapped logical eraseblock @lnum to a physical | ||
| 567 | * eraseblock. This means, that after a successfull invocation of this | ||
| 568 | * function the logical eraseblock @lnum will be empty (contain only %0xFF | ||
| 569 | * bytes) and be mapped to a physical eraseblock, even if an unclean reboot | ||
| 570 | * happens. | ||
| 571 | * | ||
| 572 | * This function returns zero in case of success, %-EBADF if the volume is | ||
| 573 | * damaged because of an interrupted update, %-EBADMSG if the logical | ||
| 574 | * eraseblock is already mapped, and other negative error codes in case of | ||
| 575 | * other failures. | ||
| 576 | */ | ||
| 577 | int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) | ||
| 578 | { | ||
| 579 | struct ubi_volume *vol = desc->vol; | ||
| 580 | struct ubi_device *ubi = vol->ubi; | ||
| 581 | |||
| 582 | dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); | ||
| 583 | |||
| 584 | if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) | ||
| 585 | return -EROFS; | ||
| 586 | |||
| 587 | if (lnum < 0 || lnum >= vol->reserved_pebs) | ||
| 588 | return -EINVAL; | ||
| 589 | |||
| 590 | if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && | ||
| 591 | dtype != UBI_UNKNOWN) | ||
| 592 | return -EINVAL; | ||
| 593 | |||
| 594 | if (vol->upd_marker) | ||
| 595 | return -EBADF; | ||
| 596 | |||
| 597 | if (vol->eba_tbl[lnum] >= 0) | ||
| 598 | return -EBADMSG; | ||
| 599 | |||
| 600 | return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); | ||
| 601 | } | ||
| 602 | EXPORT_SYMBOL_GPL(ubi_leb_map); | ||
| 603 | |||
| 604 | /** | ||
| 550 | * ubi_is_mapped - check if logical eraseblock is mapped. | 605 | * ubi_is_mapped - check if logical eraseblock is mapped. |
| 551 | * @desc: volume descriptor | 606 | * @desc: volume descriptor |
| 552 | * @lnum: logical eraseblock number | 607 | * @lnum: logical eraseblock number |
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index 9e2338c8e2cf..93e052812012 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c | |||
| @@ -79,7 +79,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) | |||
| 79 | else | 79 | else |
| 80 | size = vol->usable_leb_size; | 80 | size = vol->usable_leb_size; |
| 81 | 81 | ||
| 82 | err = ubi_eba_read_leb(ubi, vol_id, i, buf, 0, size, 1); | 82 | err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1); |
| 83 | if (err) { | 83 | if (err) { |
| 84 | if (err == -EBADMSG) | 84 | if (err == -EBADMSG) |
| 85 | err = 1; | 85 | err = 1; |
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index c7b0afc9d280..05aa3e7daba1 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c | |||
| @@ -286,9 +286,14 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, | |||
| 286 | * FIXME: but this is anyway obsolete and will be removed at | 286 | * FIXME: but this is anyway obsolete and will be removed at |
| 287 | * some point. | 287 | * some point. |
| 288 | */ | 288 | */ |
| 289 | |||
| 290 | dbg_bld("using old crappy leb_ver stuff"); | 289 | dbg_bld("using old crappy leb_ver stuff"); |
| 291 | 290 | ||
| 291 | if (v1 == v2) { | ||
| 292 | ubi_err("PEB %d and PEB %d have the same version %lld", | ||
| 293 | seb->pnum, pnum, v1); | ||
| 294 | return -EINVAL; | ||
| 295 | } | ||
| 296 | |||
| 292 | abs = v1 - v2; | 297 | abs = v1 - v2; |
| 293 | if (abs < 0) | 298 | if (abs < 0) |
| 294 | abs = -abs; | 299 | abs = -abs; |
| @@ -390,7 +395,6 @@ out_free_buf: | |||
| 390 | vfree(buf); | 395 | vfree(buf); |
| 391 | out_free_vidh: | 396 | out_free_vidh: |
| 392 | ubi_free_vid_hdr(ubi, vh); | 397 | ubi_free_vid_hdr(ubi, vh); |
| 393 | ubi_assert(err < 0); | ||
| 394 | return err; | 398 | return err; |
| 395 | } | 399 | } |
| 396 | 400 | ||
| @@ -769,7 +773,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, | |||
| 769 | */ | 773 | */ |
| 770 | static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) | 774 | static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) |
| 771 | { | 775 | { |
| 772 | long long ec; | 776 | long long uninitialized_var(ec); |
| 773 | int err, bitflips = 0, vol_id, ec_corr = 0; | 777 | int err, bitflips = 0, vol_id, ec_corr = 0; |
| 774 | 778 | ||
| 775 | dbg_bld("scan PEB %d", pnum); | 779 | dbg_bld("scan PEB %d", pnum); |
| @@ -854,7 +858,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum | |||
| 854 | } | 858 | } |
| 855 | 859 | ||
| 856 | vol_id = be32_to_cpu(vidh->vol_id); | 860 | vol_id = be32_to_cpu(vidh->vol_id); |
| 857 | if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) { | 861 | if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) { |
| 858 | int lnum = be32_to_cpu(vidh->lnum); | 862 | int lnum = be32_to_cpu(vidh->lnum); |
| 859 | 863 | ||
| 860 | /* Unsupported internal volume */ | 864 | /* Unsupported internal volume */ |
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 5e941a633030..457710615261 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h | |||
| @@ -94,8 +94,43 @@ enum { | |||
| 94 | UBI_IO_BITFLIPS | 94 | UBI_IO_BITFLIPS |
| 95 | }; | 95 | }; |
| 96 | 96 | ||
| 97 | extern int ubi_devices_cnt; | 97 | /** |
| 98 | extern struct ubi_device *ubi_devices[]; | 98 | * struct ubi_wl_entry - wear-leveling entry. |
| 99 | * @rb: link in the corresponding RB-tree | ||
| 100 | * @ec: erase counter | ||
| 101 | * @pnum: physical eraseblock number | ||
| 102 | * | ||
| 103 | * This data structure is used in the WL unit. Each physical eraseblock has a | ||
| 104 | * corresponding &struct wl_entry object which may be kept in different | ||
| 105 | * RB-trees. See WL unit for details. | ||
| 106 | */ | ||
| 107 | struct ubi_wl_entry { | ||
| 108 | struct rb_node rb; | ||
| 109 | int ec; | ||
| 110 | int pnum; | ||
| 111 | }; | ||
| 112 | |||
| 113 | /** | ||
| 114 | * struct ubi_ltree_entry - an entry in the lock tree. | ||
| 115 | * @rb: links RB-tree nodes | ||
| 116 | * @vol_id: volume ID of the locked logical eraseblock | ||
| 117 | * @lnum: locked logical eraseblock number | ||
| 118 | * @users: how many tasks are using this logical eraseblock or wait for it | ||
| 119 | * @mutex: read/write mutex to implement read/write access serialization to | ||
| 120 | * the (@vol_id, @lnum) logical eraseblock | ||
| 121 | * | ||
| 122 | * This data structure is used in the EBA unit to implement per-LEB locking. | ||
| 123 | * When a logical eraseblock is being locked - corresponding | ||
| 124 | * &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree). | ||
| 125 | * See EBA unit for details. | ||
| 126 | */ | ||
| 127 | struct ubi_ltree_entry { | ||
| 128 | struct rb_node rb; | ||
| 129 | int vol_id; | ||
| 130 | int lnum; | ||
| 131 | int users; | ||
| 132 | struct rw_semaphore mutex; | ||
| 133 | }; | ||
| 99 | 134 | ||
| 100 | struct ubi_volume_desc; | 135 | struct ubi_volume_desc; |
| 101 | 136 | ||
| @@ -105,11 +140,10 @@ struct ubi_volume_desc; | |||
| 105 | * @cdev: character device object to create character device | 140 | * @cdev: character device object to create character device |
| 106 | * @ubi: reference to the UBI device description object | 141 | * @ubi: reference to the UBI device description object |
| 107 | * @vol_id: volume ID | 142 | * @vol_id: volume ID |
| 143 | * @ref_count: volume reference count | ||
| 108 | * @readers: number of users holding this volume in read-only mode | 144 | * @readers: number of users holding this volume in read-only mode |
| 109 | * @writers: number of users holding this volume in read-write mode | 145 | * @writers: number of users holding this volume in read-write mode |
| 110 | * @exclusive: whether somebody holds this volume in exclusive mode | 146 | * @exclusive: whether somebody holds this volume in exclusive mode |
| 111 | * @removed: if the volume was removed | ||
| 112 | * @checked: if this static volume was checked | ||
| 113 | * | 147 | * |
| 114 | * @reserved_pebs: how many physical eraseblocks are reserved for this volume | 148 | * @reserved_pebs: how many physical eraseblocks are reserved for this volume |
| 115 | * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) | 149 | * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) |
| @@ -117,21 +151,30 @@ struct ubi_volume_desc; | |||
| 117 | * @used_ebs: how many logical eraseblocks in this volume contain data | 151 | * @used_ebs: how many logical eraseblocks in this volume contain data |
| 118 | * @last_eb_bytes: how many bytes are stored in the last logical eraseblock | 152 | * @last_eb_bytes: how many bytes are stored in the last logical eraseblock |
| 119 | * @used_bytes: how many bytes of data this volume contains | 153 | * @used_bytes: how many bytes of data this volume contains |
| 120 | * @upd_marker: non-zero if the update marker is set for this volume | ||
| 121 | * @corrupted: non-zero if the volume is corrupted (static volumes only) | ||
| 122 | * @alignment: volume alignment | 154 | * @alignment: volume alignment |
| 123 | * @data_pad: how many bytes are not used at the end of physical eraseblocks to | 155 | * @data_pad: how many bytes are not used at the end of physical eraseblocks to |
| 124 | * satisfy the requested alignment | 156 | * satisfy the requested alignment |
| 125 | * @name_len: volume name length | 157 | * @name_len: volume name length |
| 126 | * @name: volume name | 158 | * @name: volume name |
| 127 | * | 159 | * |
| 128 | * @updating: whether the volume is being updated | ||
| 129 | * @upd_ebs: how many eraseblocks are expected to be updated | 160 | * @upd_ebs: how many eraseblocks are expected to be updated |
| 130 | * @upd_bytes: how many bytes are expected to be received | 161 | * @ch_lnum: LEB number which is being changing by the atomic LEB change |
| 131 | * @upd_received: how many update bytes were already received | 162 | * operation |
| 132 | * @upd_buf: update buffer which is used to collect update data | 163 | * @ch_dtype: data persistency type which is being changing by the atomic LEB |
| 164 | * change operation | ||
| 165 | * @upd_bytes: how many bytes are expected to be received for volume update or | ||
| 166 | * atomic LEB change | ||
| 167 | * @upd_received: how many bytes were already received for volume update or | ||
| 168 | * atomic LEB change | ||
| 169 | * @upd_buf: update buffer which is used to collect update data or data for | ||
| 170 | * atomic LEB change | ||
| 133 | * | 171 | * |
| 134 | * @eba_tbl: EBA table of this volume (LEB->PEB mapping) | 172 | * @eba_tbl: EBA table of this volume (LEB->PEB mapping) |
| 173 | * @checked: %1 if this static volume was checked | ||
| 174 | * @corrupted: %1 if the volume is corrupted (static volumes only) | ||
| 175 | * @upd_marker: %1 if the update marker is set for this volume | ||
| 176 | * @updating: %1 if the volume is being updated | ||
| 177 | * @changing_leb: %1 if the atomic LEB change ioctl command is in progress | ||
| 135 | * | 178 | * |
| 136 | * @gluebi_desc: gluebi UBI volume descriptor | 179 | * @gluebi_desc: gluebi UBI volume descriptor |
| 137 | * @gluebi_refcount: reference count of the gluebi MTD device | 180 | * @gluebi_refcount: reference count of the gluebi MTD device |
| @@ -150,11 +193,10 @@ struct ubi_volume { | |||
| 150 | struct cdev cdev; | 193 | struct cdev cdev; |
| 151 | struct ubi_device *ubi; | 194 | struct ubi_device *ubi; |
| 152 | int vol_id; | 195 | int vol_id; |
| 196 | int ref_count; | ||
| 153 | int readers; | 197 | int readers; |
| 154 | int writers; | 198 | int writers; |
| 155 | int exclusive; | 199 | int exclusive; |
| 156 | int removed; | ||
| 157 | int checked; | ||
| 158 | 200 | ||
| 159 | int reserved_pebs; | 201 | int reserved_pebs; |
| 160 | int vol_type; | 202 | int vol_type; |
| @@ -162,23 +204,31 @@ struct ubi_volume { | |||
| 162 | int used_ebs; | 204 | int used_ebs; |
| 163 | int last_eb_bytes; | 205 | int last_eb_bytes; |
| 164 | long long used_bytes; | 206 | long long used_bytes; |
| 165 | int upd_marker; | ||
| 166 | int corrupted; | ||
| 167 | int alignment; | 207 | int alignment; |
| 168 | int data_pad; | 208 | int data_pad; |
| 169 | int name_len; | 209 | int name_len; |
| 170 | char name[UBI_VOL_NAME_MAX+1]; | 210 | char name[UBI_VOL_NAME_MAX+1]; |
| 171 | 211 | ||
| 172 | int updating; | ||
| 173 | int upd_ebs; | 212 | int upd_ebs; |
| 213 | int ch_lnum; | ||
| 214 | int ch_dtype; | ||
| 174 | long long upd_bytes; | 215 | long long upd_bytes; |
| 175 | long long upd_received; | 216 | long long upd_received; |
| 176 | void *upd_buf; | 217 | void *upd_buf; |
| 177 | 218 | ||
| 178 | int *eba_tbl; | 219 | int *eba_tbl; |
| 220 | int checked:1; | ||
| 221 | int corrupted:1; | ||
| 222 | int upd_marker:1; | ||
| 223 | int updating:1; | ||
| 224 | int changing_leb:1; | ||
| 179 | 225 | ||
| 180 | #ifdef CONFIG_MTD_UBI_GLUEBI | 226 | #ifdef CONFIG_MTD_UBI_GLUEBI |
| 181 | /* Gluebi-related stuff may be compiled out */ | 227 | /* |
| 228 | * Gluebi-related stuff may be compiled out. | ||
| 229 | * TODO: this should not be built into UBI but should be a separate | ||
| 230 | * ubimtd driver which works on top of UBI and emulates MTD devices. | ||
| 231 | */ | ||
| 182 | struct ubi_volume_desc *gluebi_desc; | 232 | struct ubi_volume_desc *gluebi_desc; |
| 183 | int gluebi_refcount; | 233 | int gluebi_refcount; |
| 184 | struct mtd_info gluebi_mtd; | 234 | struct mtd_info gluebi_mtd; |
| @@ -200,28 +250,31 @@ struct ubi_wl_entry; | |||
| 200 | 250 | ||
| 201 | /** | 251 | /** |
| 202 | * struct ubi_device - UBI device description structure | 252 | * struct ubi_device - UBI device description structure |
| 203 | * @dev: class device object to use the the Linux device model | 253 | * @dev: UBI device object to use the the Linux device model |
| 204 | * @cdev: character device object to create character device | 254 | * @cdev: character device object to create character device |
| 205 | * @ubi_num: UBI device number | 255 | * @ubi_num: UBI device number |
| 206 | * @ubi_name: UBI device name | 256 | * @ubi_name: UBI device name |
| 207 | * @major: character device major number | ||
| 208 | * @vol_count: number of volumes in this UBI device | 257 | * @vol_count: number of volumes in this UBI device |
| 209 | * @volumes: volumes of this UBI device | 258 | * @volumes: volumes of this UBI device |
| 210 | * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs, | 259 | * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs, |
| 211 | * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, @vol->readers, | 260 | * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, |
| 212 | * @vol->writers, @vol->exclusive, @vol->removed, @vol->mapping and | 261 | * @vol->readers, @vol->writers, @vol->exclusive, |
| 213 | * @vol->eba_tbl. | 262 | * @vol->ref_count, @vol->mapping and @vol->eba_tbl. |
| 263 | * @ref_count: count of references on the UBI device | ||
| 214 | * | 264 | * |
| 215 | * @rsvd_pebs: count of reserved physical eraseblocks | 265 | * @rsvd_pebs: count of reserved physical eraseblocks |
| 216 | * @avail_pebs: count of available physical eraseblocks | 266 | * @avail_pebs: count of available physical eraseblocks |
| 217 | * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB | 267 | * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB |
| 218 | * handling | 268 | * handling |
| 219 | * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling | 269 | * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling |
| 220 | * | 270 | * |
| 271 | * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end | ||
| 272 | * of UBI ititializetion | ||
| 221 | * @vtbl_slots: how many slots are available in the volume table | 273 | * @vtbl_slots: how many slots are available in the volume table |
| 222 | * @vtbl_size: size of the volume table in bytes | 274 | * @vtbl_size: size of the volume table in bytes |
| 223 | * @vtbl: in-RAM volume table copy | 275 | * @vtbl: in-RAM volume table copy |
| 224 | * @vtbl_mutex: protects on-flash volume table | 276 | * @volumes_mutex: protects on-flash volume table and serializes volume |
| 277 | * changes, like creation, deletion, update, resize | ||
| 225 | * | 278 | * |
| 226 | * @max_ec: current highest erase counter value | 279 | * @max_ec: current highest erase counter value |
| 227 | * @mean_ec: current mean erase counter value | 280 | * @mean_ec: current mean erase counter value |
| @@ -238,15 +291,15 @@ struct ubi_wl_entry; | |||
| 238 | * @prot.pnum: protection tree indexed by physical eraseblock numbers | 291 | * @prot.pnum: protection tree indexed by physical eraseblock numbers |
| 239 | * @prot.aec: protection tree indexed by absolute erase counter value | 292 | * @prot.aec: protection tree indexed by absolute erase counter value |
| 240 | * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from, | 293 | * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from, |
| 241 | * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works | 294 | * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works |
| 242 | * fields | 295 | * fields |
| 296 | * @move_mutex: serializes eraseblock moves | ||
| 243 | * @wl_scheduled: non-zero if the wear-leveling was scheduled | 297 | * @wl_scheduled: non-zero if the wear-leveling was scheduled |
| 244 | * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any | 298 | * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any |
| 245 | * physical eraseblock | 299 | * physical eraseblock |
| 246 | * @abs_ec: absolute erase counter | 300 | * @abs_ec: absolute erase counter |
| 247 | * @move_from: physical eraseblock from where the data is being moved | 301 | * @move_from: physical eraseblock from where the data is being moved |
| 248 | * @move_to: physical eraseblock where the data is being moved to | 302 | * @move_to: physical eraseblock where the data is being moved to |
| 249 | * @move_from_put: if the "from" PEB was put | ||
| 250 | * @move_to_put: if the "to" PEB was put | 303 | * @move_to_put: if the "to" PEB was put |
| 251 | * @works: list of pending works | 304 | * @works: list of pending works |
| 252 | * @works_count: count of pending works | 305 | * @works_count: count of pending works |
| @@ -273,13 +326,13 @@ struct ubi_wl_entry; | |||
| 273 | * @hdrs_min_io_size | 326 | * @hdrs_min_io_size |
| 274 | * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset | 327 | * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset |
| 275 | * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or | 328 | * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or |
| 276 | * not | 329 | * not |
| 277 | * @mtd: MTD device descriptor | 330 | * @mtd: MTD device descriptor |
| 278 | * | 331 | * |
| 279 | * @peb_buf1: a buffer of PEB size used for different purposes | 332 | * @peb_buf1: a buffer of PEB size used for different purposes |
| 280 | * @peb_buf2: another buffer of PEB size used for different purposes | 333 | * @peb_buf2: another buffer of PEB size used for different purposes |
| 281 | * @buf_mutex: proptects @peb_buf1 and @peb_buf2 | 334 | * @buf_mutex: proptects @peb_buf1 and @peb_buf2 |
| 282 | * @dbg_peb_buf: buffer of PEB size used for debugging | 335 | * @dbg_peb_buf: buffer of PEB size used for debugging |
| 283 | * @dbg_buf_mutex: proptects @dbg_peb_buf | 336 | * @dbg_buf_mutex: proptects @dbg_peb_buf |
| 284 | */ | 337 | */ |
| 285 | struct ubi_device { | 338 | struct ubi_device { |
| @@ -287,22 +340,24 @@ struct ubi_device { | |||
| 287 | struct device dev; | 340 | struct device dev; |
| 288 | int ubi_num; | 341 | int ubi_num; |
| 289 | char ubi_name[sizeof(UBI_NAME_STR)+5]; | 342 | char ubi_name[sizeof(UBI_NAME_STR)+5]; |
| 290 | int major; | ||
| 291 | int vol_count; | 343 | int vol_count; |
| 292 | struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; | 344 | struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; |
| 293 | spinlock_t volumes_lock; | 345 | spinlock_t volumes_lock; |
| 346 | int ref_count; | ||
| 294 | 347 | ||
| 295 | int rsvd_pebs; | 348 | int rsvd_pebs; |
| 296 | int avail_pebs; | 349 | int avail_pebs; |
| 297 | int beb_rsvd_pebs; | 350 | int beb_rsvd_pebs; |
| 298 | int beb_rsvd_level; | 351 | int beb_rsvd_level; |
| 299 | 352 | ||
| 353 | int autoresize_vol_id; | ||
| 300 | int vtbl_slots; | 354 | int vtbl_slots; |
| 301 | int vtbl_size; | 355 | int vtbl_size; |
| 302 | struct ubi_vtbl_record *vtbl; | 356 | struct ubi_vtbl_record *vtbl; |
| 303 | struct mutex vtbl_mutex; | 357 | struct mutex volumes_mutex; |
| 304 | 358 | ||
| 305 | int max_ec; | 359 | int max_ec; |
| 360 | /* TODO: mean_ec is not updated run-time, fix */ | ||
| 306 | int mean_ec; | 361 | int mean_ec; |
| 307 | 362 | ||
| 308 | /* EBA unit's stuff */ | 363 | /* EBA unit's stuff */ |
| @@ -320,12 +375,13 @@ struct ubi_device { | |||
| 320 | struct rb_root aec; | 375 | struct rb_root aec; |
| 321 | } prot; | 376 | } prot; |
| 322 | spinlock_t wl_lock; | 377 | spinlock_t wl_lock; |
| 378 | struct mutex move_mutex; | ||
| 379 | struct rw_semaphore work_sem; | ||
| 323 | int wl_scheduled; | 380 | int wl_scheduled; |
| 324 | struct ubi_wl_entry **lookuptbl; | 381 | struct ubi_wl_entry **lookuptbl; |
| 325 | unsigned long long abs_ec; | 382 | unsigned long long abs_ec; |
| 326 | struct ubi_wl_entry *move_from; | 383 | struct ubi_wl_entry *move_from; |
| 327 | struct ubi_wl_entry *move_to; | 384 | struct ubi_wl_entry *move_to; |
| 328 | int move_from_put; | ||
| 329 | int move_to_put; | 385 | int move_to_put; |
| 330 | struct list_head works; | 386 | struct list_head works; |
| 331 | int works_count; | 387 | int works_count; |
| @@ -355,15 +411,19 @@ struct ubi_device { | |||
| 355 | void *peb_buf1; | 411 | void *peb_buf1; |
| 356 | void *peb_buf2; | 412 | void *peb_buf2; |
| 357 | struct mutex buf_mutex; | 413 | struct mutex buf_mutex; |
| 414 | struct mutex ckvol_mutex; | ||
| 358 | #ifdef CONFIG_MTD_UBI_DEBUG | 415 | #ifdef CONFIG_MTD_UBI_DEBUG |
| 359 | void *dbg_peb_buf; | 416 | void *dbg_peb_buf; |
| 360 | struct mutex dbg_buf_mutex; | 417 | struct mutex dbg_buf_mutex; |
| 361 | #endif | 418 | #endif |
| 362 | }; | 419 | }; |
| 363 | 420 | ||
| 421 | extern struct kmem_cache *ubi_wl_entry_slab; | ||
| 422 | extern struct file_operations ubi_ctrl_cdev_operations; | ||
| 364 | extern struct file_operations ubi_cdev_operations; | 423 | extern struct file_operations ubi_cdev_operations; |
| 365 | extern struct file_operations ubi_vol_cdev_operations; | 424 | extern struct file_operations ubi_vol_cdev_operations; |
| 366 | extern struct class *ubi_class; | 425 | extern struct class *ubi_class; |
| 426 | extern struct mutex ubi_devices_mutex; | ||
| 367 | 427 | ||
| 368 | /* vtbl.c */ | 428 | /* vtbl.c */ |
| 369 | int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, | 429 | int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, |
| @@ -374,13 +434,18 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si); | |||
| 374 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); | 434 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); |
| 375 | int ubi_remove_volume(struct ubi_volume_desc *desc); | 435 | int ubi_remove_volume(struct ubi_volume_desc *desc); |
| 376 | int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); | 436 | int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); |
| 377 | int ubi_add_volume(struct ubi_device *ubi, int vol_id); | 437 | int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol); |
| 378 | void ubi_free_volume(struct ubi_device *ubi, int vol_id); | 438 | void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol); |
| 379 | 439 | ||
| 380 | /* upd.c */ | 440 | /* upd.c */ |
| 381 | int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes); | 441 | int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, |
| 382 | int ubi_more_update_data(struct ubi_device *ubi, int vol_id, | 442 | long long bytes); |
| 443 | int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, | ||
| 383 | const void __user *buf, int count); | 444 | const void __user *buf, int count); |
| 445 | int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, | ||
| 446 | const struct ubi_leb_change_req *req); | ||
| 447 | int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, | ||
| 448 | const void __user *buf, int count); | ||
| 384 | 449 | ||
| 385 | /* misc.c */ | 450 | /* misc.c */ |
| 386 | int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); | 451 | int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); |
| @@ -399,16 +464,17 @@ void ubi_gluebi_updated(struct ubi_volume *vol); | |||
| 399 | #endif | 464 | #endif |
| 400 | 465 | ||
| 401 | /* eba.c */ | 466 | /* eba.c */ |
| 402 | int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum); | 467 | int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, |
| 403 | int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, | 468 | int lnum); |
| 404 | int offset, int len, int check); | 469 | int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, |
| 405 | int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum, | 470 | void *buf, int offset, int len, int check); |
| 471 | int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, | ||
| 406 | const void *buf, int offset, int len, int dtype); | 472 | const void *buf, int offset, int len, int dtype); |
| 407 | int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum, | 473 | int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, |
| 408 | const void *buf, int len, int dtype, | 474 | int lnum, const void *buf, int len, int dtype, |
| 409 | int used_ebs); | 475 | int used_ebs); |
| 410 | int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum, | 476 | int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, |
| 411 | const void *buf, int len, int dtype); | 477 | int lnum, const void *buf, int len, int dtype); |
| 412 | int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, | 478 | int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, |
| 413 | struct ubi_vid_hdr *vid_hdr); | 479 | struct ubi_vid_hdr *vid_hdr); |
| 414 | int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); | 480 | int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); |
| @@ -421,6 +487,7 @@ int ubi_wl_flush(struct ubi_device *ubi); | |||
| 421 | int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); | 487 | int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); |
| 422 | int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); | 488 | int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); |
| 423 | void ubi_wl_close(struct ubi_device *ubi); | 489 | void ubi_wl_close(struct ubi_device *ubi); |
| 490 | int ubi_thread(void *u); | ||
| 424 | 491 | ||
| 425 | /* io.c */ | 492 | /* io.c */ |
| 426 | int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, | 493 | int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, |
| @@ -439,6 +506,14 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, | |||
| 439 | int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, | 506 | int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, |
| 440 | struct ubi_vid_hdr *vid_hdr); | 507 | struct ubi_vid_hdr *vid_hdr); |
| 441 | 508 | ||
| 509 | /* build.c */ | ||
| 510 | int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset); | ||
| 511 | int ubi_detach_mtd_dev(int ubi_num, int anyway); | ||
| 512 | struct ubi_device *ubi_get_device(int ubi_num); | ||
| 513 | void ubi_put_device(struct ubi_device *ubi); | ||
| 514 | struct ubi_device *ubi_get_by_major(int major); | ||
| 515 | int ubi_major2num(int major); | ||
| 516 | |||
| 442 | /* | 517 | /* |
| 443 | * ubi_rb_for_each_entry - walk an RB-tree. | 518 | * ubi_rb_for_each_entry - walk an RB-tree. |
| 444 | * @rb: a pointer to type 'struct rb_node' to to use as a loop counter | 519 | * @rb: a pointer to type 'struct rb_node' to to use as a loop counter |
| @@ -523,8 +598,10 @@ static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf, | |||
| 523 | */ | 598 | */ |
| 524 | static inline void ubi_ro_mode(struct ubi_device *ubi) | 599 | static inline void ubi_ro_mode(struct ubi_device *ubi) |
| 525 | { | 600 | { |
| 526 | ubi->ro_mode = 1; | 601 | if (!ubi->ro_mode) { |
| 527 | ubi_warn("switch to read-only mode"); | 602 | ubi->ro_mode = 1; |
| 603 | ubi_warn("switch to read-only mode"); | ||
| 604 | } | ||
| 528 | } | 605 | } |
| 529 | 606 | ||
| 530 | /** | 607 | /** |
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c index 0efc586a8328..ddaa1a56cc69 100644 --- a/drivers/mtd/ubi/upd.c +++ b/drivers/mtd/ubi/upd.c | |||
| @@ -22,7 +22,8 @@ | |||
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | /* | 24 | /* |
| 25 | * This file contains implementation of the volume update functionality. | 25 | * This file contains implementation of the volume update and atomic LEB change |
| 26 | * functionality. | ||
| 26 | * | 27 | * |
| 27 | * The update operation is based on the per-volume update marker which is | 28 | * The update operation is based on the per-volume update marker which is |
| 28 | * stored in the volume table. The update marker is set before the update | 29 | * stored in the volume table. The update marker is set before the update |
| @@ -45,29 +46,31 @@ | |||
| 45 | /** | 46 | /** |
| 46 | * set_update_marker - set update marker. | 47 | * set_update_marker - set update marker. |
| 47 | * @ubi: UBI device description object | 48 | * @ubi: UBI device description object |
| 48 | * @vol_id: volume ID | 49 | * @vol: volume description object |
| 49 | * | 50 | * |
| 50 | * This function sets the update marker flag for volume @vol_id. Returns zero | 51 | * This function sets the update marker flag for volume @vol. Returns zero |
| 51 | * in case of success and a negative error code in case of failure. | 52 | * in case of success and a negative error code in case of failure. |
| 52 | */ | 53 | */ |
| 53 | static int set_update_marker(struct ubi_device *ubi, int vol_id) | 54 | static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol) |
| 54 | { | 55 | { |
| 55 | int err; | 56 | int err; |
| 56 | struct ubi_vtbl_record vtbl_rec; | 57 | struct ubi_vtbl_record vtbl_rec; |
| 57 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
| 58 | 58 | ||
| 59 | dbg_msg("set update marker for volume %d", vol_id); | 59 | dbg_msg("set update marker for volume %d", vol->vol_id); |
| 60 | 60 | ||
| 61 | if (vol->upd_marker) { | 61 | if (vol->upd_marker) { |
| 62 | ubi_assert(ubi->vtbl[vol_id].upd_marker); | 62 | ubi_assert(ubi->vtbl[vol->vol_id].upd_marker); |
| 63 | dbg_msg("already set"); | 63 | dbg_msg("already set"); |
| 64 | return 0; | 64 | return 0; |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); | 67 | memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], |
| 68 | sizeof(struct ubi_vtbl_record)); | ||
| 68 | vtbl_rec.upd_marker = 1; | 69 | vtbl_rec.upd_marker = 1; |
| 69 | 70 | ||
| 70 | err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); | 71 | mutex_lock(&ubi->volumes_mutex); |
| 72 | err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); | ||
| 73 | mutex_unlock(&ubi->volumes_mutex); | ||
| 71 | vol->upd_marker = 1; | 74 | vol->upd_marker = 1; |
| 72 | return err; | 75 | return err; |
| 73 | } | 76 | } |
| @@ -75,23 +78,24 @@ static int set_update_marker(struct ubi_device *ubi, int vol_id) | |||
| 75 | /** | 78 | /** |
| 76 | * clear_update_marker - clear update marker. | 79 | * clear_update_marker - clear update marker. |
| 77 | * @ubi: UBI device description object | 80 | * @ubi: UBI device description object |
| 78 | * @vol_id: volume ID | 81 | * @vol: volume description object |
| 79 | * @bytes: new data size in bytes | 82 | * @bytes: new data size in bytes |
| 80 | * | 83 | * |
| 81 | * This function clears the update marker for volume @vol_id, sets new volume | 84 | * This function clears the update marker for volume @vol, sets new volume |
| 82 | * data size and clears the "corrupted" flag (static volumes only). Returns | 85 | * data size and clears the "corrupted" flag (static volumes only). Returns |
| 83 | * zero in case of success and a negative error code in case of failure. | 86 | * zero in case of success and a negative error code in case of failure. |
| 84 | */ | 87 | */ |
| 85 | static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long bytes) | 88 | static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, |
| 89 | long long bytes) | ||
| 86 | { | 90 | { |
| 87 | int err; | 91 | int err; |
| 88 | uint64_t tmp; | 92 | uint64_t tmp; |
| 89 | struct ubi_vtbl_record vtbl_rec; | 93 | struct ubi_vtbl_record vtbl_rec; |
| 90 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
| 91 | 94 | ||
| 92 | dbg_msg("clear update marker for volume %d", vol_id); | 95 | dbg_msg("clear update marker for volume %d", vol->vol_id); |
| 93 | 96 | ||
| 94 | memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); | 97 | memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], |
| 98 | sizeof(struct ubi_vtbl_record)); | ||
| 95 | ubi_assert(vol->upd_marker && vtbl_rec.upd_marker); | 99 | ubi_assert(vol->upd_marker && vtbl_rec.upd_marker); |
| 96 | vtbl_rec.upd_marker = 0; | 100 | vtbl_rec.upd_marker = 0; |
| 97 | 101 | ||
| @@ -106,7 +110,9 @@ static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long byt | |||
| 106 | vol->last_eb_bytes = vol->usable_leb_size; | 110 | vol->last_eb_bytes = vol->usable_leb_size; |
| 107 | } | 111 | } |
| 108 | 112 | ||
| 109 | err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); | 113 | mutex_lock(&ubi->volumes_mutex); |
| 114 | err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); | ||
| 115 | mutex_unlock(&ubi->volumes_mutex); | ||
| 110 | vol->upd_marker = 0; | 116 | vol->upd_marker = 0; |
| 111 | return err; | 117 | return err; |
| 112 | } | 118 | } |
| @@ -114,35 +120,36 @@ static int clear_update_marker(struct ubi_device *ubi, int vol_id, long long byt | |||
| 114 | /** | 120 | /** |
| 115 | * ubi_start_update - start volume update. | 121 | * ubi_start_update - start volume update. |
| 116 | * @ubi: UBI device description object | 122 | * @ubi: UBI device description object |
| 117 | * @vol_id: volume ID | 123 | * @vol: volume description object |
| 118 | * @bytes: update bytes | 124 | * @bytes: update bytes |
| 119 | * | 125 | * |
| 120 | * This function starts volume update operation. If @bytes is zero, the volume | 126 | * This function starts volume update operation. If @bytes is zero, the volume |
| 121 | * is just wiped out. Returns zero in case of success and a negative error code | 127 | * is just wiped out. Returns zero in case of success and a negative error code |
| 122 | * in case of failure. | 128 | * in case of failure. |
| 123 | */ | 129 | */ |
| 124 | int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) | 130 | int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, |
| 131 | long long bytes) | ||
| 125 | { | 132 | { |
| 126 | int i, err; | 133 | int i, err; |
| 127 | uint64_t tmp; | 134 | uint64_t tmp; |
| 128 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
| 129 | 135 | ||
| 130 | dbg_msg("start update of volume %d, %llu bytes", vol_id, bytes); | 136 | dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes); |
| 137 | ubi_assert(!vol->updating && !vol->changing_leb); | ||
| 131 | vol->updating = 1; | 138 | vol->updating = 1; |
| 132 | 139 | ||
| 133 | err = set_update_marker(ubi, vol_id); | 140 | err = set_update_marker(ubi, vol); |
| 134 | if (err) | 141 | if (err) |
| 135 | return err; | 142 | return err; |
| 136 | 143 | ||
| 137 | /* Before updating - wipe out the volume */ | 144 | /* Before updating - wipe out the volume */ |
| 138 | for (i = 0; i < vol->reserved_pebs; i++) { | 145 | for (i = 0; i < vol->reserved_pebs; i++) { |
| 139 | err = ubi_eba_unmap_leb(ubi, vol_id, i); | 146 | err = ubi_eba_unmap_leb(ubi, vol, i); |
| 140 | if (err) | 147 | if (err) |
| 141 | return err; | 148 | return err; |
| 142 | } | 149 | } |
| 143 | 150 | ||
| 144 | if (bytes == 0) { | 151 | if (bytes == 0) { |
| 145 | err = clear_update_marker(ubi, vol_id, 0); | 152 | err = clear_update_marker(ubi, vol, 0); |
| 146 | if (err) | 153 | if (err) |
| 147 | return err; | 154 | return err; |
| 148 | err = ubi_wl_flush(ubi); | 155 | err = ubi_wl_flush(ubi); |
| @@ -163,9 +170,42 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) | |||
| 163 | } | 170 | } |
| 164 | 171 | ||
| 165 | /** | 172 | /** |
| 173 | * ubi_start_leb_change - start atomic LEB change. | ||
| 174 | * @ubi: UBI device description object | ||
| 175 | * @vol: volume description object | ||
| 176 | * @req: operation request | ||
| 177 | * | ||
| 178 | * This function starts atomic LEB change operation. Returns zero in case of | ||
| 179 | * success and a negative error code in case of failure. | ||
| 180 | */ | ||
| 181 | int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, | ||
| 182 | const struct ubi_leb_change_req *req) | ||
| 183 | { | ||
| 184 | ubi_assert(!vol->updating && !vol->changing_leb); | ||
| 185 | |||
| 186 | dbg_msg("start changing LEB %d:%d, %u bytes", | ||
| 187 | vol->vol_id, req->lnum, req->bytes); | ||
| 188 | if (req->bytes == 0) | ||
| 189 | return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0, | ||
| 190 | req->dtype); | ||
| 191 | |||
| 192 | vol->upd_bytes = req->bytes; | ||
| 193 | vol->upd_received = 0; | ||
| 194 | vol->changing_leb = 1; | ||
| 195 | vol->ch_lnum = req->lnum; | ||
| 196 | vol->ch_dtype = req->dtype; | ||
| 197 | |||
| 198 | vol->upd_buf = vmalloc(req->bytes); | ||
| 199 | if (!vol->upd_buf) | ||
| 200 | return -ENOMEM; | ||
| 201 | |||
| 202 | return 0; | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 166 | * write_leb - write update data. | 206 | * write_leb - write update data. |
| 167 | * @ubi: UBI device description object | 207 | * @ubi: UBI device description object |
| 168 | * @vol_id: volume ID | 208 | * @vol: volume description object |
| 169 | * @lnum: logical eraseblock number | 209 | * @lnum: logical eraseblock number |
| 170 | * @buf: data to write | 210 | * @buf: data to write |
| 171 | * @len: data size | 211 | * @len: data size |
| @@ -191,26 +231,22 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes) | |||
| 191 | * This function returns zero in case of success and a negative error code in | 231 | * This function returns zero in case of success and a negative error code in |
| 192 | * case of failure. | 232 | * case of failure. |
| 193 | */ | 233 | */ |
| 194 | static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, | 234 | static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, |
| 195 | int len, int used_ebs) | 235 | void *buf, int len, int used_ebs) |
| 196 | { | 236 | { |
| 197 | int err, l; | 237 | int err; |
| 198 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
| 199 | 238 | ||
| 200 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) { | 239 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) { |
| 201 | l = ALIGN(len, ubi->min_io_size); | 240 | len = ALIGN(len, ubi->min_io_size); |
| 202 | memset(buf + len, 0xFF, l - len); | 241 | memset(buf + len, 0xFF, len - len); |
| 203 | 242 | ||
| 204 | l = ubi_calc_data_len(ubi, buf, l); | 243 | len = ubi_calc_data_len(ubi, buf, len); |
| 205 | if (l == 0) { | 244 | if (len == 0) { |
| 206 | dbg_msg("all %d bytes contain 0xFF - skip", len); | 245 | dbg_msg("all %d bytes contain 0xFF - skip", len); |
| 207 | return 0; | 246 | return 0; |
| 208 | } | 247 | } |
| 209 | if (len != l) | ||
| 210 | dbg_msg("skip last %d bytes (0xFF)", len - l); | ||
| 211 | 248 | ||
| 212 | err = ubi_eba_write_leb(ubi, vol_id, lnum, buf, 0, l, | 249 | err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN); |
| 213 | UBI_UNKNOWN); | ||
| 214 | } else { | 250 | } else { |
| 215 | /* | 251 | /* |
| 216 | * When writing static volume, and this is the last logical | 252 | * When writing static volume, and this is the last logical |
| @@ -222,7 +258,7 @@ static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, | |||
| 222 | * contain zeros, not random trash. | 258 | * contain zeros, not random trash. |
| 223 | */ | 259 | */ |
| 224 | memset(buf + len, 0, vol->usable_leb_size - len); | 260 | memset(buf + len, 0, vol->usable_leb_size - len); |
| 225 | err = ubi_eba_write_leb_st(ubi, vol_id, lnum, buf, len, | 261 | err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, |
| 226 | UBI_UNKNOWN, used_ebs); | 262 | UBI_UNKNOWN, used_ebs); |
| 227 | } | 263 | } |
| 228 | 264 | ||
| @@ -236,16 +272,15 @@ static int write_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf, | |||
| 236 | * @count: how much bytes to write | 272 | * @count: how much bytes to write |
| 237 | * | 273 | * |
| 238 | * This function writes more data to the volume which is being updated. It may | 274 | * This function writes more data to the volume which is being updated. It may |
| 239 | * be called arbitrary number of times until all of the update data arrive. | 275 | * be called arbitrary number of times until all the update data arriveis. This |
| 240 | * This function returns %0 in case of success, number of bytes written during | 276 | * function returns %0 in case of success, number of bytes written during the |
| 241 | * the last call if the whole volume update was successfully finished, and a | 277 | * last call if the whole volume update has been successfully finished, and a |
| 242 | * negative error code in case of failure. | 278 | * negative error code in case of failure. |
| 243 | */ | 279 | */ |
| 244 | int ubi_more_update_data(struct ubi_device *ubi, int vol_id, | 280 | int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, |
| 245 | const void __user *buf, int count) | 281 | const void __user *buf, int count) |
| 246 | { | 282 | { |
| 247 | uint64_t tmp; | 283 | uint64_t tmp; |
| 248 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
| 249 | int lnum, offs, err = 0, len, to_write = count; | 284 | int lnum, offs, err = 0, len, to_write = count; |
| 250 | 285 | ||
| 251 | dbg_msg("write %d of %lld bytes, %lld already passed", | 286 | dbg_msg("write %d of %lld bytes, %lld already passed", |
| @@ -290,8 +325,8 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id, | |||
| 290 | * is the last chunk, it's time to flush the buffer. | 325 | * is the last chunk, it's time to flush the buffer. |
| 291 | */ | 326 | */ |
| 292 | ubi_assert(flush_len <= vol->usable_leb_size); | 327 | ubi_assert(flush_len <= vol->usable_leb_size); |
| 293 | err = write_leb(ubi, vol_id, lnum, vol->upd_buf, | 328 | err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len, |
| 294 | flush_len, vol->upd_ebs); | 329 | vol->upd_ebs); |
| 295 | if (err) | 330 | if (err) |
| 296 | return err; | 331 | return err; |
| 297 | } | 332 | } |
| @@ -318,8 +353,8 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id, | |||
| 318 | 353 | ||
| 319 | if (len == vol->usable_leb_size || | 354 | if (len == vol->usable_leb_size || |
| 320 | vol->upd_received + len == vol->upd_bytes) { | 355 | vol->upd_received + len == vol->upd_bytes) { |
| 321 | err = write_leb(ubi, vol_id, lnum, vol->upd_buf, len, | 356 | err = write_leb(ubi, vol, lnum, vol->upd_buf, |
| 322 | vol->upd_ebs); | 357 | len, vol->upd_ebs); |
| 323 | if (err) | 358 | if (err) |
| 324 | break; | 359 | break; |
| 325 | } | 360 | } |
| @@ -333,16 +368,70 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id, | |||
| 333 | ubi_assert(vol->upd_received <= vol->upd_bytes); | 368 | ubi_assert(vol->upd_received <= vol->upd_bytes); |
| 334 | if (vol->upd_received == vol->upd_bytes) { | 369 | if (vol->upd_received == vol->upd_bytes) { |
| 335 | /* The update is finished, clear the update marker */ | 370 | /* The update is finished, clear the update marker */ |
| 336 | err = clear_update_marker(ubi, vol_id, vol->upd_bytes); | 371 | err = clear_update_marker(ubi, vol, vol->upd_bytes); |
| 337 | if (err) | 372 | if (err) |
| 338 | return err; | 373 | return err; |
| 339 | err = ubi_wl_flush(ubi); | 374 | err = ubi_wl_flush(ubi); |
| 340 | if (err == 0) { | 375 | if (err == 0) { |
| 376 | vol->updating = 0; | ||
| 341 | err = to_write; | 377 | err = to_write; |
| 342 | vfree(vol->upd_buf); | 378 | vfree(vol->upd_buf); |
| 343 | vol->updating = 0; | ||
| 344 | } | 379 | } |
| 345 | } | 380 | } |
| 346 | 381 | ||
| 347 | return err; | 382 | return err; |
| 348 | } | 383 | } |
| 384 | |||
| 385 | /** | ||
| 386 | * ubi_more_leb_change_data - accept more data for atomic LEB change. | ||
| 387 | * @vol: volume description object | ||
| 388 | * @buf: write data (user-space memory buffer) | ||
| 389 | * @count: how much bytes to write | ||
| 390 | * | ||
| 391 | * This function accepts more data to the volume which is being under the | ||
| 392 | * "atomic LEB change" operation. It may be called arbitrary number of times | ||
| 393 | * until all data arrives. This function returns %0 in case of success, number | ||
| 394 | * of bytes written during the last call if the whole "atomic LEB change" | ||
| 395 | * operation has been successfully finished, and a negative error code in case | ||
| 396 | * of failure. | ||
| 397 | */ | ||
| 398 | int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, | ||
| 399 | const void __user *buf, int count) | ||
| 400 | { | ||
| 401 | int err; | ||
| 402 | |||
| 403 | dbg_msg("write %d of %lld bytes, %lld already passed", | ||
| 404 | count, vol->upd_bytes, vol->upd_received); | ||
| 405 | |||
| 406 | if (ubi->ro_mode) | ||
| 407 | return -EROFS; | ||
| 408 | |||
| 409 | if (vol->upd_received + count > vol->upd_bytes) | ||
| 410 | count = vol->upd_bytes - vol->upd_received; | ||
| 411 | |||
| 412 | err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count); | ||
| 413 | if (err) | ||
| 414 | return -EFAULT; | ||
| 415 | |||
| 416 | vol->upd_received += count; | ||
| 417 | |||
| 418 | if (vol->upd_received == vol->upd_bytes) { | ||
| 419 | int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size); | ||
| 420 | |||
| 421 | memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes); | ||
| 422 | len = ubi_calc_data_len(ubi, vol->upd_buf, len); | ||
| 423 | err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum, | ||
| 424 | vol->upd_buf, len, UBI_UNKNOWN); | ||
| 425 | if (err) | ||
| 426 | return err; | ||
| 427 | } | ||
| 428 | |||
| 429 | ubi_assert(vol->upd_received <= vol->upd_bytes); | ||
| 430 | if (vol->upd_received == vol->upd_bytes) { | ||
| 431 | vol->changing_leb = 0; | ||
| 432 | err = count; | ||
| 433 | vfree(vol->upd_buf); | ||
| 434 | } | ||
| 435 | |||
| 436 | return err; | ||
| 437 | } | ||
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 88629a320c2b..a3ca2257e601 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c | |||
| @@ -63,21 +63,30 @@ static struct device_attribute attr_vol_upd_marker = | |||
| 63 | * B. process 2 removes volume Y; | 63 | * B. process 2 removes volume Y; |
| 64 | * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file; | 64 | * C. process 1 starts reading the /<sysfs>/class/ubi/ubiX_Y/reserved_ebs file; |
| 65 | * | 65 | * |
| 66 | * What we want to do in a situation like that is to return error when the file | 66 | * In this situation, this function will return %-ENODEV because it will find |
| 67 | * is read. This is done by means of the 'removed' flag and the 'vol_lock' of | 67 | * out that the volume was removed from the @ubi->volumes array. |
| 68 | * the UBI volume description object. | ||
| 69 | */ | 68 | */ |
| 70 | static ssize_t vol_attribute_show(struct device *dev, | 69 | static ssize_t vol_attribute_show(struct device *dev, |
| 71 | struct device_attribute *attr, char *buf) | 70 | struct device_attribute *attr, char *buf) |
| 72 | { | 71 | { |
| 73 | int ret; | 72 | int ret; |
| 74 | struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); | 73 | struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); |
| 74 | struct ubi_device *ubi; | ||
| 75 | 75 | ||
| 76 | spin_lock(&vol->ubi->volumes_lock); | 76 | ubi = ubi_get_device(vol->ubi->ubi_num); |
| 77 | if (vol->removed) { | 77 | if (!ubi) |
| 78 | spin_unlock(&vol->ubi->volumes_lock); | 78 | return -ENODEV; |
| 79 | |||
| 80 | spin_lock(&ubi->volumes_lock); | ||
| 81 | if (!ubi->volumes[vol->vol_id]) { | ||
| 82 | spin_unlock(&ubi->volumes_lock); | ||
| 83 | ubi_put_device(ubi); | ||
| 79 | return -ENODEV; | 84 | return -ENODEV; |
| 80 | } | 85 | } |
| 86 | /* Take a reference to prevent volume removal */ | ||
| 87 | vol->ref_count += 1; | ||
| 88 | spin_unlock(&ubi->volumes_lock); | ||
| 89 | |||
| 81 | if (attr == &attr_vol_reserved_ebs) | 90 | if (attr == &attr_vol_reserved_ebs) |
| 82 | ret = sprintf(buf, "%d\n", vol->reserved_pebs); | 91 | ret = sprintf(buf, "%d\n", vol->reserved_pebs); |
| 83 | else if (attr == &attr_vol_type) { | 92 | else if (attr == &attr_vol_type) { |
| @@ -94,15 +103,22 @@ static ssize_t vol_attribute_show(struct device *dev, | |||
| 94 | ret = sprintf(buf, "%d\n", vol->corrupted); | 103 | ret = sprintf(buf, "%d\n", vol->corrupted); |
| 95 | else if (attr == &attr_vol_alignment) | 104 | else if (attr == &attr_vol_alignment) |
| 96 | ret = sprintf(buf, "%d\n", vol->alignment); | 105 | ret = sprintf(buf, "%d\n", vol->alignment); |
| 97 | else if (attr == &attr_vol_usable_eb_size) { | 106 | else if (attr == &attr_vol_usable_eb_size) |
| 98 | ret = sprintf(buf, "%d\n", vol->usable_leb_size); | 107 | ret = sprintf(buf, "%d\n", vol->usable_leb_size); |
| 99 | } else if (attr == &attr_vol_data_bytes) | 108 | else if (attr == &attr_vol_data_bytes) |
| 100 | ret = sprintf(buf, "%lld\n", vol->used_bytes); | 109 | ret = sprintf(buf, "%lld\n", vol->used_bytes); |
| 101 | else if (attr == &attr_vol_upd_marker) | 110 | else if (attr == &attr_vol_upd_marker) |
| 102 | ret = sprintf(buf, "%d\n", vol->upd_marker); | 111 | ret = sprintf(buf, "%d\n", vol->upd_marker); |
| 103 | else | 112 | else |
| 104 | BUG(); | 113 | /* This must be a bug */ |
| 105 | spin_unlock(&vol->ubi->volumes_lock); | 114 | ret = -EINVAL; |
| 115 | |||
| 116 | /* We've done the operation, drop volume and UBI device references */ | ||
| 117 | spin_lock(&ubi->volumes_lock); | ||
| 118 | vol->ref_count -= 1; | ||
| 119 | ubi_assert(vol->ref_count >= 0); | ||
| 120 | spin_unlock(&ubi->volumes_lock); | ||
| 121 | ubi_put_device(ubi); | ||
| 106 | return ret; | 122 | return ret; |
| 107 | } | 123 | } |
| 108 | 124 | ||
| @@ -110,7 +126,7 @@ static ssize_t vol_attribute_show(struct device *dev, | |||
| 110 | static void vol_release(struct device *dev) | 126 | static void vol_release(struct device *dev) |
| 111 | { | 127 | { |
| 112 | struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); | 128 | struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); |
| 113 | ubi_assert(vol->removed); | 129 | |
| 114 | kfree(vol); | 130 | kfree(vol); |
| 115 | } | 131 | } |
| 116 | 132 | ||
| @@ -152,9 +168,7 @@ static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) | |||
| 152 | if (err) | 168 | if (err) |
| 153 | return err; | 169 | return err; |
| 154 | err = device_create_file(&vol->dev, &attr_vol_upd_marker); | 170 | err = device_create_file(&vol->dev, &attr_vol_upd_marker); |
| 155 | if (err) | 171 | return err; |
| 156 | return err; | ||
| 157 | return 0; | ||
| 158 | } | 172 | } |
| 159 | 173 | ||
| 160 | /** | 174 | /** |
| @@ -180,16 +194,18 @@ static void volume_sysfs_close(struct ubi_volume *vol) | |||
| 180 | * @req: volume creation request | 194 | * @req: volume creation request |
| 181 | * | 195 | * |
| 182 | * This function creates volume described by @req. If @req->vol_id id | 196 | * This function creates volume described by @req. If @req->vol_id id |
| 183 | * %UBI_VOL_NUM_AUTO, this function automatically assigne ID to the new volume | 197 | * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume |
| 184 | * and saves it in @req->vol_id. Returns zero in case of success and a negative | 198 | * and saves it in @req->vol_id. Returns zero in case of success and a negative |
| 185 | * error code in case of failure. | 199 | * error code in case of failure. Note, the caller has to have the |
| 200 | * @ubi->volumes_mutex locked. | ||
| 186 | */ | 201 | */ |
| 187 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | 202 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) |
| 188 | { | 203 | { |
| 189 | int i, err, vol_id = req->vol_id; | 204 | int i, err, vol_id = req->vol_id, dont_free = 0; |
| 190 | struct ubi_volume *vol; | 205 | struct ubi_volume *vol; |
| 191 | struct ubi_vtbl_record vtbl_rec; | 206 | struct ubi_vtbl_record vtbl_rec; |
| 192 | uint64_t bytes; | 207 | uint64_t bytes; |
| 208 | dev_t dev; | ||
| 193 | 209 | ||
| 194 | if (ubi->ro_mode) | 210 | if (ubi->ro_mode) |
| 195 | return -EROFS; | 211 | return -EROFS; |
| @@ -199,7 +215,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | |||
| 199 | return -ENOMEM; | 215 | return -ENOMEM; |
| 200 | 216 | ||
| 201 | spin_lock(&ubi->volumes_lock); | 217 | spin_lock(&ubi->volumes_lock); |
| 202 | |||
| 203 | if (vol_id == UBI_VOL_NUM_AUTO) { | 218 | if (vol_id == UBI_VOL_NUM_AUTO) { |
| 204 | /* Find unused volume ID */ | 219 | /* Find unused volume ID */ |
| 205 | dbg_msg("search for vacant volume ID"); | 220 | dbg_msg("search for vacant volume ID"); |
| @@ -252,6 +267,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | |||
| 252 | } | 267 | } |
| 253 | ubi->avail_pebs -= vol->reserved_pebs; | 268 | ubi->avail_pebs -= vol->reserved_pebs; |
| 254 | ubi->rsvd_pebs += vol->reserved_pebs; | 269 | ubi->rsvd_pebs += vol->reserved_pebs; |
| 270 | spin_unlock(&ubi->volumes_lock); | ||
| 255 | 271 | ||
| 256 | vol->vol_id = vol_id; | 272 | vol->vol_id = vol_id; |
| 257 | vol->alignment = req->alignment; | 273 | vol->alignment = req->alignment; |
| @@ -259,10 +275,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | |||
| 259 | vol->vol_type = req->vol_type; | 275 | vol->vol_type = req->vol_type; |
| 260 | vol->name_len = req->name_len; | 276 | vol->name_len = req->name_len; |
| 261 | memcpy(vol->name, req->name, vol->name_len + 1); | 277 | memcpy(vol->name, req->name, vol->name_len + 1); |
| 262 | vol->exclusive = 1; | ||
| 263 | vol->ubi = ubi; | 278 | vol->ubi = ubi; |
| 264 | ubi->volumes[vol_id] = vol; | ||
| 265 | spin_unlock(&ubi->volumes_lock); | ||
| 266 | 279 | ||
| 267 | /* | 280 | /* |
| 268 | * Finish all pending erases because there may be some LEBs belonging | 281 | * Finish all pending erases because there may be some LEBs belonging |
| @@ -299,9 +312,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | |||
| 299 | /* Register character device for the volume */ | 312 | /* Register character device for the volume */ |
| 300 | cdev_init(&vol->cdev, &ubi_vol_cdev_operations); | 313 | cdev_init(&vol->cdev, &ubi_vol_cdev_operations); |
| 301 | vol->cdev.owner = THIS_MODULE; | 314 | vol->cdev.owner = THIS_MODULE; |
| 302 | err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol_id + 1), 1); | 315 | dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); |
| 316 | err = cdev_add(&vol->cdev, dev, 1); | ||
| 303 | if (err) { | 317 | if (err) { |
| 304 | ubi_err("cannot add character device for volume %d", vol_id); | 318 | ubi_err("cannot add character device"); |
| 305 | goto out_mapping; | 319 | goto out_mapping; |
| 306 | } | 320 | } |
| 307 | 321 | ||
| @@ -311,12 +325,15 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | |||
| 311 | 325 | ||
| 312 | vol->dev.release = vol_release; | 326 | vol->dev.release = vol_release; |
| 313 | vol->dev.parent = &ubi->dev; | 327 | vol->dev.parent = &ubi->dev; |
| 314 | vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); | 328 | vol->dev.devt = dev; |
| 315 | vol->dev.class = ubi_class; | 329 | vol->dev.class = ubi_class; |
| 330 | |||
| 316 | sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); | 331 | sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); |
| 317 | err = device_register(&vol->dev); | 332 | err = device_register(&vol->dev); |
| 318 | if (err) | 333 | if (err) { |
| 334 | ubi_err("cannot register device"); | ||
| 319 | goto out_gluebi; | 335 | goto out_gluebi; |
| 336 | } | ||
| 320 | 337 | ||
| 321 | err = volume_sysfs_init(ubi, vol); | 338 | err = volume_sysfs_init(ubi, vol); |
| 322 | if (err) | 339 | if (err) |
| @@ -339,15 +356,27 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) | |||
| 339 | goto out_sysfs; | 356 | goto out_sysfs; |
| 340 | 357 | ||
| 341 | spin_lock(&ubi->volumes_lock); | 358 | spin_lock(&ubi->volumes_lock); |
| 359 | ubi->volumes[vol_id] = vol; | ||
| 342 | ubi->vol_count += 1; | 360 | ubi->vol_count += 1; |
| 343 | vol->exclusive = 0; | ||
| 344 | spin_unlock(&ubi->volumes_lock); | 361 | spin_unlock(&ubi->volumes_lock); |
| 345 | 362 | ||
| 346 | paranoid_check_volumes(ubi); | 363 | paranoid_check_volumes(ubi); |
| 347 | return 0; | 364 | return 0; |
| 348 | 365 | ||
| 366 | out_sysfs: | ||
| 367 | /* | ||
| 368 | * We have registered our device, we should not free the volume* | ||
| 369 | * description object in this function in case of an error - it is | ||
| 370 | * freed by the release function. | ||
| 371 | * | ||
| 372 | * Get device reference to prevent the release function from being | ||
| 373 | * called just after sysfs has been closed. | ||
| 374 | */ | ||
| 375 | dont_free = 1; | ||
| 376 | get_device(&vol->dev); | ||
| 377 | volume_sysfs_close(vol); | ||
| 349 | out_gluebi: | 378 | out_gluebi: |
| 350 | err = ubi_destroy_gluebi(vol); | 379 | ubi_destroy_gluebi(vol); |
| 351 | out_cdev: | 380 | out_cdev: |
| 352 | cdev_del(&vol->cdev); | 381 | cdev_del(&vol->cdev); |
| 353 | out_mapping: | 382 | out_mapping: |
| @@ -356,26 +385,13 @@ out_acc: | |||
| 356 | spin_lock(&ubi->volumes_lock); | 385 | spin_lock(&ubi->volumes_lock); |
| 357 | ubi->rsvd_pebs -= vol->reserved_pebs; | 386 | ubi->rsvd_pebs -= vol->reserved_pebs; |
| 358 | ubi->avail_pebs += vol->reserved_pebs; | 387 | ubi->avail_pebs += vol->reserved_pebs; |
| 359 | ubi->volumes[vol_id] = NULL; | ||
| 360 | out_unlock: | 388 | out_unlock: |
| 361 | spin_unlock(&ubi->volumes_lock); | 389 | spin_unlock(&ubi->volumes_lock); |
| 362 | kfree(vol); | 390 | if (dont_free) |
| 363 | return err; | 391 | put_device(&vol->dev); |
| 364 | 392 | else | |
| 365 | /* | 393 | kfree(vol); |
| 366 | * We are registered, so @vol is destroyed in the release function and | 394 | ubi_err("cannot create volume %d, error %d", vol_id, err); |
| 367 | * we have to de-initialize differently. | ||
| 368 | */ | ||
| 369 | out_sysfs: | ||
| 370 | err = ubi_destroy_gluebi(vol); | ||
| 371 | cdev_del(&vol->cdev); | ||
| 372 | kfree(vol->eba_tbl); | ||
| 373 | spin_lock(&ubi->volumes_lock); | ||
| 374 | ubi->rsvd_pebs -= vol->reserved_pebs; | ||
| 375 | ubi->avail_pebs += vol->reserved_pebs; | ||
| 376 | ubi->volumes[vol_id] = NULL; | ||
| 377 | spin_unlock(&ubi->volumes_lock); | ||
| 378 | volume_sysfs_close(vol); | ||
| 379 | return err; | 395 | return err; |
| 380 | } | 396 | } |
| 381 | 397 | ||
| @@ -385,7 +401,8 @@ out_sysfs: | |||
| 385 | * | 401 | * |
| 386 | * This function removes volume described by @desc. The volume has to be opened | 402 | * This function removes volume described by @desc. The volume has to be opened |
| 387 | * in "exclusive" mode. Returns zero in case of success and a negative error | 403 | * in "exclusive" mode. Returns zero in case of success and a negative error |
| 388 | * code in case of failure. | 404 | * code in case of failure. The caller has to have the @ubi->volumes_mutex |
| 405 | * locked. | ||
| 389 | */ | 406 | */ |
| 390 | int ubi_remove_volume(struct ubi_volume_desc *desc) | 407 | int ubi_remove_volume(struct ubi_volume_desc *desc) |
| 391 | { | 408 | { |
| @@ -400,30 +417,36 @@ int ubi_remove_volume(struct ubi_volume_desc *desc) | |||
| 400 | if (ubi->ro_mode) | 417 | if (ubi->ro_mode) |
| 401 | return -EROFS; | 418 | return -EROFS; |
| 402 | 419 | ||
| 420 | spin_lock(&ubi->volumes_lock); | ||
| 421 | if (vol->ref_count > 1) { | ||
| 422 | /* | ||
| 423 | * The volume is busy, probably someone is reading one of its | ||
| 424 | * sysfs files. | ||
| 425 | */ | ||
| 426 | err = -EBUSY; | ||
| 427 | goto out_unlock; | ||
| 428 | } | ||
| 429 | ubi->volumes[vol_id] = NULL; | ||
| 430 | spin_unlock(&ubi->volumes_lock); | ||
| 431 | |||
| 403 | err = ubi_destroy_gluebi(vol); | 432 | err = ubi_destroy_gluebi(vol); |
| 404 | if (err) | 433 | if (err) |
| 405 | return err; | 434 | goto out_err; |
| 406 | 435 | ||
| 407 | err = ubi_change_vtbl_record(ubi, vol_id, NULL); | 436 | err = ubi_change_vtbl_record(ubi, vol_id, NULL); |
| 408 | if (err) | 437 | if (err) |
| 409 | return err; | 438 | goto out_err; |
| 410 | 439 | ||
| 411 | for (i = 0; i < vol->reserved_pebs; i++) { | 440 | for (i = 0; i < vol->reserved_pebs; i++) { |
| 412 | err = ubi_eba_unmap_leb(ubi, vol_id, i); | 441 | err = ubi_eba_unmap_leb(ubi, vol, i); |
| 413 | if (err) | 442 | if (err) |
| 414 | return err; | 443 | goto out_err; |
| 415 | } | 444 | } |
| 416 | 445 | ||
| 417 | spin_lock(&ubi->volumes_lock); | ||
| 418 | vol->removed = 1; | ||
| 419 | ubi->volumes[vol_id] = NULL; | ||
| 420 | spin_unlock(&ubi->volumes_lock); | ||
| 421 | |||
| 422 | kfree(vol->eba_tbl); | 446 | kfree(vol->eba_tbl); |
| 423 | vol->eba_tbl = NULL; | 447 | vol->eba_tbl = NULL; |
| 424 | cdev_del(&vol->cdev); | 448 | cdev_del(&vol->cdev); |
| 425 | volume_sysfs_close(vol); | 449 | volume_sysfs_close(vol); |
| 426 | kfree(desc); | ||
| 427 | 450 | ||
| 428 | spin_lock(&ubi->volumes_lock); | 451 | spin_lock(&ubi->volumes_lock); |
| 429 | ubi->rsvd_pebs -= reserved_pebs; | 452 | ubi->rsvd_pebs -= reserved_pebs; |
| @@ -441,8 +464,15 @@ int ubi_remove_volume(struct ubi_volume_desc *desc) | |||
| 441 | spin_unlock(&ubi->volumes_lock); | 464 | spin_unlock(&ubi->volumes_lock); |
| 442 | 465 | ||
| 443 | paranoid_check_volumes(ubi); | 466 | paranoid_check_volumes(ubi); |
| 444 | module_put(THIS_MODULE); | ||
| 445 | return 0; | 467 | return 0; |
| 468 | |||
| 469 | out_err: | ||
| 470 | ubi_err("cannot remove volume %d, error %d", vol_id, err); | ||
| 471 | spin_lock(&ubi->volumes_lock); | ||
| 472 | ubi->volumes[vol_id] = vol; | ||
| 473 | out_unlock: | ||
| 474 | spin_unlock(&ubi->volumes_lock); | ||
| 475 | return err; | ||
| 446 | } | 476 | } |
| 447 | 477 | ||
| 448 | /** | 478 | /** |
| @@ -450,8 +480,9 @@ int ubi_remove_volume(struct ubi_volume_desc *desc) | |||
| 450 | * @desc: volume descriptor | 480 | * @desc: volume descriptor |
| 451 | * @reserved_pebs: new size in physical eraseblocks | 481 | * @reserved_pebs: new size in physical eraseblocks |
| 452 | * | 482 | * |
| 453 | * This function returns zero in case of success, and a negative error code in | 483 | * This function re-sizes the volume and returns zero in case of success, and a |
| 454 | * case of failure. | 484 | * negative error code in case of failure. The caller has to have the |
| 485 | * @ubi->volumes_mutex locked. | ||
| 455 | */ | 486 | */ |
| 456 | int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) | 487 | int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) |
| 457 | { | 488 | { |
| @@ -466,8 +497,6 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) | |||
| 466 | 497 | ||
| 467 | dbg_msg("re-size volume %d to from %d to %d PEBs", | 498 | dbg_msg("re-size volume %d to from %d to %d PEBs", |
| 468 | vol_id, vol->reserved_pebs, reserved_pebs); | 499 | vol_id, vol->reserved_pebs, reserved_pebs); |
| 469 | ubi_assert(desc->mode == UBI_EXCLUSIVE); | ||
| 470 | ubi_assert(vol == ubi->volumes[vol_id]); | ||
| 471 | 500 | ||
| 472 | if (vol->vol_type == UBI_STATIC_VOLUME && | 501 | if (vol->vol_type == UBI_STATIC_VOLUME && |
| 473 | reserved_pebs < vol->used_ebs) { | 502 | reserved_pebs < vol->used_ebs) { |
| @@ -487,6 +516,14 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) | |||
| 487 | for (i = 0; i < reserved_pebs; i++) | 516 | for (i = 0; i < reserved_pebs; i++) |
| 488 | new_mapping[i] = UBI_LEB_UNMAPPED; | 517 | new_mapping[i] = UBI_LEB_UNMAPPED; |
| 489 | 518 | ||
| 519 | spin_lock(&ubi->volumes_lock); | ||
| 520 | if (vol->ref_count > 1) { | ||
| 521 | spin_unlock(&ubi->volumes_lock); | ||
| 522 | err = -EBUSY; | ||
| 523 | goto out_free; | ||
| 524 | } | ||
| 525 | spin_unlock(&ubi->volumes_lock); | ||
| 526 | |||
| 490 | /* Reserve physical eraseblocks */ | 527 | /* Reserve physical eraseblocks */ |
| 491 | pebs = reserved_pebs - vol->reserved_pebs; | 528 | pebs = reserved_pebs - vol->reserved_pebs; |
| 492 | if (pebs > 0) { | 529 | if (pebs > 0) { |
| @@ -516,7 +553,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) | |||
| 516 | 553 | ||
| 517 | if (pebs < 0) { | 554 | if (pebs < 0) { |
| 518 | for (i = 0; i < -pebs; i++) { | 555 | for (i = 0; i < -pebs; i++) { |
| 519 | err = ubi_eba_unmap_leb(ubi, vol_id, reserved_pebs + i); | 556 | err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); |
| 520 | if (err) | 557 | if (err) |
| 521 | goto out_acc; | 558 | goto out_acc; |
| 522 | } | 559 | } |
| @@ -565,27 +602,28 @@ out_free: | |||
| 565 | /** | 602 | /** |
| 566 | * ubi_add_volume - add volume. | 603 | * ubi_add_volume - add volume. |
| 567 | * @ubi: UBI device description object | 604 | * @ubi: UBI device description object |
| 568 | * @vol_id: volume ID | 605 | * @vol: volume description object |
| 569 | * | 606 | * |
| 570 | * This function adds an existin volume and initializes all its data | 607 | * This function adds an existing volume and initializes all its data |
| 571 | * structures. Returnes zero in case of success and a negative error code in | 608 | * structures. Returns zero in case of success and a negative error code in |
| 572 | * case of failure. | 609 | * case of failure. |
| 573 | */ | 610 | */ |
| 574 | int ubi_add_volume(struct ubi_device *ubi, int vol_id) | 611 | int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) |
| 575 | { | 612 | { |
| 576 | int err; | 613 | int err, vol_id = vol->vol_id; |
| 577 | struct ubi_volume *vol = ubi->volumes[vol_id]; | 614 | dev_t dev; |
| 578 | 615 | ||
| 579 | dbg_msg("add volume %d", vol_id); | 616 | dbg_msg("add volume %d", vol_id); |
| 580 | ubi_dbg_dump_vol_info(vol); | 617 | ubi_dbg_dump_vol_info(vol); |
| 581 | ubi_assert(vol); | ||
| 582 | 618 | ||
| 583 | /* Register character device for the volume */ | 619 | /* Register character device for the volume */ |
| 584 | cdev_init(&vol->cdev, &ubi_vol_cdev_operations); | 620 | cdev_init(&vol->cdev, &ubi_vol_cdev_operations); |
| 585 | vol->cdev.owner = THIS_MODULE; | 621 | vol->cdev.owner = THIS_MODULE; |
| 586 | err = cdev_add(&vol->cdev, MKDEV(ubi->major, vol->vol_id + 1), 1); | 622 | dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); |
| 623 | err = cdev_add(&vol->cdev, dev, 1); | ||
| 587 | if (err) { | 624 | if (err) { |
| 588 | ubi_err("cannot add character device for volume %d", vol_id); | 625 | ubi_err("cannot add character device for volume %d, error %d", |
| 626 | vol_id, err); | ||
| 589 | return err; | 627 | return err; |
| 590 | } | 628 | } |
| 591 | 629 | ||
| @@ -595,7 +633,7 @@ int ubi_add_volume(struct ubi_device *ubi, int vol_id) | |||
| 595 | 633 | ||
| 596 | vol->dev.release = vol_release; | 634 | vol->dev.release = vol_release; |
| 597 | vol->dev.parent = &ubi->dev; | 635 | vol->dev.parent = &ubi->dev; |
| 598 | vol->dev.devt = MKDEV(ubi->major, vol->vol_id + 1); | 636 | vol->dev.devt = dev; |
| 599 | vol->dev.class = ubi_class; | 637 | vol->dev.class = ubi_class; |
| 600 | sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); | 638 | sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); |
| 601 | err = device_register(&vol->dev); | 639 | err = device_register(&vol->dev); |
| @@ -623,22 +661,19 @@ out_cdev: | |||
| 623 | /** | 661 | /** |
| 624 | * ubi_free_volume - free volume. | 662 | * ubi_free_volume - free volume. |
| 625 | * @ubi: UBI device description object | 663 | * @ubi: UBI device description object |
| 626 | * @vol_id: volume ID | 664 | * @vol: volume description object |
| 627 | * | 665 | * |
| 628 | * This function frees all resources for volume @vol_id but does not remove it. | 666 | * This function frees all resources for volume @vol but does not remove it. |
| 629 | * Used only when the UBI device is detached. | 667 | * Used only when the UBI device is detached. |
| 630 | */ | 668 | */ |
| 631 | void ubi_free_volume(struct ubi_device *ubi, int vol_id) | 669 | void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) |
| 632 | { | 670 | { |
| 633 | int err; | 671 | int err; |
| 634 | struct ubi_volume *vol = ubi->volumes[vol_id]; | ||
| 635 | 672 | ||
| 636 | dbg_msg("free volume %d", vol_id); | 673 | dbg_msg("free volume %d", vol->vol_id); |
| 637 | ubi_assert(vol); | ||
| 638 | 674 | ||
| 639 | vol->removed = 1; | 675 | ubi->volumes[vol->vol_id] = NULL; |
| 640 | err = ubi_destroy_gluebi(vol); | 676 | err = ubi_destroy_gluebi(vol); |
| 641 | ubi->volumes[vol_id] = NULL; | ||
| 642 | cdev_del(&vol->cdev); | 677 | cdev_del(&vol->cdev); |
| 643 | volume_sysfs_close(vol); | 678 | volume_sysfs_close(vol); |
| 644 | } | 679 | } |
| @@ -708,11 +743,6 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) | |||
| 708 | goto fail; | 743 | goto fail; |
| 709 | } | 744 | } |
| 710 | 745 | ||
| 711 | if (vol->upd_marker != 0 && vol->upd_marker != 1) { | ||
| 712 | ubi_err("bad upd_marker"); | ||
| 713 | goto fail; | ||
| 714 | } | ||
| 715 | |||
| 716 | if (vol->upd_marker && vol->corrupted) { | 746 | if (vol->upd_marker && vol->corrupted) { |
| 717 | dbg_err("update marker and corrupted simultaneously"); | 747 | dbg_err("update marker and corrupted simultaneously"); |
| 718 | goto fail; | 748 | goto fail; |
| @@ -747,7 +777,7 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) | |||
| 747 | 777 | ||
| 748 | n = (long long)vol->used_ebs * vol->usable_leb_size; | 778 | n = (long long)vol->used_ebs * vol->usable_leb_size; |
| 749 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) { | 779 | if (vol->vol_type == UBI_DYNAMIC_VOLUME) { |
| 750 | if (vol->corrupted != 0) { | 780 | if (vol->corrupted) { |
| 751 | ubi_err("corrupted dynamic volume"); | 781 | ubi_err("corrupted dynamic volume"); |
| 752 | goto fail; | 782 | goto fail; |
| 753 | } | 783 | } |
| @@ -764,10 +794,6 @@ static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) | |||
| 764 | goto fail; | 794 | goto fail; |
| 765 | } | 795 | } |
| 766 | } else { | 796 | } else { |
| 767 | if (vol->corrupted != 0 && vol->corrupted != 1) { | ||
| 768 | ubi_err("bad corrupted"); | ||
| 769 | goto fail; | ||
| 770 | } | ||
| 771 | if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { | 797 | if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { |
| 772 | ubi_err("bad used_ebs"); | 798 | ubi_err("bad used_ebs"); |
| 773 | goto fail; | 799 | goto fail; |
| @@ -820,9 +846,7 @@ static void paranoid_check_volumes(struct ubi_device *ubi) | |||
| 820 | { | 846 | { |
| 821 | int i; | 847 | int i; |
| 822 | 848 | ||
| 823 | mutex_lock(&ubi->vtbl_mutex); | ||
| 824 | for (i = 0; i < ubi->vtbl_slots; i++) | 849 | for (i = 0; i < ubi->vtbl_slots; i++) |
| 825 | paranoid_check_volume(ubi, i); | 850 | paranoid_check_volume(ubi, i); |
| 826 | mutex_unlock(&ubi->vtbl_mutex); | ||
| 827 | } | 851 | } |
| 828 | #endif | 852 | #endif |
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 25b3bd61c7ec..56fc3fbce838 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c | |||
| @@ -86,8 +86,10 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, | |||
| 86 | { | 86 | { |
| 87 | int i, err; | 87 | int i, err; |
| 88 | uint32_t crc; | 88 | uint32_t crc; |
| 89 | struct ubi_volume *layout_vol; | ||
| 89 | 90 | ||
| 90 | ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); | 91 | ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); |
| 92 | layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; | ||
| 91 | 93 | ||
| 92 | if (!vtbl_rec) | 94 | if (!vtbl_rec) |
| 93 | vtbl_rec = &empty_vtbl_record; | 95 | vtbl_rec = &empty_vtbl_record; |
| @@ -96,31 +98,25 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, | |||
| 96 | vtbl_rec->crc = cpu_to_be32(crc); | 98 | vtbl_rec->crc = cpu_to_be32(crc); |
| 97 | } | 99 | } |
| 98 | 100 | ||
| 99 | mutex_lock(&ubi->vtbl_mutex); | ||
| 100 | memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); | 101 | memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); |
| 101 | for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { | 102 | for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { |
| 102 | err = ubi_eba_unmap_leb(ubi, UBI_LAYOUT_VOL_ID, i); | 103 | err = ubi_eba_unmap_leb(ubi, layout_vol, i); |
| 103 | if (err) { | 104 | if (err) |
| 104 | mutex_unlock(&ubi->vtbl_mutex); | ||
| 105 | return err; | 105 | return err; |
| 106 | } | 106 | |
| 107 | err = ubi_eba_write_leb(ubi, UBI_LAYOUT_VOL_ID, i, ubi->vtbl, 0, | 107 | err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, |
| 108 | ubi->vtbl_size, UBI_LONGTERM); | 108 | ubi->vtbl_size, UBI_LONGTERM); |
| 109 | if (err) { | 109 | if (err) |
| 110 | mutex_unlock(&ubi->vtbl_mutex); | ||
| 111 | return err; | 110 | return err; |
| 112 | } | ||
| 113 | } | 111 | } |
| 114 | 112 | ||
| 115 | paranoid_vtbl_check(ubi); | 113 | paranoid_vtbl_check(ubi); |
| 116 | mutex_unlock(&ubi->vtbl_mutex); | 114 | return 0; |
| 117 | return ubi_wl_flush(ubi); | ||
| 118 | } | 115 | } |
| 119 | 116 | ||
| 120 | /** | 117 | /** |
| 121 | * vol_til_check - check if volume table is not corrupted and contains sensible | 118 | * vtbl_check - check if volume table is not corrupted and contains sensible |
| 122 | * data. | 119 | * data. |
| 123 | * | ||
| 124 | * @ubi: UBI device description object | 120 | * @ubi: UBI device description object |
| 125 | * @vtbl: volume table | 121 | * @vtbl: volume table |
| 126 | * | 122 | * |
| @@ -273,7 +269,7 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, | |||
| 273 | * this volume table copy was found during scanning. It has to be wiped | 269 | * this volume table copy was found during scanning. It has to be wiped |
| 274 | * out. | 270 | * out. |
| 275 | */ | 271 | */ |
| 276 | sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); | 272 | sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); |
| 277 | if (sv) | 273 | if (sv) |
| 278 | old_seb = ubi_scan_find_seb(sv, copy); | 274 | old_seb = ubi_scan_find_seb(sv, copy); |
| 279 | 275 | ||
| @@ -285,7 +281,7 @@ retry: | |||
| 285 | } | 281 | } |
| 286 | 282 | ||
| 287 | vid_hdr->vol_type = UBI_VID_DYNAMIC; | 283 | vid_hdr->vol_type = UBI_VID_DYNAMIC; |
| 288 | vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID); | 284 | vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID); |
| 289 | vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; | 285 | vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; |
| 290 | vid_hdr->data_size = vid_hdr->used_ebs = | 286 | vid_hdr->data_size = vid_hdr->used_ebs = |
| 291 | vid_hdr->data_pad = cpu_to_be32(0); | 287 | vid_hdr->data_pad = cpu_to_be32(0); |
| @@ -518,6 +514,17 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, | |||
| 518 | vol->name[vol->name_len] = '\0'; | 514 | vol->name[vol->name_len] = '\0'; |
| 519 | vol->vol_id = i; | 515 | vol->vol_id = i; |
| 520 | 516 | ||
| 517 | if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { | ||
| 518 | /* Auto re-size flag may be set only for one volume */ | ||
| 519 | if (ubi->autoresize_vol_id != -1) { | ||
| 520 | ubi_err("more then one auto-resize volume (%d " | ||
| 521 | "and %d)", ubi->autoresize_vol_id, i); | ||
| 522 | return -EINVAL; | ||
| 523 | } | ||
| 524 | |||
| 525 | ubi->autoresize_vol_id = i; | ||
| 526 | } | ||
| 527 | |||
| 521 | ubi_assert(!ubi->volumes[i]); | 528 | ubi_assert(!ubi->volumes[i]); |
| 522 | ubi->volumes[i] = vol; | 529 | ubi->volumes[i] = vol; |
| 523 | ubi->vol_count += 1; | 530 | ubi->vol_count += 1; |
| @@ -568,6 +575,7 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, | |||
| 568 | vol->last_eb_bytes = sv->last_data_size; | 575 | vol->last_eb_bytes = sv->last_data_size; |
| 569 | } | 576 | } |
| 570 | 577 | ||
| 578 | /* And add the layout volume */ | ||
| 571 | vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); | 579 | vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); |
| 572 | if (!vol) | 580 | if (!vol) |
| 573 | return -ENOMEM; | 581 | return -ENOMEM; |
| @@ -582,7 +590,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, | |||
| 582 | vol->last_eb_bytes = vol->reserved_pebs; | 590 | vol->last_eb_bytes = vol->reserved_pebs; |
| 583 | vol->used_bytes = | 591 | vol->used_bytes = |
| 584 | (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad); | 592 | (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad); |
| 585 | vol->vol_id = UBI_LAYOUT_VOL_ID; | 593 | vol->vol_id = UBI_LAYOUT_VOLUME_ID; |
| 594 | vol->ref_count = 1; | ||
| 586 | 595 | ||
| 587 | ubi_assert(!ubi->volumes[i]); | 596 | ubi_assert(!ubi->volumes[i]); |
| 588 | ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol; | 597 | ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol; |
| @@ -734,7 +743,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 734 | ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE; | 743 | ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE; |
| 735 | ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size); | 744 | ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size); |
| 736 | 745 | ||
| 737 | sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOL_ID); | 746 | sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); |
| 738 | if (!sv) { | 747 | if (!sv) { |
| 739 | /* | 748 | /* |
| 740 | * No logical eraseblocks belonging to the layout volume were | 749 | * No logical eraseblocks belonging to the layout volume were |
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 6330c8cc72b5..a471a491f0ab 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c | |||
| @@ -117,21 +117,6 @@ | |||
| 117 | #define WL_MAX_FAILURES 32 | 117 | #define WL_MAX_FAILURES 32 |
| 118 | 118 | ||
| 119 | /** | 119 | /** |
| 120 | * struct ubi_wl_entry - wear-leveling entry. | ||
| 121 | * @rb: link in the corresponding RB-tree | ||
| 122 | * @ec: erase counter | ||
| 123 | * @pnum: physical eraseblock number | ||
| 124 | * | ||
| 125 | * Each physical eraseblock has a corresponding &struct wl_entry object which | ||
| 126 | * may be kept in different RB-trees. | ||
| 127 | */ | ||
| 128 | struct ubi_wl_entry { | ||
| 129 | struct rb_node rb; | ||
| 130 | int ec; | ||
| 131 | int pnum; | ||
| 132 | }; | ||
| 133 | |||
| 134 | /** | ||
| 135 | * struct ubi_wl_prot_entry - PEB protection entry. | 120 | * struct ubi_wl_prot_entry - PEB protection entry. |
| 136 | * @rb_pnum: link in the @wl->prot.pnum RB-tree | 121 | * @rb_pnum: link in the @wl->prot.pnum RB-tree |
| 137 | * @rb_aec: link in the @wl->prot.aec RB-tree | 122 | * @rb_aec: link in the @wl->prot.aec RB-tree |
| @@ -216,9 +201,6 @@ static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, | |||
| 216 | #define paranoid_check_in_wl_tree(e, root) | 201 | #define paranoid_check_in_wl_tree(e, root) |
| 217 | #endif | 202 | #endif |
| 218 | 203 | ||
| 219 | /* Slab cache for wear-leveling entries */ | ||
| 220 | static struct kmem_cache *wl_entries_slab; | ||
| 221 | |||
| 222 | /** | 204 | /** |
| 223 | * wl_tree_add - add a wear-leveling entry to a WL RB-tree. | 205 | * wl_tree_add - add a wear-leveling entry to a WL RB-tree. |
| 224 | * @e: the wear-leveling entry to add | 206 | * @e: the wear-leveling entry to add |
| @@ -267,15 +249,26 @@ static int do_work(struct ubi_device *ubi) | |||
| 267 | int err; | 249 | int err; |
| 268 | struct ubi_work *wrk; | 250 | struct ubi_work *wrk; |
| 269 | 251 | ||
| 270 | spin_lock(&ubi->wl_lock); | 252 | cond_resched(); |
| 271 | 253 | ||
| 254 | /* | ||
| 255 | * @ubi->work_sem is used to synchronize with the workers. Workers take | ||
| 256 | * it in read mode, so many of them may be doing works at a time. But | ||
| 257 | * the queue flush code has to be sure the whole queue of works is | ||
| 258 | * done, and it takes the mutex in write mode. | ||
| 259 | */ | ||
| 260 | down_read(&ubi->work_sem); | ||
| 261 | spin_lock(&ubi->wl_lock); | ||
| 272 | if (list_empty(&ubi->works)) { | 262 | if (list_empty(&ubi->works)) { |
| 273 | spin_unlock(&ubi->wl_lock); | 263 | spin_unlock(&ubi->wl_lock); |
| 264 | up_read(&ubi->work_sem); | ||
| 274 | return 0; | 265 | return 0; |
| 275 | } | 266 | } |
| 276 | 267 | ||
| 277 | wrk = list_entry(ubi->works.next, struct ubi_work, list); | 268 | wrk = list_entry(ubi->works.next, struct ubi_work, list); |
| 278 | list_del(&wrk->list); | 269 | list_del(&wrk->list); |
| 270 | ubi->works_count -= 1; | ||
| 271 | ubi_assert(ubi->works_count >= 0); | ||
| 279 | spin_unlock(&ubi->wl_lock); | 272 | spin_unlock(&ubi->wl_lock); |
| 280 | 273 | ||
| 281 | /* | 274 | /* |
| @@ -286,11 +279,8 @@ static int do_work(struct ubi_device *ubi) | |||
| 286 | err = wrk->func(ubi, wrk, 0); | 279 | err = wrk->func(ubi, wrk, 0); |
| 287 | if (err) | 280 | if (err) |
| 288 | ubi_err("work failed with error code %d", err); | 281 | ubi_err("work failed with error code %d", err); |
| 282 | up_read(&ubi->work_sem); | ||
| 289 | 283 | ||
| 290 | spin_lock(&ubi->wl_lock); | ||
| 291 | ubi->works_count -= 1; | ||
| 292 | ubi_assert(ubi->works_count >= 0); | ||
| 293 | spin_unlock(&ubi->wl_lock); | ||
| 294 | return err; | 284 | return err; |
| 295 | } | 285 | } |
| 296 | 286 | ||
| @@ -549,8 +539,12 @@ retry: | |||
| 549 | * prot_tree_del - remove a physical eraseblock from the protection trees | 539 | * prot_tree_del - remove a physical eraseblock from the protection trees |
| 550 | * @ubi: UBI device description object | 540 | * @ubi: UBI device description object |
| 551 | * @pnum: the physical eraseblock to remove | 541 | * @pnum: the physical eraseblock to remove |
| 542 | * | ||
| 543 | * This function returns PEB @pnum from the protection trees and returns zero | ||
| 544 | * in case of success and %-ENODEV if the PEB was not found in the protection | ||
| 545 | * trees. | ||
| 552 | */ | 546 | */ |
| 553 | static void prot_tree_del(struct ubi_device *ubi, int pnum) | 547 | static int prot_tree_del(struct ubi_device *ubi, int pnum) |
| 554 | { | 548 | { |
| 555 | struct rb_node *p; | 549 | struct rb_node *p; |
| 556 | struct ubi_wl_prot_entry *pe = NULL; | 550 | struct ubi_wl_prot_entry *pe = NULL; |
| @@ -561,7 +555,7 @@ static void prot_tree_del(struct ubi_device *ubi, int pnum) | |||
| 561 | pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum); | 555 | pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum); |
| 562 | 556 | ||
| 563 | if (pnum == pe->e->pnum) | 557 | if (pnum == pe->e->pnum) |
| 564 | break; | 558 | goto found; |
| 565 | 559 | ||
| 566 | if (pnum < pe->e->pnum) | 560 | if (pnum < pe->e->pnum) |
| 567 | p = p->rb_left; | 561 | p = p->rb_left; |
| @@ -569,10 +563,14 @@ static void prot_tree_del(struct ubi_device *ubi, int pnum) | |||
| 569 | p = p->rb_right; | 563 | p = p->rb_right; |
| 570 | } | 564 | } |
| 571 | 565 | ||
| 566 | return -ENODEV; | ||
| 567 | |||
| 568 | found: | ||
| 572 | ubi_assert(pe->e->pnum == pnum); | 569 | ubi_assert(pe->e->pnum == pnum); |
| 573 | rb_erase(&pe->rb_aec, &ubi->prot.aec); | 570 | rb_erase(&pe->rb_aec, &ubi->prot.aec); |
| 574 | rb_erase(&pe->rb_pnum, &ubi->prot.pnum); | 571 | rb_erase(&pe->rb_pnum, &ubi->prot.pnum); |
| 575 | kfree(pe); | 572 | kfree(pe); |
| 573 | return 0; | ||
| 576 | } | 574 | } |
| 577 | 575 | ||
| 578 | /** | 576 | /** |
| @@ -744,7 +742,8 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, | |||
| 744 | static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | 742 | static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, |
| 745 | int cancel) | 743 | int cancel) |
| 746 | { | 744 | { |
| 747 | int err, put = 0; | 745 | int err, put = 0, scrubbing = 0, protect = 0; |
| 746 | struct ubi_wl_prot_entry *uninitialized_var(pe); | ||
| 748 | struct ubi_wl_entry *e1, *e2; | 747 | struct ubi_wl_entry *e1, *e2; |
| 749 | struct ubi_vid_hdr *vid_hdr; | 748 | struct ubi_vid_hdr *vid_hdr; |
| 750 | 749 | ||
| @@ -757,21 +756,17 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
| 757 | if (!vid_hdr) | 756 | if (!vid_hdr) |
| 758 | return -ENOMEM; | 757 | return -ENOMEM; |
| 759 | 758 | ||
| 759 | mutex_lock(&ubi->move_mutex); | ||
| 760 | spin_lock(&ubi->wl_lock); | 760 | spin_lock(&ubi->wl_lock); |
| 761 | ubi_assert(!ubi->move_from && !ubi->move_to); | ||
| 762 | ubi_assert(!ubi->move_to_put); | ||
| 761 | 763 | ||
| 762 | /* | 764 | if (!ubi->free.rb_node || |
| 763 | * Only one WL worker at a time is supported at this implementation, so | ||
| 764 | * make sure a PEB is not being moved already. | ||
| 765 | */ | ||
| 766 | if (ubi->move_to || !ubi->free.rb_node || | ||
| 767 | (!ubi->used.rb_node && !ubi->scrub.rb_node)) { | 765 | (!ubi->used.rb_node && !ubi->scrub.rb_node)) { |
| 768 | /* | 766 | /* |
| 769 | * Only one WL worker at a time is supported at this | 767 | * No free physical eraseblocks? Well, they must be waiting in |
| 770 | * implementation, so if a LEB is already being moved, cancel. | 768 | * the queue to be erased. Cancel movement - it will be |
| 771 | * | 769 | * triggered again when a free physical eraseblock appears. |
| 772 | * No free physical eraseblocks? Well, we cancel wear-leveling | ||
| 773 | * then. It will be triggered again when a free physical | ||
| 774 | * eraseblock appears. | ||
| 775 | * | 770 | * |
| 776 | * No used physical eraseblocks? They must be temporarily | 771 | * No used physical eraseblocks? They must be temporarily |
| 777 | * protected from being moved. They will be moved to the | 772 | * protected from being moved. They will be moved to the |
| @@ -780,10 +775,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
| 780 | */ | 775 | */ |
| 781 | dbg_wl("cancel WL, a list is empty: free %d, used %d", | 776 | dbg_wl("cancel WL, a list is empty: free %d, used %d", |
| 782 | !ubi->free.rb_node, !ubi->used.rb_node); | 777 | !ubi->free.rb_node, !ubi->used.rb_node); |
| 783 | ubi->wl_scheduled = 0; | 778 | goto out_cancel; |
| 784 | spin_unlock(&ubi->wl_lock); | ||
| 785 | ubi_free_vid_hdr(ubi, vid_hdr); | ||
| 786 | return 0; | ||
| 787 | } | 779 | } |
| 788 | 780 | ||
| 789 | if (!ubi->scrub.rb_node) { | 781 | if (!ubi->scrub.rb_node) { |
| @@ -798,27 +790,24 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
| 798 | if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) { | 790 | if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) { |
| 799 | dbg_wl("no WL needed: min used EC %d, max free EC %d", | 791 | dbg_wl("no WL needed: min used EC %d, max free EC %d", |
| 800 | e1->ec, e2->ec); | 792 | e1->ec, e2->ec); |
| 801 | ubi->wl_scheduled = 0; | 793 | goto out_cancel; |
| 802 | spin_unlock(&ubi->wl_lock); | ||
| 803 | ubi_free_vid_hdr(ubi, vid_hdr); | ||
| 804 | return 0; | ||
| 805 | } | 794 | } |
| 806 | paranoid_check_in_wl_tree(e1, &ubi->used); | 795 | paranoid_check_in_wl_tree(e1, &ubi->used); |
| 807 | rb_erase(&e1->rb, &ubi->used); | 796 | rb_erase(&e1->rb, &ubi->used); |
| 808 | dbg_wl("move PEB %d EC %d to PEB %d EC %d", | 797 | dbg_wl("move PEB %d EC %d to PEB %d EC %d", |
| 809 | e1->pnum, e1->ec, e2->pnum, e2->ec); | 798 | e1->pnum, e1->ec, e2->pnum, e2->ec); |
| 810 | } else { | 799 | } else { |
| 800 | /* Perform scrubbing */ | ||
| 801 | scrubbing = 1; | ||
| 811 | e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb); | 802 | e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb); |
| 812 | e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); | 803 | e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); |
| 813 | paranoid_check_in_wl_tree(e1, &ubi->scrub); | 804 | paranoid_check_in_wl_tree(e1, &ubi->scrub); |
| 814 | rb_erase(&e1->rb, &ubi->scrub); | 805 | rb_erase(&e1->rb, &ubi->scrub); |
| 815 | dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum); | 806 | dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum); |
| 816 | } | 807 | } |
| 817 | 808 | ||
| 818 | paranoid_check_in_wl_tree(e2, &ubi->free); | 809 | paranoid_check_in_wl_tree(e2, &ubi->free); |
| 819 | rb_erase(&e2->rb, &ubi->free); | 810 | rb_erase(&e2->rb, &ubi->free); |
| 820 | ubi_assert(!ubi->move_from && !ubi->move_to); | ||
| 821 | ubi_assert(!ubi->move_to_put && !ubi->move_from_put); | ||
| 822 | ubi->move_from = e1; | 811 | ubi->move_from = e1; |
| 823 | ubi->move_to = e2; | 812 | ubi->move_to = e2; |
| 824 | spin_unlock(&ubi->wl_lock); | 813 | spin_unlock(&ubi->wl_lock); |
| @@ -828,6 +817,10 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
| 828 | * We so far do not know which logical eraseblock our physical | 817 | * We so far do not know which logical eraseblock our physical |
| 829 | * eraseblock (@e1) belongs to. We have to read the volume identifier | 818 | * eraseblock (@e1) belongs to. We have to read the volume identifier |
| 830 | * header first. | 819 | * header first. |
| 820 | * | ||
| 821 | * Note, we are protected from this PEB being unmapped and erased. The | ||
| 822 | * 'ubi_wl_put_peb()' would wait for moving to be finished if the PEB | ||
| 823 | * which is being moved was unmapped. | ||
| 831 | */ | 824 | */ |
| 832 | 825 | ||
| 833 | err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0); | 826 | err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0); |
| @@ -842,32 +835,51 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
| 842 | * likely have the VID header in place. | 835 | * likely have the VID header in place. |
| 843 | */ | 836 | */ |
| 844 | dbg_wl("PEB %d has no VID header", e1->pnum); | 837 | dbg_wl("PEB %d has no VID header", e1->pnum); |
| 845 | err = 0; | 838 | goto out_not_moved; |
| 846 | } else { | ||
| 847 | ubi_err("error %d while reading VID header from PEB %d", | ||
| 848 | err, e1->pnum); | ||
| 849 | if (err > 0) | ||
| 850 | err = -EIO; | ||
| 851 | } | 839 | } |
| 852 | goto error; | 840 | |
| 841 | ubi_err("error %d while reading VID header from PEB %d", | ||
| 842 | err, e1->pnum); | ||
| 843 | if (err > 0) | ||
| 844 | err = -EIO; | ||
| 845 | goto out_error; | ||
| 853 | } | 846 | } |
| 854 | 847 | ||
| 855 | err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr); | 848 | err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr); |
| 856 | if (err) { | 849 | if (err) { |
| 857 | if (err == UBI_IO_BITFLIPS) | 850 | |
| 858 | err = 0; | 851 | if (err < 0) |
| 859 | goto error; | 852 | goto out_error; |
| 853 | if (err == 1) | ||
| 854 | goto out_not_moved; | ||
| 855 | |||
| 856 | /* | ||
| 857 | * For some reason the LEB was not moved - it might be because | ||
| 858 | * the volume is being deleted. We should prevent this PEB from | ||
| 859 | * being selected for wear-levelling movement for some "time", | ||
| 860 | * so put it to the protection tree. | ||
| 861 | */ | ||
| 862 | |||
| 863 | dbg_wl("cancelled moving PEB %d", e1->pnum); | ||
| 864 | pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS); | ||
| 865 | if (!pe) { | ||
| 866 | err = -ENOMEM; | ||
| 867 | goto out_error; | ||
| 868 | } | ||
| 869 | |||
| 870 | protect = 1; | ||
| 860 | } | 871 | } |
| 861 | 872 | ||
| 862 | ubi_free_vid_hdr(ubi, vid_hdr); | 873 | ubi_free_vid_hdr(ubi, vid_hdr); |
| 863 | spin_lock(&ubi->wl_lock); | 874 | spin_lock(&ubi->wl_lock); |
| 875 | if (protect) | ||
| 876 | prot_tree_add(ubi, e1, pe, protect); | ||
| 864 | if (!ubi->move_to_put) | 877 | if (!ubi->move_to_put) |
| 865 | wl_tree_add(e2, &ubi->used); | 878 | wl_tree_add(e2, &ubi->used); |
| 866 | else | 879 | else |
| 867 | put = 1; | 880 | put = 1; |
| 868 | ubi->move_from = ubi->move_to = NULL; | 881 | ubi->move_from = ubi->move_to = NULL; |
| 869 | ubi->move_from_put = ubi->move_to_put = 0; | 882 | ubi->move_to_put = ubi->wl_scheduled = 0; |
| 870 | ubi->wl_scheduled = 0; | ||
| 871 | spin_unlock(&ubi->wl_lock); | 883 | spin_unlock(&ubi->wl_lock); |
| 872 | 884 | ||
| 873 | if (put) { | 885 | if (put) { |
| @@ -877,62 +889,67 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, | |||
| 877 | */ | 889 | */ |
| 878 | dbg_wl("PEB %d was put meanwhile, erase", e2->pnum); | 890 | dbg_wl("PEB %d was put meanwhile, erase", e2->pnum); |
| 879 | err = schedule_erase(ubi, e2, 0); | 891 | err = schedule_erase(ubi, e2, 0); |
| 880 | if (err) { | 892 | if (err) |
| 881 | kmem_cache_free(wl_entries_slab, e2); | 893 | goto out_error; |
| 882 | ubi_ro_mode(ubi); | ||
| 883 | } | ||
| 884 | } | 894 | } |
| 885 | 895 | ||
| 886 | err = schedule_erase(ubi, e1, 0); | 896 | if (!protect) { |
| 887 | if (err) { | 897 | err = schedule_erase(ubi, e1, 0); |
| 888 | kmem_cache_free(wl_entries_slab, e1); | 898 | if (err) |
| 889 | ubi_ro_mode(ubi); | 899 | goto out_error; |
| 890 | } | 900 | } |
| 891 | 901 | ||
| 902 | |||
| 892 | dbg_wl("done"); | 903 | dbg_wl("done"); |
| 893 | return err; | 904 | mutex_unlock(&ubi->move_mutex); |
| 905 | return 0; | ||
| 894 | 906 | ||
| 895 | /* | 907 | /* |
| 896 | * Some error occurred. @e1 was not changed, so return it back. @e2 | 908 | * For some reasons the LEB was not moved, might be an error, might be |
| 897 | * might be changed, schedule it for erasure. | 909 | * something else. @e1 was not changed, so return it back. @e2 might |
| 910 | * be changed, schedule it for erasure. | ||
| 898 | */ | 911 | */ |
| 899 | error: | 912 | out_not_moved: |
| 900 | if (err) | ||
| 901 | dbg_wl("error %d occurred, cancel operation", err); | ||
| 902 | ubi_assert(err <= 0); | ||
| 903 | |||
| 904 | ubi_free_vid_hdr(ubi, vid_hdr); | 913 | ubi_free_vid_hdr(ubi, vid_hdr); |
| 905 | spin_lock(&ubi->wl_lock); | 914 | spin_lock(&ubi->wl_lock); |
| 906 | ubi->wl_scheduled = 0; | 915 | if (scrubbing) |
| 907 | if (ubi->move_from_put) | 916 | wl_tree_add(e1, &ubi->scrub); |
| 908 | put = 1; | ||
| 909 | else | 917 | else |
| 910 | wl_tree_add(e1, &ubi->used); | 918 | wl_tree_add(e1, &ubi->used); |
| 911 | ubi->move_from = ubi->move_to = NULL; | 919 | ubi->move_from = ubi->move_to = NULL; |
| 912 | ubi->move_from_put = ubi->move_to_put = 0; | 920 | ubi->move_to_put = ubi->wl_scheduled = 0; |
| 913 | spin_unlock(&ubi->wl_lock); | 921 | spin_unlock(&ubi->wl_lock); |
| 914 | 922 | ||
| 915 | if (put) { | ||
| 916 | /* | ||
| 917 | * Well, the target PEB was put meanwhile, schedule it for | ||
| 918 | * erasure. | ||
| 919 | */ | ||
| 920 | dbg_wl("PEB %d was put meanwhile, erase", e1->pnum); | ||
| 921 | err = schedule_erase(ubi, e1, 0); | ||
| 922 | if (err) { | ||
| 923 | kmem_cache_free(wl_entries_slab, e1); | ||
| 924 | ubi_ro_mode(ubi); | ||
| 925 | } | ||
| 926 | } | ||
| 927 | |||
| 928 | err = schedule_erase(ubi, e2, 0); | 923 | err = schedule_erase(ubi, e2, 0); |
| 929 | if (err) { | 924 | if (err) |
| 930 | kmem_cache_free(wl_entries_slab, e2); | 925 | goto out_error; |
| 931 | ubi_ro_mode(ubi); | 926 | |
| 932 | } | 927 | mutex_unlock(&ubi->move_mutex); |
| 928 | return 0; | ||
| 929 | |||
| 930 | out_error: | ||
| 931 | ubi_err("error %d while moving PEB %d to PEB %d", | ||
| 932 | err, e1->pnum, e2->pnum); | ||
| 933 | 933 | ||
| 934 | yield(); | 934 | ubi_free_vid_hdr(ubi, vid_hdr); |
| 935 | spin_lock(&ubi->wl_lock); | ||
| 936 | ubi->move_from = ubi->move_to = NULL; | ||
| 937 | ubi->move_to_put = ubi->wl_scheduled = 0; | ||
| 938 | spin_unlock(&ubi->wl_lock); | ||
| 939 | |||
| 940 | kmem_cache_free(ubi_wl_entry_slab, e1); | ||
| 941 | kmem_cache_free(ubi_wl_entry_slab, e2); | ||
| 942 | ubi_ro_mode(ubi); | ||
| 943 | |||
| 944 | mutex_unlock(&ubi->move_mutex); | ||
| 935 | return err; | 945 | return err; |
| 946 | |||
| 947 | out_cancel: | ||
| 948 | ubi->wl_scheduled = 0; | ||
| 949 | spin_unlock(&ubi->wl_lock); | ||
| 950 | mutex_unlock(&ubi->move_mutex); | ||
| 951 | ubi_free_vid_hdr(ubi, vid_hdr); | ||
| 952 | return 0; | ||
| 936 | } | 953 | } |
| 937 | 954 | ||
| 938 | /** | 955 | /** |
| @@ -1020,7 +1037,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | |||
| 1020 | if (cancel) { | 1037 | if (cancel) { |
| 1021 | dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); | 1038 | dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); |
| 1022 | kfree(wl_wrk); | 1039 | kfree(wl_wrk); |
| 1023 | kmem_cache_free(wl_entries_slab, e); | 1040 | kmem_cache_free(ubi_wl_entry_slab, e); |
| 1024 | return 0; | 1041 | return 0; |
| 1025 | } | 1042 | } |
| 1026 | 1043 | ||
| @@ -1049,7 +1066,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, | |||
| 1049 | 1066 | ||
| 1050 | ubi_err("failed to erase PEB %d, error %d", pnum, err); | 1067 | ubi_err("failed to erase PEB %d, error %d", pnum, err); |
| 1051 | kfree(wl_wrk); | 1068 | kfree(wl_wrk); |
| 1052 | kmem_cache_free(wl_entries_slab, e); | 1069 | kmem_cache_free(ubi_wl_entry_slab, e); |
| 1053 | 1070 | ||
| 1054 | if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || | 1071 | if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || |
| 1055 | err == -EBUSY) { | 1072 | err == -EBUSY) { |
| @@ -1119,8 +1136,7 @@ out_ro: | |||
| 1119 | } | 1136 | } |
| 1120 | 1137 | ||
| 1121 | /** | 1138 | /** |
| 1122 | * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling | 1139 | * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling unit. |
| 1123 | * unit. | ||
| 1124 | * @ubi: UBI device description object | 1140 | * @ubi: UBI device description object |
| 1125 | * @pnum: physical eraseblock to return | 1141 | * @pnum: physical eraseblock to return |
| 1126 | * @torture: if this physical eraseblock has to be tortured | 1142 | * @torture: if this physical eraseblock has to be tortured |
| @@ -1128,7 +1144,7 @@ out_ro: | |||
| 1128 | * This function is called to return physical eraseblock @pnum to the pool of | 1144 | * This function is called to return physical eraseblock @pnum to the pool of |
| 1129 | * free physical eraseblocks. The @torture flag has to be set if an I/O error | 1145 | * free physical eraseblocks. The @torture flag has to be set if an I/O error |
| 1130 | * occurred to this @pnum and it has to be tested. This function returns zero | 1146 | * occurred to this @pnum and it has to be tested. This function returns zero |
| 1131 | * in case of success and a negative error code in case of failure. | 1147 | * in case of success, and a negative error code in case of failure. |
| 1132 | */ | 1148 | */ |
| 1133 | int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) | 1149 | int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) |
| 1134 | { | 1150 | { |
| @@ -1139,8 +1155,8 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) | |||
| 1139 | ubi_assert(pnum >= 0); | 1155 | ubi_assert(pnum >= 0); |
| 1140 | ubi_assert(pnum < ubi->peb_count); | 1156 | ubi_assert(pnum < ubi->peb_count); |
| 1141 | 1157 | ||
| 1158 | retry: | ||
| 1142 | spin_lock(&ubi->wl_lock); | 1159 | spin_lock(&ubi->wl_lock); |
| 1143 | |||
| 1144 | e = ubi->lookuptbl[pnum]; | 1160 | e = ubi->lookuptbl[pnum]; |
| 1145 | if (e == ubi->move_from) { | 1161 | if (e == ubi->move_from) { |
| 1146 | /* | 1162 | /* |
| @@ -1148,17 +1164,22 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) | |||
| 1148 | * be moved. It will be scheduled for erasure in the | 1164 | * be moved. It will be scheduled for erasure in the |
| 1149 | * wear-leveling worker. | 1165 | * wear-leveling worker. |
| 1150 | */ | 1166 | */ |
| 1151 | dbg_wl("PEB %d is being moved", pnum); | 1167 | dbg_wl("PEB %d is being moved, wait", pnum); |
| 1152 | ubi_assert(!ubi->move_from_put); | ||
| 1153 | ubi->move_from_put = 1; | ||
| 1154 | spin_unlock(&ubi->wl_lock); | 1168 | spin_unlock(&ubi->wl_lock); |
| 1155 | return 0; | 1169 | |
| 1170 | /* Wait for the WL worker by taking the @ubi->move_mutex */ | ||
| 1171 | mutex_lock(&ubi->move_mutex); | ||
| 1172 | mutex_unlock(&ubi->move_mutex); | ||
| 1173 | goto retry; | ||
| 1156 | } else if (e == ubi->move_to) { | 1174 | } else if (e == ubi->move_to) { |
| 1157 | /* | 1175 | /* |
| 1158 | * User is putting the physical eraseblock which was selected | 1176 | * User is putting the physical eraseblock which was selected |
| 1159 | * as the target the data is moved to. It may happen if the EBA | 1177 | * as the target the data is moved to. It may happen if the EBA |
| 1160 | * unit already re-mapped the LEB but the WL unit did has not | 1178 | * unit already re-mapped the LEB in 'ubi_eba_copy_leb()' but |
| 1161 | * put the PEB to the "used" tree. | 1179 | * the WL unit has not put the PEB to the "used" tree yet, but |
| 1180 | * it is about to do this. So we just set a flag which will | ||
| 1181 | * tell the WL worker that the PEB is not needed anymore and | ||
| 1182 | * should be scheduled for erasure. | ||
| 1162 | */ | 1183 | */ |
| 1163 | dbg_wl("PEB %d is the target of data moving", pnum); | 1184 | dbg_wl("PEB %d is the target of data moving", pnum); |
| 1164 | ubi_assert(!ubi->move_to_put); | 1185 | ubi_assert(!ubi->move_to_put); |
| @@ -1172,8 +1193,15 @@ int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) | |||
| 1172 | } else if (in_wl_tree(e, &ubi->scrub)) { | 1193 | } else if (in_wl_tree(e, &ubi->scrub)) { |
| 1173 | paranoid_check_in_wl_tree(e, &ubi->scrub); | 1194 | paranoid_check_in_wl_tree(e, &ubi->scrub); |
| 1174 | rb_erase(&e->rb, &ubi->scrub); | 1195 | rb_erase(&e->rb, &ubi->scrub); |
| 1175 | } else | 1196 | } else { |
| 1176 | prot_tree_del(ubi, e->pnum); | 1197 | err = prot_tree_del(ubi, e->pnum); |
| 1198 | if (err) { | ||
| 1199 | ubi_err("PEB %d not found", pnum); | ||
| 1200 | ubi_ro_mode(ubi); | ||
| 1201 | spin_unlock(&ubi->wl_lock); | ||
| 1202 | return err; | ||
| 1203 | } | ||
| 1204 | } | ||
| 1177 | } | 1205 | } |
| 1178 | spin_unlock(&ubi->wl_lock); | 1206 | spin_unlock(&ubi->wl_lock); |
| 1179 | 1207 | ||
| @@ -1227,8 +1255,17 @@ retry: | |||
| 1227 | if (in_wl_tree(e, &ubi->used)) { | 1255 | if (in_wl_tree(e, &ubi->used)) { |
| 1228 | paranoid_check_in_wl_tree(e, &ubi->used); | 1256 | paranoid_check_in_wl_tree(e, &ubi->used); |
| 1229 | rb_erase(&e->rb, &ubi->used); | 1257 | rb_erase(&e->rb, &ubi->used); |
| 1230 | } else | 1258 | } else { |
| 1231 | prot_tree_del(ubi, pnum); | 1259 | int err; |
| 1260 | |||
| 1261 | err = prot_tree_del(ubi, e->pnum); | ||
| 1262 | if (err) { | ||
| 1263 | ubi_err("PEB %d not found", pnum); | ||
| 1264 | ubi_ro_mode(ubi); | ||
| 1265 | spin_unlock(&ubi->wl_lock); | ||
| 1266 | return err; | ||
| 1267 | } | ||
| 1268 | } | ||
| 1232 | 1269 | ||
| 1233 | wl_tree_add(e, &ubi->scrub); | 1270 | wl_tree_add(e, &ubi->scrub); |
| 1234 | spin_unlock(&ubi->wl_lock); | 1271 | spin_unlock(&ubi->wl_lock); |
| @@ -1249,17 +1286,32 @@ retry: | |||
| 1249 | */ | 1286 | */ |
| 1250 | int ubi_wl_flush(struct ubi_device *ubi) | 1287 | int ubi_wl_flush(struct ubi_device *ubi) |
| 1251 | { | 1288 | { |
| 1252 | int err, pending_count; | 1289 | int err; |
| 1253 | |||
| 1254 | pending_count = ubi->works_count; | ||
| 1255 | |||
| 1256 | dbg_wl("flush (%d pending works)", pending_count); | ||
| 1257 | 1290 | ||
| 1258 | /* | 1291 | /* |
| 1259 | * Erase while the pending works queue is not empty, but not more then | 1292 | * Erase while the pending works queue is not empty, but not more then |
| 1260 | * the number of currently pending works. | 1293 | * the number of currently pending works. |
| 1261 | */ | 1294 | */ |
| 1262 | while (pending_count-- > 0) { | 1295 | dbg_wl("flush (%d pending works)", ubi->works_count); |
| 1296 | while (ubi->works_count) { | ||
| 1297 | err = do_work(ubi); | ||
| 1298 | if (err) | ||
| 1299 | return err; | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | /* | ||
| 1303 | * Make sure all the works which have been done in parallel are | ||
| 1304 | * finished. | ||
| 1305 | */ | ||
| 1306 | down_write(&ubi->work_sem); | ||
| 1307 | up_write(&ubi->work_sem); | ||
| 1308 | |||
| 1309 | /* | ||
| 1310 | * And in case last was the WL worker and it cancelled the LEB | ||
| 1311 | * movement, flush again. | ||
| 1312 | */ | ||
| 1313 | while (ubi->works_count) { | ||
| 1314 | dbg_wl("flush more (%d pending works)", ubi->works_count); | ||
| 1263 | err = do_work(ubi); | 1315 | err = do_work(ubi); |
| 1264 | if (err) | 1316 | if (err) |
| 1265 | return err; | 1317 | return err; |
| @@ -1294,7 +1346,7 @@ static void tree_destroy(struct rb_root *root) | |||
| 1294 | rb->rb_right = NULL; | 1346 | rb->rb_right = NULL; |
| 1295 | } | 1347 | } |
| 1296 | 1348 | ||
| 1297 | kmem_cache_free(wl_entries_slab, e); | 1349 | kmem_cache_free(ubi_wl_entry_slab, e); |
| 1298 | } | 1350 | } |
| 1299 | } | 1351 | } |
| 1300 | } | 1352 | } |
| @@ -1303,7 +1355,7 @@ static void tree_destroy(struct rb_root *root) | |||
| 1303 | * ubi_thread - UBI background thread. | 1355 | * ubi_thread - UBI background thread. |
| 1304 | * @u: the UBI device description object pointer | 1356 | * @u: the UBI device description object pointer |
| 1305 | */ | 1357 | */ |
| 1306 | static int ubi_thread(void *u) | 1358 | int ubi_thread(void *u) |
| 1307 | { | 1359 | { |
| 1308 | int failures = 0; | 1360 | int failures = 0; |
| 1309 | struct ubi_device *ubi = u; | 1361 | struct ubi_device *ubi = u; |
| @@ -1394,36 +1446,22 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1394 | ubi->used = ubi->free = ubi->scrub = RB_ROOT; | 1446 | ubi->used = ubi->free = ubi->scrub = RB_ROOT; |
| 1395 | ubi->prot.pnum = ubi->prot.aec = RB_ROOT; | 1447 | ubi->prot.pnum = ubi->prot.aec = RB_ROOT; |
| 1396 | spin_lock_init(&ubi->wl_lock); | 1448 | spin_lock_init(&ubi->wl_lock); |
| 1449 | mutex_init(&ubi->move_mutex); | ||
| 1450 | init_rwsem(&ubi->work_sem); | ||
| 1397 | ubi->max_ec = si->max_ec; | 1451 | ubi->max_ec = si->max_ec; |
| 1398 | INIT_LIST_HEAD(&ubi->works); | 1452 | INIT_LIST_HEAD(&ubi->works); |
| 1399 | 1453 | ||
| 1400 | sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num); | 1454 | sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num); |
| 1401 | 1455 | ||
| 1402 | ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); | ||
| 1403 | if (IS_ERR(ubi->bgt_thread)) { | ||
| 1404 | err = PTR_ERR(ubi->bgt_thread); | ||
| 1405 | ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, | ||
| 1406 | err); | ||
| 1407 | return err; | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | if (ubi_devices_cnt == 0) { | ||
| 1411 | wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab", | ||
| 1412 | sizeof(struct ubi_wl_entry), | ||
| 1413 | 0, 0, NULL); | ||
| 1414 | if (!wl_entries_slab) | ||
| 1415 | return -ENOMEM; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | err = -ENOMEM; | 1456 | err = -ENOMEM; |
| 1419 | ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL); | 1457 | ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL); |
| 1420 | if (!ubi->lookuptbl) | 1458 | if (!ubi->lookuptbl) |
| 1421 | goto out_free; | 1459 | return err; |
| 1422 | 1460 | ||
| 1423 | list_for_each_entry_safe(seb, tmp, &si->erase, u.list) { | 1461 | list_for_each_entry_safe(seb, tmp, &si->erase, u.list) { |
| 1424 | cond_resched(); | 1462 | cond_resched(); |
| 1425 | 1463 | ||
| 1426 | e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); | 1464 | e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); |
| 1427 | if (!e) | 1465 | if (!e) |
| 1428 | goto out_free; | 1466 | goto out_free; |
| 1429 | 1467 | ||
| @@ -1431,7 +1469,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1431 | e->ec = seb->ec; | 1469 | e->ec = seb->ec; |
| 1432 | ubi->lookuptbl[e->pnum] = e; | 1470 | ubi->lookuptbl[e->pnum] = e; |
| 1433 | if (schedule_erase(ubi, e, 0)) { | 1471 | if (schedule_erase(ubi, e, 0)) { |
| 1434 | kmem_cache_free(wl_entries_slab, e); | 1472 | kmem_cache_free(ubi_wl_entry_slab, e); |
| 1435 | goto out_free; | 1473 | goto out_free; |
| 1436 | } | 1474 | } |
| 1437 | } | 1475 | } |
| @@ -1439,7 +1477,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1439 | list_for_each_entry(seb, &si->free, u.list) { | 1477 | list_for_each_entry(seb, &si->free, u.list) { |
| 1440 | cond_resched(); | 1478 | cond_resched(); |
| 1441 | 1479 | ||
| 1442 | e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); | 1480 | e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); |
| 1443 | if (!e) | 1481 | if (!e) |
| 1444 | goto out_free; | 1482 | goto out_free; |
| 1445 | 1483 | ||
| @@ -1453,7 +1491,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1453 | list_for_each_entry(seb, &si->corr, u.list) { | 1491 | list_for_each_entry(seb, &si->corr, u.list) { |
| 1454 | cond_resched(); | 1492 | cond_resched(); |
| 1455 | 1493 | ||
| 1456 | e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); | 1494 | e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); |
| 1457 | if (!e) | 1495 | if (!e) |
| 1458 | goto out_free; | 1496 | goto out_free; |
| 1459 | 1497 | ||
| @@ -1461,7 +1499,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1461 | e->ec = seb->ec; | 1499 | e->ec = seb->ec; |
| 1462 | ubi->lookuptbl[e->pnum] = e; | 1500 | ubi->lookuptbl[e->pnum] = e; |
| 1463 | if (schedule_erase(ubi, e, 0)) { | 1501 | if (schedule_erase(ubi, e, 0)) { |
| 1464 | kmem_cache_free(wl_entries_slab, e); | 1502 | kmem_cache_free(ubi_wl_entry_slab, e); |
| 1465 | goto out_free; | 1503 | goto out_free; |
| 1466 | } | 1504 | } |
| 1467 | } | 1505 | } |
| @@ -1470,7 +1508,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) | |||
| 1470 | ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { | 1508 | ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { |
| 1471 | cond_resched(); | 1509 | cond_resched(); |
| 1472 | 1510 | ||
| 1473 | e = kmem_cache_alloc(wl_entries_slab, GFP_KERNEL); | 1511 | e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); |
| 1474 | if (!e) | 1512 | if (!e) |
| 1475 | goto out_free; | 1513 | goto out_free; |
| 1476 | 1514 | ||
| @@ -1510,8 +1548,6 @@ out_free: | |||
| 1510 | tree_destroy(&ubi->free); | 1548 | tree_destroy(&ubi->free); |
| 1511 | tree_destroy(&ubi->scrub); | 1549 | tree_destroy(&ubi->scrub); |
| 1512 | kfree(ubi->lookuptbl); | 1550 | kfree(ubi->lookuptbl); |
| 1513 | if (ubi_devices_cnt == 0) | ||
| 1514 | kmem_cache_destroy(wl_entries_slab); | ||
| 1515 | return err; | 1551 | return err; |
| 1516 | } | 1552 | } |
| 1517 | 1553 | ||
| @@ -1541,7 +1577,7 @@ static void protection_trees_destroy(struct ubi_device *ubi) | |||
| 1541 | rb->rb_right = NULL; | 1577 | rb->rb_right = NULL; |
| 1542 | } | 1578 | } |
| 1543 | 1579 | ||
| 1544 | kmem_cache_free(wl_entries_slab, pe->e); | 1580 | kmem_cache_free(ubi_wl_entry_slab, pe->e); |
| 1545 | kfree(pe); | 1581 | kfree(pe); |
| 1546 | } | 1582 | } |
| 1547 | } | 1583 | } |
| @@ -1553,10 +1589,6 @@ static void protection_trees_destroy(struct ubi_device *ubi) | |||
| 1553 | */ | 1589 | */ |
| 1554 | void ubi_wl_close(struct ubi_device *ubi) | 1590 | void ubi_wl_close(struct ubi_device *ubi) |
| 1555 | { | 1591 | { |
| 1556 | dbg_wl("disable \"%s\"", ubi->bgt_name); | ||
| 1557 | if (ubi->bgt_thread) | ||
| 1558 | kthread_stop(ubi->bgt_thread); | ||
| 1559 | |||
| 1560 | dbg_wl("close the UBI wear-leveling unit"); | 1592 | dbg_wl("close the UBI wear-leveling unit"); |
| 1561 | 1593 | ||
| 1562 | cancel_pending(ubi); | 1594 | cancel_pending(ubi); |
| @@ -1565,8 +1597,6 @@ void ubi_wl_close(struct ubi_device *ubi) | |||
| 1565 | tree_destroy(&ubi->free); | 1597 | tree_destroy(&ubi->free); |
| 1566 | tree_destroy(&ubi->scrub); | 1598 | tree_destroy(&ubi->scrub); |
| 1567 | kfree(ubi->lookuptbl); | 1599 | kfree(ubi->lookuptbl); |
| 1568 | if (ubi_devices_cnt == 1) | ||
| 1569 | kmem_cache_destroy(wl_entries_slab); | ||
| 1570 | } | 1600 | } |
| 1571 | 1601 | ||
| 1572 | #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID | 1602 | #ifdef CONFIG_MTD_UBI_DEBUG_PARANOID |
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 77fc5838609c..4c80404a9aba 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
| @@ -176,7 +176,7 @@ static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct | |||
| 176 | spin_unlock(&inode->i_lock); | 176 | spin_unlock(&inode->i_lock); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | struct posix_acl *jffs2_get_acl(struct inode *inode, int type) | 179 | static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) |
| 180 | { | 180 | { |
| 181 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | 181 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); |
| 182 | struct posix_acl *acl; | 182 | struct posix_acl *acl; |
| @@ -345,8 +345,10 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | |||
| 345 | if (!clone) | 345 | if (!clone) |
| 346 | return -ENOMEM; | 346 | return -ENOMEM; |
| 347 | rc = posix_acl_create_masq(clone, (mode_t *)i_mode); | 347 | rc = posix_acl_create_masq(clone, (mode_t *)i_mode); |
| 348 | if (rc < 0) | 348 | if (rc < 0) { |
| 349 | posix_acl_release(clone); | ||
| 349 | return rc; | 350 | return rc; |
| 351 | } | ||
| 350 | if (rc > 0) | 352 | if (rc > 0) |
| 351 | jffs2_iset_acl(inode, &f->i_acl_access, clone); | 353 | jffs2_iset_acl(inode, &f->i_acl_access, clone); |
| 352 | 354 | ||
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 76c6ebd1acd9..0bb7f003fd80 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h | |||
| @@ -28,7 +28,6 @@ struct jffs2_acl_header { | |||
| 28 | 28 | ||
| 29 | #define JFFS2_ACL_NOT_CACHED ((void *)-1) | 29 | #define JFFS2_ACL_NOT_CACHED ((void *)-1) |
| 30 | 30 | ||
| 31 | extern struct posix_acl *jffs2_get_acl(struct inode *inode, int type); | ||
| 32 | extern int jffs2_permission(struct inode *, int, struct nameidata *); | 31 | extern int jffs2_permission(struct inode *, int, struct nameidata *); |
| 33 | extern int jffs2_acl_chmod(struct inode *); | 32 | extern int jffs2_acl_chmod(struct inode *); |
| 34 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); | 33 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); |
| @@ -40,7 +39,6 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler; | |||
| 40 | 39 | ||
| 41 | #else | 40 | #else |
| 42 | 41 | ||
| 43 | #define jffs2_get_acl(inode, type) (NULL) | ||
| 44 | #define jffs2_permission (NULL) | 42 | #define jffs2_permission (NULL) |
| 45 | #define jffs2_acl_chmod(inode) (0) | 43 | #define jffs2_acl_chmod(inode) (0) |
| 46 | #define jffs2_init_acl_pre(dir_i,inode,mode) (0) | 44 | #define jffs2_init_acl_pre(dir_i,inode,mode) (0) |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 6d1eaddde0ec..e26ea78c7892 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
| @@ -97,11 +97,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
| 97 | ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid); | 97 | ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid); |
| 98 | 98 | ||
| 99 | if (ivalid & ATTR_MODE) | 99 | if (ivalid & ATTR_MODE) |
| 100 | if (iattr->ia_mode & S_ISGID && | 100 | ri->mode = cpu_to_jemode(iattr->ia_mode); |
| 101 | !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID)) | ||
| 102 | ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID); | ||
| 103 | else | ||
| 104 | ri->mode = cpu_to_jemode(iattr->ia_mode); | ||
| 105 | else | 101 | else |
| 106 | ri->mode = cpu_to_jemode(inode->i_mode); | 102 | ri->mode = cpu_to_jemode(inode->i_mode); |
| 107 | 103 | ||
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 4bf86088b3ae..87c6f555e1a0 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
| @@ -32,15 +32,18 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new | |||
| 32 | if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { | 32 | if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) { |
| 33 | /* Duplicate. Free one */ | 33 | /* Duplicate. Free one */ |
| 34 | if (new->version < (*prev)->version) { | 34 | if (new->version < (*prev)->version) { |
| 35 | dbg_dentlist("Eep! Marking new dirent node is obsolete, old is \"%s\", ino #%u\n", | 35 | dbg_dentlist("Eep! Marking new dirent node obsolete, old is \"%s\", ino #%u\n", |
| 36 | (*prev)->name, (*prev)->ino); | 36 | (*prev)->name, (*prev)->ino); |
| 37 | jffs2_mark_node_obsolete(c, new->raw); | 37 | jffs2_mark_node_obsolete(c, new->raw); |
| 38 | jffs2_free_full_dirent(new); | 38 | jffs2_free_full_dirent(new); |
| 39 | } else { | 39 | } else { |
| 40 | dbg_dentlist("marking old dirent \"%s\", ino #%u bsolete\n", | 40 | dbg_dentlist("marking old dirent \"%s\", ino #%u obsolete\n", |
| 41 | (*prev)->name, (*prev)->ino); | 41 | (*prev)->name, (*prev)->ino); |
| 42 | new->next = (*prev)->next; | 42 | new->next = (*prev)->next; |
| 43 | jffs2_mark_node_obsolete(c, ((*prev)->raw)); | 43 | /* It may have been a 'placeholder' deletion dirent, |
| 44 | if jffs2_can_mark_obsolete() (see jffs2_do_unlink()) */ | ||
| 45 | if ((*prev)->raw) | ||
| 46 | jffs2_mark_node_obsolete(c, ((*prev)->raw)); | ||
| 44 | jffs2_free_full_dirent(*prev); | 47 | jffs2_free_full_dirent(*prev); |
| 45 | *prev = new; | 48 | *prev = new; |
| 46 | } | 49 | } |
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 6c1ba3566f58..e512a93d6249 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
| @@ -37,23 +37,24 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info | |||
| 37 | 37 | ||
| 38 | BUG_ON(tn->csize == 0); | 38 | BUG_ON(tn->csize == 0); |
| 39 | 39 | ||
| 40 | if (!jffs2_is_writebuffered(c)) | ||
| 41 | goto adj_acc; | ||
| 42 | |||
| 43 | /* Calculate how many bytes were already checked */ | 40 | /* Calculate how many bytes were already checked */ |
| 44 | ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode); | 41 | ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode); |
| 45 | len = ofs % c->wbuf_pagesize; | 42 | len = tn->csize; |
| 46 | if (likely(len)) | 43 | |
| 47 | len = c->wbuf_pagesize - len; | 44 | if (jffs2_is_writebuffered(c)) { |
| 48 | 45 | int adj = ofs % c->wbuf_pagesize; | |
| 49 | if (len >= tn->csize) { | 46 | if (likely(adj)) |
| 50 | dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n", | 47 | adj = c->wbuf_pagesize - adj; |
| 51 | ref_offset(ref), tn->csize, ofs); | 48 | |
| 52 | goto adj_acc; | 49 | if (adj >= tn->csize) { |
| 53 | } | 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 | 54 | ||
| 55 | ofs += len; | 55 | ofs += adj; |
| 56 | len = tn->csize - len; | 56 | len -= adj; |
| 57 | } | ||
| 57 | 58 | ||
| 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 | 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 | ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len); |
| @@ -63,7 +64,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info | |||
| 63 | * adding and jffs2_flash_read_end() interface. */ | 64 | * adding and jffs2_flash_read_end() interface. */ |
| 64 | if (c->mtd->point) { | 65 | if (c->mtd->point) { |
| 65 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); | 66 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); |
| 66 | if (!err && retlen < tn->csize) { | 67 | if (!err && retlen < len) { |
| 67 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); | 68 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); |
| 68 | c->mtd->unpoint(c->mtd, buffer, ofs, retlen); | 69 | c->mtd->unpoint(c->mtd, buffer, ofs, retlen); |
| 69 | } else if (err) | 70 | } else if (err) |
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 1b88e6e734ef..776f13cbf2b5 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c | |||
| @@ -582,7 +582,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
| 582 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); | 582 | jffs2_add_fd_to_list(c, fd, &dir_f->dents); |
| 583 | up(&dir_f->sem); | 583 | up(&dir_f->sem); |
| 584 | } else { | 584 | } else { |
| 585 | struct jffs2_full_dirent **prev = &dir_f->dents; | 585 | struct jffs2_full_dirent *fd = dir_f->dents; |
| 586 | uint32_t nhash = full_name_hash(name, namelen); | 586 | uint32_t nhash = full_name_hash(name, namelen); |
| 587 | 587 | ||
| 588 | /* We don't actually want to reserve any space, but we do | 588 | /* We don't actually want to reserve any space, but we do |
| @@ -590,21 +590,22 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
| 590 | down(&c->alloc_sem); | 590 | down(&c->alloc_sem); |
| 591 | down(&dir_f->sem); | 591 | down(&dir_f->sem); |
| 592 | 592 | ||
| 593 | while ((*prev) && (*prev)->nhash <= nhash) { | 593 | for (fd = dir_f->dents; fd; fd = fd->next) { |
| 594 | if ((*prev)->nhash == nhash && | 594 | if (fd->nhash == nhash && |
| 595 | !memcmp((*prev)->name, name, namelen) && | 595 | !memcmp(fd->name, name, namelen) && |
| 596 | !(*prev)->name[namelen]) { | 596 | !fd->name[namelen]) { |
| 597 | struct jffs2_full_dirent *this = *prev; | ||
| 598 | 597 | ||
| 599 | D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n", | 598 | D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n", |
| 600 | this->ino, ref_offset(this->raw))); | 599 | fd->ino, ref_offset(fd->raw))); |
| 601 | 600 | jffs2_mark_node_obsolete(c, fd->raw); | |
| 602 | *prev = this->next; | 601 | /* We don't want to remove it from the list immediately, |
| 603 | jffs2_mark_node_obsolete(c, (this->raw)); | 602 | because that screws up getdents()/seek() semantics even |
| 604 | jffs2_free_full_dirent(this); | 603 | more than they're screwed already. Turn it into a |
| 604 | node-less deletion dirent instead -- a placeholder */ | ||
| 605 | fd->raw = NULL; | ||
| 606 | fd->ino = 0; | ||
| 605 | break; | 607 | break; |
| 606 | } | 608 | } |
| 607 | prev = &((*prev)->next); | ||
| 608 | } | 609 | } |
| 609 | up(&dir_f->sem); | 610 | up(&dir_f->sem); |
| 610 | } | 611 | } |
| @@ -630,7 +631,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, | |||
| 630 | D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", | 631 | D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", |
| 631 | fd->name, dead_f->inocache->ino)); | 632 | fd->name, dead_f->inocache->ino)); |
| 632 | } | 633 | } |
| 633 | jffs2_mark_node_obsolete(c, fd->raw); | 634 | if (fd->raw) |
| 635 | jffs2_mark_node_obsolete(c, fd->raw); | ||
| 634 | jffs2_free_full_dirent(fd); | 636 | jffs2_free_full_dirent(fd); |
| 635 | } | 637 | } |
| 636 | } | 638 | } |
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index e17c5343cf51..b0ddf4b25862 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h | |||
| @@ -98,6 +98,18 @@ static inline int cfi_interleave_supported(int i) | |||
| 98 | #define CFI_DEVICETYPE_X32 (32 / 8) | 98 | #define CFI_DEVICETYPE_X32 (32 / 8) |
| 99 | #define CFI_DEVICETYPE_X64 (64 / 8) | 99 | #define CFI_DEVICETYPE_X64 (64 / 8) |
| 100 | 100 | ||
| 101 | |||
| 102 | /* Device Interface Code Assignments from the "Common Flash Memory Interface | ||
| 103 | * Publication 100" dated December 1, 2001. | ||
| 104 | */ | ||
| 105 | #define CFI_INTERFACE_X8_ASYNC 0x0000 | ||
| 106 | #define CFI_INTERFACE_X16_ASYNC 0x0001 | ||
| 107 | #define CFI_INTERFACE_X8_BY_X16_ASYNC 0x0002 | ||
| 108 | #define CFI_INTERFACE_X32_ASYNC 0x0003 | ||
| 109 | #define CFI_INTERFACE_X16_BY_X32_ASYNC 0x0005 | ||
| 110 | #define CFI_INTERFACE_NOT_ALLOWED 0xffff | ||
| 111 | |||
| 112 | |||
| 101 | /* NB: We keep these structures in memory in HOST byteorder, except | 113 | /* NB: We keep these structures in memory in HOST byteorder, except |
| 102 | * where individually noted. | 114 | * where individually noted. |
| 103 | */ | 115 | */ |
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 783fc983417c..0a13bb35f044 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h | |||
| @@ -152,6 +152,15 @@ struct mtd_info { | |||
| 152 | int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); | 152 | int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); |
| 153 | int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); | 153 | int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); |
| 154 | 154 | ||
| 155 | /* In blackbox flight recorder like scenarios we want to make successful | ||
| 156 | writes in interrupt context. panic_write() is only intended to be | ||
| 157 | called when its known the kernel is about to panic and we need the | ||
| 158 | write to succeed. Since the kernel is not going to be running for much | ||
| 159 | longer, this function can break locks and delay to ensure the write | ||
| 160 | succeeds (but not sleep). */ | ||
| 161 | |||
| 162 | int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); | ||
| 163 | |||
| 155 | int (*read_oob) (struct mtd_info *mtd, loff_t from, | 164 | int (*read_oob) (struct mtd_info *mtd, loff_t from, |
| 156 | struct mtd_oob_ops *ops); | 165 | struct mtd_oob_ops *ops); |
| 157 | int (*write_oob) (struct mtd_info *mtd, loff_t to, | 166 | int (*write_oob) (struct mtd_info *mtd, loff_t to, |
diff --git a/include/linux/mtd/mtdram.h b/include/linux/mtd/mtdram.h new file mode 100644 index 000000000000..04fdc07b7353 --- /dev/null +++ b/include/linux/mtd/mtdram.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #ifndef __MTD_MTDRAM_H__ | ||
| 2 | #define __MTD_MTDRAM_H__ | ||
| 3 | |||
| 4 | #include <linux/mtd/mtd.h> | ||
| 5 | int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, | ||
| 6 | unsigned long size, char *name); | ||
| 7 | |||
| 8 | #endif /* __MTD_MTDRAM_H__ */ | ||
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h index c46161f4eee3..d1b310c92eb4 100644 --- a/include/linux/mtd/onenand_regs.h +++ b/include/linux/mtd/onenand_regs.h | |||
| @@ -67,6 +67,7 @@ | |||
| 67 | /* | 67 | /* |
| 68 | * Device ID Register F001h (R) | 68 | * Device ID Register F001h (R) |
| 69 | */ | 69 | */ |
| 70 | #define ONENAND_DEVICE_DENSITY_MASK (0xf) | ||
| 70 | #define ONENAND_DEVICE_DENSITY_SHIFT (4) | 71 | #define ONENAND_DEVICE_DENSITY_SHIFT (4) |
| 71 | #define ONENAND_DEVICE_IS_DDP (1 << 3) | 72 | #define ONENAND_DEVICE_IS_DDP (1 << 3) |
| 72 | #define ONENAND_DEVICE_IS_DEMUX (1 << 2) | 73 | #define ONENAND_DEVICE_IS_DEMUX (1 << 2) |
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index da6b3d6f12a7..7c37d7e55abc 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h | |||
| @@ -71,5 +71,12 @@ extern int parse_mtd_partitions(struct mtd_info *master, const char **types, | |||
| 71 | 71 | ||
| 72 | #define put_partition_parser(p) do { module_put((p)->owner); } while(0) | 72 | #define put_partition_parser(p) do { module_put((p)->owner); } while(0) |
| 73 | 73 | ||
| 74 | #endif | 74 | struct device; |
| 75 | struct device_node; | ||
| 76 | |||
| 77 | int __devinit of_mtd_parse_partitions(struct device *dev, | ||
| 78 | struct mtd_info *mtd, | ||
| 79 | struct device_node *node, | ||
| 80 | struct mtd_partition **pparts); | ||
| 75 | 81 | ||
| 82 | #endif | ||
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h index 3d967b6b120a..f71201d0f3e7 100644 --- a/include/linux/mtd/ubi.h +++ b/include/linux/mtd/ubi.h | |||
| @@ -26,23 +26,6 @@ | |||
| 26 | #include <mtd/ubi-user.h> | 26 | #include <mtd/ubi-user.h> |
| 27 | 27 | ||
| 28 | /* | 28 | /* |
| 29 | * UBI data type hint constants. | ||
| 30 | * | ||
| 31 | * UBI_LONGTERM: long-term data | ||
| 32 | * UBI_SHORTTERM: short-term data | ||
| 33 | * UBI_UNKNOWN: data persistence is unknown | ||
| 34 | * | ||
| 35 | * These constants are used when data is written to UBI volumes in order to | ||
| 36 | * help the UBI wear-leveling unit to find more appropriate physical | ||
| 37 | * eraseblocks. | ||
| 38 | */ | ||
| 39 | enum { | ||
| 40 | UBI_LONGTERM = 1, | ||
| 41 | UBI_SHORTTERM, | ||
| 42 | UBI_UNKNOWN | ||
| 43 | }; | ||
| 44 | |||
| 45 | /* | ||
| 46 | * enum ubi_open_mode - UBI volume open mode constants. | 29 | * enum ubi_open_mode - UBI volume open mode constants. |
| 47 | * | 30 | * |
| 48 | * UBI_READONLY: read-only mode | 31 | * UBI_READONLY: read-only mode |
| @@ -167,6 +150,7 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, | |||
| 167 | int len, int dtype); | 150 | int len, int dtype); |
| 168 | int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum); | 151 | int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum); |
| 169 | int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum); | 152 | int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum); |
| 153 | int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype); | ||
| 170 | int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum); | 154 | int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum); |
| 171 | 155 | ||
| 172 | /* | 156 | /* |
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index f71dac420394..615072c4da04 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h | |||
| @@ -29,7 +29,7 @@ struct mtd_oob_buf { | |||
| 29 | #define MTD_WRITEABLE 0x400 /* Device is writeable */ | 29 | #define MTD_WRITEABLE 0x400 /* Device is writeable */ |
| 30 | #define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ | 30 | #define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */ |
| 31 | #define MTD_NO_ERASE 0x1000 /* No erase necessary */ | 31 | #define MTD_NO_ERASE 0x1000 /* No erase necessary */ |
| 32 | #define MTD_STUPID_LOCK 0x2000 /* Always locked after reset */ | 32 | #define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */ |
| 33 | 33 | ||
| 34 | // Some common devices / combinations of capabilities | 34 | // Some common devices / combinations of capabilities |
| 35 | #define MTD_CAP_ROM 0 | 35 | #define MTD_CAP_ROM 0 |
diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h index 74efa7763479..292f916ea564 100644 --- a/include/mtd/ubi-header.h +++ b/include/mtd/ubi-header.h | |||
| @@ -58,6 +58,43 @@ enum { | |||
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | /* | 60 | /* |
| 61 | * Volume flags used in the volume table record. | ||
| 62 | * | ||
| 63 | * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume | ||
| 64 | * | ||
| 65 | * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume | ||
| 66 | * table. UBI automatically re-sizes the volume which has this flag and makes | ||
| 67 | * the volume to be of largest possible size. This means that if after the | ||
| 68 | * initialization UBI finds out that there are available physical eraseblocks | ||
| 69 | * present on the device, it automatically appends all of them to the volume | ||
| 70 | * (the physical eraseblocks reserved for bad eraseblocks handling and other | ||
| 71 | * reserved physical eraseblocks are not taken). So, if there is a volume with | ||
| 72 | * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical | ||
| 73 | * eraseblocks will be zero after UBI is loaded, because all of them will be | ||
| 74 | * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared | ||
| 75 | * after the volume had been initialized. | ||
| 76 | * | ||
| 77 | * The auto-resize feature is useful for device production purposes. For | ||
| 78 | * example, different NAND flash chips may have different amount of initial bad | ||
| 79 | * eraseblocks, depending of particular chip instance. Manufacturers of NAND | ||
| 80 | * chips usually guarantee that the amount of initial bad eraseblocks does not | ||
| 81 | * exceed certain percent, e.g. 2%. When one creates an UBI image which will be | ||
| 82 | * flashed to the end devices in production, he does not know the exact amount | ||
| 83 | * of good physical eraseblocks the NAND chip on the device will have, but this | ||
| 84 | * number is required to calculate the volume sized and put them to the volume | ||
| 85 | * table of the UBI image. In this case, one of the volumes (e.g., the one | ||
| 86 | * which will store the root file system) is marked as "auto-resizable", and | ||
| 87 | * UBI will adjust its size on the first boot if needed. | ||
| 88 | * | ||
| 89 | * Note, first UBI reserves some amount of physical eraseblocks for bad | ||
| 90 | * eraseblock handling, and then re-sizes the volume, not vice-versa. This | ||
| 91 | * means that the pool of reserved physical eraseblocks will always be present. | ||
| 92 | */ | ||
| 93 | enum { | ||
| 94 | UBI_VTBL_AUTORESIZE_FLG = 0x01, | ||
| 95 | }; | ||
| 96 | |||
| 97 | /* | ||
| 61 | * Compatibility constants used by internal volumes. | 98 | * Compatibility constants used by internal volumes. |
| 62 | * | 99 | * |
| 63 | * @UBI_COMPAT_DELETE: delete this internal volume before anything is written | 100 | * @UBI_COMPAT_DELETE: delete this internal volume before anything is written |
| @@ -262,7 +299,9 @@ struct ubi_vid_hdr { | |||
| 262 | 299 | ||
| 263 | /* The layout volume contains the volume table */ | 300 | /* The layout volume contains the volume table */ |
| 264 | 301 | ||
| 265 | #define UBI_LAYOUT_VOL_ID UBI_INTERNAL_VOL_START | 302 | #define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START |
| 303 | #define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC | ||
| 304 | #define UBI_LAYOUT_VOLUME_ALIGN 1 | ||
| 266 | #define UBI_LAYOUT_VOLUME_EBS 2 | 305 | #define UBI_LAYOUT_VOLUME_EBS 2 |
| 267 | #define UBI_LAYOUT_VOLUME_NAME "layout volume" | 306 | #define UBI_LAYOUT_VOLUME_NAME "layout volume" |
| 268 | #define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT | 307 | #define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT |
| @@ -289,7 +328,8 @@ struct ubi_vid_hdr { | |||
| 289 | * @upd_marker: if volume update was started but not finished | 328 | * @upd_marker: if volume update was started but not finished |
| 290 | * @name_len: volume name length | 329 | * @name_len: volume name length |
| 291 | * @name: the volume name | 330 | * @name: the volume name |
| 292 | * @padding2: reserved, zeroes | 331 | * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) |
| 332 | * @padding: reserved, zeroes | ||
| 293 | * @crc: a CRC32 checksum of the record | 333 | * @crc: a CRC32 checksum of the record |
| 294 | * | 334 | * |
| 295 | * The volume table records are stored in the volume table, which is stored in | 335 | * The volume table records are stored in the volume table, which is stored in |
| @@ -324,7 +364,8 @@ struct ubi_vtbl_record { | |||
| 324 | __u8 upd_marker; | 364 | __u8 upd_marker; |
| 325 | __be16 name_len; | 365 | __be16 name_len; |
| 326 | __u8 name[UBI_VOL_NAME_MAX+1]; | 366 | __u8 name[UBI_VOL_NAME_MAX+1]; |
| 327 | __u8 padding2[24]; | 367 | __u8 flags; |
| 368 | __u8 padding[23]; | ||
| 328 | __be32 crc; | 369 | __be32 crc; |
| 329 | } __attribute__ ((packed)); | 370 | } __attribute__ ((packed)); |
| 330 | 371 | ||
diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h index fe06ded0e6b8..a7421f130cc0 100644 --- a/include/mtd/ubi-user.h +++ b/include/mtd/ubi-user.h | |||
| @@ -22,6 +22,21 @@ | |||
| 22 | #define __UBI_USER_H__ | 22 | #define __UBI_USER_H__ |
| 23 | 23 | ||
| 24 | /* | 24 | /* |
| 25 | * UBI device creation (the same as MTD device attachment) | ||
| 26 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 27 | * | ||
| 28 | * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI | ||
| 29 | * control device. The caller has to properly fill and pass | ||
| 30 | * &struct ubi_attach_req object - UBI will attach the MTD device specified in | ||
| 31 | * the request and return the newly created UBI device number as the ioctl | ||
| 32 | * return value. | ||
| 33 | * | ||
| 34 | * UBI device deletion (the same as MTD device detachment) | ||
| 35 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 36 | * | ||
| 37 | * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI | ||
| 38 | * control device. | ||
| 39 | * | ||
| 25 | * UBI volume creation | 40 | * UBI volume creation |
| 26 | * ~~~~~~~~~~~~~~~~~~~ | 41 | * ~~~~~~~~~~~~~~~~~~~ |
| 27 | * | 42 | * |
| @@ -48,7 +63,7 @@ | |||
| 48 | * | 63 | * |
| 49 | * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the | 64 | * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the |
| 50 | * corresponding UBI volume character device. A pointer to a 64-bit update | 65 | * corresponding UBI volume character device. A pointer to a 64-bit update |
| 51 | * size should be passed to the IOCTL. After then, UBI expects user to write | 66 | * size should be passed to the IOCTL. After this, UBI expects user to write |
| 52 | * this number of bytes to the volume character device. The update is finished | 67 | * this number of bytes to the volume character device. The update is finished |
| 53 | * when the claimed number of bytes is passed. So, the volume update sequence | 68 | * when the claimed number of bytes is passed. So, the volume update sequence |
| 54 | * is something like: | 69 | * is something like: |
| @@ -57,14 +72,24 @@ | |||
| 57 | * ioctl(fd, UBI_IOCVOLUP, &image_size); | 72 | * ioctl(fd, UBI_IOCVOLUP, &image_size); |
| 58 | * write(fd, buf, image_size); | 73 | * write(fd, buf, image_size); |
| 59 | * close(fd); | 74 | * close(fd); |
| 75 | * | ||
| 76 | * Atomic eraseblock change | ||
| 77 | * ~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 78 | * | ||
| 79 | * Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL | ||
| 80 | * command of the corresponding UBI volume character device. A pointer to | ||
| 81 | * &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is | ||
| 82 | * expected to write the requested amount of bytes. This is similar to the | ||
| 83 | * "volume update" IOCTL. | ||
| 60 | */ | 84 | */ |
| 61 | 85 | ||
| 62 | /* | 86 | /* |
| 63 | * When a new volume is created, users may either specify the volume number they | 87 | * When a new UBI volume or UBI device is created, users may either specify the |
| 64 | * want to create or to let UBI automatically assign a volume number using this | 88 | * volume/device number they want to create or to let UBI automatically assign |
| 65 | * constant. | 89 | * the number using these constants. |
| 66 | */ | 90 | */ |
| 67 | #define UBI_VOL_NUM_AUTO (-1) | 91 | #define UBI_VOL_NUM_AUTO (-1) |
| 92 | #define UBI_DEV_NUM_AUTO (-1) | ||
| 68 | 93 | ||
| 69 | /* Maximum volume name length */ | 94 | /* Maximum volume name length */ |
| 70 | #define UBI_MAX_VOLUME_NAME 127 | 95 | #define UBI_MAX_VOLUME_NAME 127 |
| @@ -80,6 +105,15 @@ | |||
| 80 | /* Re-size an UBI volume */ | 105 | /* Re-size an UBI volume */ |
| 81 | #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) | 106 | #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) |
| 82 | 107 | ||
| 108 | /* IOCTL commands of the UBI control character device */ | ||
| 109 | |||
| 110 | #define UBI_CTRL_IOC_MAGIC 'o' | ||
| 111 | |||
| 112 | /* Attach an MTD device */ | ||
| 113 | #define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req) | ||
| 114 | /* Detach an MTD device */ | ||
| 115 | #define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t) | ||
| 116 | |||
| 83 | /* IOCTL commands of UBI volume character devices */ | 117 | /* IOCTL commands of UBI volume character devices */ |
| 84 | 118 | ||
| 85 | #define UBI_VOL_IOC_MAGIC 'O' | 119 | #define UBI_VOL_IOC_MAGIC 'O' |
| @@ -88,6 +122,28 @@ | |||
| 88 | #define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) | 122 | #define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) |
| 89 | /* An eraseblock erasure command, used for debugging, disabled by default */ | 123 | /* An eraseblock erasure command, used for debugging, disabled by default */ |
| 90 | #define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) | 124 | #define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) |
| 125 | /* An atomic eraseblock change command */ | ||
| 126 | #define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t) | ||
| 127 | |||
| 128 | /* Maximum MTD device name length supported by UBI */ | ||
| 129 | #define MAX_UBI_MTD_NAME_LEN 127 | ||
| 130 | |||
| 131 | /* | ||
| 132 | * UBI data type hint constants. | ||
| 133 | * | ||
| 134 | * UBI_LONGTERM: long-term data | ||
| 135 | * UBI_SHORTTERM: short-term data | ||
| 136 | * UBI_UNKNOWN: data persistence is unknown | ||
| 137 | * | ||
| 138 | * These constants are used when data is written to UBI volumes in order to | ||
| 139 | * help the UBI wear-leveling unit to find more appropriate physical | ||
| 140 | * eraseblocks. | ||
| 141 | */ | ||
| 142 | enum { | ||
| 143 | UBI_LONGTERM = 1, | ||
| 144 | UBI_SHORTTERM = 2, | ||
| 145 | UBI_UNKNOWN = 3, | ||
| 146 | }; | ||
| 91 | 147 | ||
| 92 | /* | 148 | /* |
| 93 | * UBI volume type constants. | 149 | * UBI volume type constants. |
| @@ -97,22 +153,58 @@ | |||
| 97 | */ | 153 | */ |
| 98 | enum { | 154 | enum { |
| 99 | UBI_DYNAMIC_VOLUME = 3, | 155 | UBI_DYNAMIC_VOLUME = 3, |
| 100 | UBI_STATIC_VOLUME = 4 | 156 | UBI_STATIC_VOLUME = 4, |
| 157 | }; | ||
| 158 | |||
| 159 | /** | ||
| 160 | * struct ubi_attach_req - attach MTD device request. | ||
| 161 | * @ubi_num: UBI device number to create | ||
| 162 | * @mtd_num: MTD device number to attach | ||
| 163 | * @vid_hdr_offset: VID header offset (use defaults if %0) | ||
| 164 | * @padding: reserved for future, not used, has to be zeroed | ||
| 165 | * | ||
| 166 | * This data structure is used to specify MTD device UBI has to attach and the | ||
| 167 | * parameters it has to use. The number which should be assigned to the new UBI | ||
| 168 | * device is passed in @ubi_num. UBI may automatically assign the number if | ||
| 169 | * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in | ||
| 170 | * @ubi_num. | ||
| 171 | * | ||
| 172 | * Most applications should pass %0 in @vid_hdr_offset to make UBI use default | ||
| 173 | * offset of the VID header within physical eraseblocks. The default offset is | ||
| 174 | * the next min. I/O unit after the EC header. For example, it will be offset | ||
| 175 | * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or | ||
| 176 | * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages. | ||
| 177 | * | ||
| 178 | * But in rare cases, if this optimizes things, the VID header may be placed to | ||
| 179 | * a different offset. For example, the boot-loader might do things faster if the | ||
| 180 | * VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As | ||
| 181 | * the boot-loader would not normally need to read EC headers (unless it needs | ||
| 182 | * UBI in RW mode), it might be faster to calculate ECC. This is weird example, | ||
| 183 | * but it real-life example. So, in this example, @vid_hdr_offer would be | ||
| 184 | * 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes | ||
| 185 | * aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page | ||
| 186 | * of the first page and add needed padding. | ||
| 187 | */ | ||
| 188 | struct ubi_attach_req { | ||
| 189 | int32_t ubi_num; | ||
| 190 | int32_t mtd_num; | ||
| 191 | int32_t vid_hdr_offset; | ||
| 192 | uint8_t padding[12]; | ||
| 101 | }; | 193 | }; |
| 102 | 194 | ||
| 103 | /** | 195 | /** |
| 104 | * struct ubi_mkvol_req - volume description data structure used in | 196 | * struct ubi_mkvol_req - volume description data structure used in |
| 105 | * volume creation requests. | 197 | * volume creation requests. |
| 106 | * @vol_id: volume number | 198 | * @vol_id: volume number |
| 107 | * @alignment: volume alignment | 199 | * @alignment: volume alignment |
| 108 | * @bytes: volume size in bytes | 200 | * @bytes: volume size in bytes |
| 109 | * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) | 201 | * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) |
| 110 | * @padding1: reserved for future, not used | 202 | * @padding1: reserved for future, not used, has to be zeroed |
| 111 | * @name_len: volume name length | 203 | * @name_len: volume name length |
| 112 | * @padding2: reserved for future, not used | 204 | * @padding2: reserved for future, not used, has to be zeroed |
| 113 | * @name: volume name | 205 | * @name: volume name |
| 114 | * | 206 | * |
| 115 | * This structure is used by userspace programs when creating new volumes. The | 207 | * This structure is used by user-space programs when creating new volumes. The |
| 116 | * @used_bytes field is only necessary when creating static volumes. | 208 | * @used_bytes field is only necessary when creating static volumes. |
| 117 | * | 209 | * |
| 118 | * The @alignment field specifies the required alignment of the volume logical | 210 | * The @alignment field specifies the required alignment of the volume logical |
| @@ -139,7 +231,7 @@ struct ubi_mkvol_req { | |||
| 139 | int8_t padding1; | 231 | int8_t padding1; |
| 140 | int16_t name_len; | 232 | int16_t name_len; |
| 141 | int8_t padding2[4]; | 233 | int8_t padding2[4]; |
| 142 | char name[UBI_MAX_VOLUME_NAME+1]; | 234 | char name[UBI_MAX_VOLUME_NAME + 1]; |
| 143 | } __attribute__ ((packed)); | 235 | } __attribute__ ((packed)); |
| 144 | 236 | ||
| 145 | /** | 237 | /** |
| @@ -158,4 +250,19 @@ struct ubi_rsvol_req { | |||
| 158 | int32_t vol_id; | 250 | int32_t vol_id; |
| 159 | } __attribute__ ((packed)); | 251 | } __attribute__ ((packed)); |
| 160 | 252 | ||
| 253 | /** | ||
| 254 | * struct ubi_leb_change_req - a data structure used in atomic logical | ||
| 255 | * eraseblock change requests. | ||
| 256 | * @lnum: logical eraseblock number to change | ||
| 257 | * @bytes: how many bytes will be written to the logical eraseblock | ||
| 258 | * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) | ||
| 259 | * @padding: reserved for future, not used, has to be zeroed | ||
| 260 | */ | ||
| 261 | struct ubi_leb_change_req { | ||
| 262 | int32_t lnum; | ||
| 263 | int32_t bytes; | ||
| 264 | uint8_t dtype; | ||
| 265 | uint8_t padding[7]; | ||
| 266 | } __attribute__ ((packed)); | ||
| 267 | |||
| 161 | #endif /* __UBI_USER_H__ */ | 268 | #endif /* __UBI_USER_H__ */ |
