Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
authorDavid Woodhouse <dwmw2@infradead.org>
Sun, 3 Feb 2008 07:29:41 +0000 (18:29 +1100)
committerDavid Woodhouse <dwmw2@infradead.org>
Sun, 3 Feb 2008 07:30:32 +0000 (18:30 +1100)
56 files changed:
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/cfi_probe.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/lart.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/pnc2000.c [deleted file]
drivers/mtd/maps/scb2_flash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdoops.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/at91_nand.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/orion_nand.c [new file with mode: 0644]
drivers/mtd/nand/pasemi_nand.c [new file with mode: 0644]
drivers/mtd/nand/s3c2410.c
drivers/mtd/ofpart.c [new file with mode: 0644]
drivers/mtd/onenand/onenand_base.c
drivers/mtd/redboot.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/cdev.c
drivers/mtd/ubi/debug.h
drivers/mtd/ubi/eba.c
drivers/mtd/ubi/gluebi.c
drivers/mtd/ubi/io.c
drivers/mtd/ubi/kapi.c
drivers/mtd/ubi/misc.c
drivers/mtd/ubi/scan.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/upd.c
drivers/mtd/ubi/vmt.c
drivers/mtd/ubi/vtbl.c
drivers/mtd/ubi/wl.c
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/fs.c
fs/jffs2/nodelist.c
fs/jffs2/readinode.c
fs/jffs2/write.c
include/linux/mtd/cfi.h
include/linux/mtd/mtdram.h [new file with mode: 0644]
include/linux/mtd/partitions.h
include/linux/mtd/ubi.h
include/mtd/mtd-abi.h
include/mtd/ubi-user.h

index 8848e8ac705d9f22a35dce96d3fe788984cc52ed..e8503341e3b147f5bc242e640bb1596e261695e9 100644 (file)
@@ -150,6 +150,14 @@ config MTD_AFS_PARTS
          for your particular device. It won't happen automatically. The
          'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
 
+config MTD_OF_PARTS
+       tristate "Flash partition map based on OF description"
+       depends on PPC_OF && MTD_PARTITIONS
+       help
+         This provides a partition parsing function which derives
+         the partition map from the children of the flash node,
+         as described in Documentation/powerpc/booting-without-of.txt.
+
 comment "User Modules And Translation Layers"
 
 config MTD_CHAR
@@ -286,6 +294,9 @@ config MTD_OOPS
          buffer in a flash partition where it can be read back at some
          later point.
 
+         To use, add console=ttyMTDx to the kernel command line,
+         where x is the MTD device number to use.
+
 source "drivers/mtd/chips/Kconfig"
 
 source "drivers/mtd/maps/Kconfig"
index 7f0b04b4caa7b50e11cbbc8fe8b584f77c66ade4..538e33d11d46ce026265bc5c504b6c08222ee198 100644 (file)
@@ -11,6 +11,7 @@ obj-$(CONFIG_MTD_CONCAT)      += mtdconcat.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
 obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
 obj-$(CONFIG_MTD_AFS_PARTS)    += afs.o
+obj-$(CONFIG_MTD_OF_PARTS)      += ofpart.o
 
 # 'Users' - code which presents functionality to userspace.
 obj-$(CONFIG_MTD_CHAR)         += mtdchar.o
index 1707f98c322c589c144b59d19cd9a52cbb22377a..47794d23a42ec2029371f35cf71bea6eafd8f073 100644 (file)
@@ -50,6 +50,7 @@
 #define I82802AC       0x00ac
 #define MANUFACTURER_ST         0x0020
 #define M50LPW080       0x002F
+#define AT49BV640D     0x02de
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 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)
 }
 #endif
 
+/* Atmel chips don't use the same PRI format as Intel chips */
+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+       struct cfi_pri_atmel atmel_pri;
+       uint32_t features = 0;
+
+       /* Reverse byteswapping */
+       extp->FeatureSupport = cpu_to_le32(extp->FeatureSupport);
+       extp->BlkStatusRegMask = cpu_to_le16(extp->BlkStatusRegMask);
+       extp->ProtRegAddr = cpu_to_le16(extp->ProtRegAddr);
+
+       memcpy(&atmel_pri, extp, sizeof(atmel_pri));
+       memset((char *)extp + 5, 0, sizeof(*extp) - 5);
+
+       printk(KERN_ERR "atmel Features: %02x\n", atmel_pri.Features);
+
+       if (atmel_pri.Features & 0x01) /* chip erase supported */
+               features |= (1<<0);
+       if (atmel_pri.Features & 0x02) /* erase suspend supported */
+               features |= (1<<1);
+       if (atmel_pri.Features & 0x04) /* program suspend supported */
+               features |= (1<<2);
+       if (atmel_pri.Features & 0x08) /* simultaneous operations supported */
+               features |= (1<<9);
+       if (atmel_pri.Features & 0x20) /* page mode read supported */
+               features |= (1<<7);
+       if (atmel_pri.Features & 0x40) /* queued erase supported */
+               features |= (1<<4);
+       if (atmel_pri.Features & 0x80) /* Protection bits supported */
+               features |= (1<<6);
+
+       extp->FeatureSupport = features;
+
+       /* burst write mode not supported */
+       cfi->cfiq->BufWriteTimeoutTyp = 0;
+       cfi->cfiq->BufWriteTimeoutMax = 0;
+}
+
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 /* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
 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)
 /*
  * Some chips power-up with all sectors locked by default.
  */
-static void fixup_use_powerup_lock(struct mtd_info *mtd, void *param)
+static void fixup_unlock_powerup_lock(struct mtd_info *mtd, void *param)
 {
-       printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
-       mtd->flags |= MTD_STUPID_LOCK;
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+
+       if (cfip->FeatureSupport&32) {
+               printk(KERN_INFO "Using auto-unlock on power-up/resume\n" );
+               mtd->flags |= MTD_POWERUP_LOCK;
+       }
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+       { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
 #endif
@@ -245,7 +294,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #endif
        { CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
        { CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-       { MANUFACTURER_INTEL, 0x891c,         fixup_use_powerup_lock, NULL, },
+       { MANUFACTURER_INTEL, CFI_ID_ANY, fixup_unlock_powerup_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
 
@@ -277,7 +326,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                return NULL;
 
        if (extp->MajorVersion != '1' ||
-           (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
+           (extp->MinorVersion < '0' || extp->MinorVersion > '5')) {
                printk(KERN_ERR "  Unknown Intel/Sharp Extended Query "
                       "version %c.%c.\n",  extp->MajorVersion,
                       extp->MinorVersion);
@@ -752,6 +801,7 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
        int ret;
+       DECLARE_WAITQUEUE(wait, current);
 
  retry:
        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
                        spin_unlock(contender->mutex);
                }
 
+               /* Check if we already have suspended erase
+                * on this chip. Sleep. */
+               if (mode == FL_ERASING && shared->erasing
+                   && shared->erasing->oldstate == FL_ERASING) {
+                       spin_unlock(&shared->lock);
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       add_wait_queue(&chip->wq, &wait);
+                       spin_unlock(chip->mutex);
+                       schedule();
+                       remove_wait_queue(&chip->wq, &wait);
+                       spin_lock(chip->mutex);
+                       goto retry;
+               }
+
                /* We now own it */
                shared->writing = chip;
                if (mode == FL_ERASING)
@@ -2294,7 +2358,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
        struct flchip *chip;
        int ret = 0;
 
-       if ((mtd->flags & MTD_STUPID_LOCK)
+       if ((mtd->flags & MTD_POWERUP_LOCK)
            && extp && (extp->FeatureSupport & (1 << 5)))
                cfi_intelext_save_locks(mtd);
 
@@ -2405,7 +2469,7 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
                spin_unlock(chip->mutex);
        }
 
-       if ((mtd->flags & MTD_STUPID_LOCK)
+       if ((mtd->flags & MTD_POWERUP_LOCK)
            && extp && (extp->FeatureSupport & (1 << 5)))
                cfi_intelext_restore_locks(mtd);
 }
index 389acc600f5e9a214939f041a794e8382ff4c1d3..d072e87ce4e20cec96af6220d8bd903864b8de29 100644 (file)
@@ -185,6 +185,10 @@ static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
                extp->TopBottom = 2;
        else
                extp->TopBottom = 3;
+
+       /* burst write mode not supported */
+       cfi->cfiq->BufWriteTimeoutTyp = 0;
+       cfi->cfiq->BufWriteTimeoutMax = 0;
 }
 
 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)
 {
        mtd->lock = cfi_atmel_lock;
        mtd->unlock = cfi_atmel_unlock;
-       mtd->flags |= MTD_STUPID_LOCK;
+       mtd->flags |= MTD_POWERUP_LOCK;
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
+       { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
 #ifdef AMD_BOOTLOC_BUG
        { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
 #endif
@@ -229,7 +234,6 @@ static struct cfi_fixup cfi_fixup_table[] = {
 #if !FORCE_WORD_WRITE
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
 #endif
-       { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
        { 0, 0, NULL, NULL }
 };
 static struct cfi_fixup jedec_fixup_table[] = {
@@ -338,10 +342,12 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
                /* Modify the unlock address if we are in compatibility mode */
                if (    /* x16 in x8 mode */
                        ((cfi->device_type == CFI_DEVICETYPE_X8) &&
-                               (cfi->cfiq->InterfaceDesc == 2)) ||
+                               (cfi->cfiq->InterfaceDesc ==
+                                       CFI_INTERFACE_X8_BY_X16_ASYNC)) ||
                        /* x32 in x16 mode */
                        ((cfi->device_type == CFI_DEVICETYPE_X16) &&
-                               (cfi->cfiq->InterfaceDesc == 4)))
+                               (cfi->cfiq->InterfaceDesc ==
+                                       CFI_INTERFACE_X16_BY_X32_ASYNC)))
                {
                        cfi->addr_unlock1 = 0xaaa;
                        cfi->addr_unlock2 = 0x555;
index 60e11a0ada97b4d6ae9b1792eec64a45e6865da8..f651b6ef1c5d6c44805b066fab343eb965f952d0 100644 (file)
@@ -370,27 +370,27 @@ static void print_cfi_ident(struct cfi_ident *cfip)
        printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20));
        printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc);
        switch(cfip->InterfaceDesc) {
-       case 0:
+       case CFI_INTERFACE_X8_ASYNC:
                printk("  - x8-only asynchronous interface\n");
                break;
 
-       case 1:
+       case CFI_INTERFACE_X16_ASYNC:
                printk("  - x16-only asynchronous interface\n");
                break;
 
-       case 2:
+       case CFI_INTERFACE_X8_BY_X16_ASYNC:
                printk("  - supports x8 and x16 via BYTE# with asynchronous interface\n");
                break;
 
-       case 3:
+       case CFI_INTERFACE_X32_ASYNC:
                printk("  - x32-only asynchronous interface\n");
                break;
 
-       case 4:
+       case CFI_INTERFACE_X16_BY_X32_ASYNC:
                printk("  - supports x16 and x32 via Word# with asynchronous interface\n");
                break;
 
-       case 65535:
+       case CFI_INTERFACE_NOT_ALLOWED:
                printk("  - Not Allowed / Reserved\n");
                break;
 
index a67b23b87fc044ecad43173e7c76bc9b025e0910..4be51a86a85cbbe711eaca3973ab9716692735ae 100644 (file)
@@ -194,8 +194,8 @@ enum uaddr {
 
 
 struct unlock_addr {
-       u32 addr1;
-       u32 addr2;
+       uint32_t addr1;
+       uint32_t addr2;
 };
 
 
@@ -246,16 +246,16 @@ static const struct unlock_addr  unlock_addrs[] = {
        }
 };
 
-
 struct amd_flash_info {
-       const __u16 mfr_id;
-       const __u16 dev_id;
        const char *name;
-       const int DevSize;
-       const int NumEraseRegions;
-       const int CmdSet;
-       const __u8 uaddr[4];            /* unlock addrs for 8, 16, 32, 64 */
-       const ulong regions[6];
+       const uint16_t mfr_id;
+       const uint16_t dev_id;
+       const uint8_t dev_size;
+       const uint8_t nr_regions;
+       const uint16_t cmd_set;
+       const uint32_t regions[6];
+       const uint8_t devtypes;         /* Bitmask for x8, x16 etc. */
+       const uint8_t uaddr;            /* unlock addrs for 8, 16, 32, 64 */
 };
 
 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
@@ -280,12 +280,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F032B,
                .name           = "AMD AM29F032B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,64)
                }
@@ -293,13 +292,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV160DT,
                .name           = "AMD AM29LV160DT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -310,13 +307,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV160DB,
                .name           = "AMD AM29LV160DB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -327,13 +322,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV400BB,
                .name           = "AMD AM29LV400BB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -344,13 +337,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV400BT,
                .name           = "AMD AM29LV400BT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,7),
                        ERASEINFO(0x08000,1),
@@ -361,13 +352,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV800BB,
                .name           = "AMD AM29LV800BB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -379,13 +368,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29DL800BB,
                .name           = "AMD AM29DL800BB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 6,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 6,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x08000,1),
@@ -398,13 +385,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29DL800BT,
                .name           = "AMD AM29DL800BT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 6,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 6,
                .regions        = {
                        ERASEINFO(0x10000,14),
                        ERASEINFO(0x04000,1),
@@ -417,13 +402,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F800BB,
                .name           = "AMD AM29F800BB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -434,13 +417,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV800BT,
                .name           = "AMD AM29LV800BT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,15),
                        ERASEINFO(0x08000,1),
@@ -451,13 +432,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F800BT,
                .name           = "AMD AM29F800BT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,15),
                        ERASEINFO(0x08000,1),
@@ -468,12 +447,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F017D,
                .name           = "AMD AM29F017D",
-               .uaddr          = {
-                       [0] = MTD_UADDR_DONT_CARE     /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_DONT_CARE,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -481,12 +459,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F016D,
                .name           = "AMD AM29F016D",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -494,12 +471,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F080,
                .name           = "AMD AM29F080",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -507,12 +483,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F040,
                .name           = "AMD AM29F040",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -520,12 +495,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV040B,
                .name           = "AMD AM29LV040B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -533,12 +507,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F002T,
                .name           = "AMD AM29F002T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,3),
                        ERASEINFO(0x08000,1),
@@ -549,12 +522,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV512,
                .name           = "Atmel AT49BV512",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_64KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_64KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,1)
                }
@@ -562,12 +534,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT29LV512,
                .name           = "Atmel AT29LV512",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_64KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_64KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x80,256),
                        ERASEINFO(0x80,256)
@@ -576,13 +547,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV16X,
                .name           = "Atmel AT49BV16X",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x0AAA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,31)
@@ -591,13 +560,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV16XT,
                .name           = "Atmel AT49BV16XT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x0AAA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x02000,8)
@@ -606,13 +573,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV32X,
                .name           = "Atmel AT49BV32X",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x0AAA,      /* ???? */
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,63)
@@ -621,13 +586,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ATMEL,
                .dev_id         = AT49BV32XT,
                .name           = "Atmel AT49BV32XT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x0AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x0AAA   /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x0AAA,      /* ???? */
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,63),
                        ERASEINFO(0x02000,8)
@@ -636,12 +599,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29F040C,
                .name           = "Fujitsu MBM29F040C",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8)
                }
@@ -649,13 +611,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29F800BA,
                .name           = "Fujitsu MBM29F800BA",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -666,12 +626,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV650UE,
                .name           = "Fujitsu MBM29LV650UE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_DONT_CARE     /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_DONT_CARE,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,128)
                }
@@ -679,13 +638,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV320TE,
                .name           = "Fujitsu MBM29LV320TE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,63),
                        ERASEINFO(0x02000,8)
@@ -694,13 +651,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV320BE,
                .name           = "Fujitsu MBM29LV320BE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,63)
@@ -709,13 +664,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV160TE,
                .name           = "Fujitsu MBM29LV160TE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -726,13 +679,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV160BE,
                .name           = "Fujitsu MBM29LV160BE",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -743,13 +694,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV800BA,
                .name           = "Fujitsu MBM29LV800BA",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -760,13 +709,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV800TA,
                .name           = "Fujitsu MBM29LV800TA",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,15),
                        ERASEINFO(0x08000,1),
@@ -777,13 +724,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV400BC,
                .name           = "Fujitsu MBM29LV400BC",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -794,13 +739,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV400TC,
                .name           = "Fujitsu MBM29LV400TC",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,7),
                        ERASEINFO(0x08000,1),
@@ -811,12 +754,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_HYUNDAI,
                .dev_id         = HY29F002T,
                .name           = "Hyundai HY29F002T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,3),
                        ERASEINFO(0x08000,1),
@@ -827,12 +769,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F004B3B,
                .name           = "Intel 28F004B3B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 7),
@@ -841,12 +782,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F004B3T,
                .name           = "Intel 28F004B3T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 7),
                        ERASEINFO(0x02000, 8),
@@ -855,13 +795,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F400B3B,
                .name           = "Intel 28F400B3B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 7),
@@ -870,13 +808,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F400B3T,
                .name           = "Intel 28F400B3T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 7),
                        ERASEINFO(0x02000, 8),
@@ -885,12 +821,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F008B3B,
                .name           = "Intel 28F008B3B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 15),
@@ -899,12 +834,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F008B3T,
                .name           = "Intel 28F008B3T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 15),
                        ERASEINFO(0x02000, 8),
@@ -913,12 +847,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F008S5,
                .name           = "Intel 28F008S5",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -926,12 +859,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F016S5,
                .name           = "Intel 28F016S5",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -939,12 +871,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F008SA,
                .name           = "Intel 28F008SA",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000, 16),
                }
@@ -952,12 +883,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F800B3B,
                .name           = "Intel 28F800B3B",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 15),
@@ -966,12 +896,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F800B3T,
                .name           = "Intel 28F800B3T",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 15),
                        ERASEINFO(0x02000, 8),
@@ -980,12 +909,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F016B3B,
                .name           = "Intel 28F016B3B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 31),
@@ -994,12 +922,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F016S3,
                .name           = "Intel I28F016S3",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000, 32),
                }
@@ -1007,12 +934,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F016B3T,
                .name           = "Intel 28F016B3T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 31),
                        ERASEINFO(0x02000, 8),
@@ -1021,12 +947,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F160B3B,
                .name           = "Intel 28F160B3B",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 31),
@@ -1035,12 +960,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F160B3T,
                .name           = "Intel 28F160B3T",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 31),
                        ERASEINFO(0x02000, 8),
@@ -1049,12 +973,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F320B3B,
                .name           = "Intel 28F320B3B",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 63),
@@ -1063,12 +986,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F320B3T,
                .name           = "Intel 28F320B3T",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 63),
                        ERASEINFO(0x02000, 8),
@@ -1077,12 +999,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F640B3B,
                .name           = "Intel 28F640B3B",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000, 8),
                        ERASEINFO(0x10000, 127),
@@ -1091,12 +1012,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F640B3T,
                .name           = "Intel 28F640B3T",
-               .uaddr          = {
-                       [1] = MTD_UADDR_UNNECESSARY,    /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000, 127),
                        ERASEINFO(0x02000, 8),
@@ -1105,12 +1025,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I82802AB,
                .name           = "Intel 82802AB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1118,12 +1037,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I82802AC,
                .name           = "Intel 82802AC",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -1131,12 +1049,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29LV040C,
                .name           = "Macronix MX29LV040C",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1144,13 +1061,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29LV160T,
                .name           = "MXIC MX29LV160T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -1161,13 +1076,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_NEC,
                .dev_id         = UPD29F064115,
                .name           = "NEC uPD29F064115",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 3,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,      /* ???? */
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 3,
                .regions        = {
                        ERASEINFO(0x2000,8),
                        ERASEINFO(0x10000,126),
@@ -1177,13 +1090,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29LV160B,
                .name           = "MXIC MX29LV160B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1194,12 +1105,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F040,
                .name           = "Macronix MX29F040",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1207,12 +1117,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F016,
                .name           = "Macronix MX29F016",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -1220,12 +1129,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F004T,
                .name           = "Macronix MX29F004T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,7),
                        ERASEINFO(0x08000,1),
@@ -1236,12 +1144,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F004B,
                .name           = "Macronix MX29F004B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1252,12 +1159,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_MACRONIX,
                .dev_id         = MX29F002T,
                .name           = "Macronix MX29F002T",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,3),
                        ERASEINFO(0x08000,1),
@@ -1268,12 +1174,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_PMC,
                .dev_id         = PM49FL002,
                .name           = "PMC Pm49FL002",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO( 0x01000, 64 )
                }
@@ -1281,12 +1186,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_PMC,
                .dev_id         = PM49FL004,
                .name           = "PMC Pm49FL004",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO( 0x01000, 128 )
                }
@@ -1294,12 +1198,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_PMC,
                .dev_id         = PM49FL008,
                .name           = "PMC Pm49FL008",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO( 0x01000, 256 )
                }
@@ -1307,25 +1210,23 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SHARP,
                .dev_id         = LH28F640BF,
                .name           = "LH28F640BF",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_INTEL_STD,
-               .NumEraseRegions= 1,
-               .regions        = {
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_INTEL_STD,
+               .nr_regions     = 1,
+               .regions        = {
                        ERASEINFO(0x40000,16),
                }
         }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF512,
                .name           = "SST 39LF512",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_64KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_64KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,16),
                }
@@ -1333,12 +1234,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF010,
                .name           = "SST 39LF010",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_128KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_128KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,32),
                }
@@ -1346,36 +1246,33 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST29EE020,
                .name           = "SST 29EE020",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_SST_PAGE,
-               .NumEraseRegions= 1,
-               .regions = {ERASEINFO(0x01000,64),
-               }
-         }, {
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_SST_PAGE,
+               .nr_regions     = 1,
+               .regions = {ERASEINFO(0x01000,64),
+               }
+       }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST29LE020,
                .name           = "SST 29LE020",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_SST_PAGE,
-               .NumEraseRegions= 1,
-               .regions = {ERASEINFO(0x01000,64),
-               }
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_SST_PAGE,
+               .nr_regions     = 1,
+               .regions = {ERASEINFO(0x01000,64),
+               }
        }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF020,
                .name           = "SST 39LF020",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,64),
                }
@@ -1383,12 +1280,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF040,
                .name           = "SST 39LF040",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,128),
                }
@@ -1396,12 +1292,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39SF010A,
                .name           = "SST 39SF010A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_128KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_128KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,32),
                }
@@ -1409,26 +1304,24 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39SF020A,
                .name           = "SST 39SF020A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,64),
                }
        }, {
                .mfr_id         = MANUFACTURER_SST,
-               .dev_id         = SST49LF040B,
-               .name           = "SST 49LF040B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
-               .regions        = {
+               .dev_id         = SST49LF040B,
+               .name           = "SST 49LF040B",
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
+               .regions        = {
                        ERASEINFO(0x01000,128),
                }
        }, {
@@ -1436,12 +1329,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF004B,
                .name           = "SST 49LF004B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,128),
                }
@@ -1449,12 +1341,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF008A,
                .name           = "SST 49LF008A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,256),
                }
@@ -1462,12 +1353,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF030A,
                .name           = "SST 49LF030A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,96),
                }
@@ -1475,12 +1365,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF040A,
                .name           = "SST 49LF040A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,128),
                }
@@ -1488,57 +1377,49 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF080A,
                .name           = "SST 49LF080A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x01000,256),
                }
        }, {
-               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
-               .dev_id         = SST39LF160,
-               .name           = "SST 39LF160",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
-               .regions        = {
-                       ERASEINFO(0x1000,256),
-                       ERASEINFO(0x1000,256)
-               }
-       }, {
-               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
-               .dev_id         = SST39VF1601,
-               .name           = "SST 39VF1601",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
-               .regions        = {
-                       ERASEINFO(0x1000,256),
-                       ERASEINFO(0x1000,256)
-               }
-
+               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
+               .dev_id         = SST39LF160,
+               .name           = "SST 39LF160",
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
+               .regions        = {
+                       ERASEINFO(0x1000,256),
+                       ERASEINFO(0x1000,256)
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
+               .dev_id         = SST39VF1601,
+               .name           = "SST 39VF1601",
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
+               .regions        = {
+                       ERASEINFO(0x1000,256),
+                       ERASEINFO(0x1000,256)
+               }
        }, {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M29F800AB,
                .name           = "ST M29F800AB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1549,13 +1430,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W800DT,
                .name           = "ST M29W800DT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,      /* ???? */
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,15),
                        ERASEINFO(0x08000,1),
@@ -1566,13 +1445,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W800DB,
                .name           = "ST M29W800DB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,      /* ???? */
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1583,13 +1460,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W160DT,
                .name           = "ST M29W160DT",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -1600,13 +1475,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,      /* FIXME - CFI device? */
                .dev_id         = M29W160DB,
                .name           = "ST M29W160DB",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,      /* ???? */
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1617,12 +1490,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M29W040B,
                .name           = "ST M29W040B",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0555_0x02AA,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1630,12 +1502,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M50FW040,
                .name           = "ST M50FW040",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_512KiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_512KiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,8),
                }
@@ -1643,12 +1514,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M50FW080,
                .name           = "ST M50FW080",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -1656,12 +1526,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M50FW016,
                .name           = "ST M50FW016",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,32),
                }
@@ -1669,12 +1538,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_ST,
                .dev_id         = M50LPW080,
                .name           = "ST M50LPW080",
-               .uaddr          = {
-                       [0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-               },
-               .DevSize        = SIZE_1MiB,
-               .CmdSet         = P_ID_INTEL_EXT,
-               .NumEraseRegions= 1,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_UNNECESSARY,
+               .dev_size       = SIZE_1MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 1,
                .regions        = {
                        ERASEINFO(0x10000,16),
                }
@@ -1682,13 +1550,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVT160,
                .name           = "Toshiba TC58FVT160",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000,31),
                        ERASEINFO(0x08000,1),
@@ -1699,13 +1565,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVB160,
                .name           = "Toshiba TC58FVB160",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
-               },
-               .DevSize        = SIZE_2MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_2MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x04000,1),
                        ERASEINFO(0x02000,2),
@@ -1716,13 +1580,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVB321,
                .name           = "Toshiba TC58FVB321",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,63)
@@ -1731,13 +1593,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVT321,
                .name           = "Toshiba TC58FVT321",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA  /* x16 */
-               },
-               .DevSize        = SIZE_4MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_4MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,63),
                        ERASEINFO(0x02000,8)
@@ -1746,13 +1606,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVB641,
                .name           = "Toshiba TC58FVB641",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x02000,8),
                        ERASEINFO(0x10000,127)
@@ -1761,13 +1619,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_TOSHIBA,
                .dev_id         = TC58FVT641,
                .name           = "Toshiba TC58FVT641",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
-                       [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
-               },
-               .DevSize        = SIZE_8MiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 2,
+               .devtypes       = CFI_DEVICETYPE_X16|CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x0AAA_0x0555,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 2,
                .regions        = {
                        ERASEINFO(0x10000,127),
                        ERASEINFO(0x02000,8)
@@ -1776,12 +1632,11 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = MANUFACTURER_WINBOND,
                .dev_id         = W49V002A,
                .name           = "Winbond W49V002A",
-               .uaddr          = {
-                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
-               },
-               .DevSize        = SIZE_256KiB,
-               .CmdSet         = P_ID_AMD_STD,
-               .NumEraseRegions= 4,
+               .devtypes       = CFI_DEVICETYPE_X8,
+               .uaddr          = MTD_UADDR_0x5555_0x2AAA,
+               .dev_size       = SIZE_256KiB,
+               .cmd_set        = P_ID_AMD_STD,
+               .nr_regions     = 4,
                .regions        = {
                        ERASEINFO(0x10000, 3),
                        ERASEINFO(0x08000, 1),
@@ -1791,15 +1646,7 @@ static const struct amd_flash_info jedec_table[] = {
        }
 };
 
-
-static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
-
-static int jedec_probe_chip(struct map_info *map, __u32 base,
-                           unsigned long *chip_map, struct cfi_private *cfi);
-
-static struct mtd_info *jedec_probe(struct map_info *map);
-
-static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
+static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base,
        struct cfi_private *cfi)
 {
        map_word result;
@@ -1810,7 +1657,7 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
        return result.x[0] & mask;
 }
 
-static inline u32 jedec_read_id(struct map_info *map, __u32 base,
+static inline u32 jedec_read_id(struct map_info *map, uint32_t base,
        struct cfi_private *cfi)
 {
        map_word result;
@@ -1821,8 +1668,7 @@ static inline u32 jedec_read_id(struct map_info *map, __u32 base,
        return result.x[0] & mask;
 }
 
-static inline void jedec_reset(u32 base, struct map_info *map,
-       struct cfi_private *cfi)
+static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi)
 {
        /* Reset */
 
@@ -1832,7 +1678,7 @@ static inline void jedec_reset(u32 base, struct map_info *map,
         * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips
         * as they will ignore the writes and dont care what address
         * the F0 is written to */
-       if(cfi->addr_unlock1) {
+       if (cfi->addr_unlock1) {
                DEBUG( MTD_DEBUG_LEVEL3,
                       "reset unlock called %x %x \n",
                       cfi->addr_unlock1,cfi->addr_unlock2);
@@ -1841,7 +1687,7 @@ static inline void jedec_reset(u32 base, struct map_info *map,
        }
 
        cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-       /* Some misdesigned intel chips do not respond for 0xF0 for a reset,
+       /* Some misdesigned Intel chips do not respond for 0xF0 for a reset,
         * so ensure we're in read mode.  Send both the Intel and the AMD command
         * for this.  Intel uses 0xff for this, AMD uses 0xff for NOP, so
         * this should be safe.
@@ -1851,42 +1697,20 @@ static inline void jedec_reset(u32 base, struct map_info *map,
 }
 
 
-static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type)
-{
-       int uaddr_idx;
-       __u8 uaddr = MTD_UADDR_NOT_SUPPORTED;
-
-       switch ( device_type ) {
-       case CFI_DEVICETYPE_X8:  uaddr_idx = 0; break;
-       case CFI_DEVICETYPE_X16: uaddr_idx = 1; break;
-       case CFI_DEVICETYPE_X32: uaddr_idx = 2; break;
-       default:
-               printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n",
-                      __func__, device_type);
-               goto uaddr_done;
-       }
-
-       uaddr = finfo->uaddr[uaddr_idx];
-
-       if (uaddr != MTD_UADDR_NOT_SUPPORTED ) {
-               /* ASSERT("The unlock addresses for non-8-bit mode
-                  are bollocks. We don't really need an array."); */
-               uaddr = finfo->uaddr[0];
-       }
-
- uaddr_done:
-       return uaddr;
-}
-
-
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 {
        int i,num_erase_regions;
-       __u8 uaddr;
+       uint8_t uaddr;
 
-       printk("Found: %s\n",jedec_table[index].name);
+       if (! (jedec_table[index].devtypes & p_cfi->device_type)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n",
+                     jedec_table[index].name, 4 * (1<<p_cfi->device_type));
+               return 0;
+       }
+
+       printk(KERN_INFO "Found: %s\n",jedec_table[index].name);
 
-       num_erase_regions = jedec_table[index].NumEraseRegions;
+       num_erase_regions = jedec_table[index].nr_regions;
 
        p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
        if (!p_cfi->cfiq) {
@@ -1896,9 +1720,9 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 
        memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));
 
-       p_cfi->cfiq->P_ID = jedec_table[index].CmdSet;
-       p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions;
-       p_cfi->cfiq->DevSize = jedec_table[index].DevSize;
+       p_cfi->cfiq->P_ID = jedec_table[index].cmd_set;
+       p_cfi->cfiq->NumEraseRegions = jedec_table[index].nr_regions;
+       p_cfi->cfiq->DevSize = jedec_table[index].dev_size;
        p_cfi->cfi_mode = CFI_MODE_JEDEC;
 
        for (i=0; i<num_erase_regions; i++){
@@ -1910,14 +1734,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
        p_cfi->mfr = jedec_table[index].mfr_id;
        p_cfi->id = jedec_table[index].dev_id;
 
-       uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type);
-       if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
-               kfree( p_cfi->cfiq );
-               return 0;
-       }
+       uaddr = jedec_table[index].uaddr;
 
-       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
-       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
+       /* The table has unlock addresses in _bytes_, and we try not to let
+          our brains explode when we see the datasheets talking about address
+          lines numbered from A-1 to A18. The CFI table has unlock addresses
+          in device-words according to the mode the device is connected in */
+       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 / p_cfi->device_type;
+       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 / p_cfi->device_type;
 
        return 1;       /* ok */
 }
@@ -1930,14 +1754,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
  * be perfect - consequently there should be some module parameters that
  * could be manually specified to force the chip info.
  */
-static inline int jedec_match( __u32 base,
+static inline int jedec_match( uint32_t base,
                               struct map_info *map,
                               struct cfi_private *cfi,
                               const struct amd_flash_info *finfo )
 {
        int rc = 0;           /* failure until all tests pass */
        u32 mfr, id;
-       __u8 uaddr;
+       uint8_t uaddr;
 
        /*
         * The IDs must match.  For X16 and X32 devices operating in
@@ -1950,8 +1774,8 @@ static inline int jedec_match( __u32 base,
         */
        switch (cfi->device_type) {
        case CFI_DEVICETYPE_X8:
-               mfr = (__u8)finfo->mfr_id;
-               id = (__u8)finfo->dev_id;
+               mfr = (uint8_t)finfo->mfr_id;
+               id = (uint8_t)finfo->dev_id;
 
                /* bjd: it seems that if we do this, we can end up
                 * detecting 16bit flashes as an 8bit device, even though
@@ -1964,12 +1788,12 @@ static inline int jedec_match( __u32 base,
                }
                break;
        case CFI_DEVICETYPE_X16:
-               mfr = (__u16)finfo->mfr_id;
-               id = (__u16)finfo->dev_id;
+               mfr = (uint16_t)finfo->mfr_id;
+               id = (uint16_t)finfo->dev_id;
                break;
        case CFI_DEVICETYPE_X32:
-               mfr = (__u16)finfo->mfr_id;
-               id = (__u32)finfo->dev_id;
+               mfr = (uint16_t)finfo->mfr_id;
+               id = (uint32_t)finfo->dev_id;
                break;
        default:
                printk(KERN_WARNING
@@ -1984,25 +1808,25 @@ static inline int jedec_match( __u32 base,
        /* the part size must fit in the memory window */
        DEBUG( MTD_DEBUG_LEVEL3,
               "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",
-              __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) );
-       if ( base + cfi_interleave(cfi) * ( 1 << finfo->DevSize ) > map->size ) {
+              __func__, base, 1 << finfo->dev_size, base + (1 << finfo->dev_size) );
+       if ( base + cfi_interleave(cfi) * ( 1 << finfo->dev_size ) > map->size ) {
                DEBUG( MTD_DEBUG_LEVEL3,
                       "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",
                       __func__, finfo->mfr_id, finfo->dev_id,
-                      1 << finfo->DevSize );
+                      1 << finfo->dev_size );
                goto match_done;
        }
 
-       uaddr = finfo_uaddr(finfo, cfi->device_type);
-       if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
+       if (! (finfo->devtypes & cfi->device_type))
                goto match_done;
-       }
+
+       uaddr = finfo->uaddr;
 
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",
               __func__, cfi->addr_unlock1, cfi->addr_unlock2 );
        if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr
-            && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1 ||
-                 unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
+            && ( unlock_addrs[uaddr].addr1 / cfi->device_type != cfi->addr_unlock1 ||
+                 unlock_addrs[uaddr].addr2 / cfi->device_type != cfi->addr_unlock2 ) ) {
                DEBUG( MTD_DEBUG_LEVEL3,
                        "MTD %s(): 0x%.4x 0x%.4x did not match\n",
                        __func__,
@@ -2042,7 +1866,7 @@ static inline int jedec_match( __u32 base,
         * were truly frobbing a real device.
         */
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ );
-       if(cfi->addr_unlock1) {
+       if (cfi->addr_unlock1) {
                cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
                cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
        }
@@ -2068,8 +1892,8 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                if (MTD_UADDR_UNNECESSARY == uaddr_idx)
                        return 0;
 
-               cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
-               cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
+               cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 / cfi->device_type;
+               cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 / cfi->device_type;
        }
 
        /* 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,
 
        }
        /* Ensure the unlock addresses we try stay inside the map */
-       probe_offset1 = cfi_build_cmd_addr(
-               cfi->addr_unlock1,
-               cfi_interleave(cfi),
-               cfi->device_type);
-       probe_offset2 = cfi_build_cmd_addr(
-               cfi->addr_unlock1,
-               cfi_interleave(cfi),
-               cfi->device_type);
+       probe_offset1 = cfi_build_cmd_addr(cfi->addr_unlock1, cfi_interleave(cfi), cfi->device_type);
+       probe_offset2 = cfi_build_cmd_addr(cfi->addr_unlock2, cfi_interleave(cfi), cfi->device_type);
        if (    ((base + probe_offset1 + map_bankwidth(map)) >= map->size) ||
                ((base + probe_offset2 + map_bankwidth(map)) >= map->size))
-       {
                goto retry;
-       }
 
        /* Reset */
        jedec_reset(base, map, cfi);
@@ -2128,8 +1944,8 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                }
                goto retry;
        } else {
-               __u16 mfr;
-               __u16 id;
+               uint16_t mfr;
+               uint16_t id;
 
                /* Make sure it is a chip of the same manufacturer and id */
                mfr = jedec_read_mfr(map, base, cfi);
index 23fab14f1637cab5fb4ee175ff5eaea6db141915..b44292abd9f7bd68c94228ac11200b3549dc1711 100644 (file)
@@ -9,7 +9,7 @@
  *
  * mtdparts=<mtddef>[;<mtddef]
  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
- * <partdef> := <size>[@offset][<name>][ro]
+ * <partdef> := <size>[@offset][<name>][ro][lk]
  * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
  * <size>    := standard linux memsize OR "-" to denote all remaining space
  * <name>    := '(' NAME ')'
@@ -143,6 +143,13 @@ static struct mtd_partition * newpart(char *s,
                s += 2;
         }
 
+        /* if lk is found do NOT unlock the MTD partition*/
+        if (strncmp(s, "lk", 2) == 0)
+       {
+               mask_flags |= MTD_POWERUP_LOCK;
+               s += 2;
+        }
+
        /* test if more partitions are following */
        if (*s == ',')
        {
index 4ea50a1dda8570a1606abbbd623c93f011df2bb7..99fd210feaece71fa8f39658e3fa16d4bdebdcfb 100644 (file)
@@ -323,7 +323,7 @@ static int flash_probe (void)
    /* put the flash back into command mode */
    write32 (DATA_TO_FLASH (READ_ARRAY),0x00000000);
 
-   return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || FLASH_DEVICE_16mbit_BOTTOM));
+   return (manufacturer == FLASH_MANUFACTURER && (devtype == FLASH_DEVICE_16mbit_TOP || devtype == FLASH_DEVICE_16mbit_BOTTOM));
 }
 
 /*
index a5ed6d232c357b16b7ffacfedd10d81a9915dad8..b35e4813a3a5e146f6725fb13d6d3be0f588bfe6 100644 (file)
@@ -420,7 +420,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
                status = dataflash_waitready(priv->spi);
 
                /* Check result of the compare operation */
-               if ((status & (1 << 6)) == 1) {
+               if (status & (1 << 6)) {
                        printk(KERN_ERR "%s: compare page %u, err %d\n",
                                spi->dev.bus_id, pageaddr, status);
                        remaining = 0;
index a592fc04cf781455459bbb390227da7f72fdab50..12c253664eb223e524d31b2fb6bc800f9286cd44 100644 (file)
@@ -110,13 +110,6 @@ config MTD_SUN_UFLASH
          Sun Microsystems boardsets.  This driver will require CFI support
          in the kernel, so if you did not enable CFI previously, do that now.
 
-config MTD_PNC2000
-       tristate "CFI Flash device mapped on Photron PNC-2000"
-       depends on X86 && MTD_CFI && MTD_PARTITIONS
-       help
-         PNC-2000 is the name of Network Camera product from PHOTRON
-         Ltd. in Japan. It uses CFI-compliant flash.
-
 config MTD_SC520CDP
        tristate "CFI Flash device mapped on AMD SC520 CDP"
        depends on X86 && MTD_CFI && MTD_CONCAT
@@ -576,7 +569,7 @@ config MTD_BAST_MAXSIZE
        default "4"
 
 config MTD_SHARP_SL
-       bool "ROM mapped on Sharp SL Series"
+       tristate "ROM mapped on Sharp SL Series"
        depends on ARCH_PXA
        help
          This enables access to the flash chip on the Sharp SL Series of PDAs.
index 316382a1401be8dced078b5e2736322a08c637f8..a9cbe80f99a0d909eec2f89e109dfd53a7365a50 100644 (file)
@@ -28,7 +28,6 @@ obj-$(CONFIG_MTD_PHYSMAP)     += physmap.o
 obj-$(CONFIG_MTD_PHYSMAP_OF)   += physmap_of.o
 obj-$(CONFIG_MTD_PMC_MSP_EVM)   += pmcmsp-flash.o
 obj-$(CONFIG_MTD_PMC_MSP_RAMROOT)+= pmcmsp-ramroot.o
-obj-$(CONFIG_MTD_PNC2000)      += pnc2000.o
 obj-$(CONFIG_MTD_PCMCIA)       += pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)      += rpxlite.o
 obj-$(CONFIG_MTD_TQM8XXL)      += tqm8xxl.o
index aeed9ea79714ab56454840ee34d6eb5395e60f12..49acd41718934f2a671d887c94e6603b596f32f7 100644 (file)
@@ -80,64 +80,6 @@ static int parse_obsolete_partitions(struct of_device *dev,
 
        return nr_parts;
 }
-
-static int __devinit parse_partitions(struct of_flash *info,
-                                     struct of_device *dev)
-{
-       const char *partname;
-       static const char *part_probe_types[]
-               = { "cmdlinepart", "RedBoot", NULL };
-       struct device_node *dp = dev->node, *pp;
-       int nr_parts, i;
-
-       /* First look for RedBoot table or partitions on the command
-        * line, these take precedence over device tree information */
-       nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
-                                       &info->parts, 0);
-       if (nr_parts > 0) {
-               add_mtd_partitions(info->mtd, info->parts, nr_parts);
-               return 0;
-       }
-
-       /* First count the subnodes */
-       nr_parts = 0;
-       for (pp = dp->child; pp; pp = pp->sibling)
-               nr_parts++;
-
-       if (nr_parts == 0)
-               return parse_obsolete_partitions(dev, info, dp);
-
-       info->parts = kzalloc(nr_parts * sizeof(*info->parts),
-                             GFP_KERNEL);
-       if (!info->parts)
-               return -ENOMEM;
-
-       for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) {
-               const u32 *reg;
-               int len;
-
-               reg = of_get_property(pp, "reg", &len);
-               if (!reg || (len != 2*sizeof(u32))) {
-                       dev_err(&dev->dev, "Invalid 'reg' on %s\n",
-                               dp->full_name);
-                       kfree(info->parts);
-                       info->parts = NULL;
-                       return -EINVAL;
-               }
-               info->parts[i].offset = reg[0];
-               info->parts[i].size = reg[1];
-
-               partname = of_get_property(pp, "label", &len);
-               if (!partname)
-                       partname = of_get_property(pp, "name", &len);
-               info->parts[i].name = (char *)partname;
-
-               if (of_get_property(pp, "read-only", &len))
-                       info->parts[i].mask_flags = MTD_WRITEABLE;
-       }
-
-       return nr_parts;
-}
 #else /* MTD_PARTITIONS */
 #define        OF_FLASH_PARTS(info)            (0)
 #define parse_partitions(info, dev)    (0)
@@ -212,6 +154,10 @@ static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
 static int __devinit of_flash_probe(struct of_device *dev,
                                    const struct of_device_id *match)
 {
+#ifdef CONFIG_MTD_PARTITIONS
+       static const char *part_probe_types[]
+               = { "cmdlinepart", "RedBoot", NULL };
+#endif
        struct device_node *dp = dev->node;
        struct resource res;
        struct of_flash *info;
@@ -274,13 +220,33 @@ static int __devinit of_flash_probe(struct of_device *dev,
        }
        info->mtd->owner = THIS_MODULE;
 
-       err = parse_partitions(info, dev);
+#ifdef CONFIG_MTD_PARTITIONS
+       /* First look for RedBoot table or partitions on the command
+        * line, these take precedence over device tree information */
+       err = parse_mtd_partitions(info->mtd, part_probe_types,
+                                  &info->parts, 0);
        if (err < 0)
-               goto err_out;
+               return err;
+
+#ifdef CONFIG_MTD_OF_PARTS
+       if (err == 0) {
+               err = of_mtd_parse_partitions(&dev->dev, info->mtd,
+                                             dp, &info->parts);
+               if (err < 0)
+                       return err;
+       }
+#endif
+
+       if (err == 0) {
+               err = parse_obsolete_partitions(dev, info, dp);
+               if (err < 0)
+                       return err;
+       }
 
        if (err > 0)
-               add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
+               add_mtd_partitions(info->mtd, info->parts, err);
        else
+#endif
                add_mtd_device(info->mtd);
 
        return 0;
diff --git a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c
deleted file mode 100644 (file)
index d7e16c2..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- *     pnc2000.c - mapper for Photron PNC-2000 board.
- *
- * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
- *
- * This code is GPL
- *
- * $Id: pnc2000.c,v 1.18 2005/11/07 11:14:28 gleixner Exp $
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-
-#define WINDOW_ADDR 0xbf000000
-#define WINDOW_SIZE 0x00400000
-
-/*
- * MAP DRIVER STUFF
- */
-
-
-static struct map_info pnc_map = {
-       .name = "PNC-2000",
-       .size = WINDOW_SIZE,
-       .bankwidth = 4,
-       .phys = 0xFFFFFFFF,
-       .virt = (void __iomem *)WINDOW_ADDR,
-};
-
-
-/*
- * MTD 'PARTITIONING' STUFF
- */
-static struct mtd_partition pnc_partitions[3] = {
-       {
-               .name = "PNC-2000 boot firmware",
-               .size = 0x20000,
-               .offset = 0
-       },
-       {
-               .name = "PNC-2000 kernel",
-               .size = 0x1a0000,
-               .offset = 0x20000
-       },
-       {
-               .name = "PNC-2000 filesystem",
-               .size = 0x240000,
-               .offset = 0x1c0000
-       }
-};
-
-/*
- * This is the master MTD device for which all the others are just
- * auto-relocating aliases.
- */
-static struct mtd_info *mymtd;
-
-static int __init init_pnc2000(void)
-{
-       printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-
-       simple_map_init(&pnc_map);
-
-       mymtd = do_map_probe("cfi_probe", &pnc_map);
-       if (mymtd) {
-               mymtd->owner = THIS_MODULE;
-               return add_mtd_partitions(mymtd, pnc_partitions, 3);
-       }
-
-       return -ENXIO;
-}
-
-static void __exit cleanup_pnc2000(void)
-{
-       if (mymtd) {
-               del_mtd_partitions(mymtd);
-               map_destroy(mymtd);
-       }
-}
-
-module_init(init_pnc2000);
-module_exit(cleanup_pnc2000);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp>");
-MODULE_DESCRIPTION("MTD map driver for Photron PNC-2000 board");
index dcfb85840d1e4c5d5fd355dc783b7f55aef75464..0fc5584324e3d38488dd62627867787c2201e5d1 100644 (file)
@@ -79,7 +79,7 @@ scb2_fixup_mtd(struct mtd_info *mtd)
        struct cfi_private *cfi = map->fldrv_priv;
 
        /* barf if this doesn't look right */
-       if (cfi->cfiq->InterfaceDesc != 1) {
+       if (cfi->cfiq->InterfaceDesc != CFI_INTERFACE_X16_ASYNC) {
                printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n",
                    cfi->cfiq->InterfaceDesc);
                return -1;
index 74d9d30edabdc49c04f42b435b53e851f159c3c5..839eed8430a2c77aaf1643937de83ae99501fe6b 100644 (file)
@@ -248,9 +248,9 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
                return -EBUSY;
        }
 
-       mutex_init(&new->lock);
        list_add_tail(&new->list, &tr->devs);
  added:
+       mutex_init(&new->lock);
        if (!tr->writesect)
                new->readonly = 1;
 
index a0cee86464cae51646b148939d49b6c61b8725a1..5d3ac512ce169f1f4efc8de2cde7ae6ca21c6148 100644 (file)
@@ -481,6 +481,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
        {
                struct mtd_oob_buf buf;
                struct mtd_oob_ops ops;
+               uint32_t retlen;
 
                if(!(file->f_mode & 2))
                        return -EPERM;
@@ -520,8 +521,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                buf.start &= ~(mtd->oobsize - 1);
                ret = mtd->write_oob(mtd, buf.start, &ops);
 
-               if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen,
-                                sizeof(uint32_t)))
+               if (ops.oobretlen > 0xFFFFFFFFU)
+                       ret = -EOVERFLOW;
+               retlen = ops.oobretlen;
+               if (copy_to_user(&((struct mtd_oob_buf *)argp)->length,
+                                &retlen, sizeof(buf.length)))
                        ret = -EFAULT;
 
                kfree(ops.oobbuf);
index 6c2645e2837191e57d539222c92d68b3debac806..f7e7890e5bc6889f1ce0aa9fdc18c7be6cf42e6a 100644 (file)
@@ -61,7 +61,7 @@ int add_mtd_device(struct mtd_info *mtd)
 
                        /* Some chips always power up locked. Unlock them now */
                        if ((mtd->flags & MTD_WRITEABLE)
-                           && (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) {
+                           && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
                                if (mtd->unlock(mtd, 0, mtd->size))
                                        printk(KERN_WARNING
                                               "%s: unlock failed, "
index f8af627f0b98e68d2392039c2f4f918a3db842b5..34681bc911058ea6a12b9e497cc72aeb17877488 100644 (file)
 #include <linux/workqueue.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
+#include <linux/spinlock.h>
 #include <linux/mtd/mtd.h>
 
 #define OOPS_PAGE_SIZE 4096
 
-static struct mtdoops_context {
+struct mtdoops_context {
        int mtd_index;
-       struct work_struct work;
+       struct work_struct work_erase;
+       struct work_struct work_write;
        struct mtd_info *mtd;
        int oops_pages;
        int nextpage;
        int nextcount;
 
        void *oops_buf;
+
+       /* writecount and disabling ready are spin lock protected */
+       spinlock_t writecount_lock;
        int ready;
        int writecount;
 } oops_cxt;
@@ -62,10 +67,7 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
        erase.mtd = mtd;
        erase.callback = mtdoops_erase_callback;
        erase.addr = offset;
-       if (mtd->erasesize < OOPS_PAGE_SIZE)
-               erase.len = OOPS_PAGE_SIZE;
-       else
-               erase.len = mtd->erasesize;
+       erase.len = mtd->erasesize;
        erase.priv = (u_long)&wait_q;
 
        set_current_state(TASK_INTERRUPTIBLE);
@@ -87,7 +89,7 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset)
        return 0;
 }
 
-static int mtdoops_inc_counter(struct mtdoops_context *cxt)
+static void mtdoops_inc_counter(struct mtdoops_context *cxt)
 {
        struct mtd_info *mtd = cxt->mtd;
        size_t retlen;
@@ -103,25 +105,30 @@ static int mtdoops_inc_counter(struct mtdoops_context *cxt)
 
        ret = mtd->read(mtd, cxt->nextpage * OOPS_PAGE_SIZE, 4,
                        &retlen, (u_char *) &count);
-       if ((retlen != 4) || (ret < 0)) {
+       if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) {
                printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
                                ", err %d.\n", cxt->nextpage * OOPS_PAGE_SIZE,
                                retlen, ret);
-               return 1;
+               schedule_work(&cxt->work_erase);
+               return;
        }
 
        /* See if we need to erase the next block */
-       if (count != 0xffffffff)
-               return 1;
+       if (count != 0xffffffff) {
+               schedule_work(&cxt->work_erase);
+               return;
+       }
 
        printk(KERN_DEBUG "mtdoops: Ready %d, %d (no erase)\n",
                        cxt->nextpage, cxt->nextcount);
        cxt->ready = 1;
-       return 0;
 }
 
-static void mtdoops_prepare(struct mtdoops_context *cxt)
+/* Scheduled work - when we can't proceed without erasing a block */
+static void mtdoops_workfunc_erase(struct work_struct *work)
 {
+       struct mtdoops_context *cxt =
+                       container_of(work, struct mtdoops_context, work_erase);
        struct mtd_info *mtd = cxt->mtd;
        int i = 0, j, ret, mod;
 
@@ -136,8 +143,14 @@ static void mtdoops_prepare(struct mtdoops_context *cxt)
                        cxt->nextpage = 0;
        }
 
-       while (mtd->block_isbad &&
-                       mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE)) {
+       while (mtd->block_isbad) {
+               ret = mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+               if (!ret)
+                       break;
+               if (ret < 0) {
+                       printk(KERN_ERR "mtdoops: block_isbad failed, aborting.\n");
+                       return;
+               }
 badblock:
                printk(KERN_WARNING "mtdoops: Bad block at %08x\n",
                                cxt->nextpage * OOPS_PAGE_SIZE);
@@ -154,34 +167,61 @@ badblock:
        for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
                ret = mtdoops_erase_block(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
 
-       if (ret < 0) {
-               if (mtd->block_markbad)
-                       mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
-               goto badblock;
+       if (ret >= 0) {
+               printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
+               cxt->ready = 1;
+               return;
        }
 
-       printk(KERN_DEBUG "mtdoops: Ready %d, %d \n", cxt->nextpage, cxt->nextcount);
-
-       cxt->ready = 1;
+       if (mtd->block_markbad && (ret == -EIO)) {
+               ret = mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE);
+               if (ret < 0) {
+                       printk(KERN_ERR "mtdoops: block_markbad failed, aborting.\n");
+                       return;
+               }
+       }
+       goto badblock;
 }
 
-static void mtdoops_workfunc(struct work_struct *work)
+static void mtdoops_workfunc_write(struct work_struct *work)
 {
        struct mtdoops_context *cxt =
-                       container_of(work, struct mtdoops_context, work);
+                       container_of(work, struct mtdoops_context, work_write);
+       struct mtd_info *mtd = cxt->mtd;
+       size_t retlen;
+       int ret;
 
-       mtdoops_prepare(cxt);
-}
+       if (cxt->writecount < OOPS_PAGE_SIZE)
+               memset(cxt->oops_buf + cxt->writecount, 0xff,
+                                       OOPS_PAGE_SIZE - cxt->writecount);
+
+       ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
+                                       OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+
+       cxt->writecount = 0;
+
+       if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
+               printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
+                       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
 
-static int find_next_position(struct mtdoops_context *cxt)
+       mtdoops_inc_counter(cxt);
+}                                      
+
+static void find_next_position(struct mtdoops_context *cxt)
 {
        struct mtd_info *mtd = cxt->mtd;
-       int page, maxpos = 0;
+       int ret, page, maxpos = 0;
        u32 count, maxcount = 0xffffffff;
        size_t retlen;
 
        for (page = 0; page < cxt->oops_pages; page++) {
-               mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+               ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 4, &retlen, (u_char *) &count);
+               if ((retlen != 4) || ((ret < 0) && (ret != -EUCLEAN))) {
+                       printk(KERN_ERR "mtdoops: Read failure at %d (%td of 4 read)"
+                               ", err %d.\n", page * OOPS_PAGE_SIZE, retlen, ret);
+                       continue;
+               }
+
                if (count == 0xffffffff)
                        continue;
                if (maxcount == 0xffffffff) {
@@ -205,20 +245,19 @@ static int find_next_position(struct mtdoops_context *cxt)
                cxt->ready = 1;
                printk(KERN_DEBUG "mtdoops: Ready %d, %d (first init)\n",
                                cxt->nextpage, cxt->nextcount);
-               return 0;
+               return;
        }
 
        cxt->nextpage = maxpos;
        cxt->nextcount = maxcount;
 
-       return mtdoops_inc_counter(cxt);
+       mtdoops_inc_counter(cxt);
 }
 
 
 static void mtdoops_notify_add(struct mtd_info *mtd)
 {
        struct mtdoops_context *cxt = &oops_cxt;
-       int ret;
 
        if ((mtd->index != cxt->mtd_index) || cxt->mtd_index < 0)
                return;
@@ -229,14 +268,18 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
                return;
        }
 
+       if (mtd->erasesize < OOPS_PAGE_SIZE) {
+               printk(KERN_ERR "Eraseblock size of MTD partition %d too small\n",
+                               mtd->index);
+               return;
+       }
+
        cxt->mtd = mtd;
        cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE;
 
-       ret = find_next_position(cxt);
-       if (ret == 1)
-               mtdoops_prepare(cxt);
+       find_next_position(cxt);
 
-       printk(KERN_DEBUG "mtdoops: Attached to MTD device %d\n", mtd->index);
+       printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index);
 }
 
 static void mtdoops_notify_remove(struct mtd_info *mtd)
@@ -254,31 +297,24 @@ static void mtdoops_console_sync(void)
 {
        struct mtdoops_context *cxt = &oops_cxt;
        struct mtd_info *mtd = cxt->mtd;
-       size_t retlen;
-       int ret;
+       unsigned long flags;
 
-       if (!cxt->ready || !mtd)
+       if (!cxt->ready || !mtd || cxt->writecount == 0)
                return;
 
-       if (cxt->writecount == 0)
+       /* 
+        *  Once ready is 0 and we've held the lock no further writes to the 
+        *  buffer will happen
+        */
+       spin_lock_irqsave(&cxt->writecount_lock, flags);
+       if (!cxt->ready) {
+               spin_unlock_irqrestore(&cxt->writecount_lock, flags);
                return;
-
-       if (cxt->writecount < OOPS_PAGE_SIZE)
-               memset(cxt->oops_buf + cxt->writecount, 0xff,
-                                       OOPS_PAGE_SIZE - cxt->writecount);
-
-       ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE,
-                                       OOPS_PAGE_SIZE, &retlen, cxt->oops_buf);
+       }
        cxt->ready = 0;
-       cxt->writecount = 0;
+       spin_unlock_irqrestore(&cxt->writecount_lock, flags);
 
-       if ((retlen != OOPS_PAGE_SIZE) || (ret < 0))
-               printk(KERN_ERR "mtdoops: Write failure at %d (%td of %d written), err %d.\n",
-                       cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret);
-
-       ret = mtdoops_inc_counter(cxt);
-       if (ret == 1)
-               schedule_work(&cxt->work);
+       schedule_work(&cxt->work_write);
 }
 
 static void
@@ -286,7 +322,7 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct mtdoops_context *cxt = co->data;
        struct mtd_info *mtd = cxt->mtd;
-       int i;
+       unsigned long flags;
 
        if (!oops_in_progress) {
                mtdoops_console_sync();
@@ -296,6 +332,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
        if (!cxt->ready || !mtd)
                return;
 
+       /* Locking on writecount ensures sequential writes to the buffer */
+       spin_lock_irqsave(&cxt->writecount_lock, flags);
+
+       /* Check ready status didn't change whilst waiting for the lock */
+       if (!cxt->ready)
+               return;
+
        if (cxt->writecount == 0) {
                u32 *stamp = cxt->oops_buf;
                *stamp = cxt->nextcount;
@@ -305,10 +348,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
        if ((count + cxt->writecount) > OOPS_PAGE_SIZE)
                count = OOPS_PAGE_SIZE - cxt->writecount;
 
-       for (i = 0; i < count; i++, s++)
-               *((char *)(cxt->oops_buf) + cxt->writecount + i) = *s;
+       memcpy(cxt->oops_buf + cxt->writecount, s, count);
+       cxt->writecount += count;
+
+       spin_unlock_irqrestore(&cxt->writecount_lock, flags);
 
-       cxt->writecount = cxt->writecount + count;
+       if (cxt->writecount == OOPS_PAGE_SIZE)
+               mtdoops_console_sync();
 }
 
 static int __init mtdoops_console_setup(struct console *co, char *options)
@@ -334,7 +380,6 @@ static struct console mtdoops_console = {
        .write          = mtdoops_console_write,
        .setup          = mtdoops_console_setup,
        .unblank        = mtdoops_console_sync,
-       .flags          = CON_PRINTBUFFER,
        .index          = -1,
        .data           = &oops_cxt,
 };
@@ -347,11 +392,12 @@ static int __init mtdoops_console_init(void)
        cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE);
 
        if (!cxt->oops_buf) {
-               printk(KERN_ERR "Failed to allocate oops buffer workspace\n");
+               printk(KERN_ERR "Failed to allocate mtdoops buffer workspace\n");
                return -ENOMEM;
        }
 
-       INIT_WORK(&cxt->work, mtdoops_workfunc);
+       INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
+       INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
 
        register_console(&mtdoops_console);
        register_mtd_user(&mtdoops_notifier);
index 246d4512f64bfd8670a5731809d1280cd2cbfcaa..0a840d5d75ae5e22e489822c1d2a0101a71925a1 100644 (file)
@@ -93,7 +93,7 @@ config MTD_NAND_AU1550
 
 config MTD_NAND_BF5XX
        tristate "Blackfin on-chip NAND Flash Controller driver"
-       depends on BF54x && MTD_NAND
+       depends on (BF54x || BF52x) && MTD_NAND
        help
          This enables the Blackfin on-chip NAND flash controller
 
@@ -283,6 +283,12 @@ config MTD_NAND_CM_X270
        tristate "Support for NAND Flash on CM-X270 modules"
        depends on MTD_NAND && MACH_ARMCORE
 
+config MTD_NAND_PASEMI
+       tristate "NAND support for PA Semi PWRficient"
+       depends on MTD_NAND && PPC_PASEMI
+       help
+         Enables support for NAND Flash interface on PA Semi PWRficient
+         based boards
 
 config MTD_NAND_NANDSIM
        tristate "Support for NAND Flash Simulator"
@@ -306,4 +312,13 @@ config MTD_ALAUDA
          These two (and possibly other) Alauda-based cardreaders for
          SmartMedia and xD allow raw flash access.
 
+config MTD_NAND_ORION
+       tristate "NAND Flash support for Marvell Orion SoC"
+       depends on ARCH_ORION && MTD_NAND
+       help
+         This enables the NAND flash controller on Orion machines.
+
+         No board specific support is done by this driver, each board
+         must advertise a platform_device for the driver to attach.
+
 endif # MTD_NAND
index 3ad6c0165da3ab77ef17c80196b313ce29305cc4..e35f5ea3a7a933b3afc3b857cd4f01ab570ca42f 100644 (file)
@@ -29,5 +29,7 @@ obj-$(CONFIG_MTD_NAND_CM_X270)                += cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)   += excite_nandflash.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
 obj-$(CONFIG_MTD_ALAUDA)               += alauda.o
+obj-$(CONFIG_MTD_NAND_PASEMI)          += pasemi_nand.o
+obj-$(CONFIG_MTD_NAND_ORION)           += orion_nand.o
 
 nand-objs := nand_base.o nand_bbt.o
index b2a5672df6e0a15a2c1b2f2183087883c1a9f35e..c9fb2acf4056b3baab4ccb1ab1e980b2af08d026 100644 (file)
@@ -156,14 +156,14 @@ static int __init at91_nand_probe(struct platform_device *pdev)
        }
 
 #ifdef CONFIG_MTD_PARTITIONS
-       if (host->board->partition_info)
-               partitions = host->board->partition_info(mtd->size, &num_partitions);
 #ifdef CONFIG_MTD_CMDLINE_PARTS
-       else {
-               mtd->name = "at91_nand";
-               num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
-       }
+       mtd->name = "at91_nand";
+       num_partitions = parse_mtd_partitions(mtd, part_probes,
+                                             &partitions, 0);
 #endif
+       if (num_partitions <= 0 && host->board->partition_info)
+               partitions = host->board->partition_info(mtd->size,
+                                                        &num_partitions);
 
        if ((!partitions) || (num_partitions == 0)) {
                printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
index 1657ecd74881ee4eebd9ce1752ef692a11c05c8b..542850cd4c37c013124b25474c817fd746726899 100644 (file)
@@ -74,7 +74,22 @@ static int hardware_ecc = 1;
 static int hardware_ecc;
 #endif
 
-static unsigned short bfin_nfc_pin_req[] = {P_NAND_CE, P_NAND_RB, 0};
+static unsigned short bfin_nfc_pin_req[] =
+       {P_NAND_CE,
+        P_NAND_RB,
+        P_NAND_D0,
+        P_NAND_D1,
+        P_NAND_D2,
+        P_NAND_D3,
+        P_NAND_D4,
+        P_NAND_D5,
+        P_NAND_D6,
+        P_NAND_D7,
+        P_NAND_WE,
+        P_NAND_RE,
+        P_NAND_CLE,
+        P_NAND_ALE,
+        0};
 
 /*
  * Data structures for bf5xx nand flash controller driver
@@ -507,12 +522,13 @@ static int bf5xx_nand_dma_init(struct bf5xx_nand_info *info)
 
        init_completion(&info->dma_completion);
 
+#ifdef CONFIG_BF54x
        /* Setup DMAC1 channel mux for NFC which shared with SDH */
        val = bfin_read_DMAC1_PERIMUX();
        val &= 0xFFFE;
        bfin_write_DMAC1_PERIMUX(val);
        SSYNC();
-
+#endif
        /* Request NFC DMA channel */
        ret = request_dma(CH_NFC, "BF5XX NFC driver");
        if (ret < 0) {
index 1e811715211a56f8417bd1c8f107566b6a06d2b4..da6ceaa80ba137c1c4114a199d59efb09bcf08ed 100644 (file)
@@ -11,6 +11,7 @@
 #undef DEBUG
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
 #include <linux/rslib.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -52,6 +53,7 @@
 
 struct cafe_priv {
        struct nand_chip nand;
+       struct mtd_partition *parts;
        struct pci_dev *pdev;
        void __iomem *mmio;
        struct rs_control *rs;
@@ -84,6 +86,10 @@ static unsigned int numtimings;
 static int timing[3];
 module_param_array(timing, int, &numtimings, 0644);
 
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "RedBoot", NULL };
+#endif
+
 /* Hrm. Why isn't this already conditional on something in the struct device? */
 #define cafe_dev_dbg(dev, args...) do { if (debug) dev_dbg(dev, ##args); } while(0)
 
@@ -620,7 +626,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev,
 {
        struct mtd_info *mtd;
        struct cafe_priv *cafe;
+       struct mtd_partition *parts;
        uint32_t ctrl;
+       int nr_parts;
        int err = 0;
 
        /* 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,
                goto out_irq;
 
        pci_set_drvdata(pdev, mtd);
+
+       /* We register the whole device first, separate from the partitions */
        add_mtd_device(mtd);
+
+#ifdef CONFIG_MTD_PARTITIONS
+       nr_parts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
+       if (nr_parts > 0) {
+               cafe->parts = parts;
+               dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts);
+               add_mtd_partitions(mtd, parts, nr_parts);
+       }
+#endif
        goto out;
 
  out_irq:
index e29c1da7f56e82530a987beb96ab84a735a2b637..85a7283845ff2a0b5270d87233fbb7d73f2b471f 100644 (file)
@@ -2469,8 +2469,12 @@ int nand_scan_tail(struct mtd_info *mtd)
                        chip->ecc.write_oob = nand_write_oob_std;
 
        case NAND_ECC_HW_SYNDROME:
-               if (!chip->ecc.calculate || !chip->ecc.correct ||
-                   !chip->ecc.hwctl) {
+               if ((!chip->ecc.calculate || !chip->ecc.correct ||
+                    !chip->ecc.hwctl) &&
+                   (!chip->ecc.read_page ||
+                    chip->ecc.read_page == nand_read_page_hwecc) ||
+                    !chip->ecc.write_page ||
+                    chip->ecc.write_page == nand_write_page_hwecc) {
                        printk(KERN_WARNING "No ECC functions supplied, "
                               "Hardware ECC not possible\n");
                        BUG();
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
new file mode 100644 (file)
index 0000000..9162cca
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * drivers/mtd/nand/orion_nand.c
+ *
+ * NAND support for Marvell Orion SoC platforms
+ *
+ * Tzachi Perelstein <tzachi@marvell.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/arch/platform.h>
+#include <asm/arch/hardware.h>
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+       struct nand_chip *nc = mtd->priv;
+       struct orion_nand_data *board = nc->priv;
+       u32 offs;
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       if (ctrl & NAND_CLE)
+               offs = (1 << board->cle);
+       else if (ctrl & NAND_ALE)
+               offs = (1 << board->ale);
+       else
+               return;
+
+       if (nc->options & NAND_BUSWIDTH_16)
+               offs <<= 1;
+
+       writeb(cmd, nc->IO_ADDR_W + offs);
+}
+
+static int __init orion_nand_probe(struct platform_device *pdev)
+{
+       struct mtd_info *mtd;
+       struct nand_chip *nc;
+       struct orion_nand_data *board;
+       void __iomem *io_base;
+       int ret = 0;
+#ifdef CONFIG_MTD_PARTITIONS
+       struct mtd_partition *partitions = NULL;
+       int num_part = 0;
+#endif
+
+       nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
+       if (!nc) {
+               printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
+               ret = -ENOMEM;
+               goto no_res;
+       }
+       mtd = (struct mtd_info *)(nc + 1);
+
+       io_base = ioremap(pdev->resource[0].start,
+                       pdev->resource[0].end - pdev->resource[0].start + 1);
+       if (!io_base) {
+               printk(KERN_ERR "orion_nand: ioremap failed\n");
+               ret = -EIO;
+               goto no_res;
+       }
+
+       board = pdev->dev.platform_data;
+
+       mtd->priv = nc;
+       mtd->owner = THIS_MODULE;
+
+       nc->priv = board;
+       nc->IO_ADDR_R = nc->IO_ADDR_W = io_base;
+       nc->cmd_ctrl = orion_nand_cmd_ctrl;
+       nc->ecc.mode = NAND_ECC_SOFT;
+
+       if (board->width == 16)
+               nc->options |= NAND_BUSWIDTH_16;
+
+       platform_set_drvdata(pdev, mtd);
+
+       if (nand_scan(mtd, 1)) {
+               ret = -ENXIO;
+               goto no_dev;
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+       mtd->name = "orion_nand";
+       num_part = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
+#endif
+       /* If cmdline partitions have been passed, let them be used */
+       if (num_part <= 0) {
+               num_part = board->nr_parts;
+               partitions = board->parts;
+       }
+
+       if (partitions && num_part > 0)
+               ret = add_mtd_partitions(mtd, partitions, num_part);
+       else
+               ret = add_mtd_device(mtd);
+#else
+       ret = add_mtd_device(mtd);
+#endif
+
+       if (ret) {
+               nand_release(mtd);
+               goto no_dev;
+       }
+
+       return 0;
+
+no_dev:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(io_base);
+no_res:
+       kfree(nc);
+
+       return ret;
+}
+
+static int __devexit orion_nand_remove(struct platform_device *pdev)
+{
+       struct mtd_info *mtd = platform_get_drvdata(pdev);
+       struct nand_chip *nc = mtd->priv;
+
+       nand_release(mtd);
+
+       iounmap(nc->IO_ADDR_W);
+
+       kfree(nc);
+
+       return 0;
+}
+
+static struct platform_driver orion_nand_driver = {
+       .probe          = orion_nand_probe,
+       .remove         = orion_nand_remove,
+       .driver         = {
+               .name   = "orion_nand",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init orion_nand_init(void)
+{
+       return platform_driver_register(&orion_nand_driver);
+}
+
+static void __exit orion_nand_exit(void)
+{
+       platform_driver_unregister(&orion_nand_driver);
+}
+
+module_init(orion_nand_init);
+module_exit(orion_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tzachi Perelstein");
+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 (file)
index 0000000..75c8990
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Egor Martovetsky <egor@pasemi.com>
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip NAND flash interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#undef DEBUG
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+
+#define LBICTRL_LPCCTL_NR              0x00004000
+#define CLE_PIN_CTL                    15
+#define ALE_PIN_CTL                    14
+
+static unsigned int lpcctl;
+static struct mtd_info *pasemi_nand_mtd;
+static const char driver_name[] = "pasemi-nand";
+
+static void pasemi_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       while (len > 0x800) {
+               memcpy_fromio(buf, chip->IO_ADDR_R, 0x800);
+               buf += 0x800;
+               len -= 0x800;
+       }
+       memcpy_fromio(buf, chip->IO_ADDR_R, len);
+}
+
+static void pasemi_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       while (len > 0x800) {
+               memcpy_toio(chip->IO_ADDR_R, buf, 0x800);
+               buf += 0x800;
+               len -= 0x800;
+       }
+       memcpy_toio(chip->IO_ADDR_R, buf, len);
+}
+
+static void pasemi_hwcontrol(struct mtd_info *mtd, int cmd,
+                            unsigned int ctrl)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       if (ctrl & NAND_CLE)
+               out_8(chip->IO_ADDR_W + (1 << CLE_PIN_CTL), cmd);
+       else
+               out_8(chip->IO_ADDR_W + (1 << ALE_PIN_CTL), cmd);
+
+       /* Push out posted writes */
+       eieio();
+       inl(lpcctl);
+}
+
+int pasemi_device_ready(struct mtd_info *mtd)
+{
+       return !!(inl(lpcctl) & LBICTRL_LPCCTL_NR);
+}
+
+static int __devinit pasemi_nand_probe(struct of_device *ofdev,
+                                     const struct of_device_id *match)
+{
+       struct pci_dev *pdev;
+       struct device_node *np = ofdev->node;
+       struct resource res;
+       struct nand_chip *chip;
+       int err = 0;
+
+       err = of_address_to_resource(np, 0, &res);
+
+       if (err)
+               return -EINVAL;
+
+       /* We only support one device at the moment */
+       if (pasemi_nand_mtd)
+               return -ENODEV;
+
+       pr_debug("pasemi_nand at %lx-%lx\n", res.start, res.end);
+
+       /* Allocate memory for MTD device structure and private data */
+       pasemi_nand_mtd = kzalloc(sizeof(struct mtd_info) +
+                                 sizeof(struct nand_chip), GFP_KERNEL);
+       if (!pasemi_nand_mtd) {
+               printk(KERN_WARNING
+                      "Unable to allocate PASEMI NAND MTD device structure\n");
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Get pointer to private data */
+       chip = (struct nand_chip *)&pasemi_nand_mtd[1];
+
+       /* Link the private data with the MTD structure */
+       pasemi_nand_mtd->priv = chip;
+       pasemi_nand_mtd->owner = THIS_MODULE;
+
+       chip->IO_ADDR_R = of_iomap(np, 0);
+       chip->IO_ADDR_W = chip->IO_ADDR_R;
+
+       if (!chip->IO_ADDR_R) {
+               err = -EIO;
+               goto out_mtd;
+       }
+
+       pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa008, NULL);
+       if (!pdev) {
+               err = -ENODEV;
+               goto out_ior;
+       }
+
+       lpcctl = pci_resource_start(pdev, 0);
+
+       if (!request_region(lpcctl, 4, driver_name)) {
+               err = -EBUSY;
+               goto out_ior;
+       }
+
+       chip->cmd_ctrl = pasemi_hwcontrol;
+       chip->dev_ready = pasemi_device_ready;
+       chip->read_buf = pasemi_read_buf;
+       chip->write_buf = pasemi_write_buf;
+       chip->chip_delay = 0;
+       chip->ecc.mode = NAND_ECC_SOFT;
+
+       /* Enable the following for a flash based bad block table */
+       chip->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR;
+
+       /* Scan to find existance of the device */
+       if (nand_scan(pasemi_nand_mtd, 1)) {
+               err = -ENXIO;
+               goto out_lpc;
+       }
+
+       if (add_mtd_device(pasemi_nand_mtd)) {
+               printk(KERN_ERR "pasemi_nand: Unable to register MTD device\n");
+               err = -ENODEV;
+               goto out_lpc;
+       }
+
+       printk(KERN_INFO "PA Semi NAND flash at %08lx, control at I/O %x\n",
+              res.start, lpcctl);
+
+       return 0;
+
+ out_lpc:
+       release_region(lpcctl, 4);
+ out_ior:
+       iounmap(chip->IO_ADDR_R);
+ out_mtd:
+       kfree(pasemi_nand_mtd);
+ out:
+       return err;
+}
+
+static int __devexit pasemi_nand_remove(struct of_device *ofdev)
+{
+       struct nand_chip *chip;
+
+       if (!pasemi_nand_mtd)
+               return 0;
+
+       chip = pasemi_nand_mtd->priv;
+
+       /* Release resources, unregister device */
+       nand_release(pasemi_nand_mtd);
+
+       release_region(lpcctl, 4);
+
+       iounmap(chip->IO_ADDR_R);
+
+       /* Free the MTD device structure */
+       kfree(pasemi_nand_mtd);
+
+       pasemi_nand_mtd = NULL;
+
+       return 0;
+}
+
+static struct of_device_id pasemi_nand_match[] =
+{
+       {
+               .compatible   = "pasemi,localbus-nand",
+       },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, pasemi_nand_match);
+
+static struct of_platform_driver pasemi_nand_driver =
+{
+       .name           = (char*)driver_name,
+       .match_table    = pasemi_nand_match,
+       .probe          = pasemi_nand_probe,
+       .remove         = pasemi_nand_remove,
+};
+
+static int __init pasemi_nand_init(void)
+{
+       return of_register_platform_driver(&pasemi_nand_driver);
+}
+module_init(pasemi_nand_init);
+
+static void __exit pasemi_nand_exit(void)
+{
+       of_unregister_platform_driver(&pasemi_nand_driver);
+}
+module_exit(pasemi_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("NAND flash interface driver for PA Semi PWRficient");
index 66f76e9618ddd9005edcb60faf2b66ea2ec539b2..d31cb7b3feeb75b6f0376422f1c53a2d3c696d98 100644 (file)
@@ -120,6 +120,8 @@ struct s3c2410_nand_info {
        int                             sel_bit;
        int                             mtd_count;
 
+       unsigned long                   save_nfconf;
+
        enum s3c_cpu_type               cpu_type;
 };
 
@@ -364,23 +366,21 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
            ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) {
                /* calculate the bit position of the error */
 
-               bit  = (diff2 >> 2) & 1;
-               bit |= (diff2 >> 3) & 2;
-               bit |= (diff2 >> 4) & 4;
+               bit  = ((diff2 >> 3) & 1) |
+                      ((diff2 >> 4) & 2) |
+                      ((diff2 >> 5) & 4);
 
                /* calculate the byte position of the error */
 
-               byte  = (diff1 << 1) & 0x80;
-               byte |= (diff1 << 2) & 0x40;
-               byte |= (diff1 << 3) & 0x20;
-               byte |= (diff1 << 4) & 0x10;
-
-               byte |= (diff0 >> 3) & 0x08;
-               byte |= (diff0 >> 2) & 0x04;
-               byte |= (diff0 >> 1) & 0x02;
-               byte |= (diff0 >> 0) & 0x01;
-
-               byte |= (diff2 << 8) & 0x100;
+               byte = ((diff2 << 7) & 0x100) |
+                      ((diff1 << 0) & 0x80)  |
+                      ((diff1 << 1) & 0x40)  |
+                      ((diff1 << 2) & 0x20)  |
+                      ((diff1 << 3) & 0x10)  |
+                      ((diff0 >> 4) & 0x08)  |
+                      ((diff0 >> 3) & 0x04)  |
+                      ((diff0 >> 2) & 0x02)  |
+                      ((diff0 >> 1) & 0x01);
 
                dev_dbg(info->device, "correcting error bit %d, byte %d\n",
                        bit, byte);
@@ -399,7 +399,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
        if ((diff0 & ~(1<<fls(diff0))) == 0)
                return 1;
 
-       return 0;
+       return -1;
 }
 
 /* ECC functions
@@ -810,6 +810,16 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
        struct s3c2410_nand_info *info = platform_get_drvdata(dev);
 
        if (info) {
+               info->save_nfconf = readl(info->regs + S3C2410_NFCONF);
+
+               /* For the moment, we must ensure nFCE is high during
+                * the time we are suspended. This really should be
+                * handled by suspending the MTDs we are using, but
+                * that is currently not the case. */
+
+               writel(info->save_nfconf | info->sel_bit,
+                      info->regs + S3C2410_NFCONF);
+
                if (!allow_clk_stop(info))
                        clk_disable(info->clk);
        }
@@ -820,11 +830,19 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm)
 static int s3c24xx_nand_resume(struct platform_device *dev)
 {
        struct s3c2410_nand_info *info = platform_get_drvdata(dev);
+       unsigned long nfconf;
 
        if (info) {
                clk_enable(info->clk);
                s3c2410_nand_inithw(info, dev);
 
+               /* Restore the state of the nFCE line. */
+
+               nfconf = readl(info->regs + S3C2410_NFCONF);
+               nfconf &= ~info->sel_bit;
+               nfconf |= info->save_nfconf & info->sel_bit;
+               writel(nfconf, info->regs + S3C2410_NFCONF);
+
                if (allow_clk_stop(info))
                        clk_disable(info->clk);
        }
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
new file mode 100644 (file)
index 0000000..f86e069
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Flash partitions described by the OF (or flattened) device tree
+ *
+ * Copyright (C) 2006 MontaVista Software Inc.
+ * Author: Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * Revised to handle newer style flash binding by:
+ *   Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+int __devinit of_mtd_parse_partitions(struct device *dev,
+                                      struct mtd_info *mtd,
+                                      struct device_node *node,
+                                      struct mtd_partition **pparts)
+{
+       const char *partname;
+       struct device_node *pp;
+       int nr_parts, i;
+
+       /* First count the subnodes */
+       pp = NULL;
+       nr_parts = 0;
+       while ((pp = of_get_next_child(node, pp)))
+               nr_parts++;
+
+       if (nr_parts == 0)
+               return 0;
+
+       *pparts = kzalloc(nr_parts * sizeof(**pparts), GFP_KERNEL);
+       if (!*pparts)
+               return -ENOMEM;
+
+       pp = NULL;
+       i = 0;
+       while ((pp = of_get_next_child(node, pp))) {
+               const u32 *reg;
+               int len;
+
+               reg = of_get_property(pp, "reg", &len);
+               if (!reg || (len != 2 * sizeof(u32))) {
+                       of_node_put(pp);
+                       dev_err(dev, "Invalid 'reg' on %s\n", node->full_name);
+                       kfree(*pparts);
+                       *pparts = NULL;
+                       return -EINVAL;
+               }
+               (*pparts)[i].offset = reg[0];
+               (*pparts)[i].size = reg[1];
+
+               partname = of_get_property(pp, "label", &len);
+               if (!partname)
+                       partname = of_get_property(pp, "name", &len);
+               (*pparts)[i].name = (char *)partname;
+
+               if (of_get_property(pp, "read-only", &len))
+                       (*pparts)[i].mask_flags = MTD_WRITEABLE;
+
+               i++;
+       }
+
+       return nr_parts;
+}
+EXPORT_SYMBOL(of_mtd_parse_partitions);
index 1b0b3201141592f130d2ee6433194476cc36f2bd..ed9f9c061ac520e47f4cd0699c3bde05741d70b5 100644 (file)
@@ -855,6 +855,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                        this->command(mtd, ONENAND_CMD_READ, from, writesize);
                        ret = this->wait(mtd, FL_READING);
                        onenand_update_bufferram(mtd, from, !ret);
+                       if (ret == -EBADMSG)
+                               ret = 0;
                }
        }
 
@@ -913,6 +915,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
                /* Now wait for load */
                ret = this->wait(mtd, FL_READING);
                onenand_update_bufferram(mtd, from, !ret);
+               if (ret == -EBADMSG)
+                       ret = 0;
        }
 
        /*
@@ -923,12 +927,12 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
        ops->retlen = read;
        ops->oobretlen = oobread;
 
-       if (mtd->ecc_stats.failed - stats.failed)
-               return -EBADMSG;
-
        if (ret)
                return ret;
 
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
        return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
 }
 
@@ -944,6 +948,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                        struct mtd_oob_ops *ops)
 {
        struct onenand_chip *this = mtd->priv;
+       struct mtd_ecc_stats stats;
        int read = 0, thislen, column, oobsize;
        size_t len = ops->ooblen;
        mtd_oob_mode_t mode = ops->mode;
@@ -977,6 +982,8 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                return -EINVAL;
        }
 
+       stats = mtd->ecc_stats;
+
        while (read < len) {
                cond_resched();
 
@@ -988,18 +995,16 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
                onenand_update_bufferram(mtd, from, 0);
 
                ret = this->wait(mtd, FL_READING);
-               /* First copy data and check return value for ECC handling */
+               if (ret && ret != -EBADMSG) {
+                       printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
+                       break;
+               }
 
                if (mode == MTD_OOB_AUTO)
                        onenand_transfer_auto_oob(mtd, buf, column, thislen);
                else
                        this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
 
-               if (ret) {
-                       printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
-                       break;
-               }
-
                read += thislen;
 
                if (read == len)
@@ -1016,7 +1021,14 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
        }
 
        ops->oobretlen = read;
-       return ret;
+
+       if (ret)
+               return ret;
+
+       if (mtd->ecc_stats.failed - stats.failed)
+               return -EBADMSG;
+
+       return 0;
 }
 
 /**
index a61351f88ec046d894bf07bc042907e2a22bb364..47474903263c377555b0a5c0fefad3af737c1c78 100644 (file)
@@ -59,16 +59,31 @@ static int parse_redboot_partitions(struct mtd_info *master,
        static char nullstring[] = "unallocated";
 #endif
 
+       if ( directory < 0 ) {
+               offset = master->size + directory * master->erasesize;
+               while (master->block_isbad && 
+                      master->block_isbad(master, offset)) {
+                       if (!offset) {
+                       nogood:
+                               printk(KERN_NOTICE "Failed to find a non-bad block to check for RedBoot partition table\n");
+                               return -EIO;
+                       }
+                       offset -= master->erasesize;
+               }
+       } else {
+               offset = directory * master->erasesize;
+               while (master->block_isbad && 
+                      master->block_isbad(master, offset)) {
+                       offset += master->erasesize;
+                       if (offset == master->size)
+                               goto nogood;
+               }
+       }
        buf = vmalloc(master->erasesize);
 
        if (!buf)
                return -ENOMEM;
 
-       if ( directory < 0 )
-               offset = master->size + directory*master->erasesize;
-       else
-               offset = directory*master->erasesize;
-
        printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
               master->name, offset);
 
index 023653977a1ad762ecf1bc371d6b68fc328211fe..8f1f9feb2d60dca5c5a092ea323ff105989763e4 100644 (file)
  */
 
 /*
- * This file includes UBI initialization and building of UBI devices. At the
- * moment UBI devices may only be added while UBI is initialized, but dynamic
- * device add/remove functionality is planned. Also, at the moment we only
- * attach UBI devices by scanning, which will become a bottleneck when flashes
- * reach certain large size. Then one may improve UBI and add other methods.
+ * This file includes UBI initialization and building of UBI devices.
+ *
+ * When UBI is initialized, it attaches all the MTD devices specified as the
+ * module load parameters or the kernel boot parameters. If MTD devices were
+ * specified, UBI does not attach any MTD device, but it is possible to do
+ * later using the "UBI control device".
+ *
+ * At the moment we only attach UBI devices by scanning, which will become a
+ * bottleneck when flashes reach certain large size. Then one may improve UBI
+ * and add other methods, although it does not seem to be easy to do.
  */
 
 #include <linux/err.h>
@@ -33,7 +38,9 @@
 #include <linux/moduleparam.h>
 #include <linux/stringify.h>
 #include <linux/stat.h>
+#include <linux/miscdevice.h>
 #include <linux/log2.h>
+#include <linux/kthread.h>
 #include "ubi.h"
 
 /* Maximum length of the 'mtd=' parameter */
  * struct mtd_dev_param - MTD device parameter description data structure.
  * @name: MTD device name or number string
  * @vid_hdr_offs: VID header offset
- * @data_offs: data offset
  */
 struct mtd_dev_param
 {
        char name[MTD_PARAM_LEN_MAX];
        int vid_hdr_offs;
-       int data_offs;
 };
 
 /* Numbers of elements set in the @mtd_dev_param array */
@@ -58,14 +63,30 @@ static int mtd_devs = 0;
 /* MTD devices specification parameters */
 static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES];
 
-/* Number of UBI devices in system */
-int ubi_devices_cnt;
+/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
+struct class *ubi_class;
+
+/* Slab cache for lock-tree entries */
+struct kmem_cache *ubi_ltree_slab;
+
+/* Slab cache for wear-leveling entries */
+struct kmem_cache *ubi_wl_entry_slab;
+
+/* UBI control character device */
+static struct miscdevice ubi_ctrl_cdev = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "ubi_ctrl",
+       .fops = &ubi_ctrl_cdev_operations,
+};
 
 /* All UBI devices in system */
-struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
+static struct ubi_device *ubi_devices[UBI_MAX_DEVICES];
 
-/* Root UBI "class" object (corresponds to '/<sysfs>/class/ubi/') */
-struct class *ubi_class;
+/* Serializes UBI devices creations and removals */
+DEFINE_MUTEX(ubi_devices_mutex);
+
+/* Protects @ubi_devices and @ubi->ref_count */
+static DEFINE_SPINLOCK(ubi_devices_lock);
 
 /* "Show" method for files in '/<sysfs>/class/ubi/' */
 static ssize_t ubi_version_show(struct class *class, char *buf)
@@ -101,38 +122,150 @@ static struct device_attribute dev_min_io_size =
        __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL);
 static struct device_attribute dev_bgt_enabled =
        __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL);
+static struct device_attribute dev_mtd_num =
+       __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL);
+
+/**
+ * ubi_get_device - get UBI device.
+ * @ubi_num: UBI device number
+ *
+ * This function returns UBI device description object for UBI device number
+ * @ubi_num, or %NULL if the device does not exist. This function increases the
+ * device reference count to prevent removal of the device. In other words, the
+ * device cannot be removed if its reference count is not zero.
+ */
+struct ubi_device *ubi_get_device(int ubi_num)
+{
+       struct ubi_device *ubi;
+
+       spin_lock(&ubi_devices_lock);
+       ubi = ubi_devices[ubi_num];
+       if (ubi) {
+               ubi_assert(ubi->ref_count >= 0);
+               ubi->ref_count += 1;
+               get_device(&ubi->dev);
+       }
+       spin_unlock(&ubi_devices_lock);
+
+       return ubi;
+}
+
+/**
+ * ubi_put_device - drop an UBI device reference.
+ * @ubi: UBI device description object
+ */
+void ubi_put_device(struct ubi_device *ubi)
+{
+       spin_lock(&ubi_devices_lock);
+       ubi->ref_count -= 1;
+       put_device(&ubi->dev);
+       spin_unlock(&ubi_devices_lock);
+}
+
+/**
+ * ubi_get_by_major - get UBI device description object by character device
+ *                    major number.
+ * @major: major number
+ *
+ * This function is similar to 'ubi_get_device()', but it searches the device
+ * by its major number.
+ */
+struct ubi_device *ubi_get_by_major(int major)
+{
+       int i;
+       struct ubi_device *ubi;
+
+       spin_lock(&ubi_devices_lock);
+       for (i = 0; i < UBI_MAX_DEVICES; i++) {
+               ubi = ubi_devices[i];
+               if (ubi && MAJOR(ubi->cdev.dev) == major) {
+                       ubi_assert(ubi->ref_count >= 0);
+                       ubi->ref_count += 1;
+                       get_device(&ubi->dev);
+                       spin_unlock(&ubi_devices_lock);
+                       return ubi;
+               }
+       }
+       spin_unlock(&ubi_devices_lock);
+
+       return NULL;
+}
+
+/**
+ * ubi_major2num - get UBI device number by character device major number.
+ * @major: major number
+ *
+ * This function searches UBI device number object by its major number. If UBI
+ * device was not found, this function returns -ENODEV, otherwise the UBI device
+ * number is returned.
+ */
+int ubi_major2num(int major)
+{
+       int i, ubi_num = -ENODEV;
+
+       spin_lock(&ubi_devices_lock);
+       for (i = 0; i < UBI_MAX_DEVICES; i++) {
+               struct ubi_device *ubi = ubi_devices[i];
+
+               if (ubi && MAJOR(ubi->cdev.dev) == major) {
+                       ubi_num = ubi->ubi_num;
+                       break;
+               }
+       }
+       spin_unlock(&ubi_devices_lock);
+
+       return ubi_num;
+}
 
 /* "Show" method for files in '/<sysfs>/class/ubi/ubiX/' */
 static ssize_t dev_attribute_show(struct device *dev,
                                  struct device_attribute *attr, char *buf)
 {
-       const struct ubi_device *ubi;
+       ssize_t ret;
+       struct ubi_device *ubi;
 
+       /*
+        * The below code looks weird, but it actually makes sense. We get the
+        * UBI device reference from the contained 'struct ubi_device'. But it
+        * is unclear if the device was removed or not yet. Indeed, if the
+        * device was removed before we increased its reference count,
+        * 'ubi_get_device()' will return -ENODEV and we fail.
+        *
+        * Remember, 'struct ubi_device' is freed in the release function, so
+        * we still can use 'ubi->ubi_num'.
+        */
        ubi = container_of(dev, struct ubi_device, dev);
+       ubi = ubi_get_device(ubi->ubi_num);
+       if (!ubi)
+               return -ENODEV;
+
        if (attr == &dev_eraseblock_size)
-               return sprintf(buf, "%d\n", ubi->leb_size);
+               ret = sprintf(buf, "%d\n", ubi->leb_size);
        else if (attr == &dev_avail_eraseblocks)
-               return sprintf(buf, "%d\n", ubi->avail_pebs);
+               ret = sprintf(buf, "%d\n", ubi->avail_pebs);
        else if (attr == &dev_total_eraseblocks)
-               return sprintf(buf, "%d\n", ubi->good_peb_count);
+               ret = sprintf(buf, "%d\n", ubi->good_peb_count);
        else if (attr == &dev_volumes_count)
-               return sprintf(buf, "%d\n", ubi->vol_count);
+               ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT);
        else if (attr == &dev_max_ec)
-               return sprintf(buf, "%d\n", ubi->max_ec);
+               ret = sprintf(buf, "%d\n", ubi->max_ec);
        else if (attr == &dev_reserved_for_bad)
-               return sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
+               ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs);
        else if (attr == &dev_bad_peb_count)
-               return sprintf(buf, "%d\n", ubi->bad_peb_count);
+               ret = sprintf(buf, "%d\n", ubi->bad_peb_count);
        else if (attr == &dev_max_vol_count)
-               return sprintf(buf, "%d\n", ubi->vtbl_slots);
+               ret = sprintf(buf, "%d\n", ubi->vtbl_slots);
        else if (attr == &dev_min_io_size)
-               return sprintf(buf, "%d\n", ubi->min_io_size);
+               ret = sprintf(buf, "%d\n", ubi->min_io_size);
        else if (attr == &dev_bgt_enabled)
-               return sprintf(buf, "%d\n", ubi->thread_enabled);
+               ret = sprintf(buf, "%d\n", ubi->thread_enabled);
+       else if (attr == &dev_mtd_num)
+               ret = sprintf(buf, "%d\n", ubi->mtd->index);
        else
-               BUG();
+               ret = -EINVAL;
 
-       return 0;
+       ubi_put_device(ubi);
+       return ret;
 }
 
 /* Fake "release" method for UBI devices */
@@ -150,68 +283,44 @@ static int ubi_sysfs_init(struct ubi_device *ubi)
        int err;
 
        ubi->dev.release = dev_release;
-       ubi->dev.devt = MKDEV(ubi->major, 0);
+       ubi->dev.devt = ubi->cdev.dev;
        ubi->dev.class = ubi_class;
        sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num);
        err = device_register(&ubi->dev);
        if (err)
-               goto out;
+               return err;
 
        err = device_create_file(&ubi->dev, &dev_eraseblock_size);
        if (err)
-               goto out_unregister;
+               return err;
        err = device_create_file(&ubi->dev, &dev_avail_eraseblocks);
        if (err)
-               goto out_eraseblock_size;
+               return err;
        err = device_create_file(&ubi->dev, &dev_total_eraseblocks);
        if (err)
-               goto out_avail_eraseblocks;
+               return err;
        err = device_create_file(&ubi->dev, &dev_volumes_count);
        if (err)
-               goto out_total_eraseblocks;
+               return err;
        err = device_create_file(&ubi->dev, &dev_max_ec);
        if (err)
-               goto out_volumes_count;
+               return err;
        err = device_create_file(&ubi->dev, &dev_reserved_for_bad);
        if (err)
-               goto out_volumes_max_ec;
+               return err;
        err = device_create_file(&ubi->dev, &dev_bad_peb_count);
        if (err)
-               goto out_reserved_for_bad;
+               return err;
        err = device_create_file(&ubi->dev, &dev_max_vol_count);
        if (err)
-               goto out_bad_peb_count;
+               return err;
        err = device_create_file(&ubi->dev, &dev_min_io_size);
        if (err)
-               goto out_max_vol_count;
+               return err;
        err = device_create_file(&ubi->dev, &dev_bgt_enabled);
        if (err)
-               goto out_min_io_size;
-
-       return 0;
-
-out_min_io_size:
-       device_remove_file(&ubi->dev, &dev_min_io_size);
-out_max_vol_count:
-       device_remove_file(&ubi->dev, &dev_max_vol_count);
-out_bad_peb_count:
-       device_remove_file(&ubi->dev, &dev_bad_peb_count);
-out_reserved_for_bad:
-       device_remove_file(&ubi->dev, &dev_reserved_for_bad);
-out_volumes_max_ec:
-       device_remove_file(&ubi->dev, &dev_max_ec);
-out_volumes_count:
-       device_remove_file(&ubi->dev, &dev_volumes_count);
-out_total_eraseblocks:
-       device_remove_file(&ubi->dev, &dev_total_eraseblocks);
-out_avail_eraseblocks:
-       device_remove_file(&ubi->dev, &dev_avail_eraseblocks);
-out_eraseblock_size:
-       device_remove_file(&ubi->dev, &dev_eraseblock_size);
-out_unregister:
-       device_unregister(&ubi->dev);
-out:
-       ubi_err("failed to initialize sysfs for %s", ubi->ubi_name);
+               return err;
+       err = device_create_file(&ubi->dev, &dev_mtd_num);
        return err;
 }
 
@@ -221,6 +330,7 @@ out:
  */
 static void ubi_sysfs_close(struct ubi_device *ubi)
 {
+       device_remove_file(&ubi->dev, &dev_mtd_num);
        device_remove_file(&ubi->dev, &dev_bgt_enabled);
        device_remove_file(&ubi->dev, &dev_min_io_size);
        device_remove_file(&ubi->dev, &dev_max_vol_count);
@@ -244,7 +354,7 @@ static void kill_volumes(struct ubi_device *ubi)
 
        for (i = 0; i < ubi->vtbl_slots; i++)
                if (ubi->volumes[i])
-                       ubi_free_volume(ubi, i);
+                       ubi_free_volume(ubi, ubi->volumes[i]);
 }
 
 /**
@@ -259,7 +369,7 @@ static int uif_init(struct ubi_device *ubi)
        int i, err;
        dev_t dev;
 
-       mutex_init(&ubi->vtbl_mutex);
+       mutex_init(&ubi->volumes_mutex);
        spin_lock_init(&ubi->volumes_lock);
 
        sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num);
@@ -278,39 +388,40 @@ static int uif_init(struct ubi_device *ubi)
                return err;
        }
 
+       ubi_assert(MINOR(dev) == 0);
        cdev_init(&ubi->cdev, &ubi_cdev_operations);
-       ubi->major = MAJOR(dev);
-       dbg_msg("%s major is %u", ubi->ubi_name, ubi->major);
+       dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev));
        ubi->cdev.owner = THIS_MODULE;
 
-       dev = MKDEV(ubi->major, 0);
        err = cdev_add(&ubi->cdev, dev, 1);
        if (err) {
-               ubi_err("cannot add character device %s", ubi->ubi_name);
+               ubi_err("cannot add character device");
                goto out_unreg;
        }
 
        err = ubi_sysfs_init(ubi);
        if (err)
-               goto out_cdev;
+               goto out_sysfs;
 
        for (i = 0; i < ubi->vtbl_slots; i++)
                if (ubi->volumes[i]) {
-                       err = ubi_add_volume(ubi, i);
-                       if (err)
+                       err = ubi_add_volume(ubi, ubi->volumes[i]);
+                       if (err) {
+                               ubi_err("cannot add volume %d", i);
                                goto out_volumes;
+                       }
                }
 
        return 0;
 
 out_volumes:
        kill_volumes(ubi);
+out_sysfs:
        ubi_sysfs_close(ubi);
-out_cdev:
        cdev_del(&ubi->cdev);
 out_unreg:
-       unregister_chrdev_region(MKDEV(ubi->major, 0),
-                                ubi->vtbl_slots + 1);
+       unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
+       ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err);
        return err;
 }
 
@@ -323,7 +434,7 @@ static void uif_close(struct ubi_device *ubi)
        kill_volumes(ubi);
        ubi_sysfs_close(ubi);
        cdev_del(&ubi->cdev);
-       unregister_chrdev_region(MKDEV(ubi->major, 0), ubi->vtbl_slots + 1);
+       unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1);
 }
 
 /**
@@ -384,9 +495,9 @@ out_si:
  * assumed:
  *   o EC header is always at offset zero - this cannot be changed;
  *   o VID header starts just after the EC header at the closest address
- *   aligned to @io->@hdrs_min_io_size;
+ *     aligned to @io->hdrs_min_io_size;
  *   o data starts just after the VID header at the closest address aligned to
- *     @io->@min_io_size
+ *     @io->min_io_size
  *
  * This function returns zero in case of success and a negative error code in
  * case of failure.
@@ -407,6 +518,9 @@ static int io_init(struct ubi_device *ubi)
                return -EINVAL;
        }
 
+       if (ubi->vid_hdr_offset < 0)
+               return -EINVAL;
+
        /*
         * Note, in this implementation we support MTD devices with 0x7FFFFFFF
         * physical eraseblocks maximum.
@@ -424,7 +538,8 @@ static int io_init(struct ubi_device *ubi)
 
        /* Make sure minimal I/O unit is power of 2 */
        if (!is_power_of_2(ubi->min_io_size)) {
-               ubi_err("bad min. I/O unit");
+               ubi_err("min. I/O unit (%d) is not power of 2",
+                       ubi->min_io_size);
                return -EINVAL;
        }
 
@@ -453,10 +568,8 @@ static int io_init(struct ubi_device *ubi)
        }
 
        /* Similar for the data offset */
-       if (ubi->leb_start == 0) {
-               ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
-               ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
-       }
+       ubi->leb_start = ubi->vid_hdr_offset + ubi->vid_hdr_alsize;
+       ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size);
 
        dbg_msg("vid_hdr_offset   %d", ubi->vid_hdr_offset);
        dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset);
@@ -514,76 +627,91 @@ static int io_init(struct ubi_device *ubi)
 }
 
 /**
- * attach_mtd_dev - attach an MTD device.
- * @mtd_dev: MTD device name or number string
+ * ubi_attach_mtd_dev - attach an MTD device.
+ * @mtd_dev: MTD device description object
+ * @ubi_num: number to assign to the new UBI device
  * @vid_hdr_offset: VID header offset
- * @data_offset: data offset
  *
- * This function attaches an MTD device to UBI. It first treats @mtd_dev as the
- * MTD device name, and tries to open it by this name. If it is unable to open,
- * it tries to convert @mtd_dev to an integer and open the MTD device by its
- * number. Returns zero in case of success and a negative error code in case of
- * failure.
+ * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number
+ * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in
+ * which case this function finds a vacant device nubert and assings it
+ * automatically. Returns the new UBI device number in case of success and a
+ * negative error code in case of failure.
+ *
+ * Note, the invocations of this function has to be serialized by the
+ * @ubi_devices_mutex.
  */
-static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
-                         int data_offset)
+int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
 {
        struct ubi_device *ubi;
-       struct mtd_info *mtd;
        int i, err;
 
-       mtd = get_mtd_device_nm(mtd_dev);
-       if (IS_ERR(mtd)) {
-               int mtd_num;
-               char *endp;
-
-               if (PTR_ERR(mtd) != -ENODEV)
-                       return PTR_ERR(mtd);
-
-               /*
-                * Probably this is not MTD device name but MTD device number -
-                * check this out.
-                */
-               mtd_num = simple_strtoul(mtd_dev, &endp, 0);
-               if (*endp != '\0' || mtd_dev == endp) {
-                       ubi_err("incorrect MTD device: \"%s\"", mtd_dev);
-                       return -ENODEV;
+       /*
+        * Check if we already have the same MTD device attached.
+        *
+        * Note, this function assumes that UBI devices creations and deletions
+        * are serialized, so it does not take the &ubi_devices_lock.
+        */
+       for (i = 0; i < UBI_MAX_DEVICES; i++) {
+               ubi = ubi_devices[i];
+               if (ubi && mtd->index == ubi->mtd->index) {
+                       dbg_err("mtd%d is already attached to ubi%d",
+                               mtd->index, i);
+                       return -EEXIST;
                }
+       }
 
-               mtd = get_mtd_device(NULL, mtd_num);
-               if (IS_ERR(mtd))
-                       return PTR_ERR(mtd);
+       /*
+        * Make sure this MTD device is not emulated on top of an UBI volume
+        * already. Well, generally this recursion works fine, but there are
+        * different problems like the UBI module takes a reference to itself
+        * by attaching (and thus, opening) the emulated MTD device. This
+        * results in inability to unload the module. And in general it makes
+        * no sense to attach emulated MTD devices, so we prohibit this.
+        */
+       if (mtd->type == MTD_UBIVOLUME) {
+               ubi_err("refuse attaching mtd%d - it is already emulated on "
+                       "top of UBI", mtd->index);
+               return -EINVAL;
        }
 
-       /* Check if we already have the same MTD device attached */
-       for (i = 0; i < ubi_devices_cnt; i++)
-               if (ubi_devices[i]->mtd->index == mtd->index) {
-                       ubi_err("mtd%d is already attached to ubi%d",
-                               mtd->index, i);
-                       err = -EINVAL;
-                       goto out_mtd;
+       if (ubi_num == UBI_DEV_NUM_AUTO) {
+               /* Search for an empty slot in the @ubi_devices array */
+               for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
+                       if (!ubi_devices[ubi_num])
+                               break;
+               if (ubi_num == UBI_MAX_DEVICES) {
+                       dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES);
+                       return -ENFILE;
+               }
+       } else {
+               if (ubi_num >= UBI_MAX_DEVICES)
+                       return -EINVAL;
+
+               /* Make sure ubi_num is not busy */
+               if (ubi_devices[ubi_num]) {
+                       dbg_err("ubi%d already exists", ubi_num);
+                       return -EEXIST;
                }
-
-       ubi = ubi_devices[ubi_devices_cnt] = kzalloc(sizeof(struct ubi_device),
-                                                    GFP_KERNEL);
-       if (!ubi) {
-               err = -ENOMEM;
-               goto out_mtd;
        }
 
-       ubi->ubi_num = ubi_devices_cnt;
+       ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL);
+       if (!ubi)
+               return -ENOMEM;
+
        ubi->mtd = mtd;
+       ubi->ubi_num = ubi_num;
+       ubi->vid_hdr_offset = vid_hdr_offset;
 
-       dbg_msg("attaching mtd%d to ubi%d: VID header offset %d data offset %d",
-               ubi->mtd->index, ubi_devices_cnt, vid_hdr_offset, data_offset);
+       dbg_msg("attaching mtd%d to ubi%d: VID header offset %d",
+               mtd->index, ubi_num, vid_hdr_offset);
 
-       ubi->vid_hdr_offset = vid_hdr_offset;
-       ubi->leb_start = data_offset;
        err = io_init(ubi);
        if (err)
                goto out_free;
 
        mutex_init(&ubi->buf_mutex);
+       mutex_init(&ubi->ckvol_mutex);
        ubi->peb_buf1 = vmalloc(ubi->peb_size);
        if (!ubi->peb_buf1)
                goto out_free;
@@ -609,8 +737,16 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
        if (err)
                goto out_detach;
 
-       ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
-       ubi_msg("MTD device name:            \"%s\"", ubi->mtd->name);
+       ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name);
+       if (IS_ERR(ubi->bgt_thread)) {
+               err = PTR_ERR(ubi->bgt_thread);
+               ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name,
+                       err);
+               goto out_uif;
+       }
+
+       ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num);
+       ubi_msg("MTD device name:            \"%s\"", mtd->name);
        ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
        ubi_msg("physical eraseblock size:   %d bytes (%d KiB)",
                ubi->peb_size, ubi->peb_size >> 10);
@@ -638,9 +774,11 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
                wake_up_process(ubi->bgt_thread);
        }
 
-       ubi_devices_cnt += 1;
-       return 0;
+       ubi_devices[ubi_num] = ubi;
+       return ubi_num;
 
+out_uif:
+       uif_close(ubi);
 out_detach:
        ubi_eba_close(ubi);
        ubi_wl_close(ubi);
@@ -652,21 +790,58 @@ out_free:
        vfree(ubi->dbg_peb_buf);
 #endif
        kfree(ubi);
-out_mtd:
-       put_mtd_device(mtd);
-       ubi_devices[ubi_devices_cnt] = NULL;
        return err;
 }
 
 /**
- * detach_mtd_dev - detach an MTD device.
- * @ubi: UBI device description object
+ * ubi_detach_mtd_dev - detach an MTD device.
+ * @ubi_num: UBI device number to detach from
+ * @anyway: detach MTD even if device reference count is not zero
+ *
+ * This function destroys an UBI device number @ubi_num and detaches the
+ * underlying MTD device. Returns zero in case of success and %-EBUSY if the
+ * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not
+ * exist.
+ *
+ * Note, the invocations of this function has to be serialized by the
+ * @ubi_devices_mutex.
  */
-static void detach_mtd_dev(struct ubi_device *ubi)
+int ubi_detach_mtd_dev(int ubi_num, int anyway)
 {
-       int ubi_num = ubi->ubi_num, mtd_num = ubi->mtd->index;
+       struct ubi_device *ubi;
 
+       if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+               return -EINVAL;
+
+       spin_lock(&ubi_devices_lock);
+       ubi = ubi_devices[ubi_num];
+       if (!ubi) {
+               spin_unlock(&ubi_devices_lock);
+               return -EINVAL;
+       }
+
+       if (ubi->ref_count) {
+               if (!anyway) {
+                       spin_unlock(&ubi_devices_lock);
+                       return -EBUSY;
+               }
+               /* This may only happen if there is a bug */
+               ubi_err("%s reference count %d, destroy anyway",
+                       ubi->ubi_name, ubi->ref_count);
+       }
+       ubi_devices[ubi_num] = NULL;
+       spin_unlock(&ubi_devices_lock);
+
+       ubi_assert(ubi_num == ubi->ubi_num);
        dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num);
+
+       /*
+        * Before freeing anything, we have to stop the background thread to
+        * prevent it from doing anything on this device while we are freeing.
+        */
+       if (ubi->bgt_thread)
+               kthread_stop(ubi->bgt_thread);
+
        uif_close(ubi);
        ubi_eba_close(ubi);
        ubi_wl_close(ubi);
@@ -677,11 +852,51 @@ static void detach_mtd_dev(struct ubi_device *ubi)
 #ifdef CONFIG_MTD_UBI_DEBUG
        vfree(ubi->dbg_peb_buf);
 #endif
-       kfree(ubi_devices[ubi_num]);
-       ubi_devices[ubi_num] = NULL;
-       ubi_devices_cnt -= 1;
-       ubi_assert(ubi_devices_cnt >= 0);
-       ubi_msg("mtd%d is detached from ubi%d", mtd_num, ubi_num);
+       ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num);
+       kfree(ubi);
+       return 0;
+}
+
+/**
+ * ltree_entry_ctor - lock tree entries slab cache constructor.
+ * @obj: the lock-tree entry to construct
+ * @cache: the lock tree entry slab cache
+ * @flags: constructor flags
+ */
+static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
+{
+       struct ubi_ltree_entry *le = obj;
+
+       le->users = 0;
+       init_rwsem(&le->mutex);
+}
+
+/**
+ * find_mtd_device - open an MTD device by its name or number.
+ * @mtd_dev: name or number of the device
+ *
+ * This function tries to open and MTD device described by @mtd_dev string,
+ * which is first treated as an ASCII number, and if it is not true, it is
+ * treated as MTD device name. Returns MTD device description object in case of
+ * success and a negative error code in case of failure.
+ */
+static struct mtd_info * __init open_mtd_device(const char *mtd_dev)
+{
+       struct mtd_info *mtd;
+       int mtd_num;
+       char *endp;
+
+       mtd_num = simple_strtoul(mtd_dev, &endp, 0);
+       if (*endp != '\0' || mtd_dev == endp) {
+               /*
+                * This does not look like an ASCII integer, probably this is
+                * MTD device name.
+                */
+               mtd = get_mtd_device_nm(mtd_dev);
+       } else
+               mtd = get_mtd_device(NULL, mtd_num);
+
+       return mtd;
 }
 
 static int __init ubi_init(void)
@@ -693,47 +908,105 @@ static int __init ubi_init(void)
        BUILD_BUG_ON(sizeof(struct ubi_vid_hdr) != 64);
 
        if (mtd_devs > UBI_MAX_DEVICES) {
-               printk("UBI error: too many MTD devices, maximum is %d\n",
-                      UBI_MAX_DEVICES);
+               printk(KERN_ERR "UBI error: too many MTD devices, "
+                      "maximum is %d\n", UBI_MAX_DEVICES);
                return -EINVAL;
        }
 
+       /* Create base sysfs directory and sysfs files */
        ubi_class = class_create(THIS_MODULE, UBI_NAME_STR);
-       if (IS_ERR(ubi_class))
-               return PTR_ERR(ubi_class);
+       if (IS_ERR(ubi_class)) {
+               err = PTR_ERR(ubi_class);
+               printk(KERN_ERR "UBI error: cannot create UBI class\n");
+               goto out;
+       }
 
        err = class_create_file(ubi_class, &ubi_version);
-       if (err)
+       if (err) {
+               printk(KERN_ERR "UBI error: cannot create sysfs file\n");
                goto out_class;
+       }
+
+       err = misc_register(&ubi_ctrl_cdev);
+       if (err) {
+               printk(KERN_ERR "UBI error: cannot register device\n");
+               goto out_version;
+       }
+
+       ubi_ltree_slab = kmem_cache_create("ubi_ltree_slab",
+                                          sizeof(struct ubi_ltree_entry), 0,
+                                          0, &ltree_entry_ctor);
+       if (!ubi_ltree_slab)
+               goto out_dev_unreg;
+
+       ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
+                                               sizeof(struct ubi_wl_entry),
+                                               0, 0, NULL);
+       if (!ubi_wl_entry_slab)
+               goto out_ltree;
 
        /* Attach MTD devices */
        for (i = 0; i < mtd_devs; i++) {
                struct mtd_dev_param *p = &mtd_dev_param[i];
+               struct mtd_info *mtd;
 
                cond_resched();
-               err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
-               if (err)
+
+               mtd = open_mtd_device(p->name);
+               if (IS_ERR(mtd)) {
+                       err = PTR_ERR(mtd);
                        goto out_detach;
+               }
+
+               mutex_lock(&ubi_devices_mutex);
+               err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO,
+                                        p->vid_hdr_offs);
+               mutex_unlock(&ubi_devices_mutex);
+               if (err < 0) {
+                       put_mtd_device(mtd);
+                       printk(KERN_ERR "UBI error: cannot attach %s\n",
+                              p->name);
+                       goto out_detach;
+               }
        }
 
        return 0;
 
 out_detach:
        for (k = 0; k < i; k++)
-               detach_mtd_dev(ubi_devices[k]);
+               if (ubi_devices[k]) {
+                       mutex_lock(&ubi_devices_mutex);
+                       ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1);
+                       mutex_unlock(&ubi_devices_mutex);
+               }
+       kmem_cache_destroy(ubi_wl_entry_slab);
+out_ltree:
+       kmem_cache_destroy(ubi_ltree_slab);
+out_dev_unreg:
+       misc_deregister(&ubi_ctrl_cdev);
+out_version:
        class_remove_file(ubi_class, &ubi_version);
 out_class:
        class_destroy(ubi_class);
+out:
+       printk(KERN_ERR "UBI error: cannot initialize UBI, error %d\n", err);
        return err;
 }
 module_init(ubi_init);
 
 static void __exit ubi_exit(void)
 {
-       int i, n = ubi_devices_cnt;
+       int i;
 
-       for (i = 0; i < n; i++)
-               detach_mtd_dev(ubi_devices[i]);
+       for (i = 0; i < UBI_MAX_DEVICES; i++)
+               if (ubi_devices[i]) {
+                       mutex_lock(&ubi_devices_mutex);
+                       ubi_detach_mtd_dev(ubi_devices[i]->ubi_num, 1);
+                       mutex_unlock(&ubi_devices_mutex);
+               }
+       kmem_cache_destroy(ubi_wl_entry_slab);
+       kmem_cache_destroy(ubi_ltree_slab);
+       misc_deregister(&ubi_ctrl_cdev);
        class_remove_file(ubi_class, &ubi_version);
        class_destroy(ubi_class);
 }
@@ -754,7 +1027,8 @@ static int __init bytes_str_to_int(const char *str)
 
        result = simple_strtoul(str, &endp, 0);
        if (str == endp || result < 0) {
-               printk("UBI error: incorrect bytes count: \"%s\"\n", str);
+               printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n",
+                      str);
                return -EINVAL;
        }
 
@@ -764,15 +1038,14 @@ static int __init bytes_str_to_int(const char *str)
        case 'M':
                result *= 1024;
        case 'K':
-       case 'k':
                result *= 1024;
-               if (endp[1] == 'i' && (endp[2] == '\0' ||
-                         endp[2] == 'B'  || endp[2] == 'b'))
+               if (endp[1] == 'i' && endp[2] == 'B')
                        endp += 2;
        case '\0':
                break;
        default:
-               printk("UBI error: incorrect bytes count: \"%s\"\n", str);
+               printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n",
+                      str);
                return -EINVAL;
        }
 
@@ -795,21 +1068,25 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
        char *pbuf = &buf[0];
        char *tokens[3] = {NULL, NULL, NULL};
 
+       if (!val)
+               return -EINVAL;
+
        if (mtd_devs == UBI_MAX_DEVICES) {
-               printk("UBI error: too many parameters, max. is %d\n",
+               printk(KERN_ERR "UBI error: too many parameters, max. is %d\n",
                       UBI_MAX_DEVICES);
                return -EINVAL;
        }
 
        len = strnlen(val, MTD_PARAM_LEN_MAX);
        if (len == MTD_PARAM_LEN_MAX) {
-               printk("UBI error: parameter \"%s\" is too long, max. is %d\n",
-                      val, MTD_PARAM_LEN_MAX);
+               printk(KERN_ERR "UBI error: parameter \"%s\" is too long, "
+                      "max. is %d\n", val, MTD_PARAM_LEN_MAX);
                return -EINVAL;
        }
 
        if (len == 0) {
-               printk("UBI warning: empty 'mtd=' parameter - ignored\n");
+               printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - "
+                      "ignored\n");
                return 0;
        }
 
@@ -823,7 +1100,8 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
                tokens[i] = strsep(&pbuf, ",");
 
        if (pbuf) {
-               printk("UBI error: too many arguments at \"%s\"\n", val);
+               printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n",
+                      val);
                return -EINVAL;
        }
 
@@ -832,13 +1110,9 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
 
        if (tokens[1])
                p->vid_hdr_offs = bytes_str_to_int(tokens[1]);
-       if (tokens[2])
-               p->data_offs = bytes_str_to_int(tokens[2]);
 
        if (p->vid_hdr_offs < 0)
                return p->vid_hdr_offs;
-       if (p->data_offs < 0)
-               return p->data_offs;
 
        mtd_devs += 1;
        return 0;
@@ -846,16 +1120,15 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
 
 module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000);
 MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: "
-                     "mtd=<name|num>[,<vid_hdr_offs>,<data_offs>]. "
+                     "mtd=<name|num>[,<vid_hdr_offs>].\n"
                      "Multiple \"mtd\" parameters may be specified.\n"
-                     "MTD devices may be specified by their number or name. "
-                     "Optional \"vid_hdr_offs\" and \"data_offs\" parameters "
-                     "specify UBI VID header position and data starting "
-                     "position to be used by UBI.\n"
-                     "Example: mtd=content,1984,2048 mtd=4 - attach MTD device"
-                     "with name content using VID header offset 1984 and data "
-                     "start 2048, and MTD device number 4 using default "
-                     "offsets");
+                     "MTD devices may be specified by their number or name.\n"
+                     "Optional \"vid_hdr_offs\" parameter specifies UBI VID "
+                     "header position and data starting position to be used "
+                     "by UBI.\n"
+                     "Example: mtd=content,1984 mtd=4 - attach MTD device"
+                     "with name \"content\" using VID header offset 1984, and "
+                     "MTD device number 4 with default VID header offset.");
 
 MODULE_VERSION(__stringify(UBI_VERSION));
 MODULE_DESCRIPTION("UBI - Unsorted Block Images");
index fe4da1e96c52a67b1b79676ff281e1e4f6162b8b..5ec13dc4705b92a24ab47abb56c9bf4198d4feb7 100644 (file)
  *
  * Major and minor numbers are assigned dynamically to both UBI and volume
  * character devices.
+ *
+ * Well, there is the third kind of character devices - the UBI control
+ * character device, which allows to manipulate by UBI devices - create and
+ * delete them. In other words, it is used for attaching and detaching MTD
+ * devices.
  */
 
 #include <linux/module.h>
 #include <asm/div64.h>
 #include "ubi.h"
 
-/*
- * Maximum sequence numbers of UBI and volume character device IOCTLs (direct
- * logical eraseblock erase is a debug-only feature).
- */
-#define UBI_CDEV_IOC_MAX_SEQ 2
-#ifndef CONFIG_MTD_UBI_DEBUG_USERSPACE_IO
-#define VOL_CDEV_IOC_MAX_SEQ 1
-#else
-#define VOL_CDEV_IOC_MAX_SEQ 2
-#endif
-
-/**
- * major_to_device - get UBI device object by character device major number.
- * @major: major number
- *
- * This function returns a pointer to the UBI device object.
- */
-static struct ubi_device *major_to_device(int major)
-{
-       int i;
-
-       for (i = 0; i < ubi_devices_cnt; i++)
-               if (ubi_devices[i] && ubi_devices[i]->major == major)
-                       return ubi_devices[i];
-       BUG();
-       return NULL;
-}
-
 /**
  * get_exclusive - get exclusive access to an UBI volume.
  * @desc: volume descriptor
@@ -124,9 +101,11 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
 static int vol_cdev_open(struct inode *inode, struct file *file)
 {
        struct ubi_volume_desc *desc;
-       const struct ubi_device *ubi = major_to_device(imajor(inode));
-       int vol_id = iminor(inode) - 1;
-       int mode;
+       int vol_id = iminor(inode) - 1, mode, ubi_num;
+
+       ubi_num = ubi_major2num(imajor(inode));
+       if (ubi_num < 0)
+               return ubi_num;
 
        if (file->f_mode & FMODE_WRITE)
                mode = UBI_READWRITE;
@@ -135,7 +114,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
 
        dbg_msg("open volume %d, mode %d", vol_id, mode);
 
-       desc = ubi_open_volume(ubi->ubi_num, vol_id, mode);
+       desc = ubi_open_volume(ubi_num, vol_id, mode);
        if (IS_ERR(desc))
                return PTR_ERR(desc);
 
@@ -249,7 +228,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
                if (off + len >= vol->usable_leb_size)
                        len = vol->usable_leb_size - off;
 
-               err = ubi_eba_read_leb(ubi, vol_id, lnum, tbuf, off, len, 0);
+               err = ubi_eba_read_leb(ubi, vol, lnum, tbuf, off, len, 0);
                if (err)
                        break;
 
@@ -289,7 +268,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
        struct ubi_volume_desc *desc = file->private_data;
        struct ubi_volume *vol = desc->vol;
        struct ubi_device *ubi = vol->ubi;
-       int lnum, off, len, tbuf_size, vol_id = vol->vol_id, err = 0;
+       int lnum, off, len, tbuf_size, err = 0;
        size_t count_save = count;
        char *tbuf;
        uint64_t tmp;
@@ -339,7 +318,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
                        break;
                }
 
-               err = ubi_eba_write_leb(ubi, vol_id, lnum, tbuf, off, len,
+               err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len,
                                        UBI_UNKNOWN);
                if (err)
                        break;
@@ -377,7 +356,8 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
 
        err = ubi_more_update_data(ubi, vol->vol_id, buf, count);
        if (err < 0) {
-               ubi_err("cannot write %zd bytes of update data", count);
+               ubi_err("cannot write %zd bytes of update data, error %d",
+                       count, err);
                return err;
        }
 
@@ -483,7 +463,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
                }
 
                dbg_msg("erase LEB %d:%d", vol->vol_id, lnum);
-               err = ubi_eba_unmap_leb(ubi, vol->vol_id, lnum);
+               err = ubi_eba_unmap_leb(ubi, vol, lnum);
                if (err)
                        break;
 
@@ -580,9 +560,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
 
-       ubi = major_to_device(imajor(inode));
-       if (IS_ERR(ubi))
-               return PTR_ERR(ubi);
+       ubi = ubi_get_by_major(imajor(inode));
+       if (!ubi)
+               return -ENODEV;
 
        switch (cmd) {
        /* Create volume command */
@@ -591,8 +571,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                struct ubi_mkvol_req req;
 
                dbg_msg("create volume");
-               err = copy_from_user(&req, argp,
-                                      sizeof(struct ubi_mkvol_req));
+               err = copy_from_user(&req, argp, sizeof(struct ubi_mkvol_req));
                if (err) {
                        err = -EFAULT;
                        break;
@@ -604,7 +583,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
 
                req.name[req.name_len] = '\0';
 
+               mutex_lock(&ubi->volumes_mutex);
                err = ubi_create_volume(ubi, &req);
+               mutex_unlock(&ubi->volumes_mutex);
                if (err)
                        break;
 
@@ -633,10 +614,16 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                        break;
                }
 
+               mutex_lock(&ubi->volumes_mutex);
                err = ubi_remove_volume(desc);
-               if (err)
-                       ubi_close_volume(desc);
+               mutex_unlock(&ubi->volumes_mutex);
 
+               /*
+                * The volume is deleted (unless an error occurred), and the
+                * 'struct ubi_volume' object will be freed when
+                * 'ubi_close_volume()' will call 'put_device()'.
+                */
+               ubi_close_volume(desc);
                break;
        }
 
@@ -648,8 +635,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                struct ubi_rsvol_req req;
 
                dbg_msg("re-size volume");
-               err = copy_from_user(&req, argp,
-                                      sizeof(struct ubi_rsvol_req));
+               err = copy_from_user(&req, argp, sizeof(struct ubi_rsvol_req));
                if (err) {
                        err = -EFAULT;
                        break;
@@ -669,7 +655,9 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                pebs = !!do_div(tmp, desc->vol->usable_leb_size);
                pebs += tmp;
 
+               mutex_lock(&ubi->volumes_mutex);
                err = ubi_resize_volume(desc, pebs);
+               mutex_unlock(&ubi->volumes_mutex);
                ubi_close_volume(desc);
                break;
        }
@@ -679,9 +667,93 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
+       ubi_put_device(ubi);
+       return err;
+}
+
+static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
+                          unsigned int cmd, unsigned long arg)
+{
+       int err = 0;
+       void __user *argp = (void __user *)arg;
+
+       if (!capable(CAP_SYS_RESOURCE))
+               return -EPERM;
+
+       switch (cmd) {
+       /* Attach an MTD device command */
+       case UBI_IOCATT:
+       {
+               struct ubi_attach_req req;
+               struct mtd_info *mtd;
+
+               dbg_msg("attach MTD device");
+               err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));
+               if (err) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (req.mtd_num < 0 ||
+                   (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               mtd = get_mtd_device(NULL, req.mtd_num);
+               if (IS_ERR(mtd)) {
+                       err = PTR_ERR(mtd);
+                       break;
+               }
+
+               /*
+                * Note, further request verification is done by
+                * 'ubi_attach_mtd_dev()'.
+                */
+               mutex_lock(&ubi_devices_mutex);
+               err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset);
+               mutex_unlock(&ubi_devices_mutex);
+               if (err < 0)
+                       put_mtd_device(mtd);
+               else
+                       /* @err contains UBI device number */
+                       err = put_user(err, (__user int32_t *)argp);
+
+               break;
+       }
+
+       /* Detach an MTD device command */
+       case UBI_IOCDET:
+       {
+               int ubi_num;
+
+               dbg_msg("dettach MTD device");
+               err = get_user(ubi_num, (__user int32_t *)argp);
+               if (err) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               mutex_lock(&ubi_devices_mutex);
+               err = ubi_detach_mtd_dev(ubi_num, 0);
+               mutex_unlock(&ubi_devices_mutex);
+               break;
+       }
+
+       default:
+               err = -ENOTTY;
+               break;
+       }
+
        return err;
 }
 
+/* UBI control character device operations */
+struct file_operations ubi_ctrl_cdev_operations = {
+       .ioctl = ctrl_cdev_ioctl,
+       .owner = THIS_MODULE,
+};
+
 /* UBI character device operations */
 struct file_operations ubi_cdev_operations = {
        .owner = THIS_MODULE,
index 467722eb618b20a384320e4bee15be409f2f5e77..51c40b17f1ec5c967994666ad0f7f3ce4b689f39 100644 (file)
@@ -39,8 +39,9 @@
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG
 /* Generic debugging message */
-#define dbg_msg(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__)
+#define dbg_msg(fmt, ...)                                    \
+       printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
+              current->pid, __FUNCTION__, ##__VA_ARGS__)
 
 #define ubi_dbg_dump_stack() dump_stack()
 
@@ -76,36 +77,28 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA
 /* Messages from the eraseblock association unit */
-#define dbg_eba(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG eba: %s: " fmt "\n", __FUNCTION__, \
-              ##__VA_ARGS__)
+#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
 #else
 #define dbg_eba(fmt, ...) ({})
 #endif
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL
 /* Messages from the wear-leveling unit */
-#define dbg_wl(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG wl: %s: " fmt "\n", __FUNCTION__, \
-              ##__VA_ARGS__)
+#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
 #else
 #define dbg_wl(fmt, ...) ({})
 #endif
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO
 /* Messages from the input/output unit */
-#define dbg_io(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG io: %s: " fmt "\n", __FUNCTION__, \
-              ##__VA_ARGS__)
+#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
 #else
 #define dbg_io(fmt, ...) ({})
 #endif
 
 #ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD
 /* Initialization and build messages */
-#define dbg_bld(fmt, ...) \
-       printk(KERN_DEBUG "UBI DBG bld: %s: " fmt "\n", __FUNCTION__, \
-              ##__VA_ARGS__)
+#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__)
 #else
 #define dbg_bld(fmt, ...) ({})
 #endif
index 880fa369035296bbd85e5f8027249a78f59d42f3..85297cde4ac5eb2a3c361ce79ffa7663fd2f0e7d 100644 (file)
@@ -31,7 +31,7 @@
  * logical eraseblock it is locked for reading or writing. The per-logical
  * eraseblock locking is implemented by means of the lock tree. The lock tree
  * is an RB-tree which refers all the currently locked logical eraseblocks. The
- * lock tree elements are &struct ltree_entry objects. They are indexed by
+ * lock tree elements are &struct ubi_ltree_entry objects. They are indexed by
  * (@vol_id, @lnum) pairs.
  *
  * EBA also maintains the global sequence counter which is incremented each
 /* Number of physical eraseblocks reserved for atomic LEB change operation */
 #define EBA_RESERVED_PEBS 1
 
-/**
- * struct ltree_entry - an entry in the lock tree.
- * @rb: links RB-tree nodes
- * @vol_id: volume ID of the locked logical eraseblock
- * @lnum: locked logical eraseblock number
- * @users: how many tasks are using this logical eraseblock or wait for it
- * @mutex: read/write mutex to implement read/write access serialization to
- * the (@vol_id, @lnum) logical eraseblock
- *
- * When a logical eraseblock is being locked - corresponding &struct ltree_entry
- * object is inserted to the lock tree (@ubi->ltree).
- */
-struct ltree_entry {
-       struct rb_node rb;
-       int vol_id;
-       int lnum;
-       int users;
-       struct rw_semaphore mutex;
-};
-
-/* Slab cache for lock-tree entries */
-static struct kmem_cache *ltree_slab;
-
 /**
  * next_sqnum - get next sequence number.
  * @ubi: UBI device description object
@@ -112,20 +89,20 @@ static int ubi_get_compat(const struct ubi_device *ubi, int vol_id)
  * @vol_id: volume ID
  * @lnum: logical eraseblock number
  *
- * This function returns a pointer to the corresponding &struct ltree_entry
+ * This function returns a pointer to the corresponding &struct ubi_ltree_entry
  * object if the logical eraseblock is locked and %NULL if it is not.
  * @ubi->ltree_lock has to be locked.
  */
-static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id,
-                                       int lnum)
+static struct ubi_ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id,
+                                           int lnum)
 {
        struct rb_node *p;
 
        p = ubi->ltree.rb_node;
        while (p) {
-               struct ltree_entry *le;
+               struct ubi_ltree_entry *le;
 
-               le = rb_entry(p, struct ltree_entry, rb);
+               le = rb_entry(p, struct ubi_ltree_entry, rb);
 
                if (vol_id < le->vol_id)
                        p = p->rb_left;
@@ -155,12 +132,12 @@ static struct ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id,
  * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation
  * failed.
  */
-static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
-                                          int lnum)
+static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi,
+                                              int vol_id, int lnum)
 {
-       struct ltree_entry *le, *le1, *le_free;
+       struct ubi_ltree_entry *le, *le1, *le_free;
 
-       le = kmem_cache_alloc(ltree_slab, GFP_NOFS);
+       le = kmem_cache_alloc(ubi_ltree_slab, GFP_NOFS);
        if (!le)
                return ERR_PTR(-ENOMEM);
 
@@ -189,7 +166,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
                p = &ubi->ltree.rb_node;
                while (*p) {
                        parent = *p;
-                       le1 = rb_entry(parent, struct ltree_entry, rb);
+                       le1 = rb_entry(parent, struct ubi_ltree_entry, rb);
 
                        if (vol_id < le1->vol_id)
                                p = &(*p)->rb_left;
@@ -211,7 +188,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
        spin_unlock(&ubi->ltree_lock);
 
        if (le_free)
-               kmem_cache_free(ltree_slab, le_free);
+               kmem_cache_free(ubi_ltree_slab, le_free);
 
        return le;
 }
@@ -227,7 +204,7 @@ static struct ltree_entry *ltree_add_entry(struct ubi_device *ubi, int vol_id,
  */
 static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum)
 {
-       struct ltree_entry *le;
+       struct ubi_ltree_entry *le;
 
        le = ltree_add_entry(ubi, vol_id, lnum);
        if (IS_ERR(le))
@@ -245,7 +222,7 @@ static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum)
 static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 {
        int free = 0;
-       struct ltree_entry *le;
+       struct ubi_ltree_entry *le;
 
        spin_lock(&ubi->ltree_lock);
        le = ltree_lookup(ubi, vol_id, lnum);
@@ -259,7 +236,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 
        up_read(&le->mutex);
        if (free)
-               kmem_cache_free(ltree_slab, le);
+               kmem_cache_free(ubi_ltree_slab, le);
 }
 
 /**
@@ -273,7 +250,7 @@ static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum)
  */
 static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
 {
-       struct ltree_entry *le;
+       struct ubi_ltree_entry *le;
 
        le = ltree_add_entry(ubi, vol_id, lnum);
        if (IS_ERR(le))
@@ -282,6 +259,44 @@ static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
        return 0;
 }
 
+/**
+ * leb_write_lock - lock logical eraseblock for writing.
+ * @ubi: UBI device description object
+ * @vol_id: volume ID
+ * @lnum: logical eraseblock number
+ *
+ * This function locks a logical eraseblock for writing if there is no
+ * contention and does nothing if there is contention. Returns %0 in case of
+ * success, %1 in case of contention, and and a negative error code in case of
+ * failure.
+ */
+static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum)
+{
+       int free;
+       struct ubi_ltree_entry *le;
+
+       le = ltree_add_entry(ubi, vol_id, lnum);
+       if (IS_ERR(le))
+               return PTR_ERR(le);
+       if (down_write_trylock(&le->mutex))
+               return 0;
+
+       /* Contention, cancel */
+       spin_lock(&ubi->ltree_lock);
+       le->users -= 1;
+       ubi_assert(le->users >= 0);
+       if (le->users == 0) {
+               rb_erase(&le->rb, &ubi->ltree);
+               free = 1;
+       } else
+               free = 0;
+       spin_unlock(&ubi->ltree_lock);
+       if (free)
+               kmem_cache_free(ubi_ltree_slab, le);
+
+       return 1;
+}
+
 /**
  * leb_write_unlock - unlock logical eraseblock.
  * @ubi: UBI device description object
@@ -291,7 +306,7 @@ static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum)
 static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 {
        int free;
-       struct ltree_entry *le;
+       struct ubi_ltree_entry *le;
 
        spin_lock(&ubi->ltree_lock);
        le = ltree_lookup(ubi, vol_id, lnum);
@@ -306,23 +321,26 @@ static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum)
 
        up_write(&le->mutex);
        if (free)
-               kmem_cache_free(ltree_slab, le);
+               kmem_cache_free(ubi_ltree_slab, le);
 }
 
 /**
  * ubi_eba_unmap_leb - un-map logical eraseblock.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  *
  * This function un-maps logical eraseblock @lnum and schedules corresponding
  * physical eraseblock for erasure. Returns zero in case of success and a
  * negative error code in case of failure.
  */
-int ubi_eba_unmap_leb(struct ubi_device *ubi, int vol_id, int lnum)
+int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
+                     int lnum)
 {
-       int idx = vol_id2idx(ubi, vol_id), err, pnum;
-       struct ubi_volume *vol = ubi->volumes[idx];
+       int err, pnum, vol_id = vol->vol_id;
+
+       ubi_assert(ubi->ref_count > 0);
+       ubi_assert(vol->ref_count > 0);
 
        if (ubi->ro_mode)
                return -EROFS;
@@ -349,7 +367,7 @@ out_unlock:
 /**
  * ubi_eba_read_leb - read data.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: buffer to store the read data
  * @offset: offset from where to read
@@ -365,14 +383,16 @@ out_unlock:
  * returned for any volume type if an ECC error was detected by the MTD device
  * driver. Other negative error cored may be returned in case of other errors.
  */
-int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
-                    int offset, int len, int check)
+int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
+                    void *buf, int offset, int len, int check)
 {
-       int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id);
+       int err, pnum, scrub = 0, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
-       struct ubi_volume *vol = ubi->volumes[idx];
        uint32_t uninitialized_var(crc);
 
+       ubi_assert(ubi->ref_count > 0);
+       ubi_assert(vol->ref_count > 0);
+
        err = leb_read_lock(ubi, vol_id, lnum);
        if (err)
                return err;
@@ -578,7 +598,7 @@ write_error:
 /**
  * ubi_eba_write_leb - write data to dynamic volume.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: the data to write
  * @offset: offset within the logical eraseblock where to write
@@ -586,17 +606,19 @@ write_error:
  * @dtype: data type
  *
  * This function writes data to logical eraseblock @lnum of a dynamic volume
- * @vol_id. Returns zero in case of success and a negative error code in case
+ * @vol. Returns zero in case of success and a negative error code in case
  * of failure. In case of error, it is possible that something was still
  * written to the flash media, but may be some garbage.
  */
-int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
+int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
                      const void *buf, int offset, int len, int dtype)
 {
-       int idx = vol_id2idx(ubi, vol_id), err, pnum, tries = 0;
-       struct ubi_volume *vol = ubi->volumes[idx];
+       int err, pnum, tries = 0, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
 
+       ubi_assert(ubi->ref_count > 0);
+       ubi_assert(vol->ref_count > 0);
+
        if (ubi->ro_mode)
                return -EROFS;
 
@@ -613,7 +635,8 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
                if (err) {
                        ubi_warn("failed to write data to PEB %d", pnum);
                        if (err == -EIO && ubi->bad_allowed)
-                               err = recover_peb(ubi, pnum, vol_id, lnum, buf, offset, len);
+                               err = recover_peb(ubi, pnum, vol_id, lnum, buf,
+                                                 offset, len);
                        if (err)
                                ubi_ro_mode(ubi);
                }
@@ -656,11 +679,14 @@ retry:
                goto write_error;
        }
 
-       err = ubi_io_write_data(ubi, buf, pnum, offset, len);
-       if (err) {
-               ubi_warn("failed to write %d bytes at offset %d of LEB %d:%d, "
-                        "PEB %d", len, offset, vol_id, lnum, pnum);
-               goto write_error;
+       if (len) {
+               err = ubi_io_write_data(ubi, buf, pnum, offset, len);
+               if (err) {
+                       ubi_warn("failed to write %d bytes at offset %d of "
+                                "LEB %d:%d, PEB %d", len, offset, vol_id,
+                                lnum, pnum);
+                       goto write_error;
+               }
        }
 
        vol->eba_tbl[lnum] = pnum;
@@ -698,7 +724,7 @@ write_error:
 /**
  * ubi_eba_write_leb_st - write data to static volume.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: data to write
  * @len: how many bytes to write
@@ -706,7 +732,7 @@ write_error:
  * @used_ebs: how many logical eraseblocks will this volume contain
  *
  * This function writes data to logical eraseblock @lnum of static volume
- * @vol_id. The @used_ebs argument should contain total number of logical
+ * @vol. The @used_ebs argument should contain total number of logical
  * eraseblock in this static volume.
  *
  * When writing to the last logical eraseblock, the @len argument doesn't have
@@ -718,15 +744,17 @@ write_error:
  * volumes. This function returns zero in case of success and a negative error
  * code in case of failure.
  */
-int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
-                        const void *buf, int len, int dtype, int used_ebs)
+int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
+                        int lnum, const void *buf, int len, int dtype,
+                        int used_ebs)
 {
-       int err, pnum, tries = 0, data_size = len;
-       int idx = vol_id2idx(ubi, vol_id);
-       struct ubi_volume *vol = ubi->volumes[idx];
+       int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
        uint32_t crc;
 
+       ubi_assert(ubi->ref_count > 0);
+       ubi_assert(vol->ref_count > 0);
+
        if (ubi->ro_mode)
                return -EROFS;
 
@@ -819,7 +847,7 @@ write_error:
 /*
  * ubi_eba_atomic_leb_change - change logical eraseblock atomically.
  * @ubi: UBI device description object
- * @vol_id: volume ID
+ * @vol: volume description object
  * @lnum: logical eraseblock number
  * @buf: data to write
  * @len: how many bytes to write
@@ -834,14 +862,16 @@ write_error:
  * UBI reserves one LEB for the "atomic LEB change" operation, so only one
  * LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
  */
-int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
-                             const void *buf, int len, int dtype)
+int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
+                             int lnum, const void *buf, int len, int dtype)
 {
-       int err, pnum, tries = 0, idx = vol_id2idx(ubi, vol_id);
-       struct ubi_volume *vol = ubi->volumes[idx];
+       int err, pnum, tries = 0, vol_id = vol->vol_id;
        struct ubi_vid_hdr *vid_hdr;
        uint32_t crc;
 
+       ubi_assert(ubi->ref_count > 0);
+       ubi_assert(vol->ref_count > 0);
+
        if (ubi->ro_mode)
                return -EROFS;
 
@@ -927,20 +957,6 @@ write_error:
        goto retry;
 }
 
-/**
- * ltree_entry_ctor - lock tree entries slab cache constructor.
- * @obj: the lock-tree entry to construct
- * @cache: the lock tree entry slab cache
- * @flags: constructor flags
- */
-static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
-{
-       struct ltree_entry *le = obj;
-
-       le->users = 0;
-       init_rwsem(&le->mutex);
-}
-
 /**
  * ubi_eba_copy_leb - copy logical eraseblock.
  * @ubi: UBI device description object
@@ -950,14 +966,16 @@ static void ltree_entry_ctor(struct kmem_cache *cache, void *obj)
  *
  * This function copies logical eraseblock from physical eraseblock @from to
  * physical eraseblock @to. The @vid_hdr buffer may be changed by this
- * function. Returns zero in case of success, %UBI_IO_BITFLIPS if the operation
- * was canceled because bit-flips were detected at the target PEB, and a
- * negative error code in case of failure.
+ * function. Returns:
+ *   o %0  in case of success;
+ *   o %1 if the operation was canceled and should be tried later (e.g.,
+ *     because a bit-flip was detected at the target PEB);
+ *   o %2 if the volume is being deleted and this LEB should not be moved.
  */
 int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                     struct ubi_vid_hdr *vid_hdr)
 {
-       int err, vol_id, lnum, data_size, aldata_size, pnum, idx;
+       int err, vol_id, lnum, data_size, aldata_size, idx;
        struct ubi_volume *vol;
        uint32_t crc;
 
@@ -973,51 +991,67 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                data_size = aldata_size =
                            ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
 
-       /*
-        * We do not want anybody to write to this logical eraseblock while we
-        * are moving it, so we lock it.
-        */
-       err = leb_write_lock(ubi, vol_id, lnum);
-       if (err)
-               return err;
-
-       mutex_lock(&ubi->buf_mutex);
-
-       /*
-        * But the logical eraseblock might have been put by this time.
-        * Cancel if it is true.
-        */
        idx = vol_id2idx(ubi, vol_id);
-
+       spin_lock(&ubi->volumes_lock);
        /*
-        * We may race with volume deletion/re-size, so we have to hold
-        * @ubi->volumes_lock.
+        * Note, we may race with volume deletion, which means that the volume
+        * this logical eraseblock belongs to might be being deleted. Since the
+        * volume deletion unmaps all the volume's logical eraseblocks, it will
+        * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish.
         */
-       spin_lock(&ubi->volumes_lock);
        vol = ubi->volumes[idx];
        if (!vol) {
-               dbg_eba("volume %d was removed meanwhile", vol_id);
+               /* No need to do further work, cancel */
+               dbg_eba("volume %d is being removed, cancel", vol_id);
                spin_unlock(&ubi->volumes_lock);
-               goto out_unlock;
+               return 2;
+       }
+       spin_unlock(&ubi->volumes_lock);
+
+       /*
+        * We do not want anybody to write to this logical eraseblock while we
+        * are moving it, so lock it.
+        *
+        * Note, we are using non-waiting locking here, because we cannot sleep
+        * on the LEB, since it may cause deadlocks. Indeed, imagine a task is
+        * unmapping the LEB which is mapped to the PEB we are going to move
+        * (@from). This task locks the LEB and goes sleep in the
+        * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are
+        * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the
+        * LEB is already locked, we just do not move it and return %1.
+        */
+       err = leb_write_trylock(ubi, vol_id, lnum);
+       if (err) {
+               dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum);
+               return err;
        }
 
-       pnum = vol->eba_tbl[lnum];
-       if (pnum != from) {
+       /*
+        * The LEB might have been put meanwhile, and the task which put it is
+        * probably waiting on @ubi->move_mutex. No need to continue the work,
+        * cancel it.
+        */
+       if (vol->eba_tbl[lnum] != from) {
                dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to "
-                       "PEB %d, cancel", vol_id, lnum, from, pnum);
-               spin_unlock(&ubi->volumes_lock);
-               goto out_unlock;
+                       "PEB %d, cancel", vol_id, lnum, from,
+                       vol->eba_tbl[lnum]);
+               err = 1;
+               goto out_unlock_leb;
        }
-       spin_unlock(&ubi->volumes_lock);
-
-       /* OK, now the LEB is locked and we can safely start moving it */
 
+       /*
+        * OK, now the LEB is locked and we can safely start moving iy. Since
+        * this function utilizes thie @ubi->peb1_buf buffer which is shared
+        * with some other functions, so lock the buffer by taking the
+        * @ubi->buf_mutex.
+        */
+       mutex_lock(&ubi->buf_mutex);
        dbg_eba("read %d bytes of data", aldata_size);
        err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size);
        if (err && err != UBI_IO_BITFLIPS) {
                ubi_warn("error %d while reading data from PEB %d",
                         err, from);
-               goto out_unlock;
+               goto out_unlock_buf;
        }
 
        /*
@@ -1053,7 +1087,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
 
        err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
        if (err)
-               goto out_unlock;
+               goto out_unlock_buf;
 
        cond_resched();
 
@@ -1062,13 +1096,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
        if (err) {
                if (err != UBI_IO_BITFLIPS)
                        ubi_warn("cannot read VID header back from PEB %d", to);
-               goto out_unlock;
+               else
+                       err = 1;
+               goto out_unlock_buf;
        }
 
        if (data_size > 0) {
                err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size);
                if (err)
-                       goto out_unlock;
+                       goto out_unlock_buf;
 
                cond_resched();
 
@@ -1082,7 +1118,9 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                        if (err != UBI_IO_BITFLIPS)
                                ubi_warn("cannot read data back from PEB %d",
                                         to);
-                       goto out_unlock;
+                       else
+                               err = 1;
+                       goto out_unlock_buf;
                }
 
                cond_resched();
@@ -1090,15 +1128,16 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
                if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) {
                        ubi_warn("read data back from PEB %d - it is different",
                                 to);
-                       goto out_unlock;
+                       goto out_unlock_buf;
                }
        }
 
        ubi_assert(vol->eba_tbl[lnum] == from);
        vol->eba_tbl[lnum] = to;
 
-out_unlock:
+out_unlock_buf:
        mutex_unlock(&ubi->buf_mutex);
+out_unlock_leb:
        leb_write_unlock(ubi, vol_id, lnum);
        return err;
 }
@@ -1125,14 +1164,6 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
        mutex_init(&ubi->alc_mutex);
        ubi->ltree = RB_ROOT;
 
-       if (ubi_devices_cnt == 0) {
-               ltree_slab = kmem_cache_create("ubi_ltree_slab",
-                                              sizeof(struct ltree_entry), 0,
-                                              0, &ltree_entry_ctor);
-               if (!ltree_slab)
-                       return -ENOMEM;
-       }
-
        ubi->global_sqnum = si->max_sqnum + 1;
        num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
 
@@ -1168,6 +1199,15 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
                }
        }
 
+       if (ubi->avail_pebs < EBA_RESERVED_PEBS) {