]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
authorDavid Woodhouse <dwmw2@infradead.org>
Sat, 21 Oct 2006 15:46:04 +0000 (16:46 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Sat, 21 Oct 2006 15:46:04 +0000 (16:46 +0100)
18 files changed:
drivers/mtd/Kconfig
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/cstm_mips_ixx.c
drivers/mtd/maps/esb2rom.c [new file with mode: 0644]
drivers/mtd/mtdchar.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/at91_nand.c [new file with mode: 0644]
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nandsim.c
fs/jffs2/nodelist.h
fs/jffs2/symlink.c
fs/jffs2/xattr.c

index a304b34c2632f32c1713a9d337c02a4e27453bdd..291660abe3a6802bda098f847974bae66873e26b 100644 (file)
@@ -265,8 +265,7 @@ config RFD_FTL
 
 config SSFDC
        tristate "NAND SSFDC (SmartMedia) read only translation layer"
-       depends on MTD
-       default n
+       depends on MTD && BLOCK
        help
          This enables read only access to SmartMedia formatted NAND
          flash. You can mount it with FAT file system.
index 7ea49a0d5ec32490633e27a3219e9b2335c3024b..e24973636e61bbf0123aeb8a82ad8550e63c3aa6 100644 (file)
@@ -2224,6 +2224,8 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
                case FL_CFI_QUERY:
                case FL_JEDEC_QUERY:
                        if (chip->oldstate == FL_READY) {
+                               /* place the chip in a known state before suspend */
+                               map_write(map, CMD(0xFF), cfi->chips[i].start);
                                chip->oldstate = chip->state;
                                chip->state = FL_PM_SUSPENDED;
                                /* No need to wake_up() on this state change -
index 702ae4cd8691c510e33ecc3892bccd0c16653f61..ca0882b5819f4dbcd6fd929770c088e3363f62c0 100644 (file)
@@ -48,6 +48,7 @@
 #define MANUFACTURER_ATMEL     0x001F
 #define MANUFACTURER_SST       0x00BF
 #define SST49LF004B            0x0060
+#define SST49LF040B            0x0050
 #define SST49LF008A            0x005a
 #define AT49BV6416             0x00d6
 
@@ -233,6 +234,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
 };
 static struct cfi_fixup jedec_fixup_table[] = {
        { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
+       { MANUFACTURER_SST, SST49LF040B, fixup_use_fwh_lock, NULL, },
        { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
@@ -519,10 +521,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
                        goto sleep;
 
-               if (!(mode == FL_READY || mode == FL_POINT
+               if (!(   mode == FL_READY
+                     || mode == FL_POINT
                      || !cfip
                      || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
-                     || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
+                     || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1)
+                   )))
                        goto sleep;
 
                /* We could check to see if we're trying to access the sector
index 1154dac715aa62b6f89eea9337809ad14b38d7a5..58e561e87699026de75ff94b9960128adb1490ac 100644 (file)
 #define SST39SF010A    0x00B5
 #define SST39SF020A    0x00B6
 #define SST49LF004B    0x0060
+#define SST49LF040B    0x0050
 #define SST49LF008A    0x005a
 #define SST49LF030A    0x001C
 #define SST49LF040A    0x0051
@@ -1400,6 +1401,20 @@ static const struct amd_flash_info jedec_table[] = {
                        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        = {
+                       ERASEINFO(0x01000,128),
+               }
+       }, {
+
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF004B,
                .name           = "SST 49LF004B",
@@ -1874,7 +1889,7 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 
 
 /*
- * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing
+ * There is a BIG problem properly ID'ing the JEDEC device and guaranteeing
  * the mapped address, unlock addresses, and proper chip ID.  This function
  * attempts to minimize errors.  It is doubtfull that this probe will ever
  * be perfect - consequently there should be some module parameters that
index 24747bdc3e19fd85ab2c6fe03a8352e78a6ec966..7514a9bee0154716aac0c1b27b7af33e3e5b6761 100644 (file)
@@ -184,6 +184,15 @@ config MTD_ICHXROM
 
          BE VERY CAREFUL.
 
+config MTD_ESB2ROM
+        tristate "BIOS flash chip on Intel ESB Controller Hub 2"
+        depends on X86 && MTD_JEDECPROBE
+        help
+          Support for treating the BIOS flash chip on ESB2 motherboards
+          as an MTD device - with this you can reprogram your BIOS.
+
+          BE VERY CAREFUL.
+
 config MTD_SCB2_FLASH
        tristate "BIOS flash chip on Intel SCB2 boards"
        depends on X86 && MTD_JEDECPROBE
index 191c1928bbeca6715b3e889e28f64e30012668f5..9061432c5e1a57eb603dcbf0969b48cb8378781d 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_MTD_DC21285)     += dc21285.o
 obj-$(CONFIG_MTD_DILNETPC)     += dilnetpc.o
 obj-$(CONFIG_MTD_L440GX)       += l440gx.o
 obj-$(CONFIG_MTD_AMD76XROM)    += amd76xrom.o
+obj-$(CONFIG_MTD_ESB2ROM)      += esb2rom.o
 obj-$(CONFIG_MTD_ICHXROM)      += ichxrom.o
 obj-$(CONFIG_MTD_TSUNAMI)      += tsunami_flash.o
 obj-$(CONFIG_MTD_LUBBOCK)      += lubbock-flash.o
index 797caffb20b138b74eebe602878d0c617cb2253e..78b671172bb225d6978cacd5f164c13628a39066 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <asm/io.h>
@@ -44,6 +45,23 @@ struct amd76xrom_map_info {
        char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
 };
 
+/* The 2 bits controlling the window size are often set to allow reading
+ * the BIOS, but too small to allow writing, since the lock registers are
+ * 4MiB lower in the address space than the data.
+ *
+ * This is intended to prevent flashing the bios, perhaps accidentally.
+ *
+ * This parameter allows the normal driver to over-ride the BIOS settings.
+ *
+ * The bits are 6 and 7.  If both bits are set, it is a 5MiB window.
+ * If only the 7 Bit is set, it is a 4MiB window.  Otherwise, a
+ * 64KiB window.
+ *
+ */
+static uint win_size_bits;
+module_param(win_size_bits, uint, 0);
+MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x43 byte, normally set by BIOS.");
+
 static struct amd76xrom_window amd76xrom_window = {
        .maps = LIST_HEAD_INIT(amd76xrom_window.maps),
 };
@@ -95,6 +113,16 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
        /* Remember the pci dev I find the window in - already have a ref */
        window->pdev = pdev;
 
+       /* Enable the selected rom window.  This is often incorrectly
+        * set up by the BIOS, and the 4MiB offset for the lock registers
+        * requires the full 5MiB of window space.
+        *
+        * This 'write, then read' approach leaves the bits for
+        * other uses of the hardware info.
+        */
+       pci_read_config_byte(pdev, 0x43, &byte);
+       pci_write_config_byte(pdev, 0x43, byte | win_size_bits );
+
        /* Assume the rom window is properly setup, and find it's size */
        pci_read_config_byte(pdev, 0x43, &byte);
        if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) {
@@ -129,12 +157,6 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
                        (unsigned long long)window->rsrc.end);
        }
 
-#if 0
-
-       /* Enable the selected rom window */
-       pci_read_config_byte(pdev, 0x43, &byte);
-       pci_write_config_byte(pdev, 0x43, byte | rwindow->segen_bits);
-#endif
 
        /* Enable writes through the rom window */
        pci_read_config_byte(pdev, 0x40, &byte);
index df2c38ef105ad476769c0d30004f6a3ea61e9549..d57eba24c20181acd45ffca854a21e9b5d05144d 100644 (file)
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-#define CC_GCR             0xB4013818
-#define CC_GPBCR           0xB401380A
-#define CC_GPBDR           0xB4013808
-#define CC_M68K_DEVICE     1
-#define CC_M68K_FUNCTION   6
-#define CC_CONFADDR        0xB8004000
-#define CC_CONFDATA        0xB8004004
-#define CC_FC_FCR          0xB8002004
-#define CC_FC_DCR          0xB8002008
-#define CC_GPACR           0xB4013802
-#define CC_GPAICR          0xB4013804
-#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
-{
-       static DEFINE_SPINLOCK(vpp_lock);
-       static int vpp_count = 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&vpp_lock, flags);
-
-       if (vpp) {
-               if (!vpp_count++) {
-                       __u16   data;
-                       __u8    data1;
-                       static u8 first = 1;
-
-                       // Set GPIO port B pin3 to high
-                       data = *(__u16 *)(CC_GPBCR);
-                       data = (data & 0xff0f) | 0x0040;
-                       *(__u16 *)CC_GPBCR = data;
-                       *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08;
-                       if (first) {
-                               first = 0;
-                               /* need to have this delay for first
-                                  enabling vpp after powerup */
-                               udelay(40);
-                       }
-               }
-       } else {
-               if (!--vpp_count) {
-                       __u16   data;
-
-                       // Set GPIO port B pin3 to high
-                       data = *(__u16 *)(CC_GPBCR);
-                       data = (data & 0xff3f) | 0x0040;
-                       *(__u16 *)CC_GPBCR = data;
-                       *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7;
-               }
-       }
-       spin_unlock_irqrestore(&vpp_lock, flags);
-}
-#endif
-
 /* board and partition description */
 
 #define MAX_PHYSMAP_PARTITIONS    8
@@ -107,29 +51,6 @@ struct cstm_mips_ixx_info {
        int num_partitions;
 };
 
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-#define PHYSMAP_NUMBER  1  // number of board desc structs needed, one per contiguous flash type
-const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
-{
-    {   // 28F128J3A in 2x16 configuration
-        "big flash",     // name
-       0x08000000,      // window_addr
-       0x02000000,      // window_size
-        4,               // bankwidth
-       1,               // num_partitions
-    }
-
-};
-static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
-{   // 28F128J3A in 2x16 configuration
-       {
-               .name = "main partition ",
-               .size = 0x02000000, // 128 x 2 x 128k byte sectors
-               .offset = 0,
-       },
-},
-};
-#else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
 #define PHYSMAP_NUMBER  1  // number of board desc structs needed, one per contiguous flash type
 const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
 {
@@ -151,7 +72,6 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP
        },
 },
 };
-#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
 
 struct map_info cstm_mips_ixx_map[PHYSMAP_NUMBER];
 
@@ -184,17 +104,10 @@ int __init init_cstm_mips_ixx(void)
                cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
                cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
                cstm_mips_ixx_map[i].bankwidth = cstm_mips_ixx_board_desc[i].bankwidth;
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-                cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp;
-#endif
                simple_map_init(&cstm_mips_ixx_map[i]);
                //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt));
        }
 
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-        setup_ITE_IVR_flash();
-#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-
        for (i=0;i<PHYSMAP_NUMBER;i++) {
                 parts = &cstm_mips_ixx_partitions[i][0];
                jedec = 0;
@@ -241,38 +154,6 @@ static void __exit cleanup_cstm_mips_ixx(void)
                }
        }
 }
-#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-void PCISetULongByOffset(__u32 DevNumber, __u32 FuncNumber, __u32 Offset, __u32 data)
-{
-       __u32   offset;
-
-       offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ;
-
-       *(__u32 *)CC_CONFADDR = offset;
-       *(__u32 *)CC_CONFDATA = data;
-}
-void setup_ITE_IVR_flash()
-{
-               __u32   size, base;
-
-               size = 0x0e000000;              // 32MiB
-               base = (0x08000000) >> 8 >>1; // Bug: we must shift one more bit
-
-               /* need to set ITE flash to 32 bits instead of default 8 */
-#ifdef CONFIG_MIPS_IVR
-               *(__u32 *)CC_FC_FCR = 0x55;
-               *(__u32 *)CC_GPACR = 0xfffc;
-#else
-               *(__u32 *)CC_FC_FCR = 0x77;
-#endif
-               /* turn bursting off */
-               *(__u32 *)CC_FC_DCR = 0x0;
-
-               /* setup for one chip 4 byte PCI access */
-               PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x60, size | base);
-               PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x64, 0x02);
-}
-#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
 
 module_init(init_cstm_mips_ixx);
 module_exit(cleanup_cstm_mips_ixx);
@@ -280,4 +161,4 @@ module_exit(cleanup_cstm_mips_ixx);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-MODULE_DESCRIPTION("MTD map driver for ITE 8172G and Globespan IVR boards");
+MODULE_DESCRIPTION("MTD map driver for MIPS boards");
diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c
new file mode 100644 (file)
index 0000000..a9d808a
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * esb2rom.c
+ *
+ * Normal mappings of flash chips in physical memory
+ * through the Intel ESB2 Southbridge.
+ *
+ * This was derived from ichxrom.c in May 2006 by
+ *     Lew Glendenning <lglendenning@lnxi.com>
+ *
+ * Eric Biederman, of course, was a major help in this effort.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/flashchip.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/list.h>
+
+#define MOD_NAME KBUILD_BASENAME
+
+#define ADDRESS_NAME_LEN 18
+
+#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
+
+#define BIOS_CNTL      0xDC
+#define BIOS_LOCK_ENABLE       0x02
+#define BIOS_WRITE_ENABLE      0x01
+
+/* This became a 16-bit register, and EN2 has disappeared */
+#define FWH_DEC_EN1    0xD8
+#define FWH_F8_EN      0x8000
+#define FWH_F0_EN      0x4000
+#define FWH_E8_EN      0x2000
+#define FWH_E0_EN      0x1000
+#define FWH_D8_EN      0x0800
+#define FWH_D0_EN      0x0400
+#define FWH_C8_EN      0x0200
+#define FWH_C0_EN      0x0100
+#define FWH_LEGACY_F_EN        0x0080
+#define FWH_LEGACY_E_EN        0x0040
+/* reserved  0x0020 and 0x0010 */
+#define FWH_70_EN      0x0008
+#define FWH_60_EN      0x0004
+#define FWH_50_EN      0x0002
+#define FWH_40_EN      0x0001
+
+/* these are 32-bit values */
+#define FWH_SEL1       0xD0
+#define FWH_SEL2       0xD4
+
+#define FWH_8MiB       (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+                        FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
+                        FWH_70_EN | FWH_60_EN | FWH_50_EN | FWH_40_EN)
+
+#define FWH_7MiB       (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+                        FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
+                        FWH_70_EN | FWH_60_EN | FWH_50_EN)
+
+#define FWH_6MiB       (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+                        FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
+                        FWH_70_EN | FWH_60_EN)
+
+#define FWH_5MiB       (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+                        FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
+                        FWH_70_EN)
+
+#define FWH_4MiB       (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+                        FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN)
+
+#define FWH_3_5MiB     (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+                        FWH_D8_EN | FWH_D0_EN | FWH_C8_EN)
+
+#define FWH_3MiB       (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+                        FWH_D8_EN | FWH_D0_EN)
+
+#define FWH_2_5MiB     (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
+                        FWH_D8_EN)
+
+#define FWH_2MiB       (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN)
+
+#define FWH_1_5MiB     (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN)
+
+#define FWH_1MiB       (FWH_F8_EN | FWH_F0_EN)
+
+#define FWH_0_5MiB     (FWH_F8_EN)
+
+
+struct esb2rom_window {
+       void __iomem* virt;
+       unsigned long phys;
+       unsigned long size;
+       struct list_head maps;
+       struct resource rsrc;
+       struct pci_dev *pdev;
+};
+
+struct esb2rom_map_info {
+       struct list_head list;
+       struct map_info map;
+       struct mtd_info *mtd;
+       struct resource rsrc;
+       char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
+};
+
+static struct esb2rom_window esb2rom_window = {
+       .maps = LIST_HEAD_INIT(esb2rom_window.maps),
+};
+
+static void esb2rom_cleanup(struct esb2rom_window *window)
+{
+       struct esb2rom_map_info *map, *scratch;
+       u8 byte;
+
+       /* Disable writes through the rom window */
+       pci_read_config_byte(window->pdev, BIOS_CNTL, &byte);
+       pci_write_config_byte(window->pdev, BIOS_CNTL,
+               byte & ~BIOS_WRITE_ENABLE);
+
+       /* Free all of the mtd devices */
+       list_for_each_entry_safe(map, scratch, &window->maps, list) {
+               if (map->rsrc.parent)
+                       release_resource(&map->rsrc);
+               del_mtd_device(map->mtd);
+               map_destroy(map->mtd);
+               list_del(&map->list);
+               kfree(map);
+       }
+       if (window->rsrc.parent)
+               release_resource(&window->rsrc);
+       if (window->virt) {
+               iounmap(window->virt);
+               window->virt = NULL;
+               window->phys = 0;
+               window->size = 0;
+       }
+       pci_dev_put(window->pdev);
+}
+
+static int __devinit esb2rom_init_one(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
+       struct esb2rom_window *window = &esb2rom_window;
+       struct esb2rom_map_info *map = NULL;
+       unsigned long map_top;
+       u8 byte;
+       u16 word;
+
+       /* For now I just handle the ecb2 and I assume there
+        * are not a lot of resources up at the top of the address
+        * space.  It is possible to handle other devices in the
+        * top 16MiB but it is very painful.  Also since
+        * you can only really attach a FWH to an ICHX there
+        * a number of simplifications you can make.
+        *
+        * Also you can page firmware hubs if an 8MiB window isn't enough
+        * but don't currently handle that case either.
+        */
+       window->pdev = pci_dev_get(pdev);
+
+       /* RLG:  experiment 2.  Force the window registers to the widest values */
+
+/*
+       pci_read_config_word(pdev, FWH_DEC_EN1, &word);
+       printk(KERN_DEBUG "Original FWH_DEC_EN1 : %x\n", word);
+       pci_write_config_byte(pdev, FWH_DEC_EN1, 0xff);
+       pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
+       printk(KERN_DEBUG "New FWH_DEC_EN1 : %x\n", byte);
+
+       pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
+       printk(KERN_DEBUG "Original FWH_DEC_EN2 : %x\n", byte);
+       pci_write_config_byte(pdev, FWH_DEC_EN2, 0x0f);
+       pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
+       printk(KERN_DEBUG "New FWH_DEC_EN2 : %x\n", byte);
+*/
+
+       /* Find a region continuous to the end of the ROM window  */
+       window->phys = 0;
+       pci_read_config_word(pdev, FWH_DEC_EN1, &word);
+       printk(KERN_DEBUG "pci_read_config_byte : %x\n", word);
+
+       if ((word & FWH_8MiB) == FWH_8MiB)
+               window->phys = 0xff400000;
+       else if ((word & FWH_7MiB) == FWH_7MiB)
+               window->phys = 0xff500000;
+       else if ((word & FWH_6MiB) == FWH_6MiB)
+               window->phys = 0xff600000;
+       else if ((word & FWH_5MiB) == FWH_5MiB)
+               window->phys = 0xFF700000;
+       else if ((word & FWH_4MiB) == FWH_4MiB)
+               window->phys = 0xffc00000;
+       else if ((word & FWH_3_5MiB) == FWH_3_5MiB)
+               window->phys = 0xffc80000;
+       else if ((word & FWH_3MiB) == FWH_3MiB)
+               window->phys = 0xffd00000;
+       else if ((word & FWH_2_5MiB) == FWH_2_5MiB)
+               window->phys = 0xffd80000;
+       else if ((word & FWH_2MiB) == FWH_2MiB)
+               window->phys = 0xffe00000;
+       else if ((word & FWH_1_5MiB) == FWH_1_5MiB)
+               window->phys = 0xffe80000;
+       else if ((word & FWH_1MiB) == FWH_1MiB)
+               window->phys = 0xfff00000;
+       else if ((word & FWH_0_5MiB) == FWH_0_5MiB)
+               window->phys = 0xfff80000;
+
+       /* reserved  0x0020 and 0x0010 */
+       window->phys -= 0x400000UL;
+       window->size = (0xffffffffUL - window->phys) + 1UL;
+
+       /* Enable writes through the rom window */
+       pci_read_config_byte(pdev, BIOS_CNTL, &byte);
+       if (!(byte & BIOS_WRITE_ENABLE)  && (byte & (BIOS_LOCK_ENABLE))) {
+               /* The BIOS will generate an error if I enable
+                * this device, so don't even try.
+                */
+               printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
+               goto out;
+       }
+       pci_write_config_byte(pdev, BIOS_CNTL, byte | BIOS_WRITE_ENABLE);
+
+       /*
+        * Try to reserve the window mem region.  If this fails then
+        * it is likely due to the window being "reseved" by the BIOS.
+        */
+       window->rsrc.name = MOD_NAME;
+       window->rsrc.start = window->phys;
+       window->rsrc.end   = window->phys + window->size - 1;
+       window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+       if (request_resource(&iomem_resource, &window->rsrc)) {
+               window->rsrc.parent = NULL;
+               printk(KERN_DEBUG MOD_NAME
+                       ": %s(): Unable to register resource"
+                       " 0x%.08llx-0x%.08llx - kernel bug?\n",
+                       __func__,
+                       (unsigned long long)window->rsrc.start,
+                       (unsigned long long)window->rsrc.end);
+       }
+
+       /* Map the firmware hub into my address space. */
+       window->virt = ioremap_nocache(window->phys, window->size);
+       if (!window->virt) {
+               printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
+                       window->phys, window->size);
+               goto out;
+       }
+
+       /* Get the first address to look for an rom chip at */
+       map_top = window->phys;
+       if ((window->phys & 0x3fffff) != 0) {
+               /* if not aligned on 4MiB, look 4MiB lower in address space */
+               map_top = window->phys + 0x400000;
+       }
+#if 1
+       /* The probe sequence run over the firmware hub lock
+        * registers sets them to 0x7 (no access).
+        * (Insane hardware design, but most copied Intel's.)
+        * ==> Probe at most the last 4M of the address space.
+        */
+       if (map_top < 0xffc00000)
+               map_top = 0xffc00000;
+#endif
+       /* Loop through and look for rom chips */
+       while ((map_top - 1) < 0xffffffffUL) {
+               struct cfi_private *cfi;
+               unsigned long offset;
+               int i;
+
+               if (!map)
+                       map = kmalloc(sizeof(*map), GFP_KERNEL);
+               if (!map) {
+                       printk(KERN_ERR MOD_NAME ": kmalloc failed");
+                       goto out;
+               }
+               memset(map, 0, sizeof(*map));
+               INIT_LIST_HEAD(&map->list);
+               map->map.name = map->map_name;
+               map->map.phys = map_top;
+               offset = map_top - window->phys;
+               map->map.virt = (void __iomem *)
+                       (((unsigned long)(window->virt)) + offset);
+               map->map.size = 0xffffffffUL - map_top + 1UL;
+               /* Set the name of the map to the address I am trying */
+               sprintf(map->map_name, "%s @%08lx",
+                       MOD_NAME, map->map.phys);
+
+               /* Firmware hubs only use vpp when being programmed
+                * in a factory setting.  So in-place programming
+                * needs to use a different method.
+                */
+               for(map->map.bankwidth = 32; map->map.bankwidth;
+                       map->map.bankwidth >>= 1) {
+                       char **probe_type;
+                       /* Skip bankwidths that are not supported */
+                       if (!map_bankwidth_supported(map->map.bankwidth))
+                               continue;
+
+                       /* Setup the map methods */
+                       simple_map_init(&map->map);
+
+                       /* Try all of the probe methods */
+                       probe_type = rom_probe_types;
+                       for(; *probe_type; probe_type++) {
+                               map->mtd = do_map_probe(*probe_type, &map->map);
+                               if (map->mtd)
+                                       goto found;
+                       }
+               }
+               map_top += ROM_PROBE_STEP_SIZE;
+               continue;
+       found:
+               /* Trim the size if we are larger than the map */
+               if (map->mtd->size > map->map.size) {
+                       printk(KERN_WARNING MOD_NAME
+                               " rom(%u) larger than window(%lu). fixing...\n",
+                               map->mtd->size, map->map.size);
+                       map->mtd->size = map->map.size;
+               }
+               if (window->rsrc.parent) {
+                       /*
+                        * Registering the MTD device in iomem may not be possible
+                        * if there is a BIOS "reserved" and BUSY range.  If this
+                        * fails then continue anyway.
+                        */
+                       map->rsrc.name  = map->map_name;
+                       map->rsrc.start = map->map.phys;
+                       map->rsrc.end   = map->map.phys + map->mtd->size - 1;
+                       map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+                       if (request_resource(&window->rsrc, &map->rsrc)) {
+                               printk(KERN_ERR MOD_NAME
+                                       ": cannot reserve MTD resource\n");
+                               map->rsrc.parent = NULL;
+                       }
+               }
+
+               /* Make the whole region visible in the map */
+               map->map.virt = window->virt;
+               map->map.phys = window->phys;
+               cfi = map->map.fldrv_priv;
+               for(i = 0; i < cfi->numchips; i++)
+                       cfi->chips[i].start += offset;
+
+               /* Now that the mtd devices is complete claim and export it */
+               map->mtd->owner = THIS_MODULE;
+               if (add_mtd_device(map->mtd)) {
+                       map_destroy(map->mtd);
+                       map->mtd = NULL;
+                       goto out;
+               }
+
+               /* Calculate the new value of map_top */
+               map_top += map->mtd->size;
+
+               /* File away the map structure */
+               list_add(&map->list, &window->maps);
+               map = NULL;
+       }
+
+ out:
+       /* Free any left over map structures */
+       kfree(map);
+
+       /* See if I have any map structures */
+       if (list_empty(&window->maps)) {
+               esb2rom_cleanup(window);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void __devexit esb2rom_remove_one (struct pci_dev *pdev)
+{
+       struct esb2rom_window *window = &esb2rom_window;
+       esb2rom_cleanup(window);
+}
+
+static struct pci_device_id esb2rom_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
+         PCI_ANY_ID, PCI_ANY_ID, },
+       { 0, },
+};
+
+#if 0
+MODULE_DEVICE_TABLE(pci, esb2rom_pci_tbl);
+
+static struct pci_driver esb2rom_driver = {
+       .name =         MOD_NAME,
+       .id_table =     esb2rom_pci_tbl,
+       .probe =        esb2rom_init_one,
+       .remove =       esb2rom_remove_one,
+};
+#endif
+
+static int __init init_esb2rom(void)
+{
+       struct pci_dev *pdev;
+       struct pci_device_id *id;
+       int retVal;
+
+       pdev = NULL;
+       for (id = esb2rom_pci_tbl; id->vendor; id++) {
+               printk(KERN_DEBUG "device id = %x\n", id->device);
+               pdev = pci_get_device(id->vendor, id->device, NULL);
+               if (pdev) {
+                       printk(KERN_DEBUG "matched device = %x\n", id->device);
+                       break;
+               }
+       }
+       if (pdev) {
+               printk(KERN_DEBUG "matched device id %x\n", id->device);
+               retVal = esb2rom_init_one(pdev, &esb2rom_pci_tbl[0]);
+               pci_dev_put(pdev);
+               printk(KERN_DEBUG "retVal = %d\n", retVal);
+               return retVal;
+       }
+       return -ENXIO;
+#if 0
+       return pci_register_driver(&esb2rom_driver);
+#endif
+}
+
+static void __exit cleanup_esb2rom(void)
+{
+       esb2rom_remove_one(esb2rom_window.pdev);
+}
+
+module_init(init_esb2rom);
+module_exit(cleanup_esb2rom);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lew Glendenning <lglendenning@lnxi.com>");
+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ESB2 southbridge");
index 5b6acfcb2b880be00cc77be7abafbf0c71b264da..866c8e0d57e4c331c49b0781a146e0f9f128de34 100644 (file)
@@ -616,6 +616,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
                memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
                       sizeof(oi.oobfree));
+               oi.eccbytes = mtd->ecclayout->eccbytes;
 
                if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
                        return -EFAULT;
@@ -715,7 +716,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                if (!mtd->ecclayout)
                        return -EOPNOTSUPP;
 
-               if (copy_to_user(argp, &mtd->ecclayout,
+               if (copy_to_user(argp, mtd->ecclayout,
                                 sizeof(struct nand_ecclayout)))
                        return -EFAULT;
                break;
index 1831340e5f5141e87777d0ef4c54b66ae7e6030c..b4b1656735bd33486eb62c6f36f963f29e0ee702 100644 (file)
@@ -232,6 +232,13 @@ config MTD_NAND_CS553X
 
          If you say "m", the module will be called "cs553x_nand.ko".
 
+config MTD_NAND_AT91
+       bool "Support for NAND Flash / SmartMedia on AT91"
+       depends on MTD_NAND && ARCH_AT91
+       help
+         Enables support for NAND Flash / Smart Media Card interface
+         on Atmel AT91 processors.
+
 config MTD_NAND_NANDSIM
        tristate "Support for NAND Flash Simulator"
        depends on MTD_NAND && MTD_PARTITIONS
index f74759351c912a2fd3d7d4cb840e44f428e5fd5f..27c9f0a1ef83042af158ac5cd438a70c3086bef7 100644 (file)
@@ -22,5 +22,6 @@ obj-$(CONFIG_MTD_NAND_TS7250)         += ts7250.o
 obj-$(CONFIG_MTD_NAND_NANDSIM)         += nandsim.o
 obj-$(CONFIG_MTD_NAND_CS553X)          += cs553x_nand.o
 obj-$(CONFIG_MTD_NAND_NDFC)            += ndfc.o
+obj-$(CONFIG_MTD_NAND_AT91)            += at91_nand.o
 
 nand-objs = nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
new file mode 100644 (file)
index 0000000..a58ed37
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * drivers/mtd/nand/at91_nand.c
+ *
+ *  Copyright (C) 2003 Rick Bronson
+ *
+ *  Derived from drivers/mtd/nand/autcpu12.c
+ *      Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *
+ *  Derived from drivers/mtd/spia.c
+ *      Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ * 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.
+ *
+ */
+
+#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/hardware.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+struct at91_nand_host {
+       struct nand_chip        nand_chip;
+       struct mtd_info         mtd;
+       void __iomem            *io_base;
+       struct at91_nand_data   *board;
+};
+
+/*
+ * Hardware specific access to control-lines
+ */
+static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct at91_nand_host *host = nand_chip->priv;
+
+       if (cmd == NAND_CMD_NONE)
+               return;
+
+       if (ctrl & NAND_CLE)
+               writeb(cmd, host->io_base + (1 << host->board->cle));
+       else
+               writeb(cmd, host->io_base + (1 << host->board->ale));
+}
+
+/*
+ * Read the Device Ready pin.
+ */
+static int at91_nand_device_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct at91_nand_host *host = nand_chip->priv;
+
+       return at91_get_gpio_value(host->board->rdy_pin);
+}
+
+/*
+ * Enable NAND.
+ */
+static void at91_nand_enable(struct at91_nand_host *host)
+{
+       if (host->board->enable_pin)
+               at91_set_gpio_value(host->board->enable_pin, 0);
+}
+
+/*
+ * Disable NAND.
+ */
+static void at91_nand_disable(struct at91_nand_host *host)
+{
+       if (host->board->enable_pin)
+               at91_set_gpio_value(host->board->enable_pin, 1);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int __init at91_nand_probe(struct platform_device *pdev)
+{
+       struct at91_nand_host *host;
+       struct mtd_info *mtd;
+       struct nand_chip *nand_chip;
+       int res;
+
+#ifdef CONFIG_MTD_PARTITIONS
+       struct mtd_partition *partitions = NULL;
+       int num_partitions = 0;
+#endif
+
+       /* Allocate memory for the device structure (and zero it) */
+       host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL);
+       if (!host) {
+               printk(KERN_ERR "at91_nand: failed to allocate device structure.\n");
+               return -ENOMEM;
+       }
+
+       host->io_base = ioremap(pdev->resource[0].start,
+                               pdev->resource[0].end - pdev->resource[0].start + 1);
+       if (host->io_base == NULL) {
+               printk(KERN_ERR "at91_nand: ioremap failed\n");
+               kfree(host);
+               return -EIO;
+       }
+
+       mtd = &host->mtd;
+       nand_chip = &host->nand_chip;
+       host->board = pdev->dev.platform_data;
+
+       nand_chip->priv = host;         /* link the private data structures */
+       mtd->priv = nand_chip;
+       mtd->owner = THIS_MODULE;
+
+       /* Set address of NAND IO lines */
+       nand_chip->IO_ADDR_R = host->io_base;
+       nand_chip->IO_ADDR_W = host->io_base;
+       nand_chip->cmd_ctrl = at91_nand_cmd_ctrl;
+       nand_chip->dev_ready = at91_nand_device_ready;
+       nand_chip->ecc.mode = NAND_ECC_SOFT;    /* enable ECC */
+       nand_chip->chip_delay = 20;             /* 20us command delay time */
+
+       platform_set_drvdata(pdev, host);
+       at91_nand_enable(host);
+
+       if (host->board->det_pin) {
+               if (at91_get_gpio_value(host->board->det_pin)) {
+                       printk ("No SmartMedia card inserted.\n");
+                       res = ENXIO;
+                       goto out;
+               }
+       }
+
+       /* Scan to find existance of the device */
+       if (nand_scan(mtd, 1)) {
+               res = -ENXIO;
+               goto out;
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (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");
+               res = ENXIO;
+               goto release;
+       }
+
+       res = add_mtd_partitions(mtd, partitions, num_partitions);
+#else
+       res = add_mtd_device(mtd);
+#endif
+
+       if (!res)
+               return res;
+
+release:
+       nand_release(mtd);
+out:
+       at91_nand_disable(host);
+       platform_set_drvdata(pdev, NULL);
+       iounmap(host->io_base);
+       kfree(host);
+       return res;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int __devexit at91_nand_remove(struct platform_device *pdev)
+{
+       struct at91_nand_host *host = platform_get_drvdata(pdev);
+       struct mtd_info *mtd = &host->mtd;
+
+       nand_release(mtd);
+
+       at91_nand_disable(host);
+
+       iounmap(host->io_base);
+       kfree(host);
+
+       return 0;
+}
+
+static struct platform_driver at91_nand_driver = {
+       .probe          = at91_nand_probe,
+       .remove         = at91_nand_remove,
+       .driver         = {
+               .name   = "at91_nand",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init at91_nand_init(void)
+{
+       return platform_driver_register(&at91_nand_driver);
+}
+
+
+static void __exit at91_nand_exit(void)
+{
+       platform_driver_unregister(&at91_nand_driver);
+}
+
+
+module_init(at91_nand_init);
+module_exit(at91_nand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200");
index baece61169f4933af73704779143ddbaf21c08f7..53c66d5c8d1a4427c4999cc10f4da159997bab56 100644 (file)
@@ -755,7 +755,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_page_swecc - {REPLACABLE] software ecc based page read function
+ * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
@@ -795,7 +795,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function
+ * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
@@ -839,7 +839,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
+ * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       buffer to store read data
@@ -1375,7 +1375,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_write_page_swecc - {REPLACABLE] software ecc based page write function
+ * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       data buffer
@@ -1401,7 +1401,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_write_page_hwecc - {REPLACABLE] hardware ecc based page write function
+ * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       data buffer
@@ -1429,7 +1429,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /**
- * nand_write_page_syndrome - {REPLACABLE] hardware ecc syndrom based page write
+ * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
  * @buf:       data buffer
index 545ff252d81eb675dfa7c5bf349b212461ee8240..abebcab47631d456341ff3594d26e330b90ac04e 100644 (file)
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
-#ifdef CONFIG_NS_ABS_POS
-#include <asm/io.h>
-#endif
-
 
 /* Default simulator parameters values */
 #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
@@ -230,6 +226,14 @@ MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
  */
 #define NS_MAX_PREVSTATES 1
 
+/*
+ * A union to represent flash memory contents and flash buffer.
+ */
+union ns_mem {
+       u_char *byte;    /* for byte access */
+       uint16_t *word;  /* for 16-bit word access */
+};
+
 /*
  * The structure which describes all the internal simulator data.
  */
@@ -247,17 +251,11 @@ struct nandsim {
        uint16_t npstates;      /* number of previous states saved */
        uint16_t stateidx;      /* current state index */
 
-       /* The simulated NAND flash image */
-       union flash_media {
-               u_char *byte;
-               uint16_t    *word;
-       } mem;
+       /* The simulated NAND flash pages array */
+       union ns_mem *pages;
 
        /* Internal buffer of page + OOB size bytes */
-       union internal_buffer {
-               u_char *byte;    /* for byte access */
-               uint16_t *word;  /* for 16-bit word access */
-       } buf;
+       union ns_mem buf;
 
        /* NAND flash "geometry" */
        struct nandsin_geometry {
@@ -345,13 +343,50 @@ static struct mtd_info *nsmtd;
 
 static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
 
+/*
+ * Allocate array of page pointers and initialize the array to NULL
+ * pointers.
+ *
+ * RETURNS: 0 if success, -ENOMEM if memory alloc fails.
+ */
+static int alloc_device(struct nandsim *ns)
+{
+       int i;
+
+       ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
+       if (!ns->pages) {
+               NS_ERR("alloc_map: unable to allocate page array\n");
+               return -ENOMEM;
+       }
+       for (i = 0; i < ns->geom.pgnum; i++) {
+               ns->pages[i].byte = NULL;
+       }
+
+       return 0;
+}
+
+/*
+ * Free any allocated pages, and free the array of page pointers.
+ */
+static void free_device(struct nandsim *ns)
+{
+       int i;
+
+       if (ns->pages) {
+               for (i = 0; i < ns->geom.pgnum; i++) {
+                       if (ns->pages[i].byte)
+                               kfree(ns->pages[i].byte);
+               }
+               vfree(ns->pages);
+       }
+}
+
 /*
  * Initialize the nandsim structure.
  *
  * RETURNS: 0 if success, -ERRNO if failure.
  */
-static int
-init_nandsim(struct mtd_info *mtd)
+static int init_nandsim(struct mtd_info *mtd)
 {
        struct nand_chip *chip = (struct nand_chip *)mtd->priv;
        struct nandsim   *ns   = (struct nandsim *)(chip->priv);
@@ -439,23 +474,8 @@ init_nandsim(struct mtd_info *mtd)
        printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
        printk("options: %#x\n",                ns->options);
 
-       /* Map / allocate and initialize the flash image */
-#ifdef CONFIG_NS_ABS_POS
-       ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob);
-       if (!ns->mem.byte) {
-               NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n",
-                       (void *)CONFIG_NS_ABS_POS);
-               return -ENOMEM;
-       }
-#else
-       ns->mem.byte = vmalloc(ns->geom.totszoob);
-       if (!ns->mem.byte) {
-               NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n",
-                       ns->geom.totszoob);
-               return -ENOMEM;
-       }
-       memset(ns->mem.byte, 0xFF, ns->geom.totszoob);
-#endif
+       if (alloc_device(ns) != 0)
+               goto error;
 
        /* Allocate / initialize the internal buffer */
        ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
@@ -474,11 +494,7 @@ init_nandsim(struct mtd_info *mtd)
        return 0;
 
 error:
-#ifdef CONFIG_NS_ABS_POS
-       iounmap(ns->mem.byte);
-#else
-       vfree(ns->mem.byte);
-#endif
+       free_device(ns);
 
        return -ENOMEM;
 }
@@ -486,16 +502,10 @@ error:
 /*
  * Free the nandsim structure.
  */
-static void
-free_nandsim(struct nandsim *ns)
+static void free_nandsim(struct nandsim *ns)
 {
        kfree(ns->buf.byte);
-
-#ifdef CONFIG_NS_ABS_POS
-       iounmap(ns->mem.byte);
-#else
-       vfree(ns->mem.byte);
-#endif
+       free_device(ns);
 
        return;
 }
@@ -503,8 +513,7 @@ free_nandsim(struct nandsim *ns)
 /*
  * Returns the string representation of 'state' state.
  */
-static char *
-get_state_name(uint32_t state)
+static char *get_state_name(uint32_t state)
 {
        switch (NS_STATE(state)) {
                case STATE_CMD_READ0:
@@ -562,8 +571,7 @@ get_state_name(uint32_t state)
  *
  * RETURNS: 1 if wrong command, 0 if right.
  */
-static int
-check_command(int cmd)
+static int check_command(int cmd)
 {
        switch (cmd) {
 
@@ -589,8 +597,7 @@ check_command(int cmd)
 /*
  * Returns state after command is accepted by command number.
  */
-static uint32_t
-get_state_by_command(unsigned command)
+static uint32_t get_state_by_command(unsigned command)
 {
        switch (command) {
                case NAND_CMD_READ0:
@@ -626,8 +633,7 @@ get_state_by_command(unsigned command)
 /*
  * Move an address byte to the correspondent internal register.
  */
-static inline void
-accept_addr_byte(struct nandsim *ns, u_char bt)
+static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
 {
        uint byte = (uint)bt;
 
@@ -645,8 +651,7 @@ accept_addr_byte(struct nandsim *ns, u_char bt)
 /*
  * Switch to STATE_READY state.
  */
-static inline void
-switch_to_ready_state(struct nandsim *ns, u_char status)
+static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
 {
        NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
 
@@ -705,8 +710,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
  *          -1 - several matches.
  *           0 - operation is found.
  */
-static int
-find_operation(struct nandsim *ns, uint32_t flag)
+static int find_operation(struct nandsim *ns, uint32_t flag)
 {
        int opsfound = 0;
        int i, j, idx = 0;
@@ -790,15 +794,94 @@ find_operation(struct nandsim *ns, uint32_t flag)
        return -1;
 }
 
+/*
+ * Returns a pointer to the current page.
+ */
+static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
+{
+       return &(ns->pages[ns->regs.row]);
+}
+
+/*
+ * Retuns a pointer to the current byte, within the current page.
+ */
+static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
+{
+       return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
+}
+
+/*
+ * Fill the NAND buffer with data read from the specified page.
+ */
+static void read_page(struct nandsim *ns, int num)
+{
+       union ns_mem *mypage;
+
+       mypage = NS_GET_PAGE(ns);
+       if (mypage->byte == NULL) {
+               NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
+               memset(ns->buf.byte, 0xFF, num);
+       } else {
+               NS_DBG("read_page: page %d allocated, reading from %d\n",
+                       ns->regs.row, ns->regs.column + ns->regs.off);
+               memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
+       }
+}
+
+/*
+ * Erase all pages in the specified sector.
+ */
+static void erase_sector(struct nandsim *ns)
+{
+       union ns_mem *mypage;
+       int i;
+
+       mypage = NS_GET_PAGE(ns);
+       for (i = 0; i < ns->geom.pgsec; i++) {
+               if (mypage->byte != NULL) {
+                       NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
+                       kfree(mypage->byte);
+                       mypage->byte = NULL;
+               }
+               mypage++;
+       }
+}
+
+/*
+ * Program the specified page with the contents from the NAND buffer.
+ */
+static int prog_page(struct nandsim *ns, int num)
+{
+       int i;
+       union ns_mem *mypage;
+       u_char *pg_off;
+
+       mypage = NS_GET_PAGE(ns);
+       if (mypage->byte == NULL) {
+               NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
+               mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+               if (mypage->byte == NULL) {
+                       NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
+                       return -1;
+               }
+               memset(mypage->byte, 0xFF, ns->geom.pgszoob);
+       }
+
+       pg_off = NS_PAGE_BYTE_OFF(ns);
+       for (i = 0; i < num; i++)
+               pg_off[i] &= ns->buf.byte[i];
+
+       return 0;
+}
+
 /*
  * If state has any action bit, perform this action.
  *
  * RETURNS: 0 if success, -1 if error.
  */
-static int
-do_state_action(struct nandsim *ns, uint32_t action)
+static int do_state_action(struct nandsim *ns, uint32_t action)
 {
-       int i, num;
+       int num;
        int busdiv = ns->busw == 8 ? 1 : 2;
 
        action &= ACTION_MASK;
@@ -822,7 +905,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
                        break;
                }
                num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
-               memcpy(ns->buf.byte, ns->mem.byte + NS_RAW_OFFSET(ns) + ns->regs.off, num);
+               read_page(ns, num);
 
                NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
                        num, NS_RAW_OFFSET(ns) + ns->regs.off);
@@ -863,7 +946,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
                                ns->regs.row, NS_RAW_OFFSET(ns));
                NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
 
-               memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob);
+               erase_sector(ns);
 
                NS_MDELAY(erase_delay);
 
@@ -886,8 +969,8 @@ do_state_action(struct nandsim *ns, uint32_t action)
                        return -1;
                }
 
-               for (i = 0; i < num; i++)
-                       ns->mem.byte[NS_RAW_OFFSET(ns) + ns->regs.off + i] &= ns->buf.byte[i];
+               if (prog_page(ns, num) == -1)
+                       return -1;
 
                NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
                        num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
@@ -928,8 +1011,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
 /*
  * Switch simulator's state.
  */
-static void
-switch_state(struct nandsim *ns)
+static void switch_state(struct nandsim *ns)
 {
        if (ns->op) {
                /*
@@ -1070,8 +1152,7 @@ switch_state(struct nandsim *ns)
        }
 }
 
-static u_char
-ns_nand_read_byte(struct mtd_info *mtd)
+static u_char ns_nand_read_byte(struct mtd_info *mtd)
 {
         struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
        u_char outb = 0x00;
@@ -1144,8 +1225,7 @@ ns_nand_read_byte(struct mtd_info *mtd)
        return outb;
 }
 
-static void
-ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
+static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 {
         struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
 
@@ -1308,15 +1388,13 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
                ns_nand_write_byte(mtd, cmd);
 }
 
-static int
-ns_device_ready(struct mtd_info *mtd)
+static int ns_device_ready(struct mtd_info *mtd)
 {
        NS_DBG("device_ready\n");
        return 1;
 }
 
-static uint16_t
-ns_nand_read_word(struct mtd_info *mtd)
+static uint16_t ns_nand_read_word(struct mtd_info *mtd)
 {
        struct nand_chip *chip = (struct nand_chip *)mtd->priv;
 
@@ -1325,8 +1403,7 @@ ns_nand_read_word(struct mtd_info *mtd)
        return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
 }
 
-static void
-ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
         struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
 
@@ -1353,8 +1430,7 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
        }
 }
 
-static void
-ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
         struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
 
@@ -1407,8 +1483,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
        return;
 }
 
-static int
-ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
+static int ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
        ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len);
 
index 0ddfd70307fb33dc1bf27404111bceffd48fa6cd..4178b4b5594824997e33948fd063d7d6248dea4f 100644 (file)
@@ -294,23 +294,21 @@ static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev)
 
 static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
 {
-       struct rb_node *node = root->rb_node;
+       struct rb_node *node = rb_first(root);
 
        if (!node)
                return NULL;
-       while(node->rb_left)
-               node = node->rb_left;
+
        return rb_entry(node, struct jffs2_node_frag, rb);
 }
 
 static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
 {
-       struct rb_node *node = root->rb_node;
+       struct rb_node *node = rb_last(root);
 
        if (!node)
                return NULL;
-       while(node->rb_right)
-               node = node->rb_right;
+
        return rb_entry(node, struct jffs2_node_frag, rb);
 }
 
index fc211b6e9b03ec1b6dd4641179d18854d8df3d4b..b90d5aa3d96972a14fbd144c933cd894a4df69ca 100644 (file)
@@ -51,7 +51,7 @@ static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
         */
 
        if (!p) {
-               printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
+               printk(KERN_ERR "jffs2_follow_link(): can't find symlink target\n");
                p = ERR_PTR(-EIO);
        }
        D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target));
index 4da09ce1d1f52fc12182ab34afceef584706b186..4bb3f189733027d159462f91a131b929909481f4 100644 (file)
@@ -399,8 +399,6 @@ static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datu
 {
        /* must be called under down_write(xattr_sem) */
        if (atomic_dec_and_lock(&xd->refcnt, &c->erase_completion_lock)) {
-               uint32_t xid = xd->xid, version = xd->version;
-
                unload_xattr_datum(c, xd);
                xd->flags |= JFFS2_XFLAGS_DEAD;
                if (xd->node == (void *)xd) {
@@ -411,7 +409,8 @@ static void unrefer_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datu
                }
                spin_unlock(&c->erase_completion_lock);
 
-               dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n", xid, version);
+               dbg_xattr("xdatum(xid=%u, version=%u) was removed.\n",
+                         xd->xid, xd->version);
        }
 }