]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge with rsync://fileserver/linux
authorThomas Gleixner <tglx@tglx.tec.linutronix.de>
Sun, 26 Jun 2005 21:20:36 +0000 (23:20 +0200)
committerThomas Gleixner <tglx@mtd.linutronix.de>
Sun, 26 Jun 2005 21:20:36 +0000 (23:20 +0200)
Update to Linus latest

67 files changed:
drivers/mtd/chips/Kconfig
drivers/mtd/chips/amd_flash.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/gen_probe.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/mtdram.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/slram.c
drivers/mtd/ftl.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/alchemy-flash.c [new file with mode: 0644]
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/bast-flash.c
drivers/mtd/maps/db1550-flash.c [deleted file]
drivers/mtd/maps/db1x00-flash.c [deleted file]
drivers/mtd/maps/elan-104nc.c [deleted file]
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/pb1550-flash.c [deleted file]
drivers/mtd/maps/pb1xxx-flash.c [deleted file]
drivers/mtd/maps/pci.c
drivers/mtd/maps/plat-ram.c [new file with mode: 0644]
drivers/mtd/maps/scb2_flash.c
drivers/mtd/maps/sharpsl-flash.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/rtc_from4.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sharpsl.c
fs/Kconfig
fs/jffs2/Makefile
fs/jffs2/README.Locking
fs/jffs2/background.c
fs/jffs2/build.c
fs/jffs2/compr_zlib.c
fs/jffs2/dir.c
fs/jffs2/erase.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/nodelist.c
fs/jffs2/nodelist.h
fs/jffs2/nodemgmt.c
fs/jffs2/os-linux.h
fs/jffs2/read.c
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/super.c
fs/jffs2/symlink.c
fs/jffs2/wbuf.c
fs/jffs2/write.c
include/linux/jffs2_fs_sb.h
include/linux/mtd/cfi.h
include/linux/mtd/flashchip.h
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/plat-ram.h [new file with mode: 0644]
include/mtd/mtd-abi.h

index d682dbc8157e4030a641a245b305ea7d112593e2..f4eda1e40d519edb3e423246d9b8f03ba6e1d81a 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $
+# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $
 
 menu "RAM/ROM/Flash chip drivers"
        depends on MTD!=n
@@ -155,6 +155,31 @@ config MTD_CFI_I8
          If your flash chips are interleaved in eights - i.e. you have eight
          flash chips addressed by each bus cycle, then say 'Y'.
 
+config MTD_OTP
+       bool "Protection Registers aka one-time programmable (OTP) bits"
+       depends on MTD_CFI_ADV_OPTIONS
+       default n
+       help
+         This enables support for reading, writing and locking so called
+         "Protection Registers" present on some flash chips.
+         A subset of them are pre-programmed at the factory with a
+         unique set of values. The rest is user-programmable.
+
+         The user-programmable Protection Registers contain one-time
+         programmable (OTP) bits; when programmed, register bits cannot be
+         erased. Each Protection Register can be accessed multiple times to
+         program individual bits, as long as the register remains unlocked.
+
+         Each Protection Register has an associated Lock Register bit. When a
+         Lock Register bit is programmed, the associated Protection Register
+         can only be read; it can no longer be programmed. Additionally,
+         because the Lock Register bits themselves are OTP, when programmed,
+         Lock Register bits cannot be erased. Therefore, when a Protection
+         Register is locked, it cannot be unlocked.
+
+         This feature should therefore be used with extreme care. Any mistake
+         in the programming of OTP bits will waste them.
+
 config MTD_CFI_INTELEXT
        tristate "Support for Intel/Sharp flash chips"
        depends on MTD_GEN_PROBE
index 41e2e3e31603cc9dd7cd5c412c81add96137b170..2dafeba3f3d5afb9ce165794e86286da7b064e77 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
@@ -67,7 +67,6 @@
 #define AM29LV160DT    0x22C4
 #define AM29LV160DB    0x2249
 #define AM29BDS323D     0x22D1
-#define AM29BDS643D    0x227E
 
 /* Atmel */
 #define AT49xV16x      0x00C0
@@ -617,17 +616,6 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
                        { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
                        { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks =  8 },
                }
-       }, {
-               .mfr_id = MANUFACTURER_AMD,
-               .dev_id = AM29BDS643D,
-               .name = "AMD AM29BDS643D",
-               .size = 0x00800000,
-               .numeraseregions = 3,
-               .regions = {
-                       { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
-                       { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
-                       { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks =  8 },
-               }
        }, {
                .mfr_id = MANUFACTURER_ATMEL,
                .dev_id = AT49xV16x,
index c268bcd7172025a5312960f338903085086cc366..8b1304531d8f13dfdb69a4d3b9881df7450b17c6 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.164 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $
  *
  * 
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
@@ -29,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/reboot.h>
 #include <linux/mtd/xip.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #define M50LPW080       0x002F
 
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_fact_prot_reg (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 *);
 static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
 static void cfi_intelext_sync (struct mtd_info *);
 static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
 static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+#ifdef CONFIG_MTD_OTP
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
+static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
+                                           struct otp_info *, size_t);
+static int cfi_intelext_get_user_prot_info (struct mtd_info *,
+                                           struct otp_info *, size_t);
+#endif
 static int cfi_intelext_suspend (struct mtd_info *);
 static void cfi_intelext_resume (struct mtd_info *);
+static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *);
 
 static void cfi_intelext_destroy(struct mtd_info *);
 
@@ -252,7 +262,8 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                int nb_parts, i;
 
                /* Protection Register info */
-               extra_size += (extp->NumProtectionFields - 1) * (4 + 6);
+               extra_size += (extp->NumProtectionFields - 1) *
+                             sizeof(struct cfi_intelext_otpinfo);
 
                /* Burst Read info */
                extra_size += 6;
@@ -324,7 +335,9 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
        mtd->resume  = cfi_intelext_resume;
        mtd->flags   = MTD_CAP_NORFLASH;
        mtd->name    = map->name;
-       
+
+       mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
+
        if (cfi->cfi_mode == CFI_MODE_CFI) {
                /* 
                 * It's a real CFI chip, not one for which the probe
@@ -422,9 +435,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
                       mtd->eraseregions[i].numblocks);
        }
 
-#if 0
-       mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+#ifdef CONFIG_MTD_OTP
        mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+       mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+       mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
+       mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
+       mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
+       mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
 #endif
 
        /* This function has the potential to distort the reality
@@ -433,6 +450,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
                goto setup_err;
 
        __module_get(THIS_MODULE);
+       register_reboot_notifier(&mtd->reboot_notifier);
        return mtd;
 
  setup_err:
@@ -471,7 +489,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                int offs, numregions, numparts, partshift, numvirtchips, i, j;
 
                /* Protection Register info */
-               offs = (extp->NumProtectionFields - 1) * (4 + 6);
+               offs = (extp->NumProtectionFields - 1) *
+                      sizeof(struct cfi_intelext_otpinfo);
 
                /* Burst Read info */
                offs += 6;
@@ -563,7 +582,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
  resettime:
        timeo = jiffies + HZ;
  retry:
-       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) {
+       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
                /*
                 * OK. We have possibility for contension on the write/erase
                 * operations which are global to the real chip and not per
@@ -807,10 +826,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
  * assembly to make sure inline functions were actually inlined and that gcc
  * didn't emit calls to its own support functions). Also configuring MTD CFI
  * support to a single buswidth and a single interleave is also recommended.
- * Note that not only IRQs are disabled but the preemption count is also
- * increased to prevent other locking primitives (namely spin_unlock) from
- * decrementing the preempt count to zero and scheduling the CPU away while
- * not in array mode.
  */
 
 static void xip_disable(struct map_info *map, struct flchip *chip,
@@ -818,7 +833,6 @@ static void xip_disable(struct map_info *map, struct flchip *chip,
 {
        /* TODO: chips with no XIP use should ignore and return */
        (void) map_read(map, adr); /* ensure mmu mapping is up to date */
-       preempt_disable();
        local_irq_disable();
 }
 
@@ -833,7 +847,6 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
        (void) map_read(map, adr);
        asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */
        local_irq_enable();
-       preempt_enable();
 }
 
 /*
@@ -909,7 +922,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
                        (void) map_read(map, adr);
                        asm volatile (".rep 8; nop; .endr");
                        local_irq_enable();
-                       preempt_enable();
+                       spin_unlock(chip->mutex);
                        asm volatile (".rep 8; nop; .endr");
                        cond_resched();
 
@@ -919,15 +932,15 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
                         * a suspended erase state.  If so let's wait
                         * until it's done.
                         */
-                       preempt_disable();
+                       spin_lock(chip->mutex);
                        while (chip->state != newstate) {
                                DECLARE_WAITQUEUE(wait, current);
                                set_current_state(TASK_UNINTERRUPTIBLE);
                                add_wait_queue(&chip->wq, &wait);
-                               preempt_enable();
+                               spin_unlock(chip->mutex);
                                schedule();
                                remove_wait_queue(&chip->wq, &wait);
-                               preempt_disable();
+                               spin_lock(chip->mutex);
                        }
                        /* Disallow XIP again */
                        local_irq_disable();
@@ -956,12 +969,14 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
  * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
  * the flash is actively programming or erasing since we have to poll for
  * the operation to complete anyway.  We can't do that in a generic way with
- * a XIP setup so do it before the actual flash operation in this case.
+ * a XIP setup so do it before the actual flash operation in this case
+ * and stub it out from INVALIDATE_CACHE_UDELAY.
  */
-#undef INVALIDATE_CACHED_RANGE
-#define INVALIDATE_CACHED_RANGE(x...)
-#define XIP_INVAL_CACHED_RANGE(map, from, size) \
-       do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
+#define XIP_INVAL_CACHED_RANGE(map, from, size)  \
+       INVALIDATE_CACHED_RANGE(map, from, size)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
+       UDELAY(map, chip, adr, usec)
 
 /*
  * Extra notes:
@@ -984,11 +999,23 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
 
 #define xip_disable(map, chip, adr)
 #define xip_enable(map, chip, adr)
-
-#define UDELAY(map, chip, adr, usec)  cfi_udelay(usec)
-
 #define XIP_INVAL_CACHED_RANGE(x...)
 
+#define UDELAY(map, chip, adr, usec)  \
+do {  \
+       spin_unlock(chip->mutex);  \
+       cfi_udelay(usec);  \
+       spin_lock(chip->mutex);  \
+} while (0)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec)  \
+do {  \
+       spin_unlock(chip->mutex);  \
+       INVALIDATE_CACHED_RANGE(map, adr, len);  \
+       cfi_udelay(usec);  \
+       spin_lock(chip->mutex);  \
+} while (0)
+
 #endif
 
 static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
@@ -1176,111 +1203,11 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
        return ret;
 }
 
-#if 0
-static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd,
-                                               loff_t from, size_t len,
-                                               size_t *retlen,
-                                               u_char *buf,
-                                               int base_offst, int reg_sz)
-{
-       struct map_info *map = mtd->priv;
-       struct cfi_private *cfi = map->fldrv_priv;
-       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
-       struct flchip *chip;
-       int ofs_factor = cfi->interleave * cfi->device_type;
-       int count = len;
-       int chip_num, offst;
-       int ret;
-
-       chip_num = ((unsigned int)from/reg_sz);
-       offst = from - (reg_sz*chip_num)+base_offst;
-
-       while (count) {
-       /* Calculate which chip & protection register offset we need */
-
-               if (chip_num >= cfi->numchips)
-                       goto out;
-
-               chip = &cfi->chips[chip_num];
-               
-               spin_lock(chip->mutex);
-               ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
-               if (ret) {
-                       spin_unlock(chip->mutex);
-                       return (len-count)?:ret;
-               }
-
-               xip_disable(map, chip, chip->start);
-
-               if (chip->state != FL_JEDEC_QUERY) {
-                       map_write(map, CMD(0x90), chip->start);
-                       chip->state = FL_JEDEC_QUERY;
-               }
-
-               while (count && ((offst-base_offst) < reg_sz)) {
-                       *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
-                       buf++;
-                       offst++;
-                       count--;
-               }
-
-               xip_enable(map, chip, chip->start);
-               put_chip(map, chip, chip->start);
-               spin_unlock(chip->mutex);
-
-               /* Move on to the next chip */
-               chip_num++;
-               offst = base_offst;
-       }
-       
- out:  
-       return len-count;
-}
-       
-static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct cfi_private *cfi = map->fldrv_priv;
-       struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-       int base_offst,reg_sz;
-       
-       /* Check that we actually have some protection registers */
-       if(!extp || !(extp->FeatureSupport&64)){
-               printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-               return 0;
-       }
-
-       base_offst=(1<<extp->FactProtRegSize);
-       reg_sz=(1<<extp->UserProtRegSize);
-
-       return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-
-static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
-       struct map_info *map = mtd->priv;
-       struct cfi_private *cfi = map->fldrv_priv;
-       struct cfi_pri_intelext *extp=cfi->cmdset_priv;
-       int base_offst,reg_sz;
-       
-       /* Check that we actually have some protection registers */
-       if(!extp || !(extp->FeatureSupport&64)){
-               printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
-               return 0;
-       }
-
-       base_offst=0;
-       reg_sz=(1<<extp->FactProtRegSize);
-
-       return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-#endif
-
 static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
-                                    unsigned long adr, map_word datum)
+                                    unsigned long adr, map_word datum, int mode)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       map_word status, status_OK;
+       map_word status, status_OK, write_cmd;
        unsigned long timeo;
        int z, ret=0;
 
@@ -1288,9 +1215,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 
        /* Let's determine this according to the interleave only once */
        status_OK = CMD(0x80);
+       switch (mode) {
+       case FL_WRITING:   write_cmd = CMD(0x40); break;
+       case FL_OTP_WRITE: write_cmd = CMD(0xc0); break;
+       default: return -EINVAL;
+       }
 
        spin_lock(chip->mutex);
-       ret = get_chip(map, chip, adr, FL_WRITING);
+       ret = get_chip(map, chip, adr, mode);
        if (ret) {
                spin_unlock(chip->mutex);
                return ret;
@@ -1299,19 +1231,18 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
        XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
        ENABLE_VPP(map);
        xip_disable(map, chip, adr);
-       map_write(map, CMD(0x40), adr);
+       map_write(map, write_cmd, adr);
        map_write(map, datum, adr);
-       chip->state = FL_WRITING;
+       chip->state = mode;
 
-       spin_unlock(chip->mutex);
-       INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
-       UDELAY(map, chip, adr, chip->word_write_time);
-       spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip,
+                               adr, map_bankwidth(map),
+                               chip->word_write_time);
 
        timeo = jiffies + (HZ/2);
        z = 0;
        for (;;) {
-               if (chip->state != FL_WRITING) {
+               if (chip->state != mode) {
                        /* Someone's suspended the write. Sleep */
                        DECLARE_WAITQUEUE(wait, current);
 
@@ -1339,10 +1270,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
                }
 
                /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock(chip->mutex);
                z++;
                UDELAY(map, chip, adr, 1);
-               spin_lock(chip->mutex);
        }
        if (!z) {
                chip->word_write_time--;
@@ -1399,7 +1328,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                datum = map_word_load_partial(map, datum, buf, gap, n);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                                              bus_ofs, datum);
+                                              bus_ofs, datum, FL_WRITING);
                if (ret) 
                        return ret;
 
@@ -1420,7 +1349,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                map_word datum = map_word_load(map, buf);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                               ofs, datum);
+                                      ofs, datum, FL_WRITING);
                if (ret)
                        return ret;
 
@@ -1444,7 +1373,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                datum = map_word_load_partial(map, datum, buf, 0, len);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
-                                              ofs, datum);
+                                      ofs, datum, FL_WRITING);
                if (ret) 
                        return ret;
                
@@ -1506,9 +1435,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
 
-               spin_unlock(chip->mutex);
                UDELAY(map, chip, cmd_adr, 1);
-               spin_lock(chip->mutex);
 
                if (++z > 20) {
                        /* Argh. Not ready for write to buffer */
@@ -1554,10 +1481,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        map_write(map, CMD(0xd0), cmd_adr);
        chip->state = FL_WRITING;
 
-       spin_unlock(chip->mutex);
-       INVALIDATE_CACHED_RANGE(map, adr, len);
-       UDELAY(map, chip, cmd_adr, chip->buffer_write_time);
-       spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip, 
+                               cmd_adr, len,
+                               chip->buffer_write_time);
 
        timeo = jiffies + (HZ/2);
        z = 0;
@@ -1589,10 +1515,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                }
                
                /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock(chip->mutex);
-               UDELAY(map, chip, cmd_adr, 1);
                z++;
-               spin_lock(chip->mutex);
+               UDELAY(map, chip, cmd_adr, 1);
        }
        if (!z) {
                chip->buffer_write_time--;
@@ -1720,10 +1644,9 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
 
-       spin_unlock(chip->mutex);
-       INVALIDATE_CACHED_RANGE(map, adr, len);
-       UDELAY(map, chip, adr, chip->erase_time*1000/2);
-       spin_lock(chip->mutex);
+       INVALIDATE_CACHE_UDELAY(map, chip,
+                               adr, len,
+                               chip->erase_time*1000/2);
 
        /* FIXME. Use a timer to check this, and return immediately. */
        /* Once the state machine's known to be working I'll do that */
@@ -1768,9 +1691,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
                }
                
                /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock(chip->mutex);
                UDELAY(map, chip, adr, 1000000/HZ);
-               spin_lock(chip->mutex);
        }
 
        /* We've broken this before. It doesn't hurt to be safe */
@@ -1780,44 +1701,34 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
 
        /* check for lock bit */
        if (map_word_bitsset(map, status, CMD(0x3a))) {
-               unsigned char chipstatus;
+               unsigned long chipstatus;
 
                /* Reset the error bits */
                map_write(map, CMD(0x50), adr);
                map_write(map, CMD(0x70), adr);
                xip_enable(map, chip, adr);
 
-               chipstatus = status.x[0];
-               if (!map_word_equal(map, status, CMD(chipstatus))) {
-                       int i, w;
-                       for (w=0; w<map_words(map); w++) {
-                               for (i = 0; i<cfi_interleave(cfi); i++) {
-                                       chipstatus |= status.x[w] >> (cfi->device_type * 8);
-                               }
-                       }
-                       printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
-                              status.x[0], chipstatus);
-               }
+               chipstatus = MERGESTATUS(status);
 
                if ((chipstatus & 0x30) == 0x30) {
-                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
+                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus);
                        ret = -EIO;
                } else if (chipstatus & 0x02) {
                        /* Protection bit set */
                        ret = -EROFS;
                } else if (chipstatus & 0x8) {
                        /* Voltage */
-                       printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
+                       printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus);
                        ret = -EIO;
                } else if (chipstatus & 0x20) {
                        if (retries--) {
-                               printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
+                               printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
                                timeo = jiffies + HZ;
                                put_chip(map, chip, adr);
                                spin_unlock(chip->mutex);
                                goto retry;
                        }
-                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
+                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus);
                        ret = -EIO;
                }
        } else {
@@ -1882,6 +1793,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
                
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
+                       chip->oldstate = FL_READY;
                        wake_up(&chip->wq);
                }
                spin_unlock(chip->mutex);
@@ -1897,8 +1809,9 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map,
        struct cfi_private *cfi = map->fldrv_priv;
        int status, ofs_factor = cfi->interleave * cfi->device_type;
 
+       adr += chip->start;
        xip_disable(map, chip, adr+(2*ofs_factor));
-       cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+       map_write(map, CMD(0x90), adr+(2*ofs_factor));
        chip->state = FL_JEDEC_QUERY;
        status = cfi_read_query(map, adr+(2*ofs_factor));
        xip_enable(map, chip, 0);
@@ -1915,6 +1828,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
                                       unsigned long adr, int len, void *thunk)
 {
        struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
        map_word status, status_OK;
        unsigned long timeo = jiffies + HZ;
        int ret;
@@ -1944,9 +1858,13 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
        } else
                BUG();
 
-       spin_unlock(chip->mutex);
-       UDELAY(map, chip, adr, 1000000/HZ);
-       spin_lock(chip->mutex);
+       /*
+        * If Instant Individual Block Locking supported then no need
+        * to delay.
+        */
+
+       if (!extp || !(extp->FeatureSupport & (1 << 5)))
+               UDELAY(map, chip, adr, 1000000/HZ);
 
        /* FIXME. Use a timer to check this, and return immediately. */
        /* Once the state machine's known to be working I'll do that */
@@ -1973,9 +1891,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
                }
                
                /* Latency issues. Drop the lock, wait a while and retry */
-               spin_unlock(chip->mutex);
                UDELAY(map, chip, adr, 1);
-               spin_lock(chip->mutex);
        }
        
        /* Done and happy. */
@@ -2034,6 +1950,274 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
        return ret;
 }
 
+#ifdef CONFIG_MTD_OTP
+
+typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, 
+                       u_long data_offset, u_char *buf, u_int size,
+                       u_long prot_offset, u_int groupno, u_int groupsize);
+
+static int __xipram
+do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
+           u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       int ret;
+
+       spin_lock(chip->mutex);
+       ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
+       if (ret) {
+               spin_unlock(chip->mutex);
+               return ret;
+       }
+
+       /* let's ensure we're not reading back cached data from array mode */
+       INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
+
+       xip_disable(map, chip, chip->start);
+       if (chip->state != FL_JEDEC_QUERY) {
+               map_write(map, CMD(0x90), chip->start);
+               chip->state = FL_JEDEC_QUERY;
+       }
+       map_copy_from(map, buf, chip->start + offset, size);
+       xip_enable(map, chip, chip->start);
+
+       /* then ensure we don't keep OTP data in the cache */
+       INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
+
+       put_chip(map, chip, chip->start);
+       spin_unlock(chip->mutex);
+       return 0;
+}
+
+static int
+do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
+            u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       int ret;
+
+       while (size) {
+               unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
+               int gap = offset - bus_ofs;
+               int n = min_t(int, size, map_bankwidth(map)-gap);
+               map_word datum = map_word_ff(map);
+
+               datum = map_word_load_partial(map, datum, buf, gap, n);
+               ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
+               if (ret) 
+                       return ret;
+
+               offset += n;
+               buf += n;
+               size -= n;
+       }
+
+       return 0;
+}
+
+static int
+do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
+           u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       map_word datum;
+
+       /* make sure area matches group boundaries */
+       if (size != grpsz)
+               return -EXDEV;
+
+       datum = map_word_ff(map);
+       datum = map_word_clr(map, datum, CMD(1 << grpno));
+       return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
+}
+
+static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
+                                size_t *retlen, u_char *buf,
+                                otp_op_t action, int user_regs)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+       struct flchip *chip;
+       struct cfi_intelext_otpinfo *otp;
+       u_long devsize, reg_prot_offset, data_offset;
+       u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
+       u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
+       int ret;
+
+       *retlen = 0;
+
+       /* Check that we actually have some OTP registers */
+       if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
+               return -ENODATA;
+
+       /* we need real chips here not virtual ones */
+       devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
+       chip_step = devsize >> cfi->chipshift;
+       chip_num = 0;
+
+       /* Some chips have OTP located in the _top_ partition only.
+          For example: Intel 28F256L18T (T means top-parameter device) */
+       if (cfi->mfr == MANUFACTURER_INTEL) {
+               switch (cfi->id) {
+               case 0x880b:
+               case 0x880c:
+               case 0x880d:
+                       chip_num = chip_step - 1;
+               }
+       }
+
+       for ( ; chip_num < cfi->numchips; chip_num += chip_step) {
+               chip = &cfi->chips[chip_num];
+               otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
+
+               /* first OTP region */
+               field = 0;
+               reg_prot_offset = extp->ProtRegAddr;
+               reg_fact_groups = 1;
+               reg_fact_size = 1 << extp->FactProtRegSize;
+               reg_user_groups = 1;
+               reg_user_size = 1 << extp->UserProtRegSize;
+
+               while (len > 0) {
+                       /* flash geometry fixup */
+                       data_offset = reg_prot_offset + 1;
+                       data_offset *= cfi->interleave * cfi->device_type;
+                       reg_prot_offset *= cfi->interleave * cfi->device_type;
+                       reg_fact_size *= cfi->interleave;
+                       reg_user_size *= cfi->interleave;
+
+                       if (user_regs) {
+                               groups = reg_user_groups;
+                               groupsize = reg_user_size;
+                               /* skip over factory reg area */
+                               groupno = reg_fact_groups;
+                               data_offset += reg_fact_groups * reg_fact_size;
+                       } else {
+                               groups = reg_fact_groups;
+                               groupsize = reg_fact_size;
+                               groupno = 0;
+                       }
+
+                       while (len > 0 && groups > 0) {
+                               if (!action) {
+                                       /*
+                                        * Special case: if action is NULL
+                                        * we fill buf with otp_info records.
+                                        */
+                                       struct otp_info *otpinfo;
+                                       map_word lockword;
+                                       len -= sizeof(struct otp_info);
+                                       if (len <= 0)
+                                               return -ENOSPC;
+                                       ret = do_otp_read(map, chip,
+                                                         reg_prot_offset,
+                                                         (u_char *)&lockword,
+                                                         map_bankwidth(map),
+                                                         0, 0,  0);
+                                       if (ret)
+                                               return ret;
+                                       otpinfo = (struct otp_info *)buf;
+                                       otpinfo->start = from;
+                                       otpinfo->length = groupsize;
+                                       otpinfo->locked =
+                                          !map_word_bitsset(map, lockword,
+                                                            CMD(1 << groupno));
+                                       from += groupsize;
+                                       buf += sizeof(*otpinfo);
+                                       *retlen += sizeof(*otpinfo);
+                               } else if (from >= groupsize) {
+                                       from -= groupsize;
+                                       data_offset += groupsize;
+                               } else {
+                                       int size = groupsize;
+                                       data_offset += from;
+                                       size -= from;
+                                       from = 0;
+                                       if (size > len)
+                                               size = len;
+                                       ret = action(map, chip, data_offset,
+                                                    buf, size, reg_prot_offset,
+                                                    groupno, groupsize);
+                                       if (ret < 0)
+                                               return ret;
+                                       buf += size;
+                                       len -= size;
+                                       *retlen += size;
+                                       data_offset += size;
+                               }
+                               groupno++;
+                               groups--;
+                       }
+
+                       /* next OTP region */
+                       if (++field == extp->NumProtectionFields)
+                               break;
+                       reg_prot_offset = otp->ProtRegAddr;
+                       reg_fact_groups = otp->FactGroups;
+                       reg_fact_size = 1 << otp->FactProtRegSize;
+                       reg_user_groups = otp->UserGroups;
+                       reg_user_size = 1 << otp->UserProtRegSize;
+                       otp++;
+               }
+       }
+
+       return 0;
+}
+
+static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
+                                          size_t len, size_t *retlen,
+                                           u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_read, 0);
+}
+
+static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
+                                          size_t len, size_t *retlen,
+                                           u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_read, 1);
+}
+
+static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
+                                           size_t len, size_t *retlen,
+                                            u_char *buf)
+{
+       return cfi_intelext_otp_walk(mtd, from, len, retlen,
+                                    buf, do_otp_write, 1);
+}
+
+static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
+                                          loff_t from, size_t len)
+{
+       size_t retlen;
+       return cfi_intelext_otp_walk(mtd, from, len, &retlen,
+                                    NULL, do_otp_lock, 1);
+}
+
+static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, 
+                                          struct otp_info *buf, size_t len)
+{
+       size_t retlen;
+       int ret;
+
+       ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
+       return ret ? : retlen;
+}
+
+static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
+                                          struct otp_info *buf, size_t len)
+{
+       size_t retlen;
+       int ret;
+
+       ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
+       return ret ? : retlen;
+}
+
+#endif
+
 static int cfi_intelext_suspend(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
@@ -2125,10 +2309,46 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
        }
 }
 
+static int cfi_intelext_reset(struct mtd_info *mtd)
+{
+       struct map_info *map = mtd->priv;
+       struct cfi_private *cfi = map->fldrv_priv;
+       int i, ret;
+
+       for (i=0; i < cfi->numchips; i++) {
+               struct flchip *chip = &cfi->chips[i];
+
+               /* force the completion of any ongoing operation
+                  and switch to array mode so any bootloader in 
+                  flash is accessible for soft reboot. */
+               spin_lock(chip->mutex);
+               ret = get_chip(map, chip, chip->start, FL_SYNCING);
+               if (!ret) {
+                       map_write(map, CMD(0xff), chip->start);
+                       chip->state = FL_READY;
+               }
+               spin_unlock(chip->mutex);
+       }
+
+       return 0;
+}
+
+static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,
+                              void *v)
+{
+       struct mtd_info *mtd;
+
+       mtd = container_of(nb, struct mtd_info, reboot_notifier);
+       cfi_intelext_reset(mtd);
+       return NOTIFY_DONE;
+}
+
 static void cfi_intelext_destroy(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
+       cfi_intelext_reset(mtd);
+       unregister_reboot_notifier(&mtd->reboot_notifier);
        kfree(cfi->cmdset_priv);
        kfree(cfi->cfiq);
        kfree(cfi->chips[0].priv);
index fca8ff6f7e140eb0518be9a6a9b96b9ee9ccb146..49cd81207137b5aaf742e29e5cfc275af230022f 100644 (file)
@@ -13,7 +13,7 @@
  *
  * This code is GPL
  *
- * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.116 2005/05/24 13:29:42 gleixner Exp $
  *
  */
 
@@ -43,6 +43,7 @@
 #define MANUFACTURER_AMD       0x0001
 #define MANUFACTURER_SST       0x00BF
 #define SST49LF004B            0x0060
+#define SST49LF008A            0x005a
 
 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -191,6 +192,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, SST49LF008A, fixup_use_fwh_lock, NULL, },
        { 0, 0, NULL, NULL }
 };
 
@@ -401,6 +403,32 @@ static int chip_ready(struct map_info *map, unsigned long addr)
        return map_word_equal(map, d, t);
 }
 
+/*
+ * Return true if the chip is ready and has the correct value.
+ *
+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
+ * non-suspended sector) and it is indicated by no bits toggling.
+ *
+ * Error are indicated by toggling bits or bits held with the wrong value,
+ * or with bits toggling.
+ *
+ * Note that anything more complicated than checking if no bits are toggling
+ * (including checking DQ5 for an error status) is tricky to get working
+ * correctly and is therefore not done (particulary with interleaved chips
+ * as each chip must be checked independantly of the others).
+ *
+ */
+static int chip_good(struct map_info *map, unsigned long addr, map_word expected)
+{
+       map_word oldd, curd;
+
+       oldd = map_read(map, addr);
+       curd = map_read(map, addr);
+
+       return  map_word_equal(map, oldd, curd) && 
+               map_word_equal(map, curd, expected);
+}
+
 static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
        DECLARE_WAITQUEUE(wait, current);
@@ -765,26 +793,29 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
                }
 
                if (chip_ready(map, adr))
-                       goto op_done;
+                       break;
 
-               if (time_after(jiffies, timeo))
+               if (time_after(jiffies, timeo)) {
+                       printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
                         break;
+               }
 
                /* Latency issues. Drop the lock, wait a while and retry */
                cfi_spin_unlock(chip->mutex);
                cfi_udelay(1);
                cfi_spin_lock(chip->mutex);
        }
+       /* Did we succeed? */
+       if (!chip_good(map, adr, datum)) {
+               /* reset on all failures. */
+               map_write( map, CMD(0xF0), chip->start );
+               /* FIXME - should have reset delay before continuing */
 
-       printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
-
-       /* reset on all failures. */
-       map_write( map, CMD(0xF0), chip->start );
-       /* FIXME - should have reset delay before continuing */
-       if (++retry_cnt <= MAX_WORD_RETRIES) 
-               goto retry;
+               if (++retry_cnt <= MAX_WORD_RETRIES) 
+                       goto retry;
 
-       ret = -EIO;
+               ret = -EIO;
+       }
  op_done:
        chip->state = FL_READY;
        put_chip(map, chip, adr);
@@ -1187,10 +1218,13 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
                }
 
                if (chip_ready(map, adr))
-                       goto op_done;
+                       break;
 
-               if (time_after(jiffies, timeo))
+               if (time_after(jiffies, timeo)) {
+                       printk(KERN_WARNING "MTD %s(): software timeout\n",
+                               __func__ );
                        break;
+               }
 
                /* Latency issues. Drop the lock, wait a while and retry */
                cfi_spin_unlock(chip->mutex);
@@ -1198,16 +1232,15 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
                schedule_timeout(1);
                cfi_spin_lock(chip->mutex);
        }
+       /* Did we succeed? */
+       if (!chip_good(map, adr, map_word_ff(map))) {
+               /* reset on all failures. */
+               map_write( map, CMD(0xF0), chip->start );
+               /* FIXME - should have reset delay before continuing */
 
-       printk(KERN_WARNING "MTD %s(): software timeout\n",
-              __func__ );
-
-       /* reset on all failures. */
-       map_write( map, CMD(0xF0), chip->start );
-       /* FIXME - should have reset delay before continuing */
+               ret = -EIO;
+       }
 
-       ret = -EIO;
- op_done:
        chip->state = FL_READY;
        put_chip(map, chip, adr);
        cfi_spin_unlock(chip->mutex);
@@ -1272,10 +1305,13 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
                }
 
                if (chip_ready(map, adr))
-                       goto op_done;
+                       break;
 
-               if (time_after(jiffies, timeo))
+               if (time_after(jiffies, timeo)) {
+                       printk(KERN_WARNING "MTD %s(): software timeout\n",
+                               __func__ );
                        break;
+               }
 
                /* Latency issues. Drop the lock, wait a while and retry */
                cfi_spin_unlock(chip->mutex);
@@ -1283,16 +1319,15 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
                schedule_timeout(1);
                cfi_spin_lock(chip->mutex);
        }
-       
-       printk(KERN_WARNING "MTD %s(): software timeout\n",
-              __func__ );
-       
-       /* reset on all failures. */
-       map_write( map, CMD(0xF0), chip->start );
-       /* FIXME - should have reset delay before continuing */
+       /* Did we succeed? */
+       if (!chip_good(map, adr, map_word_ff(map))) {
+               /* reset on all failures. */
+               map_write( map, CMD(0xF0), chip->start );
+               /* FIXME - should have reset delay before continuing */
+
+               ret = -EIO;
+       }
 
-       ret = -EIO;
- op_done:
        chip->state = FL_READY;
        put_chip(map, chip, adr);
        cfi_spin_unlock(chip->mutex);
index fc982c4671f0cb7a976ce355cc01ecfb4eb6d5c6..dc065b22f79ece4ee37440038c965766cfcaa8d4 100644 (file)
@@ -2,7 +2,7 @@
  * Routines common to all CFI-type probes.
  * (C) 2001-2003 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $
  */
 
 #include <linux/kernel.h>
@@ -162,7 +162,7 @@ static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
        int max_chips = map_bankwidth(map); /* And minimum 1 */
        int nr_chips, type;
 
-       for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
+       for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
 
                if (!cfi_interleave_supported(nr_chips))
                    continue;
index 30325a25ab953e3f4bdc18515af0dfae4e83b4c9..30da428eb7b99e0c9a265928d8d4303654a21264 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
+   $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $
    See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
    for the standard this probe goes back to.
 
 #define SST29LE512     0x003d
 #define SST39LF800     0x2781
 #define SST39LF160     0x2782
+#define SST39VF1601    0x234b
 #define SST39LF512     0x00D4
 #define SST39LF010     0x00D5
 #define SST39LF020     0x00D6
@@ -1448,6 +1449,21 @@ static const struct amd_flash_info jedec_table[] = {
                        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_ST,      /* FIXME - CFI device? */
@@ -1856,6 +1872,16 @@ static inline int jedec_match( __u32 base,
        case CFI_DEVICETYPE_X8:
                mfr = (__u8)finfo->mfr_id;
                id = (__u8)finfo->dev_id;
+
+               /* bjd: it seems that if we do this, we can end up
+                * detecting 16bit flashes as an 8bit device, even though
+                * there aren't.
+                */
+               if (finfo->dev_id > 0xff) {
+                       DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n",
+                              __func__);
+                       goto match_done;
+               }
                break;
        case CFI_DEVICETYPE_X16:
                mfr = (__u16)finfo->mfr_id;
index cfe6ccf07972e26c3c8ae186016117b381d0e627..4a7a805e7564c4d359f9049daf1ebc54a284c39b 100644 (file)
@@ -1,10 +1,9 @@
 /*
- * $Id: block2mtd.c,v 1.23 2005/01/05 17:05:46 dwmw2 Exp $
+ * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $
  *
  * block2mtd.c - create an mtd from a block device
  *
  * Copyright (C) 2001,2002     Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004          Gareth Bult <Gareth@Encryptec.net>
  * Copyright (C) 2004,2005     Jörn Engel <joern@wh.fh-wedel.de>
  *
  * Licence: GPL
@@ -20,7 +19,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/buffer_head.h>
 
-#define VERSION "$Revision: 1.23 $"
+#define VERSION "$Revision: 1.28 $"
 
 
 #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
@@ -89,7 +88,6 @@ void cache_readahead(struct address_space *mapping, int index)
 static struct page* page_readahead(struct address_space *mapping, int index)
 {
        filler_t *filler = (filler_t*)mapping->a_ops->readpage;
-       //do_page_cache_readahead(mapping, index, XXX, 64);
        cache_readahead(mapping, index);
        return read_cache_page(mapping, index, filler, NULL);
 }
@@ -157,7 +155,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
        struct block2mtd_dev *dev = mtd->priv;
        struct page *page;
        int index = from >> PAGE_SHIFT;
-       int offset = from & (PAGE_SHIFT-1);
+       int offset = from & (PAGE_SIZE-1);
        int cpylen;
 
        if (from > mtd->size)
@@ -370,16 +368,16 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
 }
 
 
-static int parse_num32(u32 *num32, const char *token)
+static int parse_num(size_t *num, const char *token)
 {
        char *endp;
-       unsigned long n;
+       size_t n;
 
-       n = ustrtoul(token, &endp, 0);
+       n = (size_t) ustrtoul(token, &endp, 0);
        if (*endp)
                return -EINVAL;
 
-       *num32 = n;
+       *num = n;
        return 0;
 }
 
@@ -422,7 +420,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
        char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
        char *token[2];
        char *name;
-       u32 erase_size = PAGE_SIZE;
+       size_t erase_size = PAGE_SIZE;
        int i, ret;
 
        if (strnlen(val, sizeof(buf)) >= sizeof(buf))
@@ -449,7 +447,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
                return 0;
 
        if (token[1]) {
-               ret = parse_num32(&erase_size, token[1]);
+               ret = parse_num(&erase_size, token[1]);
                if (ret)
                        parse_err("illegal erase size");
        }
index edac4156d69c86003385ba4cdbc4a83ee63f2074..bb713fed2f373c66fd13e8f29be3abbc733963bb 100644 (file)
@@ -1,9 +1,10 @@
 /*
  * mtdram - a test mtd device
- * $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $
  * Author: Alexander Larsson <alex@cendio.se>
  *
  * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
+ * Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de>
  *
  * This code is GPL
  *
 #include <linux/mtd/compatmac.h>
 #include <linux/mtd/mtd.h>
 
-#ifndef CONFIG_MTDRAM_ABS_POS
-  #define CONFIG_MTDRAM_ABS_POS 0
-#endif
-
-#if CONFIG_MTDRAM_ABS_POS > 0
-  #include <asm/io.h>
-#endif
-
-#ifdef MODULE
 static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
 static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
-module_param(total_size,ulong,0);
-MODULE_PARM_DESC(total_size, "Total device size in KiB");
-module_param(erase_size,ulong,0);
-MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
 #define MTDRAM_TOTAL_SIZE (total_size * 1024)
 #define MTDRAM_ERASE_SIZE (erase_size * 1024)
-#else
-#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024)
-#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024)
-#endif
 
+#ifdef MODULE
+module_param(total_size, ulong, 0);
+MODULE_PARM_DESC(total_size, "Total device size in KiB");
+module_param(erase_size, ulong, 0);
+MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
+#endif
 
 // We could store these in the mtd structure, but we only support 1 device..
 static struct mtd_info *mtd_info;
 
-
-static int
-ram_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-  DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
-  if (instr->addr + instr->len > mtd->size) {
-    DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size);
-    return -EINVAL;
-  }
-       
-  memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
-       
-  instr->state = MTD_ERASE_DONE;
-  mtd_erase_callback(instr);
-
-  return 0;
+       if (instr->addr + instr->len > mtd->size)
+               return -EINVAL;
+
+       memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
+
+       instr->state = MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+
+       return 0;
 }
 
-static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, u_char **mtdbuf)
 {
-  if (from + len > mtd->size)
-    return -EINVAL;
-       
-  *mtdbuf = mtd->priv + from;
-  *retlen = len;
-  return 0;
+       if (from + len > mtd->size)
+               return -EINVAL;
+
+       *mtdbuf = mtd->priv + from;
+       *retlen = len;
+       return 0;
 }
 
-static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
-                        size_t len)
+static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
+               size_t len)
 {
-  DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
 }
 
 static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
-            size_t *retlen, u_char *buf)
+               size_t *retlen, u_char *buf)
 {
-  DEBUG(MTD_DEBUG_LEVEL2, "ram_read(pos:%ld, len:%ld)\n", (long)from, (long)len);
-  if (from + len > mtd->size) {
-    DEBUG(MTD_DEBUG_LEVEL1, "ram_read() out of bounds (%ld > %ld)\n", (long)(from + len), (long)mtd->size);
-    return -EINVAL;
-  }
+       if (from + len > mtd->size)
+               return -EINVAL;
 
-  memcpy(buf, mtd->priv + from, len);
+       memcpy(buf, mtd->priv + from, len);
 
-  *retlen=len;
-  return 0;
+       *retlen = len;
+       return 0;
 }
 
 static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
-             size_t *retlen, const u_char *buf)
+               size_t *retlen, const u_char *buf)
 {
-  DEBUG(MTD_DEBUG_LEVEL2, "ram_write(pos:%ld, len:%ld)\n", (long)to, (long)len);
-  if (to + len > mtd->size) {
-    DEBUG(MTD_DEBUG_LEVEL1, "ram_write() out of bounds (%ld > %ld)\n", (long)(to + len), (long)mtd->size);
-    return -EINVAL;
-  }
+       if (to + len > mtd->size)
+               return -EINVAL;
 
-  memcpy ((char *)mtd->priv + to, buf, len);
+       memcpy((char *)mtd->priv + to, buf, len);
 
-  *retlen=len;
-  return 0;
+       *retlen = len;
+       return 0;
 }
 
 static void __exit cleanup_mtdram(void)
 {
-  if (mtd_info) {
-    del_mtd_device(mtd_info);
-#if CONFIG_MTDRAM_TOTAL_SIZE > 0
-    if (mtd_info->priv)
-#if CONFIG_MTDRAM_ABS_POS > 0
-      iounmap(mtd_info->priv);
-#else
-      vfree(mtd_info->priv);
-#endif 
-#endif
-    kfree(mtd_info);
-  }
-}
-
-int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, 
-                       unsigned long size, char *name)
-{
-   memset(mtd, 0, sizeof(*mtd));
-
-   /* Setup the MTD structure */
-   mtd->name = name;
-   mtd->type = MTD_RAM;
-   mtd->flags = MTD_CAP_RAM;
-   mtd->size = size;
-   mtd->erasesize = MTDRAM_ERASE_SIZE;
-   mtd->priv = mapped_address;
-
-   mtd->owner = THIS_MODULE;
-   mtd->erase = ram_erase;
-   mtd->point = ram_point;
-   mtd->unpoint = ram_unpoint;
-   mtd->read = ram_read;
-   mtd->write = ram_write;
-
-   if (add_mtd_device(mtd)) {
-     return -EIO;
-   }
-   
-   return 0;
-}
-
-#if CONFIG_MTDRAM_TOTAL_SIZE > 0
-#if CONFIG_MTDRAM_ABS_POS > 0
-static int __init init_mtdram(void)
-{
-  void *addr;
-  int err;
-  /* Allocate some memory */
-   mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-   if (!mtd_info)
-     return -ENOMEM;
-   
-  addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
-  if (!addr) {
-    DEBUG(MTD_DEBUG_LEVEL1, 
-          "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n", 
-          (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
-    kfree(mtd_info);
-    mtd_info = NULL;
-    return -ENOMEM;
-  }
-  err = mtdram_init_device(mtd_info, addr, 
-                           MTDRAM_TOTAL_SIZE, "mtdram test device");
-  if (err) 
-  {
-    iounmap(addr);
-    kfree(mtd_info);
-    mtd_info = NULL;
-    return err;
-  }
-  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
-  return err;
+       if (mtd_info) {
+               del_mtd_device(mtd_info);
+               if (mtd_info->priv)
+                       vfree(mtd_info->priv);
+               kfree(mtd_info);
+       }
 }
 
-#else /* CONFIG_MTDRAM_ABS_POS > 0 */
-
-static int __init init_mtdram(void)
+int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
+               unsigned long size, char *name)
 {
-  void *addr;
-  int err;
-  /* Allocate some memory */
-   mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-   if (!mtd_info)
-     return -ENOMEM;
-
-  addr = vmalloc(MTDRAM_TOTAL_SIZE);
-  if (!addr) {
-    DEBUG(MTD_DEBUG_LEVEL1, 
-          "Failed to vmalloc memory region of size %ld\n", 
-          (long)MTDRAM_TOTAL_SIZE);
-    kfree(mtd_info);
-    mtd_info = NULL;
-    return -ENOMEM;
-  }
-  err = mtdram_init_device(mtd_info, addr, 
-                           MTDRAM_TOTAL_SIZE, "mtdram test device");
-  if (err) 
-  {
-    vfree(addr);
-    kfree(mtd_info);
-    mtd_info = NULL;
-    return err;
-  }
-  memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
-  return err;
+       memset(mtd, 0, sizeof(*mtd));
+
+       /* Setup the MTD structure */
+       mtd->name = name;
+       mtd->type = MTD_RAM;
+       mtd->flags = MTD_CAP_RAM;
+       mtd->size = size;
+       mtd->erasesize = MTDRAM_ERASE_SIZE;
+       mtd->priv = mapped_address;
+
+       mtd->owner = THIS_MODULE;
+       mtd->erase = ram_erase;
+       mtd->point = ram_point;
+       mtd->unpoint = ram_unpoint;
+       mtd->read = ram_read;
+       mtd->write = ram_write;
+
+       if (add_mtd_device(mtd)) {
+               return -EIO;
+       }
+
+       return 0;
 }
-#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */
-
-#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
 
 static int __init init_mtdram(void)
 {
-  return 0;
+       void *addr;
+       int err;
+
+       if (!total_size)
+               return -EINVAL;
+
+       /* Allocate some memory */
+       mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+       if (!mtd_info)
+               return -ENOMEM;
+
+       addr = vmalloc(MTDRAM_TOTAL_SIZE);
+       if (!addr) {
+               kfree(mtd_info);
+               mtd_info = NULL;
+               return -ENOMEM;
+       }
+       err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device");
+       if (err) {
+               vfree(addr);
+               kfree(mtd_info);
+               mtd_info = NULL;
+               return err;
+       }
+       memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+       return err;
 }
-#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */
 
 module_init(init_mtdram);
 module_exit(cleanup_mtdram);
@@ -232,4 +160,3 @@ module_exit(cleanup_mtdram);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>");
 MODULE_DESCRIPTION("Simulated MTD driver for testing");
-
index 5f8e164ddb710fa9d219845e1623c35bae73783b..a423a382095a7231f23391979df5f9a6145af580 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * $Id: phram.c,v 1.11 2005/01/05 18:05:13 dwmw2 Exp $
+ * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $
  *
  * Copyright (c) ????          Jochen Schäuble <psionic@psionic.de>
  * Copyright (c) 2003-2004     Jörn Engel <joern@wh.fh-wedel.de>
@@ -15,9 +15,7 @@
  *
  * Example:
  *     phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
- *
  */
-
 #include <asm/io.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -36,7 +34,6 @@ struct phram_mtd_list {
 static LIST_HEAD(phram_list);
 
 
-
 static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
        u_char *start = mtd->priv;
@@ -71,7 +68,8 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
        return 0;
 }
 
-static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
+               size_t len)
 {
 }
 
@@ -80,8 +78,11 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
 {
        u_char *start = mtd->priv;
 
-       if (from + len > mtd->size)
+       if (from >= mtd->size)
                return -EINVAL;
+
+       if (len > mtd->size - from)
+               len = mtd->size - from;
        
        memcpy(buf, start + from, len);
 
@@ -94,8 +95,11 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
 {
        u_char *start = mtd->priv;
 
-       if (to + len > mtd->size)
+       if (to >= mtd->size)
                return -EINVAL;
+
+       if (len > mtd->size - to)
+               len = mtd->size - to;
        
        memcpy(start + to, buf, len);
 
@@ -107,9 +111,9 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 static void unregister_devices(void)
 {
-       struct phram_mtd_list *this;
+       struct phram_mtd_list *this, *safe;
 
-       list_for_each_entry(this, &phram_list, list) {
+       list_for_each_entry_safe(this, safe, &phram_list, list) {
                del_mtd_device(&this->mtd);
                iounmap(this->mtd.priv);
                kfree(this);
@@ -145,7 +149,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
        new->mtd.write = phram_write;
        new->mtd.owner = THIS_MODULE;
        new->mtd.type = MTD_RAM;
-       new->mtd.erasesize = 0;
+       new->mtd.erasesize = PAGE_SIZE;
 
        ret = -EAGAIN;
        if (add_mtd_device(&new->mtd)) {
@@ -214,6 +218,15 @@ static int parse_name(char **pname, const char *token)
        return 0;
 }
 
+
+static inline void kill_final_newline(char *str)
+{
+       char *newline = strrchr(str, '\n');
+       if (newline && !newline[1])
+               *newline = 0;
+}
+
+
 #define parse_err(fmt, args...) do {   \
        ERROR(fmt , ## args);   \
        return 0;               \
@@ -232,6 +245,7 @@ static int phram_setup(const char *val, struct kernel_param *kp)
                parse_err("parameter too long\n");
 
        strcpy(str, val);
+       kill_final_newline(str);
 
        for (i=0; i<3; i++)
                token[i] = strsep(&str, ",");
index 5ab15e643be789485b48bcd3d92b7c6da12199f6..84fa91392a8c7180b5113a15a290e76f49f4a50a 100644 (file)
@@ -1,6 +1,6 @@
 /*======================================================================
 
-  $Id: slram.c,v 1.33 2005/01/05 18:05:13 dwmw2 Exp $
+  $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $
 
   This driver provides a method to access memory not used by the kernel
   itself (i.e. if the kernel commandline mem=xxx is used). To actually
@@ -50,6 +50,7 @@
 #include <linux/mtd/mtd.h>
 
 #define SLRAM_MAX_DEVICES_PARAMS 6             /* 3 parameters / device */
+#define SLRAM_BLK_SZ 0x4000
 
 #define T(fmt, args...) printk(KERN_DEBUG fmt, ## args)
 #define E(fmt, args...) printk(KERN_NOTICE fmt, ## args)
@@ -108,6 +109,9 @@ static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
 {
        slram_priv_t *priv = mtd->priv;
 
+       if (from + len > mtd->size)
+               return -EINVAL;
+
        *mtdbuf = priv->start + from;
        *retlen = len;
        return(0);
@@ -121,7 +125,13 @@ static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
                size_t *retlen, u_char *buf)
 {
        slram_priv_t *priv = mtd->priv;
-       
+
+       if (from > mtd->size)
+               return -EINVAL;
+
+       if (from + len > mtd->size)
+               len = mtd->size - from;
+
        memcpy(buf, priv->start + from, len);
 
        *retlen = len;
@@ -133,6 +143,9 @@ static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
 {
        slram_priv_t *priv = mtd->priv;
 
+       if (to + len > mtd->size)
+               return -EINVAL;
+
        memcpy(priv->start + to, buf, len);
 
        *retlen = len;
@@ -188,7 +201,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
        (*curmtd)->mtdinfo->name = name;
        (*curmtd)->mtdinfo->size = length;
        (*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
-                                       MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
+                                       MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM;
         (*curmtd)->mtdinfo->erase = slram_erase;
        (*curmtd)->mtdinfo->point = slram_point;
        (*curmtd)->mtdinfo->unpoint = slram_unpoint;
@@ -196,7 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
        (*curmtd)->mtdinfo->write = slram_write;
        (*curmtd)->mtdinfo->owner = THIS_MODULE;
        (*curmtd)->mtdinfo->type = MTD_RAM;
-       (*curmtd)->mtdinfo->erasesize = 0x0;
+       (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
 
        if (add_mtd_device((*curmtd)->mtdinfo)) {
                E("slram: Failed to register new device\n");
@@ -261,7 +274,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
        }
        T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n",
                        devname, devstart, devlength);
-       if ((devstart < 0) || (devlength < 0)) {
+       if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) {
                E("slram: Illegal start / length parameter.\n");
                return(-EINVAL);
        }
index 18cc8846e7337015609eb1c0ff449dc5ebaf2d1e..d9ab60b36fd43d571995165d3df190fdbebbb01b 100644 (file)
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $
+ * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -357,6 +357,7 @@ static int erase_xfer(partition_t *part,
     if (!erase) 
             return -ENOMEM;
 
+    erase->mtd = part->mbd.mtd;
     erase->callback = ftl_erase_callback;
     erase->addr = xfer->Offset;
     erase->len = 1 << part->header.EraseUnitSize;
@@ -1096,7 +1097,7 @@ struct mtd_blktrans_ops ftl_tr = {
 
 int init_ftl(void)
 {
-       DEBUG(0, "$Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $\n");
+       DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
 
        return register_mtd_blktrans(&ftl_tr);
 }
index 8480057eadb494da50bc1c1f428c80b3c6bfc795..8d27dbf3fa8eee3b412a202eafea3a75346f6fd5 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.42 2005/01/05 16:59:50 dwmw2 Exp $
+# $Id: Kconfig,v 1.51 2005/03/18 02:07:22 gleixner Exp $
 
 menu "Mapping drivers for chip access"
        depends on MTD!=n
@@ -122,16 +122,6 @@ config MTD_SBC_GXX
          More info at
          <http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>.
 
-config MTD_ELAN_104NC
-       tristate "CFI Flash device mapped on Arcom ELAN-104NC"
-       depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS
-       help
-         This provides a driver for the on-board flash of the Arcom Control
-         System's ELAN-104NC development board. By default the flash
-         is split into 3 partitions which are accessed as separate MTD
-         devices. This board utilizes Intel StrataFlash. More info at
-         <http://www.arcomcontrols.com/products/icp/pc104/processors/ELAN104NC.htm>.
-
 config MTD_LUBBOCK
        tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
        depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
@@ -213,74 +203,11 @@ config MTD_NETtel
        help
          Support for flash chips on NETtel/SecureEdge/SnapGear boards.
 
-config MTD_PB1XXX
-       tristate "Flash devices on Alchemy PB1xxx boards"
-       depends on MIPS && ( MIPS_PB1000 || MIPS_PB1100 || MIPS_PB1500 )
-       help
-         Flash memory access on Alchemy Pb1000/Pb1100/Pb1500 boards
-
-config MTD_PB1XXX_BOOT
-       bool "PB1x00 boot flash device"
-       depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
-       help
-         Use the first of the two 32MiB flash banks on Pb1100/Pb1500 board.
-         You can say 'Y' to both this and 'MTD_PB1XXX_USER' below, to use
-         both banks.
-
-config MTD_PB1XXX_USER
-       bool "PB1x00 user flash device"
-       depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
-       default y if MTD_PB1XX_BOOT = n
-       help
-         Use the second of the two 32MiB flash banks on Pb1100/Pb1500 board.
-         You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use
-         both banks.
-
-config MTD_PB1550
-       tristate "Flash devices on Alchemy PB1550 board"
-       depends on MIPS && MIPS_PB1550
+config MTD_ALCHEMY
+       tristate '  AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' 
+       depends on MIPS && SOC_AU1X00
        help
-         Flash memory access on Alchemy Pb1550 board
-
-config MTD_PB1550_BOOT
-       bool "PB1550 boot flash device"
-       depends on MTD_PB1550
-       help
-         Use the first of the two 64MiB flash banks on Pb1550 board.
-         You can say 'Y' to both this and 'MTD_PB1550_USER' below, to use
-         both banks.
-
-config MTD_PB1550_USER
-       bool "PB1550 user flash device"
-       depends on MTD_PB1550
-       default y if MTD_PB1550_BOOT = n
-       help
-         Use the second of the two 64MiB flash banks on Pb1550 board.
-         You can say 'Y' to both this and 'MTD_PB1550_BOOT' above, to use
-         both banks.
-
-config MTD_DB1550
-       tristate "Flash devices on Alchemy DB1550 board"
-       depends on MIPS && MIPS_DB1550
-       help
-         Flash memory access on Alchemy Db1550 board
-
-config MTD_DB1550_BOOT
-       bool "DB1550 boot flash device"
-       depends on MTD_DB1550
-       help
-         Use the first of the two 64MiB flash banks on Db1550 board.
-         You can say 'Y' to both this and 'MTD_DB1550_USER' below, to use
-         both banks.
-
-config MTD_DB1550_USER
-       bool "DB1550 user flash device"
-       depends on MTD_DB1550
-       default y if MTD_DB1550_BOOT = n
-       help
-         Use the second of the two 64MiB flash banks on Db1550 board.
-         You can say 'Y' to both this and 'MTD_DB1550_BOOT' above, to use
-         both banks.
+         Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
 
 config MTD_DILNETPC
        tristate "CFI Flash device mapped on DIL/Net PC"
@@ -637,13 +564,14 @@ config MTD_DMV182
           Map driver for Dy-4 SVME/DMV-182 board.
 
 config MTD_BAST
-       tristate "Map driver for Simtec BAST (EB2410ITX)"
-       depends on ARCH_BAST
+       tristate "Map driver for Simtec BAST (EB2410ITX) or Thorcom VR1000"
+       depends on ARCH_BAST || MACH_VR1000
        select MTD_PARTITIONS
        select MTD_MAP_BANK_WIDTH_16
        select MTD_JEDECPROBE
        help
-         Map driver for NOR flash on the Simtec BAST (EB2410ITX).
+         Map driver for NOR flash on the Simtec BAST (EB2410ITX), or the
+         Thorcom VR1000
 
          Note, this driver *cannot* over-ride the WP link on the
          board, or currently detect the state of the link.
@@ -659,5 +587,15 @@ config MTD_SHARP_SL
        help
          This enables access to the flash chip on the Sharp SL Series of PDAs.
 
+config MTD_PLATRAM
+       tristate "Map driver for platform device RAM (mtd-ram)"
+       depends on MTD
+       select MTD_RAM
+       help
+         Map driver for RAM areas described via the platform device
+         system.
+
+         This selection automatically selects the map_ram driver.
+
 endmenu
 
index 7ffe02b85301657650be057ab40949ce1fdec675..164cafc101ca474e8fd546f94b6048d0fbfcc04a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile.common,v 1.23 2005/01/05 17:06:36 dwmw2 Exp $
+# $Id: Makefile.common,v 1.26 2005/03/02 14:51:04 dvrabel Exp $
 
 ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
 obj-$(CONFIG_MTD)              += map_funcs.o
@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
 obj-$(CONFIG_MTD_CSTM_MIPS_IXX)        += cstm_mips_ixx.o
 obj-$(CONFIG_MTD_DC21285)      += dc21285.o
 obj-$(CONFIG_MTD_DILNETPC)     += dilnetpc.o
-obj-$(CONFIG_MTD_ELAN_104NC)   += elan-104nc.o
 obj-$(CONFIG_MTD_EPXA10DB)     += epxa10db-flash.o
 obj-$(CONFIG_MTD_IQ80310)      += iq80310.o
 obj-$(CONFIG_MTD_L440GX)       += l440gx.o
@@ -44,10 +43,7 @@ obj-$(CONFIG_MTD_DBOX2)              += dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)       += ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)          += pci.o
-obj-$(CONFIG_MTD_PB1XXX)       += pb1xxx-flash.o
-obj-$(CONFIG_MTD_DB1X00)        += db1x00-flash.o
-obj-$(CONFIG_MTD_PB1550)        += pb1550-flash.o
-obj-$(CONFIG_MTD_DB1550)        += db1550-flash.o
+obj-$(CONFIG_MTD_ALCHEMY)       += alchemy-flash.o
 obj-$(CONFIG_MTD_LASAT)                += lasat.o
 obj-$(CONFIG_MTD_AUTCPU12)     += autcpu12-nvram.o
 obj-$(CONFIG_MTD_EDB7312)      += edb7312.o
@@ -71,3 +67,4 @@ obj-$(CONFIG_MTD_IXP2000)     += ixp2000.o
 obj-$(CONFIG_MTD_WRSBC8260)    += wr_sbc82xx_flash.o
 obj-$(CONFIG_MTD_DMV182)       += dmv182.o
 obj-$(CONFIG_MTD_SHARP_SL)     += sharpsl-flash.o
+obj-$(CONFIG_MTD_PLATRAM)      += plat-ram.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
new file mode 100644 (file)
index 0000000..27fd2a3
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Flash memory access on AMD Alchemy evaluation boards
+ * 
+ * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $
+ *
+ * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#ifdef         DEBUG_RW
+#define        DBG(x...)       printk(x)
+#else
+#define        DBG(x...)       
+#endif
+
+#ifdef CONFIG_MIPS_PB1000
+#define BOARD_MAP_NAME "Pb1000 Flash"
+#define BOARD_FLASH_SIZE 0x00800000 /* 8MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1500
+#define BOARD_MAP_NAME "Pb1500 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1100
+#define BOARD_MAP_NAME "Pb1100 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1550
+#define BOARD_MAP_NAME "Pb1550 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1200
+#define BOARD_MAP_NAME "Pb1200 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1000
+#define BOARD_MAP_NAME "Db1000 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1500
+#define BOARD_MAP_NAME "Db1500 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1100
+#define BOARD_MAP_NAME "Db1100 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1550
+#define BOARD_MAP_NAME "Db1550 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1200
+#define BOARD_MAP_NAME "Db1200 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_HYDROGEN3
+#define BOARD_MAP_NAME "Hydrogen3 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#define USE_LOCAL_ACCESSORS /* why? */
+#endif
+
+#ifdef CONFIG_MIPS_BOSPORUS
+#define BOARD_MAP_NAME "Bosporus Flash"
+#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_MIRAGE
+#define BOARD_MAP_NAME "Mirage Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#define USE_LOCAL_ACCESSORS /* why? */
+#endif
+
+static struct map_info alchemy_map = {
+       .name = BOARD_MAP_NAME,
+};
+
+static struct mtd_partition alchemy_partitions[] = {
+        {
+                .name = "User FS",
+                .size = BOARD_FLASH_SIZE - 0x00400000,
+                .offset = 0x0000000
+        },{
+                .name = "YAMON",
+                .size = 0x0100000,
+               .offset = MTDPART_OFS_APPEND,
+                .mask_flags = MTD_WRITEABLE
+        },{
+                .name = "raw kernel",
+               .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
+               .offset = MTDPART_OFS_APPEND,
+        }
+};
+
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
+
+static struct mtd_info *mymtd;
+
+int __init alchemy_mtd_init(void)
+{
+       struct mtd_partition *parts;
+       int nb_parts = 0;
+       unsigned long window_addr;
+       unsigned long window_size;
+       
+       /* Default flash buswidth */
+       alchemy_map.bankwidth = BOARD_FLASH_WIDTH;
+
+       window_addr = 0x20000000 - BOARD_FLASH_SIZE;
+       window_size = BOARD_FLASH_SIZE;
+#ifdef CONFIG_MIPS_MIRAGE_WHY
+       /* Boot ROM flash bank only; no user bank */
+       window_addr = 0x1C000000;
+       window_size = 0x04000000;
+       /* USERFS from 0x1C00 0000 to 0x1FC00000 */
+       alchemy_partitions[0].size = 0x03C00000;
+#endif
+
+       /*
+        * Static partition definition selection
+        */
+       parts = alchemy_partitions;
+       nb_parts = NB_OF(alchemy_partitions);
+       alchemy_map.size = window_size;
+
+       /*
+        * Now let's probe for the actual flash.  Do it here since
+        * specific machine settings might have been set above.
+        */
+       printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", 
+                       alchemy_map.bankwidth*8);
+       alchemy_map.virt = ioremap(window_addr, window_size);
+       mymtd = do_map_probe("cfi_probe", &alchemy_map);
+       if (!mymtd) {
+               iounmap(alchemy_map.virt);
+               return -ENXIO;
+       }
+       mymtd->owner = THIS_MODULE;
+
+       add_mtd_partitions(mymtd, parts, nb_parts);
+       return 0;
+}
+
+static void __exit alchemy_mtd_cleanup(void)
+{
+       if (mymtd) {
+               del_mtd_partitions(mymtd);
+               map_destroy(mymtd);
+               iounmap(alchemy_map.virt);
+       }
+}
+
+module_init(alchemy_mtd_init);
+module_exit(alchemy_mtd_cleanup);
+
+MODULE_AUTHOR("Embedded Alley Solutions, Inc");
+MODULE_DESCRIPTION(BOARD_MAP_NAME " MTD driver");
+MODULE_LICENSE("GPL");
index 51e97b05304e4ee37f5bf8a6e3d0b3e0269cde8b..e8a900a77685e4bb024a3c510a2b3e5dc3d11c1b 100644 (file)
@@ -2,7 +2,7 @@
  * amd76xrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $
  */
 
 #include <linux/module.h>
@@ -314,7 +314,7 @@ static int __init init_amd76xrom(void)
        }
        return -ENXIO;
 #if 0
-       return pci_module_init(&amd76xrom_driver);
+       return pci_register_driver(&amd76xrom_driver);
 #endif
 }
 
index 44de3a81b2774e026d628dca870caf49b3e770b9..0c45464e3f7b8636f6d816b280a150e930dea6de 100644 (file)
@@ -1,14 +1,15 @@
 /* linux/drivers/mtd/maps/bast_flash.c
  *
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004-2005 Simtec Electronics
+ *     Ben Dooks <ben@simtec.co.uk>
  *
  * Simtec Bast (EB2410ITX) NOR MTD Mapping driver
  *
  * Changelog:
  *     20-Sep-2004  BJD  Initial version
+ *     17-Jan-2005  BJD  Add whole device if no partitions found
  *
- * $Id: bast-flash.c,v 1.1 2004/09/21 14:29:04 bjd Exp $
+ * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $
  *
  * 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
@@ -46,9 +47,9 @@
 #include <asm/arch/bast-cpld.h>
 
 #ifdef CONFIG_MTD_BAST_MAXSIZE
-#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * (1024*1024))
+#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M)
 #else
-#define AREA_MAXSIZE (32*1024*1024)
+#define AREA_MAXSIZE (32 * SZ_1M)
 #endif
 
 #define PFX "bast-flash: "
@@ -189,6 +190,8 @@ static int bast_flash_probe(struct device *dev)
                err = add_mtd_partitions(info->mtd, info->partitions, err);
                if (err) 
                        printk(KERN_ERR PFX "cannot add/parse partitions\n");
+       } else {
+               err = add_mtd_device(info->mtd);
        }
 
        if (err == 0)
diff --git a/drivers/mtd/maps/db1550-flash.c b/drivers/mtd/maps/db1550-flash.c
deleted file mode 100644 (file)
index d213888..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Flash memory access on Alchemy Db1550 board
- * 
- * $Id: db1550-flash.c,v 1.7 2004/11/04 13:24:14 gleixner Exp $
- *
- * (C) 2004 Embedded Edge, LLC, based on db1550-flash.c:
- * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
- * 
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)       
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-
-
-static struct map_info db1550_map = {
-       .name = "Db1550 flash",
-};
-
-static unsigned char flash_bankwidth = 4;
-
-/* 
- * Support only 64MB NOR Flash parts
- */
-
-#if defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_BOTH_BANKS
-#elif defined(CONFIG_MTD_DB1550_BOOT) && !defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_BOOT_ONLY
-#elif !defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_USER_ONLY
-#endif
-
-#ifdef DB1550_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first 
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition db1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-        * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size =   (0x1FC00000 - 0x18000000),
-                .offset = 0x0000000
-        },{
-                .name = "yamon",
-                .size = 0x0100000,
-               .offset = MTDPART_OFS_APPEND,
-                .mask_flags = MTD_WRITEABLE
-        },{
-                .name = "raw kernel",
-               .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(DB1550_BOOT_ONLY)
-static struct mtd_partition db1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size =   0x03c00000,
-                .offset = 0x0000000
-        },{
-                .name = "yamon",
-                .size = 0x0100000,
-               .offset = MTDPART_OFS_APPEND,
-                .mask_flags = MTD_WRITEABLE
-        },{
-                .name = "raw kernel",
-               .size = (0x300000-0x40000), /* last 256KB is yamon env */
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(DB1550_USER_ONLY)
-static struct mtd_partition db1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
-                .offset = 0x0000000
-        },{
-                .name = "raw kernel",
-               .size = MTDPART_SIZ_FULL,
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#else
-#error MTD_DB1550 define combo error /* should never happen */
-#endif
-
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
-#if defined(DB1550_BOTH_BANKS)
-                       window_addr = 0x18000000;
-                       window_size = 0x8000000; 
-#elif defined(DB1550_BOOT_ONLY)
-                       window_addr = 0x1C000000;
-                       window_size = 0x4000000; 
-#else /* USER ONLY */
-                       window_addr = 0x18000000;
-                       window_size = 0x4000000; 
-#endif
-       return 0;
-}
-
-int __init db1550_mtd_init(void)
-{
-       struct mtd_partition *parts;
-       int nb_parts = 0;
-       
-       /* Default flash bankwidth */
-       db1550_map.bankwidth = flash_bankwidth;
-
-       if (setup_flash_params()) 
-               return -ENXIO;
-
-       /*
-        * Static partition definition selection
-        */
-       parts = db1550_partitions;
-       nb_parts = NB_OF(db1550_partitions);
-       db1550_map.size = window_size;
-
-       /*
-        * Now let's probe for the actual flash.  Do it here since
-        * specific machine settings might have been set above.
-        */
-       printk(KERN_NOTICE "Db1550 flash: probing %d-bit flash bus\n", 
-                       db1550_map.bankwidth*8);
-       db1550_map.virt = ioremap(window_addr, window_size);
-       mymtd = do_map_probe("cfi_probe", &db1550_map);
-       if (!mymtd) return -ENXIO;
-       mymtd->owner = THIS_MODULE;
-
-       add_mtd_partitions(mymtd, parts, nb_parts);
-       return 0;
-}
-
-static void __exit db1550_mtd_cleanup(void)
-{
-       if (mymtd) {
-               del_mtd_partitions(mymtd);
-               map_destroy(mymtd);
-               iounmap((void *) db1550_map.virt);
-       }
-}
-
-module_init(db1550_mtd_init);
-module_exit(db1550_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Db1550 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/db1x00-flash.c b/drivers/mtd/maps/db1x00-flash.c
deleted file mode 100644 (file)
index faa68ec..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Flash memory access on Alchemy Db1xxx boards
- * 
- * $Id: db1x00-flash.c,v 1.6 2004/11/04 13:24:14 gleixner Exp $
- *
- * (C) 2003 Pete Popov <ppopov@embeddedalley.com>
- * 
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)       
-#endif
-
-/* MTD CONFIG OPTIONS */
-#if defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_BOTH_BANKS
-#elif defined(CONFIG_MTD_DB1X00_BOOT) && !defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_BOOT_ONLY
-#elif !defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_USER_ONLY
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-static unsigned long flash_size;
-
-static unsigned short *bcsr = (unsigned short *)0xAE000000;
-static unsigned char flash_bankwidth = 4;
-
-/* 
- * The Db1x boards support different flash densities. We setup
- * the mtd_partition structures below for default of 64Mbit 
- * flash densities, and override the partitions sizes, if
- * necessary, after we check the board status register.
- */
-
-#ifdef DB1X00_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first 
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition db1x00_partitions[] = {
-        {
-                .name         =  "User FS",
-                .size         =  0x1c00000,
-                .offset       =  0x0000000
-        },{
-                .name         =  "yamon",
-                .size         =  0x0100000,
-               .offset       =  MTDPART_OFS_APPEND,
-                .mask_flags   =  MTD_WRITEABLE
-        },{
-                .name         =  "raw kernel",
-               .size         =  (0x300000-0x40000), /* last 256KB is env */
-               .offset       =  MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(DB1X00_BOOT_ONLY)
-static struct mtd_partition db1x00_partitions[] = {
-        {
-                .name         =  "User FS",
-                .size         =  0x00c00000,
-                .offset       =  0x0000000
-        },{
-                .name         =  "yamon",
-                .size         =  0x0100000,
-               .offset       =  MTDPART_OFS_APPEND,
-                .mask_flags   =  MTD_WRITEABLE
-        },{
-                .name         =  "raw kernel",
-               .size         =  (0x300000-0x40000), /* last 256KB is env */
-               .offset       =  MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(DB1X00_USER_ONLY)
-static struct mtd_partition db1x00_partitions[] = {
-        {
-                .name         =  "User FS",
-                .size         =  0x0e00000,
-                .offset       =  0x0000000
-        },{
-                .name         =  "raw kernel",
-               .size         =  MTDPART_SIZ_FULL,
-               .offset       =  MTDPART_OFS_APPEND,
-        }
-};
-#else
-#error MTD_DB1X00 define combo error /* should never happen */
-#endif
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
-#define NAME           "Db1x00 Linux Flash"
-
-static struct map_info db1xxx_mtd_map = {
-       .name           = NAME,
-};
-
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *db1xxx_mtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
-       switch ((bcsr[2] >> 14) & 0x3) {
-               case 0: /* 64Mbit devices */
-                       flash_size = 0x800000; /* 8MB per part */
-#if defined(DB1X00_BOTH_BANKS)
-                       window_addr = 0x1E000000;
-                       window_size = 0x2000000; 
-#elif defined(DB1X00_BOOT_ONLY)
-                       window_addr = 0x1F000000;
-                       window_size = 0x1000000; 
-#else /* USER ONLY */
-                       window_addr = 0x1E000000;
-                       window_size = 0x1000000; 
-#endif
-                       break;
-               case 1:
-                       /* 128 Mbit devices */
-                       flash_size = 0x1000000; /* 16MB per part */
-#if defined(DB1X00_BOTH_BANKS)
-                       window_addr = 0x1C000000;
-                       window_size = 0x4000000;
-                       /* USERFS from 0x1C00 0000 to 0x1FC0 0000 */
-                       db1x00_partitions[0].size = 0x3C00000;
-#elif defined(DB1X00_BOOT_ONLY)
-                       window_addr = 0x1E000000;
-                       window_size = 0x2000000;
-                       /* USERFS from 0x1E00 0000 to 0x1FC0 0000 */
-                       db1x00_partitions[0].size = 0x1C00000;
-#else /* USER ONLY */
-                       window_addr = 0x1C000000;
-                       window_size = 0x2000000;
-                       /* USERFS from 0x1C00 0000 to 0x1DE00000 */
-                       db1x00_partitions[0].size = 0x1DE0000;
-#endif
-                       break;
-               case 2:
-                       /* 256 Mbit devices */
-                       flash_size = 0x4000000; /* 64MB per part */
-#if defined(DB1X00_BOTH_BANKS)
-                       return 1;
-#elif defined(DB1X00_BOOT_ONLY)
-                       /* Boot ROM flash bank only; no user bank */
-                       window_addr = 0x1C000000;
-                       window_size = 0x4000000;
-                       /* USERFS from 0x1C00 0000 to 0x1FC00000 */
-                       db1x00_partitions[0].size = 0x3C00000;
-#else /* USER ONLY */
-                       return 1;
-#endif
-                       break;
-               default:
-                       return 1;
-       }
-       db1xxx_mtd_map.size = window_size;
-       db1xxx_mtd_map.bankwidth = flash_bankwidth;
-       db1xxx_mtd_map.phys = window_addr;
-       db1xxx_mtd_map.bankwidth = flash_bankwidth;
-       return 0;
-}
-
-int __init db1x00_mtd_init(void)
-{
-       struct mtd_partition *parts;
-       int nb_parts = 0;
-       
-       if (setup_flash_params()) 
-               return -ENXIO;
-
-       /*
-        * Static partition definition selection
-        */
-       parts = db1x00_partitions;
-       nb_parts = NB_OF(db1x00_partitions);
-
-       /*
-        * Now let's probe for the actual flash.  Do it here since
-        * specific machine settings might have been set above.
-        */
-       printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n", 
-                       db1xxx_mtd_map.bankwidth*8);
-       db1xxx_mtd_map.virt = ioremap(window_addr, window_size);
-       db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map);
-       if (!db1xxx_mtd) return -ENXIO;
-       db1xxx_mtd->owner = THIS_MODULE;
-
-       add_mtd_partitions(db1xxx_mtd, parts, nb_parts);
-       return 0;
-}
-
-static void __exit db1x00_mtd_cleanup(void)
-{
-       if (db1xxx_mtd) {
-               del_mtd_partitions(db1xxx_mtd);
-               map_destroy(db1xxx_mtd);
-               if (parsed_parts)
-                       kfree(parsed_parts);
-       }
-}
-
-module_init(db1x00_mtd_init);
-module_exit(db1x00_mtd_cleanup);
-
-MODULE_AUTHOR("Pete Popov");
-MODULE_DESCRIPTION("Db1x00 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c
deleted file mode 100644 (file)
index e9465f5..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-/* elan-104nc.c -- MTD map driver for Arcom Control Systems ELAN-104NC
-   Copyright (C) 2000 Arcom Control System Ltd
-   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.
-   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
-
-   $Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $
-
-The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
-mode.  This drivers uses the CFI probe and Intel Extended Command Set drivers.
-
-The flash is accessed as follows:
-
-   32 kbyte memory window at 0xb0000-0xb7fff
-   
-   16 bit I/O port (0x22) for some sort of paging.
-
-The single flash device is divided into 3 partition which appear as separate
-MTD devices.
-
-Linux thinks that the I/O port is used by the PIC and hence check_region() will
-always fail.  So we don't do it.  I just hope it doesn't break anything.
-*/
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
-#define WINDOW_START 0xb0000
-/* Number of bits in offset. */
-#define WINDOW_SHIFT 15
-#define WINDOW_LENGTH (1 << WINDOW_SHIFT)
-/* The bits for the offset into the window. */
-#define WINDOW_MASK (WINDOW_LENGTH-1)
-#define PAGE_IO 0x22
-#define PAGE_IO_SIZE 2
-
-static volatile int page_in_window = -1; // Current page in window.
-static void __iomem *iomapadr;
-static DEFINE_SPINLOCK(elan_104nc_spin);
-
-/* partition_info gives details on the logical partitions that the split the 
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
-static struct mtd_partition partition_info[]={
-    { .name = "ELAN-104NC flash boot partition", 
-      .offset = 0, 
-      .size = 640*1024 },
-    { .name = "ELAN-104NC flash partition 1", 
-      .offset = 640*1024, 
-      .size = 896*1024 },
-    { .name = "ELAN-104NC flash partition 2", 
-      .offset = (640+896)*1024 }
-};
-#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
-
-/*
- * If no idea what is going on here.  This is taken from the FlashFX stuff.
- */
-#define ROMCS 1
-
-static inline void elan_104nc_setup(void)
-{
-    u16 t;
-
-    outw( 0x0023 + ROMCS*2, PAGE_IO );
-    t=inb( PAGE_IO+1 );
-
-    t=(t & 0xf9) | 0x04;
-
-    outw( ((0x0023 + ROMCS*2) | (t << 8)), PAGE_IO );
-}
-
-static inline void elan_104nc_page(struct map_info *map, unsigned long ofs)
-{
-       unsigned long page = ofs >> WINDOW_SHIFT;
-       
-       if( page!=page_in_window ) {
-               int cmd1;
-               int cmd2;
-
-               cmd1=(page & 0x700) + 0x0833 + ROMCS*0x4000;
-               cmd2=((page & 0xff) << 8) + 0x0032;
-
-               outw( cmd1, PAGE_IO );
-               outw( cmd2, PAGE_IO );
-
-               page_in_window = page;
-       }
-}
-
-
-static map_word elan_104nc_read16(struct map_info *map, unsigned long ofs)
-{
-       map_word ret;
-       spin_lock(&elan_104nc_spin);
-       elan_104nc_page(map, ofs);
-       ret.x[0] = readw(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&elan_104nc_spin);
-       return ret;
-}
-
-static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-       while (len) {
-               unsigned long thislen = len;
-               if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
-                       thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-               
-               spin_lock(&elan_104nc_spin);
-               elan_104nc_page(map, from);
-               memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
-               spin_unlock(&elan_104nc_spin);
-               to += thislen;
-               from += thislen;
-               len -= thislen;
-       }
-}
-
-static void elan_104nc_write16(struct map_info *map, map_word d, unsigned long adr)
-{
-       spin_lock(&elan_104nc_spin);
-       elan_104nc_page(map, adr);
-       writew(d.x[0], iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&elan_104nc_spin);
-}
-
-static void elan_104nc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{      
-       while(len) {
-               unsigned long thislen = len;
-               if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
-                       thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-               
-               spin_lock(&elan_104nc_spin);
-               elan_104nc_page(map, to);
-               memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen);
-               spin_unlock(&elan_104nc_spin);
-               to += thislen;
-               from += thislen;
-               len -= thislen;
-       }
-}
-
-static struct map_info elan_104nc_map = {
-       .name = "ELAN-104NC flash",
-       .phys = NO_XIP,
-       .size = 8*1024*1024, /* this must be set to a maximum possible amount
-                       of flash so the cfi probe routines find all
-                       the chips */
-       .bankwidth = 2,
-       .read = elan_104nc_read16,
-       .copy_from = elan_104nc_copy_from,
-       .write = elan_104nc_write16,
-       .copy_to = elan_104nc_copy_to
-};
-
-/* MTD device for all of the flash. */
-static struct mtd_info *all_mtd;
-
-static void cleanup_elan_104nc(void)
-{
-       if( all_mtd ) {
-               del_mtd_partitions( all_mtd );
-               map_destroy( all_mtd );
-       }
-
-       iounmap(iomapadr);
-}
-
-static int __init init_elan_104nc(void)
-{
-       /* Urg! We use I/O port 0x22 without request_region()ing it,
-          because it's already allocated to the PIC. */
-
-       iomapadr = ioremap(WINDOW_START, WINDOW_LENGTH);
-       if (!iomapadr) {
-               printk( KERN_ERR"%s: failed to ioremap memory region\n",
-                       elan_104nc_map.name );
-               return -EIO;
-       }
-
-       printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
-               elan_104nc_map.name,
-               PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1,
-               WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 );
-
-       elan_104nc_setup();
-
-       /* Probe for chip. */
-       all_mtd = do_map_probe("cfi_probe",  &elan_104nc_map );
-       if( !all_mtd ) {
-               cleanup_elan_104nc();
-               return -ENXIO;
-       }
-       
-       all_mtd->owner = THIS_MODULE;
-
-       /* Create MTD devices for each partition. */
-       add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS );
-
-       return 0;
-}
-
-module_init(init_elan_104nc);
-module_exit(cleanup_elan_104nc);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Arcom Control Systems Ltd.");
-MODULE_DESCRIPTION("MTD map driver for Arcom Control Systems ELAN-104NC");
index 29d1cc1bb426c112f5dc8e7a88c1e2680e2778a8..1800ceedf3809ce3cec8474df38e3ed66df3ceba 100644 (file)
@@ -2,7 +2,7 @@
  * ichxrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: ichxrom.c,v 1.17 2005/03/18 14:04:35 gleixner Exp $
  */
 
 #include <linux/module.h>
@@ -366,7 +366,7 @@ static int __init init_ichxrom(void)
        }
        return -ENXIO;
 #if 0
-       return pci_module_init(&ichxrom_driver);
+       return pci_register_driver(&ichxrom_driver);
 #endif
 }
 
index c5b5f447e34b6a72c14f35e6eb7dcf3d315c8175..3e94b616743d0cec3cc123fb8952b2aedf4f236b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ixp2000.c,v 1.5 2004/11/16 17:15:48 dsaxena Exp $
+ * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $
  *
  * drivers/mtd/maps/ixp2000.c
  *
@@ -216,11 +216,6 @@ static int ixp2000_flash_probe(struct device *_dev)
                goto Error;
        }
 
-       /*
-        * Setup read mode for FLASH
-        */
-       *IXP2000_SLOWPORT_FRM = 1;
-
 #if defined(__ARMEB__)
        /*
         * Enable erratum 44 workaround for NPUs with broken slowport
diff --git a/drivers/mtd/maps/pb1550-flash.c b/drivers/mtd/maps/pb1550-flash.c
deleted file mode 100644 (file)
index 1424726..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Flash memory access on Alchemy Pb1550 board
- * 
- * $Id: pb1550-flash.c,v 1.6 2004/11/04 13:24:15 gleixner Exp $
- *
- * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c:
- * (C) 2003 Pete Popov <ppopov@pacbell.net>
- * 
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/au1000.h>
-#include <asm/pb1550.h>
-
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)       
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-
-
-static struct map_info pb1550_map = {
-       .name = "Pb1550 flash",
-};
-
-static unsigned char flash_bankwidth = 4;
-
-/* 
- * Support only 64MB NOR Flash parts
- */
-
-#ifdef PB1550_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first 
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition pb1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-        * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size =   (0x1FC00000 - 0x18000000),
-                .offset = 0x0000000
-        },{
-                .name = "yamon",
-                .size = 0x0100000,
-               .offset = MTDPART_OFS_APPEND,
-                .mask_flags = MTD_WRITEABLE
-        },{
-                .name = "raw kernel",
-               .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(PB1550_BOOT_ONLY)
-static struct mtd_partition pb1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size =   0x03c00000,
-                .offset = 0x0000000
-        },{
-                .name = "yamon",
-                .size = 0x0100000,
-               .offset = MTDPART_OFS_APPEND,
-                .mask_flags = MTD_WRITEABLE
-        },{
-                .name = "raw kernel",
-               .size = (0x300000-0x40000), /* last 256KB is yamon env */
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#elif defined(PB1550_USER_ONLY)
-static struct mtd_partition pb1550_partitions[] = {
-       /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-        * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-        */
-        {
-                .name = "User FS",
-                .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
-                .offset = 0x0000000
-        },{
-                .name = "raw kernel",
-               .size = MTDPART_SIZ_FULL,
-               .offset = MTDPART_OFS_APPEND,
-        }
-};
-#else
-#error MTD_PB1550 define combo error /* should never happen */
-#endif
-
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
-       u16 boot_swapboot;
-       boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | 
-               ((bcsr->status >> 6)  & 0x1);
-       printk("Pb1550 MTD: boot:swap %d\n", boot_swapboot);
-
-       switch (boot_swapboot) {
-               case 0: /* 512Mbit devices, both enabled */
-               case 1: 
-               case 8:
-               case 9: 
-#if defined(PB1550_BOTH_BANKS)
-                       window_addr = 0x18000000;
-                       window_size = 0x8000000; 
-#elif defined(PB1550_BOOT_ONLY)
-                       window_addr = 0x1C000000;
-                       window_size = 0x4000000; 
-#else /* USER ONLY */
-                       window_addr = 0x1E000000;
-                       window_size = 0x4000000; 
-#endif
-                       break;
-               case 0xC:
-               case 0xD:
-               case 0xE:
-               case 0xF: 
-                       /* 64 MB Boot NOR Flash is disabled */
-                       /* and the start address is moved to 0x0C00000 */
-                       window_addr = 0x0C000000;
-                       window_size = 0x4000000; 
-               default:
-                       printk("Pb1550 MTD: unsupported boot:swap setting\n");
-                       return 1;
-       }
-       return 0;
-}
-
-int __init pb1550_mtd_init(void)
-{
-       struct mtd_partition *parts;
-       int nb_parts = 0;
-       
-       /* Default flash bankwidth */
-       pb1550_map.bankwidth = flash_bankwidth;
-
-       if (setup_flash_params()) 
-               return -ENXIO;
-
-       /*
-        * Static partition definition selection
-        */
-       parts = pb1550_partitions;
-       nb_parts = NB_OF(pb1550_partitions);
-       pb1550_map.size = window_size;
-
-       /*
-        * Now let's probe for the actual flash.  Do it here since
-        * specific machine settings might have been set above.
-        */
-       printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", 
-                       pb1550_map.bankwidth*8);
-       pb1550_map.virt = ioremap(window_addr, window_size);
-       mymtd = do_map_probe("cfi_probe", &pb1550_map);
-       if (!mymtd) return -ENXIO;
-       mymtd->owner = THIS_MODULE;
-
-       add_mtd_partitions(mymtd, parts, nb_parts);
-       return 0;
-}
-
-static void __exit pb1550_mtd_cleanup(void)
-{
-       if (mymtd) {
-               del_mtd_partitions(mymtd);
-               map_destroy(mymtd);
-       }
-}
-
-module_init(pb1550_mtd_init);
-module_exit(pb1550_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Pb1550 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c
deleted file mode 100644 (file)
index 06e7315..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Flash memory access on Alchemy Pb1xxx boards
- * 
- * (C) 2001 Pete Popov <ppopov@mvista.com>
- * 
- * $Id: pb1xxx-flash.c,v 1.14 2004/11/04 13:24:15 gleixner Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef         DEBUG_RW
-#define        DBG(x...)       printk(x)
-#else
-#define        DBG(x...)       
-#endif
-
-#ifdef CONFIG_MIPS_PB1000
-
-#define WINDOW_ADDR 0x1F800000
-#define WINDOW_SIZE 0x800000
-
-static struct mtd_partition pb1xxx_partitions[] = {
-        {
-                .name         =  "yamon env",
-                .size         =   0x00020000,
-                .offset       =   0,
-                .mask_flags   =   MTD_WRITEABLE},
-       {
-                .name         =   "User FS",
-                .size         =   0x003e0000,
-                .offset       =   0x20000,},
-       {
-                .name         =   "boot code",
-                .size         =   0x100000,
-                .offset       =   0x400000,
-                .mask_flags   =   MTD_WRITEABLE},
-       {
-                .name         =   "raw/kernel",
-                .size         =   0x300000,
-                .offset       =   0x500000}
-};
-
-#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
-
-#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-/* both 32MB banks will be used. Combine the first 32MB bank and the
- * first 28MB of the second bank together into a single jffs/jffs2
- * partition.
- */
-#define WINDOW_ADDR 0x1C000000
-#define WINDOW_SIZE 0x4000000
-static struct mtd_partition pb1xxx_partitions[] = {
-        {
-                .name         =   "User FS",
-                .size         =   0x3c00000,
-                .offset       =   0x0000000
-        },{
-                .name         =   "yamon",
-                .size         =   0x0100000,
-                .offset       =   0x3c00000,
-                .mask_flags   =   MTD_WRITEABLE
-        },{
-                .name         =   "raw kernel",
-                .size         =   0x02c0000,
-                .offset       =   0x3d00000
-        }
-};
-#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
-#define WINDOW_ADDR 0x1E000000
-#define WINDOW_SIZE 0x2000000
-static struct mtd_partition pb1xxx_partitions[] = {
-        {
-                .name         =   "User FS",
-                .size         =   0x1c00000,
-                .offset       =   0x0000000
-        },{
-                .name         =   "yamon",
-                .size         =   0x0100000,
-                .offset       =   0x1c00000,
-                .mask_flags   =   MTD_WRITEABLE
-        },{
-                .name         =   "raw kernel",
-                .size         =   0x02c0000,
-                .offset       =   0x1d00000
-        }
-};
-#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-#define WINDOW_ADDR 0x1C000000
-#define WINDOW_SIZE 0x2000000
-static struct mtd_partition pb1xxx_partitions[] = {
-        {
-                .name         =   "User FS",
-                .size         =    0x1e00000,
-                .offset       =    0x0000000
-        },{
-                .name         =    "raw kernel",
-                .size         =    0x0200000,
-                .offset       =    0x1e00000,
-        }
-};
-#else
-#error MTD_PB1500 define combo error /* should never happen */
-#endif
-#else
-#error Unsupported board
-#endif
-
-#define NAME           "Pb1x00 Linux Flash"
-#define PADDR          WINDOW_ADDR
-#define BUSWIDTH       4
-#define SIZE           WINDOW_SIZE
-#define PARTITIONS     4
-
-static struct map_info pb1xxx_mtd_map = {
-       .name           = NAME,
-       .size           = SIZE,
-       .bankwidth      = BUSWIDTH,
-       .phys           = PADDR,
-};
-
-static struct mtd_info *pb1xxx_mtd;
-
-int __init pb1xxx_mtd_init(void)
-{
-       struct mtd_partition *parts;
-       int nb_parts = 0;
-       char *part_type;
-       
-       /*
-        * Static partition definition selection
-        */
-       part_type = "static";
-       parts = pb1xxx_partitions;
-       nb_parts = ARRAY_SIZE(pb1xxx_partitions);
-
-       /*
-        * Now let's probe for the actual flash.  Do it here since
-        * specific machine settings might have been set above.
-        */
-       printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", 
-                       BUSWIDTH*8);
-       pb1xxx_mtd_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
-       simple_map_init(&pb1xxx_mtd_map);
-
-       pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map);
-       if (!pb1xxx_mtd) return -ENXIO;
-       pb1xxx_mtd->owner = THIS_MODULE;
-
-       add_mtd_partitions(pb1xxx_mtd, parts, nb_parts);
-       return 0;
-}
-
-static void __exit pb1xxx_mtd_cleanup(void)
-{
-       if (pb1xxx_mtd) {
-               del_mtd_partitions(pb1xxx_mtd);
-               map_destroy(pb1xxx_mtd);
-               iounmap((void *) pb1xxx_mtd_map.virt);
-       }
-}
-
-module_init(pb1xxx_mtd_init);
-module_exit(pb1xxx_mtd_cleanup);
-
-MODULE_AUTHOR("Pete Popov");
-MODULE_DESCRIPTION("Pb1xxx CFI map driver");
-MODULE_LICENSE("GPL");
index 08b60bdc53812949939c4aa4fed79638bd2125a0..18dbd3af1eaa652a34d4677a97f1742d4851d74c 100644 (file)
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
+ *  $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $
  * 
  * Generic PCI memory map driver.  We support the following boards:
  *  - Intel IQ80310 ATU.
@@ -370,7 +370,7 @@ static struct pci_driver mtd_pci_driver = {
 
 static int __init mtd_pci_maps_init(void)
 {
-       return pci_module_init(&mtd_pci_driver);
+       return pci_register_driver(&mtd_pci_driver);
 }
 
 static void __exit mtd_pci_maps_exit(void)
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
new file mode 100644 (file)
index 0000000..118b045
--- /dev/null
@@ -0,0 +1,278 @@
+/* drivers/mtd/maps/plat-ram.c
+ *
+ * (c) 2004-2005 Simtec Electronics
+ *     http://www.simtec.co.uk/products/SWLINUX/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Generic platfrom device based RAM map
+ *
+ * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $
+ *
+ * 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.
+ *
+ * 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
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/plat-ram.h>
+
+#include <asm/io.h>
+
+/* private structure for each mtd platform ram device created */
+
+struct platram_info {
+       struct device           *dev;
+       struct mtd_info         *mtd;
+       struct map_info          map;
+       struct mtd_partition    *partitions;
+       struct resource         *area;
+       struct platdata_mtd_ram *pdata;
+};
+
+/* to_platram_info()
+ *
+ * device private data to struct platram_info conversion
+*/
+
+static inline struct platram_info *to_platram_info(struct device *dev)
+{
+       return (struct platram_info *)dev_get_drvdata(dev);
+}
+
+/* platram_setrw
+ *
+ * call the platform device's set rw/ro control
+ *
+ * to = 0 => read-only
+ *    = 1 => read-write
+*/
+
+static inline void platram_setrw(struct platram_info *info, int to)
+{
+       if (info->pdata == NULL)
+               return;
+
+       if (info->pdata->set_rw != NULL)
+               (info->pdata->set_rw)(info->dev, to);
+}
+
+/* platram_remove
+ *
+ * called to remove the device from the driver's control
+*/
+
+static int platram_remove(struct device *dev)
+{
+       struct platram_info *info = to_platram_info(dev);
+
+       dev_set_drvdata(dev, NULL);
+
+       dev_dbg(dev, "removing device\n");
+
+       if (info == NULL) 
+               return 0;
+
+       if (info->mtd) {
+#ifdef CONFIG_MTD_PARTITIONS
+               if (info->partitions) {
+                       del_mtd_partitions(info->mtd);
+                       kfree(info->partitions);
+               }
+#endif
+               del_mtd_device(info->mtd);
+               map_destroy(info->mtd);
+       }
+
+       /* ensure ram is left read-only */
+
+       platram_setrw(info, PLATRAM_RO);
+
+       /* release resources */
+
+       if (info->area) {
+               release_resource(info->area);
+               kfree(info->area);
+       }
+
+       if (info->map.virt != NULL)
+               iounmap(info->map.virt);
+       
+       kfree(info);
+
+       return 0;
+}
+
+/* platram_probe
+ *
+ * called from device drive system when a device matching our
+ * driver is found.
+*/
+
+static int platram_probe(struct device *dev)
+{
+       struct platform_device *pd = to_platform_device(dev);
+       struct platdata_mtd_ram *pdata;
+       struct platram_info *info;
+       struct resource *res;
+       int err = 0;
+
+       dev_dbg(dev, "probe entered\n");
+       
+       if (dev->platform_data == NULL) {
+               dev_err(dev, "no platform data supplied\n");
+               err = -ENOENT;
+               goto exit_error;
+       }
+
+       pdata = dev->platform_data;
+
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (info == NULL) {
+               dev_err(dev, "no memory for flash info\n");
+               err = -ENOMEM;
+               goto exit_error;
+       }
+
+       memset(info, 0, sizeof(*info));
+       dev_set_drvdata(dev, info);
+
+       info->dev = dev;
+       info->pdata = pdata;
+
+       /* get the resource for the memory mapping */
+
+       res = platform_get_resource(pd, IORESOURCE_MEM, 0);
+
+       if (res == NULL) {
+               dev_err(dev, "no memory resource specified\n");
+               err = -ENOENT;
+               goto exit_free;
+       }
+
+       dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start);
+
+       /* setup map parameters */
+
+       info->map.phys = res->start;
+       info->map.size = (res->end - res->start) + 1;
+       info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name;
+       info->map.bankwidth = pdata->bankwidth;
+
+       /* register our usage of the memory area */
+
+       info->area = request_mem_region(res->start, info->map.size, pd->name);
+       if (info->area == NULL) {
+               dev_err(dev, "failed to request memory region\n");
+               err = -EIO;
+               goto exit_free;
+       }
+
+       /* remap the memory area */
+
+       info->map.virt = ioremap(res->start, info->map.size);
+       dev_dbg(dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size);
+
+       if (info->map.virt == NULL) {
+               dev_err(dev, "failed to ioremap() region\n");
+               err = -EIO;
+               goto exit_free;
+       }
+
+       simple_map_init(&info->map);
+
+       dev_dbg(dev, "initialised map, probing for mtd\n");
+
+       /* probe for the right mtd map driver */
+
+       info->mtd = do_map_probe("map_ram" , &info->map);
+       if (info->mtd == NULL) {
+               dev_err(dev, "failed to probe for map_ram\n");
+               err = -ENOMEM;
+               goto exit_free;
+       }
+
+       info->mtd->owner = THIS_MODULE;
+
+       platram_setrw(info, PLATRAM_RW);
+
+       /* check to see if there are any available partitions, or wether
+        * to add this device whole */
+
+#ifdef CONFIG_MTD_PARTITIONS
+       if (pdata->nr_partitions > 0) {
+               const char **probes = { NULL };
+
+               if (pdata->probes)
+                       probes = (const char **)pdata->probes;
+
+               err = parse_mtd_partitions(info->mtd, probes,
+                                          &info->partitions, 0);
+               if (err > 0) {
+                       err = add_mtd_partitions(info->mtd, info->partitions,
+                                                err);
+               }
+       }
+#endif /* CONFIG_MTD_PARTITIONS */
+
+       if (add_mtd_device(info->mtd)) {
+               dev_err(dev, "add_mtd_device() failed\n");
+               err = -ENOMEM;
+       }
+       
+       dev_info(dev, "registered mtd device\n");
+       return err;
+
+ exit_free:
+       platram_remove(dev);
+ exit_error:
+       return err;
+}
+
+/* device driver info */
+
+static struct device_driver platram_driver = {
+       .name           = "mtd-ram",
+       .bus            = &platform_bus_type,
+       .probe          = platram_probe,
+       .remove         = platram_remove,
+};
+
+/* module init/exit */
+
+static int __init platram_init(void)
+{
+       printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n");
+       return driver_register(&platram_driver);
+}
+
+static void __exit platram_exit(void)
+{
+       driver_unregister(&platram_driver);
+}
+
+module_init(platram_init);
+module_exit(platram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("MTD platform RAM map driver");
index 5bb3b600e5d0cc8ab3e827e303a7a3b719a3347f..97a8dfd69258188a29bea7afd3c64c08a594fbbe 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * MTD map driver for BIOS Flash on Intel SCB2 boards
- * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: scb2_flash.c,v 1.12 2005/03/18 14:04:35 gleixner Exp $
  * Copyright (C) 2002 Sun Microsystems, Inc.
  * Tim Hockin <thockin@sun.com>
  *
@@ -238,7 +238,7 @@ static struct pci_driver scb2_flash_driver = {
 static int __init
 scb2_flash_init(void)
 {
-       return pci_module_init(&scb2_flash_driver);
+       return pci_register_driver(&scb2_flash_driver);
 }
 
 static void __exit
index b3b39cb7c608f6f2c0b871d00422cd1e4db6e75f..d15da6fd84c10fce1c41aaba3f96a87afe997816 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2001 Lineo Japan, Inc.
  * Copyright (C) 2002  SHARP
  *
- * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $
+ * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $
  *
  * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp
  *          Handle mapping of the flash on the RPX Lite and CLLF boards
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
 
 #define WINDOW_ADDR 0x00000000
-#define WINDOW_SIZE 0x01000000
+#define WINDOW_SIZE 0x00800000
 #define BANK_WIDTH 2
 
 static struct mtd_info *mymtd;
@@ -44,9 +45,7 @@ struct map_info sharpsl_map = {
 
 static struct mtd_partition sharpsl_partitions[1] = {
        {
-               name:           "Filesystem",
-               size:           0x006d0000,
-               offset:         0x00120000
+               name:           "Boot PROM Filesystem",
        }
 };
 
@@ -58,12 +57,16 @@ int __init init_sharpsl(void)
        int nb_parts = 0;
        char *part_type = "static";
 
-       printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+       printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", 
+               WINDOW_SIZE, WINDOW_ADDR);
        sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
        if (!sharpsl_map.virt) {
                printk("Failed to ioremap\n");
                return -EIO;
        }
+
+       simple_map_init(&sharpsl_map);
+
        mymtd = do_map_probe("map_rom", &sharpsl_map);
        if (!mymtd) {
                iounmap(sharpsl_map.virt);
@@ -72,6 +75,22 @@ int __init init_sharpsl(void)
 
        mymtd->owner = THIS_MODULE;
 
+       if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() 
+               || machine_is_poodle()) {
+               sharpsl_partitions[0].size=0x006d0000;
+               sharpsl_partitions[0].offset=0x00120000;
+       } else if (machine_is_tosa()) {
+               sharpsl_partitions[0].size=0x006a0000;
+               sharpsl_partitions[0].offset=0x00160000;
+       } else if (machine_is_spitz()) {
+               sharpsl_partitions[0].size=0x006b0000;
+               sharpsl_partitions[0].offset=0x00140000;
+       } else {
+               map_destroy(mymtd);
+               iounmap(sharpsl_map.virt);      
+               return -ENODEV;
+       }
+       
        parts = sharpsl_partitions;
        nb_parts = NB_OF(sharpsl_partitions);
 
index 510ad78312cc67155a22813b8c893c8ad4011004..da3f1a8f756e9594813d154f931ef925f224bc01 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdchar.c,v 1.66 2005/01/05 18:05:11 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.70 2005/04/01 15:36:11 nico Exp $
  *
  * Character-device access to raw MTD devices.
  *
@@ -59,9 +59,25 @@ static inline void mtdchar_devfs_exit(void)
 #define mtdchar_devfs_exit() do { } while(0)
 #endif
 
+/*
+ * We use file->private_data to store a pointer to the MTDdevice.
+ * Since alighment is at least 32 bits, we have 2 bits free for OTP
+ * modes as well.
+ */
+
+#define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L)
+
+#define MTD_MODE_OTP_FACT      1
+#define MTD_MODE_OTP_USER      2
+#define MTD_MODE(file)         ((long)((file)->private_data) & 3)
+
+#define SET_MTD_MODE(file, mode) \
+       do { long __p = (long)((file)->private_data); \
+            (file)->private_data = (void *)((__p & ~3L) | mode); } while (0)
+
 static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
 {
-       struct mtd_info *mtd = file->private_data;
+       struct mtd_info *mtd = TO_MTD(file);
 
        switch (orig) {
        case 0:
@@ -134,7 +150,7 @@ static int mtd_close(struct inode *inode, struct file *file)
 
        DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
 
-       mtd = file->private_data;
+       mtd = TO_MTD(file);
        
        if (mtd->sync)
                mtd->sync(mtd);
@@ -151,7 +167,7 @@ static int mtd_close(struct inode *inode, struct file *file)
 
 static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
 {
-       struct mtd_info *mtd = file->private_data;
+       struct mtd_info *mtd = TO_MTD(file);
        size_t retlen=0;
        size_t total_retlen=0;
        int ret=0;
@@ -178,7 +194,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
                if (!kbuf)
                        return -ENOMEM;
                
-               ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+               switch (MTD_MODE(file)) {
+               case MTD_MODE_OTP_FACT:
+                       ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+                       break;
+               case MTD_MODE_OTP_USER:
+                       ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+                       break;
+               default:
+                       ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+               }
                /* Nand returns -EBADMSG on ecc errors, but it returns
                 * the data. For our userspace tools it is important
                 * to dump areas with ecc errors ! 
@@ -196,6 +221,8 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
 
                        count -= retlen;
                        buf += retlen;
+                       if (retlen == 0)
+                               count = 0;
                }
                else {
                        kfree(kbuf);
@@ -210,7 +237,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
 
 static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
 {
-       struct mtd_info *mtd = file->private_data;
+       struct mtd_info *mtd = TO_MTD(file);
        char *kbuf;
        size_t retlen;
        size_t total_retlen=0;
@@ -245,7 +272,20 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
                        return -EFAULT;
                }
                
-               ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+               switch (MTD_MODE(file)) {
+               case MTD_MODE_OTP_FACT:
+                       ret = -EROFS;
+                       break;
+               case MTD_MODE_OTP_USER:
+                       if (!mtd->write_user_prot_reg) {
+                               ret = -EOPNOTSUPP;
+                               break;
+                       }
+                       ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+                       break;
+               default:
+                       ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+               }
                if (!ret) {
                        *ppos += retlen;
                        total_retlen += retlen;
@@ -276,7 +316,7 @@ static void mtdchar_erase_callback (struct erase_info *instr)
 static int mtd_ioctl(struct inode *inode, struct file *file,
                     u_int cmd, u_long arg)
 {
-       struct mtd_info *mtd = file->private_data;
+       struct mtd_info *mtd = TO_MTD(file);
        void __user *argp = (void __user *)arg;
        int ret = 0;
        u_long size;
@@ -518,6 +558,80 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                break;
        }
 
+#ifdef CONFIG_MTD_OTP
+       case OTPSELECT:
+       {
+               int mode;
+               if (copy_from_user(&mode, argp, sizeof(int)))
+                       return -EFAULT;
+               SET_MTD_MODE(file, 0);
+               switch (mode) {
+               case MTD_OTP_FACTORY:
+                       if (!mtd->read_fact_prot_reg)
+                               ret = -EOPNOTSUPP;
+                       else
+                               SET_MTD_MODE(file, MTD_MODE_OTP_FACT);
+                       break;
+               case MTD_OTP_USER:
+                       if (!mtd->read_fact_prot_reg)
+                               ret = -EOPNOTSUPP;
+                       else
+                               SET_MTD_MODE(file, MTD_MODE_OTP_USER);
+                       break;
+               default:
+                       ret = -EINVAL;
+               case MTD_OTP_OFF:
+                       break;
+               }
+               file->f_pos = 0;
+               break;
+       }
+
+       case OTPGETREGIONCOUNT:
+       case OTPGETREGIONINFO:
+       {
+               struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+               ret = -EOPNOTSUPP;
+               switch (MTD_MODE(file)) {
+               case MTD_MODE_OTP_FACT:
+                       if (mtd->get_fact_prot_info)
+                               ret = mtd->get_fact_prot_info(mtd, buf, 4096);
+                       break;
+               case MTD_MODE_OTP_USER:
+                       if (mtd->get_user_prot_info)
+                               ret = mtd->get_user_prot_info(mtd, buf, 4096);
+                       break;
+               }
+               if (ret >= 0) {
+                       if (cmd == OTPGETREGIONCOUNT) {
+                               int nbr = ret / sizeof(struct otp_info);
+                               ret = copy_to_user(argp, &nbr, sizeof(int));
+                       } else
+                               ret = copy_to_user(argp, buf, ret);
+                       if (ret)
+                               ret = -EFAULT;
+               }
+               kfree(buf);
+               break;
+       }
+
+       case OTPLOCK:
+       {
+               struct otp_info info;
+
+               if (MTD_MODE(file) != MTD_MODE_OTP_USER)
+                       return -EINVAL;
+               if (copy_from_user(&info, argp, sizeof(info)))
+                       return -EFAULT;
+               if (!mtd->lock_user_prot_reg)
+                       return -EOPNOTSUPP;
+               ret = mtd->lock_user_prot_reg(mtd, info.start, info.length);
+               break;
+       }
+#endif
+
        default:
                ret = -ENOTTY;
        }
index 9c0315d1b1c4f59fa7ffd123b2c0e9063ea529b5..dc86df18e94b72768ce0d7beaaf06e629c9217a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.44 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -149,8 +149,8 @@ void register_mtd_user (struct mtd_notifier *new)
 }
 
 /**
- *     register_mtd_user - unregister a 'user' of MTD devices.
- *     @new: pointer to notifier info structure
+ *     unregister_mtd_user - unregister a 'user' of MTD devices.
+ *     @old: pointer to notifier info structure
  *
  *     Removes a callback function pair from the list of 'users' to be
  *     notified upon addition or removal of MTD devices. Causes the
index 96ebb52f24b1cdb4ea4cd2a6499d8fd9aef0bd86..b92e6bfffaf2afa78cf3aad8fe38d7248509200c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
  *
  *     02-21-2002      Thomas Gleixner <gleixner@autronix.de>
  *                     added support for read_oob, write_oob
@@ -116,6 +116,13 @@ static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
                                        len, retlen, buf);
 }
 
+static int part_get_user_prot_info (struct mtd_info *mtd,
+                                   struct otp_info *buf, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->get_user_prot_info (part->master, buf, len);
+}
+
 static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
                        size_t *retlen, u_char *buf)
 {
@@ -124,6 +131,13 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
                                        len, retlen, buf);
 }
 
+static int part_get_fact_prot_info (struct mtd_info *mtd,
+                                   struct otp_info *buf, size_t len)
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->get_fact_prot_info (part->master, buf, len);
+}
+
 static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
                        size_t *retlen, const u_char *buf)
 {
@@ -182,6 +196,12 @@ static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t l
                                        len, retlen, buf);
 }
 
+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) 
+{
+       struct mtd_part *part = PART(mtd);
+       return part->master->lock_user_prot_reg (part->master, from, len);
+}
+
 static int part_writev (struct mtd_info *mtd,  const struct kvec *vecs,
                         unsigned long count, loff_t to, size_t *retlen)
 {
@@ -409,6 +429,12 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
                if(master->write_user_prot_reg)
                        slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
+               if(master->lock_user_prot_reg)
+                       slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
+               if(master->get_user_prot_info)
+                       slave->mtd.get_user_prot_info = part_get_user_prot_info;
+               if(master->get_fact_prot_info)
+                       slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
                if (master->sync)
                        slave->mtd.sync = part_sync;
                if (!i && master->suspend && master->resume) {
index 02135c3ac29a0372f19a05784cb7da8e90f38245..fdb5d4ad3d526d0953629e26b5c433b07e5231ac 100644 (file)
@@ -16,7 +16,7 @@
  *  
  * Interface to generic NAND code for M-Systems DiskOnChip devices
  *
- * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $
+ * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $
  */
 
 #include <linux/kernel.h>
 #include <linux/mtd/inftl.h>
 
 /* Where to look for the devices? */
-#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
-#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
+#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
 #endif
 
 static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
        0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
        0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
        0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
@@ -81,11 +81,6 @@ struct doc_priv {
        struct mtd_info *nextdoc;
 };
 
-/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
-   MediaHeader.  The spec says to just keep going, I think, but that's just
-   silly. */
-#define MAX_MEDIAHEADER_SCAN 8
-
 /* This is the syndrome computed by the HW ecc generator upon reading an empty
    page, one with all 0xff for data and stored ecc code. */
 static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
@@ -111,10 +106,11 @@ module_param(try_dword, int, 0);
 static int no_ecc_failures=0;
 module_param(no_ecc_failures, int, 0);
 
-#ifdef CONFIG_MTD_PARTITIONS
 static int no_autopart=0;
 module_param(no_autopart, int, 0);
-#endif
+
+static int show_firmware_partition=0;
+module_param(show_firmware_partition, int, 0);
 
 #ifdef MTD_NAND_DISKONCHIP_BBTWRITE
 static int inftl_bbt_write=1;
@@ -123,7 +119,7 @@ static int inftl_bbt_write=0;
 #endif
 module_param(inftl_bbt_write, int, 0);
 
-static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
+static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
 module_param(doc_config_location, ulong, 0);
 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
 
@@ -410,7 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
        doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
        this->write_byte(mtd, 0);
        doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-
+       
+       /* We cant' use dev_ready here, but at least we wait for the
+        * command to complete 
+        */
+       udelay(50);
+       
        ret = this->read_byte(mtd) << 8;
        ret |= this->read_byte(mtd);
 
@@ -429,6 +430,8 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
                doc2000_write_byte(mtd, 0);
                doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
 
+               udelay(50);
+
                ident.dword = readl(docptr + DoC_2k_CDSN_IO);
                if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
                        printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
@@ -1046,11 +1049,21 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
                
 //u_char mydatabuf[528];
 
+/* The strange out-of-order .oobfree list below is a (possibly unneeded)
+ * attempt to retain compatibility.  It used to read:
+ *     .oobfree = { {8, 8} }
+ * Since that leaves two bytes unusable, it was changed.  But the following
+ * scheme might affect existing jffs2 installs by moving the cleanmarker:
+ *     .oobfree = { {6, 10} }
+ * jffs2 seems to handle the above gracefully, but the current scheme seems
+ * safer.  The only problem with it is that any code that parses oobfree must
+ * be able to handle out-of-order segments.
+ */
 static struct nand_oobinfo doc200x_oobinfo = {
         .useecc = MTD_NANDECC_AUTOPLACE,
         .eccbytes = 6,
         .eccpos = {0, 1, 2, 3, 4, 5},
-        .oobfree = { {8, 8} }
+        .oobfree = { {8, 8}, {6, 2} }
 };
  
 /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@@ -1064,12 +1077,11 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
 {
        struct nand_chip *this = mtd->priv;
        struct doc_priv *doc = this->priv;
-       unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
+       unsigned offs;
        int ret;
        size_t retlen;
 
-       end = min(end, mtd->size); // paranoia
-       for (offs = 0; offs < end; offs += mtd->erasesize) {
+       for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
                ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
                if (retlen != mtd->oobblock) continue;
                if (ret) {
@@ -1111,6 +1123,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
        u_char *buf;
        struct NFTLMediaHeader *mh;
        const unsigned psize = 1 << this->page_shift;
+       int numparts = 0;
        unsigned blocks, maxblocks;
        int offs, numheaders;
 
@@ -1122,8 +1135,10 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
        if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
        mh = (struct NFTLMediaHeader *) buf;
 
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-//     if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+       mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
+       mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
+       mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
+
        printk(KERN_INFO "    DataOrgID        = %s\n"
                         "    NumEraseUnits    = %d\n"
                         "    FirstPhysicalEUN = %d\n"
@@ -1132,7 +1147,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
                mh->DataOrgID, mh->NumEraseUnits,
                mh->FirstPhysicalEUN, mh->FormattedSize,
                mh->UnitSizeFactor);
-//#endif
 
        blocks = mtd->size >> this->phys_erase_shift;
        maxblocks = min(32768U, mtd->erasesize - psize);
@@ -1175,23 +1189,28 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
        offs <<= this->page_shift;
        offs += mtd->erasesize;
 
-       //parts[0].name = " DiskOnChip Boot / Media Header partition";
-       //parts[0].offset = 0;
-       //parts[0].size = offs;
+       if (show_firmware_partition == 1) {
+               parts[0].name = " DiskOnChip Firmware / Media Header partition";
+               parts[0].offset = 0;
+               parts[0].size = offs;
+               numparts = 1;
+       }
 
-       parts[0].name = " DiskOnChip BDTL partition";
-       parts[0].offset = offs;
-       parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+       parts[numparts].name = " DiskOnChip BDTL partition";
+       parts[numparts].offset = offs;
+       parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+
+       offs += parts[numparts].size;
+       numparts++;
 
-       offs += parts[0].size;
        if (offs < mtd->size) {
-               parts[1].name = " DiskOnChip Remainder partition";
-               parts[1].offset = offs;
-               parts[1].size = mtd->size - offs;
-               ret = 2;
-               goto out;
+               parts[numparts].name = " DiskOnChip Remainder partition";
+               parts[numparts].offset = offs;
+               parts[numparts].size = mtd->size - offs;
+               numparts++;
        }
-       ret = 1;
+
+       ret = numparts;
 out:
        kfree(buf);
        return ret;
@@ -1233,8 +1252,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
        mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
        mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
  
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-//     if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
        printk(KERN_INFO "    bootRecordID          = %s\n"
                         "    NoOfBootImageBlocks   = %d\n"
                         "    NoOfBinaryPartitions  = %d\n"
@@ -1252,7 +1269,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
                ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
                ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
                mh->PercentUsed);
-//#endif
 
        vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
 
@@ -1278,8 +1294,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
                ip->spareUnits = le32_to_cpu(ip->spareUnits);
                ip->Reserved0 = le32_to_cpu(ip->Reserved0);
 
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-//             if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
                printk(KERN_INFO        "    PARTITION[%d] ->\n"
                        "        virtualUnits    = %d\n"
                        "        firstUnit       = %d\n"
@@ -1289,16 +1303,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
                        i, ip->virtualUnits, ip->firstUnit,
                        ip->lastUnit, ip->flags,
                        ip->spareUnits);
-//#endif
 
-/*
-               if ((i == 0) && (ip->firstUnit > 0)) {
+               if ((show_firmware_partition == 1) &&
+                   (i == 0) && (ip->firstUnit > 0)) {
                        parts[0].name = " DiskOnChip IPL / Media Header partition";
                        parts[0].offset = 0;
                        parts[0].size = mtd->erasesize * ip->firstUnit;
                        numparts = 1;
                }
-*/
 
                if (ip->flags & INFTL_BINARY)
                        parts[numparts].name = " DiskOnChip BDK partition";
index 44d5b128911f665a6071565216c3a786ade11acf..f1db0bf9306b3db950d1dea515e50deac8ccf299 100644 (file)
  *             among multiple independend devices. Suggestions and initial patch
  *             from Ben Dooks <ben-mtd@fluff.org>
  *
+ *  12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
+ *             Basically, any block not rewritten may lose data when surrounding blocks
+ *             are rewritten many times.  JFFS2 ensures this doesn't happen for blocks 
+ *             it uses, but the Bad Block Table(s) may not be rewritten.  To ensure they
+ *             do not lose data, force them to be rewritten when some of the surrounding
+ *             blocks are erased.  Rather than tracking a specific nearby block (which 
+ *             could itself go bad), use a page address 'mask' to select several blocks 
+ *             in the same area, and rewrite the BBT when any of them are erased.
+ *
+ *  01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas 
+ *             AG-AND chips.  If there was a sudden loss of power during an erase operation,
+ *             a "device recovery" operation must be performed when power is restored
+ *             to ensure correct operation.
+ *
+ *  01-20-2005 dmarlin: added support for optional hardware specific callback routine to 
+ *             perform extra error status checks on erase and write failures.  This required
+ *             adding a wrapper function for nand_read_ecc.
+ *
  * Credits:
  *     David Woodhouse for adding multichip support  
  *     
@@ -41,7 +59,7 @@
  *     The AG-AND chips have nice features for speed improvement,
  *     which are not supported yet. Read / program 4 pages in one go.
  *
- * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $
+ * $Id: nand_base.c,v 1.143 2005/05/19 16:10:22 gleixner Exp $
  *
  * 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
@@ -443,7 +461,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        
        /* Get block number */
        block = ((int) ofs) >> this->bbt_erase_shift;
-       this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+       if (this->bbt)
+               this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
 
        /* Do we have a flash based bad block table ? */
        if (this->options & NAND_USE_FLASH_BBT)
@@ -466,7 +485,7 @@ static int nand_check_wp (struct mtd_info *mtd)
        struct nand_chip *this = mtd->priv;
        /* Check the WP bit */
        this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-       return (this->read_byte(mtd) & 0x80) ? 0 : 1; 
+       return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; 
 }
 
 /**
@@ -490,6 +509,22 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i
        return nand_isbad_bbt (mtd, ofs, allowbbt);
 }
 
+/* 
+ * Wait for the ready pin, after a command
+ * The timeout is catched later.
+ */
+static void nand_wait_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+       unsigned long   timeo = jiffies + 2;
+
+       /* wait until command is processed or timeout occures */
+       do {
+               if (this->dev_ready(mtd))
+                       return;
+       } while (time_before(jiffies, timeo));  
+}
+
 /**
  * nand_command - [DEFAULT] Send command to NAND device
  * @mtd:       MTD device structure
@@ -571,7 +606,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                this->hwcontrol(mtd, NAND_CTL_SETCLE);
                this->write_byte(mtd, NAND_CMD_STATUS);
                this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-               while ( !(this->read_byte(mtd) & 0x40));
+               while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
                return;
 
        /* This applies to read commands */     
@@ -585,12 +620,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                        return;
                }       
        }
-       
        /* Apply this short delay always to ensure that we do wait tWB in
         * any case on any machine. */
        ndelay (100);
-       /* wait until command is processed */
-       while (!this->dev_ready(mtd));
+
+       nand_wait_ready(mtd);
 }
 
 /**
@@ -619,7 +653,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
        /* Begin command latch cycle */
        this->hwcontrol(mtd, NAND_CTL_SETCLE);
        /* Write out the command to the device. */
-       this->write_byte(mtd, command);
+       this->write_byte(mtd, (command & 0xff));
        /* End command latch cycle */
        this->hwcontrol(mtd, NAND_CTL_CLRCLE);
 
@@ -647,8 +681,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
        
        /* 
         * program and erase have their own busy handlers 
-        * status and sequential in needs no delay
-       */
+        * status, sequential in, and deplete1 need no delay
+        */
        switch (command) {
                        
        case NAND_CMD_CACHEDPROG:
@@ -657,8 +691,19 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
        case NAND_CMD_ERASE2:
        case NAND_CMD_SEQIN:
        case NAND_CMD_STATUS:
+       case NAND_CMD_DEPLETE1:
                return;
 
+       /* 
+        * read error status commands require only a short delay
+        */
+       case NAND_CMD_STATUS_ERROR:
+       case NAND_CMD_STATUS_ERROR0:
+       case NAND_CMD_STATUS_ERROR1:
+       case NAND_CMD_STATUS_ERROR2:
+       case NAND_CMD_STATUS_ERROR3:
+               udelay(this->chip_delay);
+               return;
 
        case NAND_CMD_RESET:
                if (this->dev_ready)    
@@ -667,7 +712,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                this->hwcontrol(mtd, NAND_CTL_SETCLE);
                this->write_byte(mtd, NAND_CMD_STATUS);
                this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-               while ( !(this->read_byte(mtd) & 0x40));
+               while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
                return;
 
        case NAND_CMD_READ0:
@@ -690,12 +735,12 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                        return;
                }       
        }
-       
+
        /* Apply this short delay always to ensure that we do wait tWB in
         * any case on any machine. */
        ndelay (100);
-       /* wait until command is processed */
-       while (!this->dev_ready(mtd));
+
+       nand_wait_ready(mtd);
 }
 
 /**
@@ -785,7 +830,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
                        if (this->read_byte(mtd) & NAND_STATUS_READY)
                                break;
                }
-               yield ();
+               cond_resched();
        }
        status = (int) this->read_byte(mtd);
        return status;
@@ -871,8 +916,14 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
        if (!cached) {
                /* call wait ready function */
                status = this->waitfunc (mtd, this, FL_WRITING);
+
+               /* See if operation failed and additional status checks are available */
+               if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+                       status = this->errstat(mtd, this, FL_WRITING, status, page);
+               }
+
                /* See if device thinks it succeeded */
-               if (status & 0x01) {
+               if (status & NAND_STATUS_FAIL) {
                        DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
                        return -EIO;
                }
@@ -975,7 +1026,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
 
                /* All done, return happy */
                if (!numpages)
@@ -997,23 +1048,24 @@ out:
 #endif
 
 /**
- * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
+ * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
  * @mtd:       MTD device structure
  * @from:      offset to read from
  * @len:       number of bytes to read
  * @retlen:    pointer to variable to store the number of read bytes
  * @buf:       the databuffer to put data
  *
- * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
-*/
+ * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
+ * and flags = 0xff
+ */
 static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
 {
-       return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
-}                         
+       return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
+}
 
 
 /**
- * nand_read_ecc - [MTD Interface] Read data with ECC
+ * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
  * @mtd:       MTD device structure
  * @from:      offset to read from
  * @len:       number of bytes to read
@@ -1022,11 +1074,39 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
  * @oob_buf:   filesystem supplied oob data buffer
  * @oobsel:    oob selection structure
  *
- * NAND read with ECC
+ * This function simply calls nand_do_read_ecc with flags = 0xff
  */
 static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                          size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
 {
+       /* use userspace supplied oobinfo, if zero */
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
+       return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
+}
+
+
+/**
+ * nand_do_read_ecc - [MTD Interface] Read data with ECC
+ * @mtd:       MTD device structure
+ * @from:      offset to read from
+ * @len:       number of bytes to read
+ * @retlen:    pointer to variable to store the number of read bytes
+ * @buf:       the databuffer to put data
+ * @oob_buf:   filesystem supplied oob data buffer (can be NULL)
+ * @oobsel:    oob selection structure
+ * @flags:     flag to indicate if nand_get_device/nand_release_device should be preformed
+ *             and how many corrected error bits are acceptable:
+ *               bits 0..7 - number of tolerable errors
+ *               bit  8    - 0 == do not get/release chip, 1 == get/release chip
+ *
+ * NAND read with ECC
+ */
+int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                            size_t * retlen, u_char * buf, u_char * oob_buf, 
+                            struct nand_oobinfo *oobsel, int flags)
+{
+
        int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
        int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
        struct nand_chip *this = mtd->priv;
@@ -1051,12 +1131,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        }
 
        /* Grab the lock and see if the device is available */
-       nand_get_device (this, mtd ,FL_READING);
+       if (flags & NAND_GET_DEVICE)
+               nand_get_device (this, mtd, FL_READING);
 
-       /* use userspace supplied oobinfo, if zero */
-       if (oobsel == NULL)
-               oobsel = &mtd->oobinfo;
-       
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
                oobsel = this->autooob;
@@ -1118,7 +1195,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                }       
 
                /* get oob area, if we have no oob buffer from fs-driver */
-               if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE)
+               if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
+                       oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                        oob_data = &this->data_buf[end];
 
                eccsteps = this->eccsteps;
@@ -1155,7 +1233,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                                        /* We calc error correction directly, it checks the hw
                                         * generator for an error, reads back the syndrome and
                                         * does the error correction on the fly */
-                                       if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
+                                       ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
+                                       if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
                                                DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 
                                                        "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
                                                ecc_failed++;
@@ -1194,7 +1273,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                                p[i] = ecc_status;
                        }
                        
-                       if (ecc_status == -1) { 
+                       if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {     
                                DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
                                ecc_failed++;
                        }
@@ -1206,14 +1285,14 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                        /* without autoplace. Legacy mode used by YAFFS1 */
                        switch(oobsel->useecc) {
                        case MTD_NANDECC_AUTOPLACE:
+                       case MTD_NANDECC_AUTOPL_USR:
                                /* Walk through the autoplace chunks */
-                               for (i = 0, j = 0; j < mtd->oobavail; i++) {
+                               for (i = 0; oobsel->oobfree[i][1]; i++) {
                                        int from = oobsel->oobfree[i][0];
                                        int num = oobsel->oobfree[i][1];
                                        memcpy(&oob_buf[oob], &oob_data[from], num);
-                                       j+= num;
+                                       oob += num;
                                }
-                               oob += mtd->oobavail;
                                break;
                        case MTD_NANDECC_PLACE:
                                /* YAFFS1 legacy mode */
@@ -1239,7 +1318,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
                        
                if (read == len)
                        break;  
@@ -1264,7 +1343,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        }
 
        /* Deselect and wake up anyone waiting on the device */
-       nand_release_device(mtd);
+       if (flags & NAND_GET_DEVICE)
+               nand_release_device(mtd);
 
        /*
         * Return success, if no ECC failures, else -EBADMSG
@@ -1337,7 +1417,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
 
                /* Read more ? */
                if (i < len) {
@@ -1417,7 +1497,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
                if (!this->dev_ready) 
                        udelay (this->chip_delay);
                else
-                       while (!this->dev_ready(mtd));  
+                       nand_wait_ready(mtd);
                        
                /* Check, if the chip supports auto page increment */ 
                if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
@@ -1567,6 +1647,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                oobsel = this->autooob;
                autoplace = 1;
        }       
+       if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+               autoplace = 1;
 
        /* Setup variables and oob buffer */
        totalpages = len >> this->page_shift;
@@ -1733,7 +1815,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *
        status = this->waitfunc (mtd, this, FL_WRITING);
 
        /* See if device thinks it succeeded */
-       if (status & 0x01) {
+       if (status & NAND_STATUS_FAIL) {
                DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
                ret = -EIO;
                goto out;
@@ -1841,6 +1923,8 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                oobsel = this->autooob;
                autoplace = 1;
        }       
+       if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+               autoplace = 1;
 
        /* Setup start page */
        page = (int) (to >> this->page_shift);
@@ -1987,6 +2071,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
        return nand_erase_nand (mtd, instr, 0);
 }
  
+#define BBT_PAGE_MASK  0xffffff3f
 /**
  * nand_erase_intern - [NAND Interface] erase block(s)
  * @mtd:       MTD device structure
@@ -1999,6 +2084,10 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
 {
        int page, len, status, pages_per_block, ret, chipnr;
        struct nand_chip *this = mtd->priv;
+       int rewrite_bbt[NAND_MAX_CHIPS]={0};    /* flags to indicate the page, if bbt needs to be rewritten. */
+       unsigned int bbt_masked_page;           /* bbt mask to compare to page being erased. */
+                                               /* It is used to see if the current page is in the same */
+                                               /*   256 block group and the same bank as the bbt. */
 
        DEBUG (MTD_DEBUG_LEVEL3,
               "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
@@ -2044,6 +2133,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
                goto erase_exit;
        }
 
+       /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
+       if (this->options & BBT_AUTO_REFRESH) {
+               bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+       } else {
+               bbt_masked_page = 0xffffffff;   /* should not match anything */
+       }
+
        /* Loop through the pages */
        len = instr->len;
 
@@ -2066,13 +2162,26 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
                
                status = this->waitfunc (mtd, this, FL_ERASING);
 
+               /* See if operation failed and additional status checks are available */
+               if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+                       status = this->errstat(mtd, this, FL_ERASING, status, page);
+               }
+
                /* See if block erase succeeded */
-               if (status & 0x01) {
+               if (status & NAND_STATUS_FAIL) {
                        DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
                        instr->state = MTD_ERASE_FAILED;
                        instr->fail_addr = (page << this->page_shift);
                        goto erase_exit;
                }
+
+               /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
+               if (this->options & BBT_AUTO_REFRESH) {
+                       if (((page & BBT_PAGE_MASK) == bbt_masked_page) && 
+                            (page != this->bbt_td->pages[chipnr])) {
+                               rewrite_bbt[chipnr] = (page << this->page_shift);
+                       }
+               }
                
                /* Increment page address and decrement length */
                len -= (1 << this->phys_erase_shift);
@@ -2083,6 +2192,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
                        chipnr++;
                        this->select_chip(mtd, -1);
                        this->select_chip(mtd, chipnr);
+
+                       /* if BBT requires refresh and BBT-PERCHIP, 
+                        *   set the BBT page mask to see if this BBT should be rewritten */
+                       if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
+                               bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+                       }
+
                }
        }
        instr->state = MTD_ERASE_DONE;
@@ -2097,6 +2213,18 @@ erase_exit:
        /* Deselect and wake up anyone waiting on the device */
        nand_release_device(mtd);
 
+       /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
+       if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
+               for (chipnr = 0; chipnr < this->numchips; chipnr++) {
+                       if (rewrite_bbt[chipnr]) {
+                               /* update the BBT for chip */
+                               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", 
+                                       chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
+                               nand_update_bbt (mtd, rewrite_bbt[chipnr]);
+                       }
+               }
+       }
+
        /* Return more or less happy */
        return ret;
 }
@@ -2168,7 +2296,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
  */
 int nand_scan (struct mtd_info *mtd, int maxchips)
 {
-       int i, j, nand_maf_id, nand_dev_id, busw;
+       int i, nand_maf_id, nand_dev_id, busw, maf_id;
        struct nand_chip *this = mtd->priv;
 
        /* Get buswidth to select the correct functions*/
@@ -2256,12 +2384,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                        busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
                }
 
+               /* Try to identify manufacturer */
+               for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
+                       if (nand_manuf_ids[maf_id].id == nand_maf_id)
+                               break;
+               }
+
                /* Check, if buswidth is correct. Hardware drivers should set
                 * this correct ! */
                if (busw != (this->options & NAND_BUSWIDTH_16)) {
                        printk (KERN_INFO "NAND device: Manufacturer ID:"
                                " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-                               nand_manuf_ids[i].name , mtd->name);
+                               nand_manuf_ids[maf_id].name , mtd->name);
                        printk (KERN_WARNING 
                                "NAND bus width %d instead %d bit\n", 
                                        (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
@@ -2300,14 +2434,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
                        this->cmdfunc = nand_command_lp;
                                
-               /* Try to identify manufacturer */
-               for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
-                       if (nand_manuf_ids[j].id == nand_maf_id)
-                               break;
-               }
                printk (KERN_INFO "NAND device: Manufacturer ID:"
                        " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-                       nand_manuf_ids[j].name , nand_flash_ids[i].name);
+                       nand_manuf_ids[maf_id].name , nand_flash_ids[i].name);
                break;
        }
 
@@ -2388,12 +2517,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        
        /* The number of bytes available for the filesystem to place fs dependend
         * oob data */
-       if (this->options & NAND_BUSWIDTH_16) {
-               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
-               if (this->autooob->eccbytes & 0x01)
-                       mtd->oobavail--;
-       } else
-               mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
+       mtd->oobavail = 0;
+       for (i = 0; this->autooob->oobfree[i][1]; i++)
+               mtd->oobavail += this->autooob->oobfree[i][1];
 
        /* 
         * check ECC mode, default to software
@@ -2524,6 +2650,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
 
        mtd->owner = THIS_MODULE;
+       
+       /* Check, if we should skip the bad block table scan */
+       if (this->options & NAND_SKIP_BBTSCAN)
+               return 0;
 
        /* Build bad block table */
        return this->scan_bbt (mtd);
index 9a1949751c1f6c994f3f7f8bb242f820cf6c3e81..c85c69dec540dc7dc7b6e072984129f6931c7668 100644 (file)
@@ -6,7 +6,7 @@
  *   
  *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
  *
- * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.31 2005/02/16 17:09:36 dedekind Exp $
  *
  * 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
 */
 static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
 {
-       int i, end;
+       int i, end = 0;
        uint8_t *p = buf;
 
-       end = paglen + td->offs;
        if (td->options & NAND_BBT_SCANEMPTY) {
+               end = paglen + td->offs;
                for (i = 0; i < end; i++) {
                        if (p[i] != 0xff)
                                return -1;
                }
+               p += end;
        }       
-       p += end;
        
        /* Compare the pattern */
        for (i = 0; i < td->len; i++) {
@@ -95,9 +95,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
                        return -1;
        }
 
-       p += td->len;
-       end += td->len;
        if (td->options & NAND_BBT_SCANEMPTY) {
+               p += td->len;
+               end += td->len;
                for (i = end; i < len; i++) {
                        if (*p++ != 0xff)
                                return -1;
@@ -252,7 +252,7 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de
  * Create a bad block table by scanning the device
  * for the given good/bad block identify pattern
  */
-static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
+static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
 {
        struct nand_chip *this = mtd->priv;
        int i, j, numblocks, len, scanlen;
@@ -270,9 +270,17 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                else    
                        len = 1;
        }
-       scanlen = mtd->oobblock + mtd->oobsize;
-       readlen = len * mtd->oobblock;
-       ooblen = len * mtd->oobsize;
+
+       if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+               /* We need only read few bytes from the OOB area */
+               scanlen = ooblen = 0;
+               readlen = bd->len;
+       } else {
+               /* Full page content should be read */
+               scanlen = mtd->oobblock + mtd->oobsize;
+               readlen = len * mtd->oobblock;
+               ooblen = len * mtd->oobsize;
+       }
 
        if (chip == -1) {
                /* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
@@ -284,7 +292,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                if (chip >= this->numchips) {
                        printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
                                chip + 1, this->numchips);
-                       return
+                       return -EINVAL;
                }
                numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
                startblock = chip * numblocks;
@@ -293,8 +301,22 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
        }
        
        for (i = startblock; i < numblocks;) {
-               nand_read_raw (mtd, buf, from, readlen, ooblen);
+               int ret;
+               
+               if (bd->options & NAND_BBT_SCANEMPTY)
+                       if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
+                               return ret;
+
                for (j = 0; j < len; j++) {
+                       if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+                               size_t retlen;
+                               
+                               /* No need to read pages fully, just read required OOB bytes */
+                               ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs,
+                                                       readlen, &retlen, &buf[0]);
+                               if (ret)
+                                       return ret;
+                       }
                        if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
                                this->bbt[i >> 3] |= 0x03 << (i & 0x6);
                                printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 
@@ -305,6 +327,8 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                i += 2;
                from += (1 << this->bbt_erase_shift);
        }
+
+       return 0;
 }
 
 /**
@@ -589,14 +613,12 @@ write:
  * The function creates a memory based bbt by scanning the device 
  * for manufacturer / software marked good / bad blocks
 */
-static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
 {
        struct nand_chip *this = mtd->priv;
 
-       /* Ensure that we only scan for the pattern and nothing else */
-       bd->options = 0;
-       create_bbt (mtd, this->data_buf, bd, -1);
-       return 0;
+       bd->options &= ~NAND_BBT_SCANEMPTY;
+       return create_bbt (mtd, this->data_buf, bd, -1);
 }
 
 /**
@@ -808,8 +830,14 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
        /* If no primary table decriptor is given, scan the device
         * to build a memory based bad block table
         */
-       if (!td)
-               return nand_memory_bbt(mtd, bd);
+       if (!td) {
+               if ((res = nand_memory_bbt(mtd, bd))) {
+                       printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
+                       kfree (this->bbt);
+                       this->bbt = NULL;
+               }
+               return res;
+       }
 
        /* Allocate a temporary buffer for one eraseblock incl. oob */
        len = (1 << this->bbt_erase_shift);
@@ -904,14 +932,11 @@ out:
 }
 
 /* Define some generic bad / good block scan pattern which are used 
- * while scanning a device for factory marked good / bad blocks
- * 
- * The memory based patterns just 
- */
+ * while scanning a device for factory marked good / bad blocks. */
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
 
 static struct nand_bbt_descr smallpage_memorybased = {
-       .options = 0,
+       .options = NAND_BBT_SCAN2NDPAGE,
        .offs = 5,
        .len = 1,
        .pattern = scan_ff_pattern
@@ -1042,7 +1067,7 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
        res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
 
        DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", 
-               (unsigned int)offs, res, block >> 1);
+               (unsigned int)offs, block >> 1, res);
 
        switch ((int)res) {
        case 0x00:      return 0;
index 2d8c4321275bbc60308fd333a7cb0c32a8ff253c..4b2bfae6f50154dcca037dc500c07ff27a4966e6 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
   *
- * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
+ * $Id: nand_ids.c,v 1.12 2005/02/16 09:33:27 gleixner Exp $
  *
  * 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
@@ -62,8 +62,6 @@ struct nand_flash_dev nand_flash_ids[] = {
        
        {"NAND 256MiB 3,3V 8-bit",      0x71, 512, 256, 0x4000, 0},
 
-       {"NAND 512MiB 3,3V 8-bit",      0xDC, 512, 512, 0x4000, 0},
-       
        /* These are the new chips with large page size. The pagesize
        * and the erasesize is determined from the extended id bytes
        */
@@ -103,7 +101,7 @@ struct nand_flash_dev nand_flash_ids[] = {
         * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
         * There are more speed improvements for reads and writes possible, but not implemented now 
         */
-       {"AND 128MiB 3,3V 8-bit",       0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+       {"AND 128MiB 3,3V 8-bit",       0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
 
        {NULL,}
 };
@@ -118,6 +116,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_NATIONAL, "National"},
        {NAND_MFR_RENESAS, "Renesas"},
        {NAND_MFR_STMICRO, "ST Micro"},
+        {NAND_MFR_HYNIX, "Hynix"},
        {0x0, "Unknown"}
 };
 
index 13feefd7d8caf2bc12aa7a9a1637d65c68d7ad2a..754b6ed7ce140b5470f5c8533ac45b0aedf4030a 100644 (file)
@@ -22,7 +22,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
  *
- * $Id: nandsim.c,v 1.7 2004/12/06 11:53:06 dedekind Exp $
+ * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $
  */
 
 #include <linux/config.h>
@@ -1483,33 +1483,6 @@ ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
        }
 }
 
-/*
- * Having only NAND chip IDs we call nand_scan which detects NAND flash
- * parameters and then calls scan_bbt in order to scan/find/build the
- * NAND flash bad block table. But since at that moment the NAND flash
- * image isn't allocated in the simulator, errors arise. To avoid this
- * we redefine the scan_bbt callback and initialize the nandsim structure
- * before the flash media scanning.
- */
-int ns_scan_bbt(struct mtd_info *mtd)
-{ 
-       struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-       struct nandsim   *ns   = (struct nandsim *)(chip->priv);
-       int retval;
-
-       if (!NS_IS_INITIALIZED(ns))
-               if ((retval = init_nandsim(mtd)) != 0) {
-                       NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
-                       return retval;
-               }
-       if ((retval = nand_default_bbt(mtd)) != 0) {
-               free_nandsim(ns);
-               return retval;
-       }
-
-       return 0;
-}
-
 /*
  * Module initialization function
  */
@@ -1544,7 +1517,6 @@ int __init ns_init_module(void)
        chip->hwcontrol  = ns_hwcontrol;
        chip->read_byte  = ns_nand_read_byte;
        chip->dev_ready  = ns_device_ready;
-       chip->scan_bbt   = ns_scan_bbt;
        chip->write_byte = ns_nand_write_byte;
        chip->write_buf  = ns_nand_write_buf;
        chip->read_buf   = ns_nand_read_buf;
@@ -1552,6 +1524,7 @@ int __init ns_init_module(void)
        chip->write_word = ns_nand_write_word;
        chip->read_word  = ns_nand_read_word;
        chip->eccmode    = NAND_ECC_SOFT;
+       chip->options   |= NAND_SKIP_BBTSCAN;
 
        /* 
         * Perform minimum nandsim structure initialization to handle
@@ -1580,6 +1553,16 @@ int __init ns_init_module(void)
                goto error;
        }
 
+       if ((retval = init_nandsim(nsmtd)) != 0) {
+               NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
+               goto error;
+       }
+       
+       if ((retval = nand_default_bbt(nsmtd)) != 0) {
+               free_nandsim(nand);
+               goto error;
+       }
+
        /* Register NAND as one big partition */
        add_mtd_partitions(nsmtd, &nand->part, 1);
 
index 02305a2adca7cf0e1202fdc68eaa4c002a2281de..031051cbde7637589a224f14f618485fcb688040 100644 (file)
@@ -6,7 +6,7 @@
  *  Derived from drivers/mtd/nand/spia.c
  *       Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *
- * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $
+ * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $
  *
  * 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
@@ -83,13 +83,18 @@ static struct mtd_info *rtc_from4_mtd = NULL;
 #define RTC_FROM4_RS_ECC_CHK           (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070)
 #define RTC_FROM4_RS_ECC_CHK_ERROR     (1 << 7)
 
+#define ERR_STAT_ECC_AVAILABLE         0x20
+
 /* Undefine for software ECC */
 #define RTC_FROM4_HWECC        1
 
+/* Define as 1 for no virtual erase blocks (in JFFS2) */
+#define RTC_FROM4_NO_VIRTBLOCKS        0
+
 /*
  * Module stuff
  */
-static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE);
+static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE);
 
 const static struct mtd_partition partition_info[] = {
         {
@@ -267,7 +272,6 @@ static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip)
 }
 
 
-
 /*
  * rtc_from4_nand_device_ready - hardware specific ready/busy check
  * @mtd:       MTD device structure
@@ -286,6 +290,40 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
 
 }
 
+
+/*
+ * deplete - code to perform device recovery in case there was a power loss
+ * @mtd:       MTD device structure
+ * @chip:      Chip to select (0 == slot 3, 1 == slot 4)
+ *
+ * If there was a sudden loss of power during an erase operation, a 
+ * "device recovery" operation must be performed when power is restored
+ * to ensure correct operation.  This routine performs the required steps
+ * for the requested chip.
+ *
+ * See page 86 of the data sheet for details.
+ *
+ */
+static void deplete(struct mtd_info *mtd, int chip)
+{
+        struct nand_chip *this = mtd->priv;
+
+        /* wait until device is ready */
+        while (!this->dev_ready(mtd));
+
+       this->select_chip(mtd, chip);
+                                                                                                                                              
+       /* Send the commands for device recovery, phase 1 */
+       this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
+       this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
+
+       /* Send the commands for device recovery, phase 2 */
+       this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004);
+       this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
+
+}
+
+
 #ifdef RTC_FROM4_HWECC
 /*
  * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function
@@ -329,6 +367,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
 
 }
 
+
 /*
  * rtc_from4_calculate_ecc - hardware specific code to read ECC code
  * @mtd:       MTD device structure
@@ -356,6 +395,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
        ecc_code[7] |= 0x0f;    /* set the last four bits (not used) */
 }
 
+
 /*
  * rtc_from4_correct_data - hardware specific code to correct data using ECC code
  * @mtd:       MTD device structure
@@ -365,16 +405,14 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
  *
  * The FPGA tells us fast, if there's an error or not. If no, we go back happy
  * else we read the ecc results from the fpga and call the rs library to decode
- * and hopefully correct the error
+ * and hopefully correct the error.
  *
- * For now I use the code, which we read from the FLASH to use the RS lib,
- * as the syndrom conversion has a unresolved issue.
  */
 static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
 {
        int i, j, res;
        unsigned short status; 
-       uint16_t par[6], syn[6], tmp;
+       uint16_t par[6], syn[6];
        uint8_t ecc[8];
         volatile unsigned short *rs_ecc;
 
@@ -416,15 +454,86 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
        }
 
        /* Let the library code do its magic.*/
-       res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL);
+       res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
        if (res > 0) {
                DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " 
                        "ECC corrected %d errors on read\n", res);
        }
        return res;
 }
+
+
+/**
+ * rtc_from4_errstat - perform additional error status checks
+ * @mtd:       MTD device structure
+ * @this:      NAND chip structure
+ * @state:     state or the operation
+ * @status:    status code returned from read status
+ * @page:      startpage inside the chip, must be called with (page & this->pagemask)
+ * 
+ * Perform additional error status checks on erase and write failures 
+ * to determine if errors are correctable.  For this device, correctable 
+ * 1-bit errors on erase and write are considered acceptable.
+ *
+ * note: see pages 34..37 of data sheet for details.
+ *
+ */
+static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page)
+{
+       int     er_stat=0;
+       int     rtn, retlen;
+       size_t  len;
+       uint8_t *buf;
+       int     i;
+
+       this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
+
+        if (state == FL_ERASING) {
+               for (i=0; i<4; i++) {
+                       if (status & 1<<(i+1)) {
+                               this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1);
+                               rtn = this->read_byte(mtd);
+                               this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
+                               if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
+                                       er_stat |= 1<<(i+1);    /* err_ecc_not_avail */
+                               }
+                       }
+               }
+       } else if (state == FL_WRITING) {
+               /* single bank write logic */
+               this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1);
+               rtn = this->read_byte(mtd);
+               this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
+               if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
+                       er_stat |= 1<<1;        /* err_ecc_not_avail */
+               } else {
+                       len = mtd->oobblock;
+                       buf = kmalloc (len, GFP_KERNEL);
+                       if (!buf) {
+                               printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n");
+                               er_stat = 1;                    /* if we can't check, assume failed */
+                       } else {
+                               /* recovery read */
+                               /* page read */
+                               rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1);
+                               if (rtn) {      /* if read failed or > 1-bit error corrected */
+                                       er_stat |= 1<<1;        /* ECC read failed */
+                               }
+                               kfree(buf);
+                       }
+               }
+       }
+
+       rtn = status;
+       if (er_stat == 0) {                             /* if ECC is available   */
+               rtn = (status & ~NAND_STATUS_FAIL);     /*   clear the error bit */
+       }
+
+       return rtn;
+}
 #endif
 
+
 /*
  * Main initialization routine
  */
@@ -432,6 +541,7 @@ int __init rtc_from4_init (void)
 {
        struct nand_chip *this;
        unsigned short bcr1, bcr2, wcr2;
+       int i;
 
        /* Allocate memory for MTD device structure and private data */
        rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip),
@@ -483,6 +593,8 @@ int __init rtc_from4_init (void)
 
         this->eccmode = NAND_ECC_HW8_512;
        this->options |= NAND_HWECC_SYNDROME;
+       /* return the status of extra status and ECC checks */
+       this->errstat = rtc_from4_errstat;
        /* set the nand_oobinfo to support FPGA H/W error detection */
        this->autooob = &rtc_from4_nand_oobinfo;
        this->enable_hwecc = rtc_from4_enable_hwecc;
@@ -504,6 +616,18 @@ int __init rtc_from4_init (void)
                return -ENXIO;
        }
 
+       /* Perform 'device recovery' for each chip in case there was a power loss. */
+       for (i=0; i < this->numchips; i++) {
+               deplete(rtc_from4_mtd, i);
+       }
+
+#if RTC_FROM4_NO_VIRTBLOCKS
+       /* use a smaller erase block to minimize wasted space when a block is bad */
+       /* note: this uses eight times as much RAM as using the default and makes */
+       /*       mounts take four times as long. */
+       rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS;
+#endif
+
        /* Register the partitions */
        add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
 
index d05e9b97947d575a79300ea1526f9b95541813d3..64b1d95e3e37c7de348bc265cc1876590f41094a 100644 (file)
@@ -1,7 +1,8 @@
 /* linux/drivers/mtd/nand/s3c2410.c
  *
  * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ *     http://www.simtec.co.uk/products/SWLINUX/
+ *     Ben Dooks <ben@simtec.co.uk>
  *
  * Samsung S3C2410 NAND driver
  *
  *     23-Sep-2004  BJD  Mulitple device support
  *     28-Sep-2004  BJD  Fixed ECC placement for Hardware mode
  *     12-Oct-2004  BJD  Fixed errors in use of platform data
+ *     18-Feb-2005  BJD  Fix sparse errors
+ *     14-Mar-2005  BJD  Applied tglx's code reduction patch
  *
- * $Id: s3c2410.c,v 1.7 2005/01/05 18:05:14 dwmw2 Exp $
+ * $Id: s3c2410.c,v 1.12 2005/03/17 11:31:26 bjd Exp $
  *
  * 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
@@ -69,10 +72,10 @@ static int hardware_ecc = 0;
  */
 
 static struct nand_oobinfo nand_hw_eccoob = {
-       .useecc = MTD_NANDECC_AUTOPLACE,
-       .eccbytes = 3,
-       .eccpos = {0, 1, 2 },
-       .oobfree = { {8, 8} }
+       .useecc         = MTD_NANDECC_AUTOPLACE,
+       .eccbytes       = 3,
+       .eccpos         = {0, 1, 2 },
+       .oobfree        = { {8, 8} }
 };
 
 /* controller and mtd information */
@@ -99,7 +102,7 @@ struct s3c2410_nand_info {
        struct device                   *device;
        struct resource                 *area;
        struct clk                      *clk;
-       void                            *regs;
+       void __iomem                    *regs;
        int                             mtd_count;
 };
 
@@ -234,6 +237,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
 static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
 {
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+       struct nand_chip *chip = mtd->priv;
        unsigned long cur;
 
        switch (cmd) {
@@ -249,117 +253,22 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
                writel(cur, info->regs + S3C2410_NFCONF);
                break;
 
-               /* we don't need to implement these */
        case NAND_CTL_SETCLE:
-       case NAND_CTL_CLRCLE:
-       case NAND_CTL_SETALE:
-       case NAND_CTL_CLRALE:
-               pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd);
+               chip->IO_ADDR_W    = info->regs + S3C2410_NFCMD;
                break;
-       }
-}
-
-/* s3c2410_nand_command
- *
- * This function implements sending commands and the relevant address
- * information to the chip, via the hardware controller. Since the
- * S3C2410 generates the correct ALE/CLE signaling automatically, we
- * do not need to use hwcontrol.
-*/
-
-static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command,
-                                 int column, int page_addr)
-{
-       register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-       register struct nand_chip *this = mtd->priv;
-
-       /*
-        * Write out the command to the device.
-        */
-       if (command == NAND_CMD_SEQIN) {
-               int readcmd;
-
-               if (column >= mtd->oobblock) {
-                       /* OOB area */
-                       column -= mtd->oobblock;
-                       readcmd = NAND_CMD_READOOB;
-               } else if (column < 256) {
-                       /* First 256 bytes --> READ0 */
-                       readcmd = NAND_CMD_READ0;
-               } else {
-                       column -= 256;
-                       readcmd = NAND_CMD_READ1;
-               }
-               
-               writeb(readcmd, info->regs + S3C2410_NFCMD);
-       }
-       writeb(command, info->regs + S3C2410_NFCMD);
-
-       /* Set ALE and clear CLE to start address cycle */
 
-       if (column != -1 || page_addr != -1) {
+       case NAND_CTL_SETALE:
+               chip->IO_ADDR_W    = info->regs + S3C2410_NFADDR;
+               break;
 
-               /* Serially input address */
-               if (column != -1) {
-                       /* Adjust columns for 16 bit buswidth */
-                       if (this->options & NAND_BUSWIDTH_16)
-                               column >>= 1;
-                       writeb(column, info->regs + S3C2410_NFADDR);
-               }
-               if (page_addr != -1) {
-                       writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR);
-                       writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR);
-                       /* One more address cycle for higher density devices */
-                       if (this->chipsize & 0x0c000000) 
-                               writeb((unsigned char) ((page_addr >> 16) & 0x0f),
-                                      info->regs + S3C2410_NFADDR);
-               }
-               /* Latch in address */
-       }
-       
-       /* 
-        * program and erase have their own busy handlers 
-        * status and sequential in needs no delay
-       */
-       switch (command) {
-                       
-       case NAND_CMD_PAGEPROG:
-       case NAND_CMD_ERASE1:
-       case NAND_CMD_ERASE2:
-       case NAND_CMD_SEQIN:
-       case NAND_CMD_STATUS:
-               return;
-
-       case NAND_CMD_RESET:
-               if (this->dev_ready)    
-                       break;
-
-               udelay(this->chip_delay);
-               writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD);
-
-               while ( !(this->read_byte(mtd) & 0x40));
-               return;
-
-       /* This applies to read commands */     
+               /* NAND_CTL_CLRCLE: */
+               /* NAND_CTL_CLRALE: */
        default:
-               /* 
-                * If we don't have access to the busy pin, we apply the given
-                * command delay
-               */
-               if (!this->dev_ready) {
-                       udelay (this->chip_delay);
-                       return;
-               }       
+               chip->IO_ADDR_W    = info->regs + S3C2410_NFDATA;
+               break;
        }
-       
-       /* Apply this short delay always to ensure that we do wait tWB in
-        * any case on any machine. */
-       ndelay (100);
-       /* wait until command is processed */
-       while (!this->dev_ready(mtd));
 }
 
-
 /* s3c2410_nand_devready()
  *
  * returns 0 if the nand is busy, 1 if it is ready
@@ -523,11 +432,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
 {
        struct nand_chip *chip = &nmtd->chip;
 
-       chip->IO_ADDR_R    = (char *)info->regs + S3C2410_NFDATA;
-       chip->IO_ADDR_W    = (char *)info->regs + S3C2410_NFDATA;
+       chip->IO_ADDR_R    = info->regs + S3C2410_NFDATA;
+       chip->IO_ADDR_W    = info->regs + S3C2410_NFDATA;
        chip->hwcontrol    = s3c2410_nand_hwcontrol;
        chip->dev_ready    = s3c2410_nand_devready;
-       chip->cmdfunc      = s3c2410_nand_command;
        chip->write_buf    = s3c2410_nand_write_buf;
        chip->read_buf     = s3c2410_nand_read_buf;
        chip->select_chip  = s3c2410_nand_select_chip;
index 29572793334c2ad70a06f22d85c7dedc484da7d0..9853b87bb756d67ce7f42899f5af54b68a28814d 100755 (executable)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2004 Richard Purdie
  *
- *  $Id: sharpsl.c,v 1.3 2005/01/03 14:53:50 rpurdie Exp $
+ *  $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $
  *
  *  Based on Sharp's NAND driver sharp_sl.c
  *
@@ -216,7 +216,7 @@ sharpsl_nand_init(void)
                nr_partitions = DEFAULT_NUM_PARTITIONS;
                sharpsl_partition_info = sharpsl_nand_default_partition_info;
                if (machine_is_poodle()) {
-                       sharpsl_partition_info[1].size=22 * 1024 * 1024;
+                       sharpsl_partition_info[1].size=30 * 1024 * 1024;
                } else if (machine_is_corgi() || machine_is_shepherd()) {
                        sharpsl_partition_info[1].size=25 * 1024 * 1024;
                } else if (machine_is_husky()) {
index 062177956239b1c25c6199579e9f72faecc21212..8d50a610c0e0bc34adcdc62f46fd55ab203e74d2 100644 (file)
@@ -1036,26 +1036,18 @@ config JFFS2_FS_DEBUG
          If reporting bugs, please try to have available a full dump of the
          messages at debug level 1 while the misbehaviour was occurring.
 
-config JFFS2_FS_NAND
-       bool "JFFS2 support for NAND flash"
+config JFFS2_FS_WRITEBUFFER
+       bool "JFFS2 write-buffering support"
        depends on JFFS2_FS
-       default n
+       default y
        help
-         This enables the support for NAND flash in JFFS2. NAND is a newer
-         type of flash chip design than the traditional NOR flash, with
-         higher density but a handful of characteristics which make it more
-         interesting for the file system to use.
+         This enables the write-buffering support in JFFS2.
 
-         Say 'N' unless you have NAND flash.
-
-config JFFS2_FS_NOR_ECC
-        bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)"
-        depends on JFFS2_FS && EXPERIMENTAL
-        default n
-        help
-          This enables the experimental support for NOR flash with transparent
-          ECC for JFFS2. This type of flash chip is not common, however it is
-          available from ST Microelectronics.
+         This functionality is required to support JFFS2 on the following
+         types of flash devices:
+           - NAND flash
+           - NOR flash with transparent ECC
+           - DataFlash
 
 config JFFS2_COMPRESSION_OPTIONS
        bool "Advanced compression options for JFFS2"
index e3c38ccf9c7d86fe9b9b503c25937ff2e1ffee31..f1afe681ecd6a950f685476905b24b0e164a881e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux Journalling Flash File System v2 (JFFS2)
 #
-# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $
+# $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $
 #
 
 obj-$(CONFIG_JFFS2_FS) += jffs2.o
@@ -11,8 +11,7 @@ jffs2-y       += read.o nodemgmt.o readinode.o write.o scan.o gc.o
 jffs2-y        += symlink.o build.o erase.o background.o fs.o writev.o
 jffs2-y        += super.o
 
-jffs2-$(CONFIG_JFFS2_FS_NAND)  += wbuf.o
-jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
+jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER)   += wbuf.o
 jffs2-$(CONFIG_JFFS2_RUBIN)    += compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)    += compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)     += compr_zlib.o
index 49771cf8513a2e1489f0e92bf051744fda285993..b7943439b6ec995cbe795603c91c63566526e211 100644 (file)
@@ -1,4 +1,4 @@
-       $Id: README.Locking,v 1.9 2004/11/20 10:35:40 dwmw2 Exp $
+       $Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $
 
        JFFS2 LOCKING DOCUMENTATION
        ---------------------------
@@ -108,6 +108,10 @@ in-core jffs2_inode_cache objects (each inode in JFFS2 has the
 correspondent jffs2_inode_cache object). So, the inocache_lock
 has to be locked while walking the c->inocache_list hash buckets.
 
+This spinlock also covers allocation of new inode numbers, which is
+currently just '++->highest_ino++', but might one day get more complicated
+if we need to deal with wrapping after 4 milliard inode numbers are used.
+
 Note, the f->sem guarantees that the correspondent jffs2_inode_cache
 will not be removed. So, it is allowed to access it without locking
 the inocache_lock spinlock. 
index 638836b277d444d36c07acc8284a0824e99769f2..0f224384f176fa1d529e9c3feb06d576de1b1096 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $
+ * $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $
  *
  */
 
@@ -37,7 +37,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
        if (c->gc_task)
                BUG();
 
-       init_MUTEX_LOCKED(&c->gc_thread_start);
+       init_completion(&c->gc_thread_start);
        init_completion(&c->gc_thread_exit);
 
        pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES);
@@ -48,7 +48,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
        } else {
                /* Wait for it... */
                D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid));
-               down(&c->gc_thread_start);
+               wait_for_completion(&c->gc_thread_start);
        }
  
        return ret;
@@ -56,13 +56,16 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
 
 void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
 {
+       int wait = 0;
        spin_lock(&c->erase_completion_lock);
        if (c->gc_task) {
                D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
                send_sig(SIGKILL, c->gc_task, 1);
+               wait = 1;
        }
        spin_unlock(&c->erase_completion_lock);
-       wait_for_completion(&c->gc_thread_exit);
+       if (wait)
+               wait_for_completion(&c->gc_thread_exit);
 }
 
 static int jffs2_garbage_collect_thread(void *_c)
@@ -75,7 +78,7 @@ static int jffs2_garbage_collect_thread(void *_c)
        allow_signal(SIGCONT);
 
        c->gc_task = current;
-       up(&c->gc_thread_start);
+       complete(&c->gc_thread_start);
 
        set_user_nice(current, 10);
 
index a01dd5fdbb95f4280dd3f8900e8e8a43277bc20a..3dd5394921c9c6bb09a1dae11f87799f3c8be68f 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $
+ * $Id: build.c,v 1.70 2005/02/28 08:21:05 dedekind Exp $
  *
  */
 
@@ -97,14 +97,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        /* First, scan the medium and build all the inode caches with
           lists of physical nodes */
 
-       c->flags |= JFFS2_SB_FLAG_MOUNTING;
+       c->flags |= JFFS2_SB_FLAG_SCANNING;
        ret = jffs2_scan_medium(c);
+       c->flags &= ~JFFS2_SB_FLAG_SCANNING;
        if (ret)
                goto exit;
 
        D1(printk(KERN_DEBUG "Scanned flash completely\n"));
        D2(jffs2_dump_block_lists(c));
 
+       c->flags |= JFFS2_SB_FLAG_BUILDING;
        /* Now scan the directory tree, increasing nlink according to every dirent found. */
        for_each_inode(i, c, ic) {
                D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
@@ -116,7 +118,6 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
                        cond_resched();
                }
        }
-       c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
 
        D1(printk(KERN_DEBUG "Pass 1 complete\n"));
 
@@ -164,6 +165,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
                ic->scan_dents = NULL;
                cond_resched();
        }
+       c->flags &= ~JFFS2_SB_FLAG_BUILDING;
+       
        D1(printk(KERN_DEBUG "Pass 3 complete\n"));
        D2(jffs2_dump_block_lists(c));
 
index 078a30e406b52668b4e9daa4fa5d5b1a4aced6db..83f7e0788fd0a551ad715b2ad2ea380fa07d7a33 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $
  *
  */
 
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/zlib.h>
 #include <linux/zutil.h>
-#include <asm/semaphore.h>
 #include "nodelist.h"
 #include "compr.h"
 
index 757306fa3ff477aebcfa0ab861d45bfd7360acdd..6421be874ce3db128e59a18c96fa9595b6edeb34 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: dir.c,v 1.85 2005/03/01 10:34:03 dedekind Exp $
  *
  */
 
@@ -296,11 +296,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        struct jffs2_full_dirent *fd;
        int namelen;
        uint32_t alloclen, phys_ofs;
-       int ret;
+       int ret, targetlen = strlen(target);
 
        /* FIXME: If you care. We'd need to use frags for the target
           if it grows much more than this */
-       if (strlen(target) > 254)
+       if (targetlen > 254)
                return -EINVAL;
 
        ri = jffs2_alloc_raw_inode();
@@ -314,7 +314,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
         * Just the node will do for now, though 
         */
        namelen = dentry->d_name.len;
-       ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
 
        if (ret) {
                jffs2_free_raw_inode(ri);
@@ -333,16 +333,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
 
        f = JFFS2_INODE_INFO(inode);
 
-       inode->i_size = strlen(target);
+       inode->i_size = targetlen;
        ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
        ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
        ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
 
        ri->compr = JFFS2_COMPR_NONE;
-       ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target)));
+       ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
        
-       fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL);
+       fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL);
 
        jffs2_free_raw_inode(ri);
 
@@ -353,6 +353,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                jffs2_clear_inode(inode);
                return PTR_ERR(fn);
        }
+
+       /* We use f->dents field to store the target path. */
+       f->dents = kmalloc(targetlen + 1, GFP_KERNEL);
+       if (!f->dents) {
+               printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
+               up(&f->sem);
+               jffs2_complete_reservation(c);
+               jffs2_clear_inode(inode);
+               return -ENOMEM;
+       }
+
+       memcpy(f->dents, target, targetlen + 1);
+       D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents));
+
        /* No data here. Only a metadata node, which will be 
           obsoleted by the first data write
        */
index 41451e8bf36125d9bb25be772f0f4e4a79caefd4..6a4c0a3685daf41bce5b054719ef104b42ef7c3a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: erase.c,v 1.76 2005/05/03 15:11:40 dedekind Exp $
  *
  */
 
@@ -48,6 +48,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
 #else /* Linux */
        struct erase_info *instr;
 
+       D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size));
        instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
        if (!instr) {
                printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
@@ -233,7 +234,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
                        continue;
                } 
 
-               if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) {
+               if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) {
                        /* It's in the block we're erasing */
                        struct jffs2_raw_node_ref *this;
 
@@ -277,11 +278,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
                printk("\n");
        });
 
-       if (ic->nodes == (void *)ic) {
-               D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
+       if (ic->nodes == (void *)ic && ic->nlink == 0)
                jffs2_del_ino_cache(c, ic);
-               jffs2_free_inode_cache(ic);
-       }
 }
 
 static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
@@ -310,7 +308,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
        int ret;
        uint32_t bad_offset;
 
-       if (!jffs2_cleanmarker_oob(c)) {
+       if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) {
                marker_ref = jffs2_alloc_raw_node_ref();
                if (!marker_ref) {
                        printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
@@ -335,7 +333,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
 
                        bad_offset = ofs;
 
-                       ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
+                       ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
+
                        if (ret) {
                                printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
                                goto bad;
@@ -351,7 +350,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                                        bad_offset += i;
                                        printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
                                bad: 
-                                       if (!jffs2_cleanmarker_oob(c))
+                                       if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0))
                                                jffs2_free_raw_node_ref(marker_ref);
                                        kfree(ebuf);
                                bad2:
@@ -383,6 +382,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                        
                jeb->first_node = jeb->last_node = NULL;
 
+               jeb->free_size = c->sector_size;
+               jeb->used_size = 0;
+               jeb->dirty_size = 0;
+               jeb->wasted_size = 0;
+       } else if (c->cleanmarker_size == 0) {
+               jeb->first_node = jeb->last_node = NULL;
+
                jeb->free_size = c->sector_size;
                jeb->used_size = 0;
                jeb->dirty_size = 0;
index 30ab233fe423010abcb7504796e56985ca565e93..c91c66e5e869fa9bc1d3f31361ccdfc9d8d21c86 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $
+ * $Id: fs.c,v 1.53 2005/02/09 09:23:53 pavlov Exp $
  *
  */
 
@@ -450,11 +450,15 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
 
        c = JFFS2_SB_INFO(sb);
 
-#ifndef CONFIG_JFFS2_FS_NAND
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
        if (c->mtd->type == MTD_NANDFLASH) {
                printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n");
                return -EINVAL;
        }
+       if (c->mtd->type == MTD_DATAFLASH) {
+               printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n");
+               return -EINVAL;
+       }
 #endif
 
        c->flash_size = c->mtd->size;
@@ -661,6 +665,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
                if (ret)
                        return ret;
        }
+       
+       /* and Dataflash */
+       if (jffs2_dataflash(c)) {
+               ret = jffs2_dataflash_setup(c);
+               if (ret)
+                       return ret;
+       }
+       
        return ret;
 }
 
@@ -674,4 +686,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
        if (jffs2_nor_ecc(c)) {
                jffs2_nor_ecc_flash_cleanup(c);
        }
+       
+       /* and DataFlash */
+       if (jffs2_dataflash(c)) {
+               jffs2_dataflash_cleanup(c);
+       }
 }
index 87ec74ff5930eb0b9d591a93dbb9d8d1aab9c800..7086cd6345038cbc9015dacb4b23dcaf7f4f081f 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $
+ * $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $
  *
  */
 
@@ -50,6 +50,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
           put the clever wear-levelling algorithms. Eventually.  */
        /* We possibly want to favour the dirtier blocks more when the
           number of free blocks is low. */
+again:
        if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) {
                D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
                nextlist = &c->bad_used_list;
@@ -79,6 +80,13 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
                D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"));
 
                nextlist = &c->erasable_list;
+       } else if (!list_empty(&c->erasable_pending_wbuf_list)) {
+               /* There are blocks are wating for the wbuf sync */
+               D1(printk(KERN_DEBUG "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n"));
+               spin_unlock(&c->erase_completion_lock);
+               jffs2_flush_wbuf_pad(c);
+               spin_lock(&c->erase_completion_lock);
+               goto again;
        } else {
                /* Eep. All were empty */
                D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"));
@@ -661,9 +669,10 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
 {
        struct jffs2_full_dnode *new_fn;
        struct jffs2_raw_inode ri;
+       struct jffs2_node_frag *last_frag;
        jint16_t dev;
        char *mdata = NULL, mdatalen = 0;
-       uint32_t alloclen, phys_ofs;
+       uint32_t alloclen, phys_ofs, ilen;
        int ret;
 
        if (S_ISBLK(JFFS2_F_I_MODE(f)) ||
@@ -699,6 +708,14 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
                goto out;
        }
        
+       last_frag = frag_last(&f->fragtree);
+       if (last_frag)
+               /* Fetch the inode length from the fragtree rather then
+                * from i_size since i_size may have not been updated yet */
+               ilen = last_frag->ofs + last_frag->size;
+       else
+               ilen = JFFS2_F_I_SIZE(f);
+       
        memset(&ri, 0, sizeof(ri));
        ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
@@ -710,7 +727,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
        ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
        ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
        ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
-       ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
+       ri.isize = cpu_to_je32(ilen);
        ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
        ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
        ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
@@ -816,8 +833,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
 
                        /* Doesn't matter if there's one in the same erase block. We're going to 
                           delete it too at the same time. */
-                       if ((raw->flash_offset & ~(c->sector_size-1)) ==
-                           (fd->raw->flash_offset & ~(c->sector_size-1)))
+                       if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset))
                                continue;
 
                        D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
@@ -891,7 +907,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
        struct jffs2_raw_inode ri;
        struct jffs2_node_frag *frag;
        struct jffs2_full_dnode *new_fn;
-       uint32_t alloclen, phys_ofs;
+       uint32_t alloclen, phys_ofs, ilen;
        int ret;
 
        D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",
@@ -951,10 +967,19 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
                ri.csize = cpu_to_je32(0);
                ri.compr = JFFS2_COMPR_ZERO;
        }
+       
+       frag = frag_last(&f->fragtree);
+       if (frag)
+               /* Fetch the inode length from the fragtree rather then
+                * from i_size since i_size may have not been updated yet */
+               ilen = frag->ofs + frag->size;
+       else
+               ilen = JFFS2_F_I_SIZE(f);
+
        ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
        ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
        ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
-       ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
+       ri.isize = cpu_to_je32(ilen);
        ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
        ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
        ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
@@ -1161,7 +1186,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", 
                          orig_start, orig_end, start, end));
 
-               BUG_ON(end > JFFS2_F_I_SIZE(f));
+               D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size));
                BUG_ON(end < orig_end);
                BUG_ON(start > orig_start);
        }
index cd6a8bd13e0b514d5ad2df1654be9aac93cc9931..8a8e4b86382477c2a2a8ba2bcff9fd04ef02953a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.c,v 1.90 2004/12/08 17:59:20 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.94 2005/04/13 13:22:35 dwmw2 Exp $
  *
  */
 
@@ -127,7 +127,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 
        valid_ref = jffs2_first_valid_node(f->inocache->nodes);
 
-       if (!valid_ref)
+       if (!valid_ref && (f->inocache->ino != 1))
                printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
 
        while (valid_ref) {
@@ -489,9 +489,13 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t
 void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new)
 {
        struct jffs2_inode_cache **prev;
-       D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
+
        spin_lock(&c->inocache_lock);
-       
+       if (!new->ino)
+               new->ino = ++c->highest_ino;
+
+       D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
+
        prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE];
 
        while ((*prev) && (*prev)->ino < new->ino) {
@@ -506,7 +510,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new
 void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
 {
        struct jffs2_inode_cache **prev;
-       D2(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
+       D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
        spin_lock(&c->inocache_lock);
        
        prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE];
@@ -518,6 +522,14 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
                *prev = old->next;
        }
 
+       /* Free it now unless it's in READING or CLEARING state, which
+          are the transitions upon read_inode() and clear_inode(). The
+          rest of the time we know nobody else is looking at it, and 
+          if it's held by read_inode() or clear_inode() they'll free it
+          for themselves. */
+       if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING)
+               jffs2_free_inode_cache(old);
+
        spin_unlock(&c->inocache_lock);
 }
 
@@ -530,7 +542,6 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c)
                this = c->inocache_list[i];
                while (this) {
                        next = this->next;
-                       D2(printk(KERN_DEBUG "jffs2_free_ino_caches: Freeing ino #%u at %p\n", this->ino, this));
                        jffs2_free_inode_cache(this);
                        this = next;
                }
index a4864d05ea926da21683f01af25c0a227978681f..a65539f28b067fdae3fa92627403530525ea7c75 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $
+ * $Id: nodelist.h,v 1.130 2005/04/09 10:46:59 dedekind Exp $
  *
  */
 
@@ -135,6 +135,7 @@ struct jffs2_inode_cache {
 #define INO_STATE_CHECKEDABSENT        3       /* Checked, cleared again */
 #define INO_STATE_GC           4       /* GCing a 'pristine' node */
 #define INO_STATE_READING      5       /* In read_inode() */
+#define INO_STATE_CLEARING     6       /* In clear_inode() */
 
 #define INOCACHE_HASHSIZE 128
 
@@ -362,6 +363,18 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
                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;
+
+       if (!node)
+               return NULL;
+       while(node->rb_right)
+               node = node->rb_right;
+       return rb_entry(node, struct jffs2_node_frag, rb);
+}
+
 #define rb_parent(rb) ((rb)->rb_parent)
 #define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb)
 #define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb)
@@ -462,7 +475,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c);
 /* erase.c */
 void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
 
-#ifdef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 /* wbuf.c */
 int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
 int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
index 2651135bdf427b417d652fa2839afb289d2b0d09..c1d8b5ed9ab95221b89b2af4bbcdd985de16775f 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodemgmt.c,v 1.115 2004/11/22 11:07:21 dwmw2 Exp $
+ * $Id: nodemgmt.c,v 1.122 2005/05/06 09:30:27 dedekind Exp $
  *
  */
 
@@ -75,7 +75,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
                        dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
                        if (dirty < c->nospc_dirty_size) {
                                if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
-                                       printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n");
+                                       D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n"));
                                        break;
                                }
                                D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
@@ -98,7 +98,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
                        avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
                        if ( (avail / c->sector_size) <= blocksneeded) {
                                if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
-                                       printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n");
+                                       D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n"));
                                        break;
                                }
 
@@ -308,7 +308,10 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
 
        D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len));
 #if 1
-       if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) {
+       /* we could get some obsolete nodes after nextblock was refiled
+          in wbuf.c */
+       if ((c->nextblock || !ref_obsolete(new))
+           &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) {
                printk(KERN_WARNING "argh. node added in wrong place\n");
                jffs2_free_raw_node_ref(new);
                return -EINVAL;
@@ -332,7 +335,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
                c->used_size += len;
        }
 
-       if (!jeb->free_size && !jeb->dirty_size) {
+       if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) {
                /* If it lives on the dirty_list, jffs2_reserve_space will put it there */
                D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
                          jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
@@ -400,7 +403,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
        jeb = &c->blocks[blocknr];
 
        if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) &&
-           !(c->flags & JFFS2_SB_FLAG_MOUNTING)) {
+           !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) {
                /* Hm. This may confuse static lock analysis. If any of the above 
                   three conditions is false, we're going to return from this 
                   function without actually obliterating any nodes or freeing
@@ -434,7 +437,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
 
        // Take care, that wasted size is taken into concern
        if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
-               D1(printk("Dirtying\n"));
+               D1(printk(KERN_DEBUG "Dirtying\n"));
                addedsize = ref_totlen(c, jeb, ref);
                jeb->dirty_size += ref_totlen(c, jeb, ref);
                c->dirty_size += ref_totlen(c, jeb, ref);
@@ -456,7 +459,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                        }
                }
        } else {
-               D1(printk("Wasting\n"));
+               D1(printk(KERN_DEBUG "Wasting\n"));
                addedsize = 0;
                jeb->wasted_size += ref_totlen(c, jeb, ref);
                c->wasted_size += ref_totlen(c, jeb, ref);      
@@ -467,8 +470,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
 
        D1(ACCT_PARANOIA_CHECK(jeb));
 
-       if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
-               /* Mount in progress. Don't muck about with the block
+       if (c->flags & JFFS2_SB_FLAG_SCANNING) {
+               /* Flash scanning is in progress. Don't muck about with the block
                   lists because they're not ready yet, and don't actually
                   obliterate nodes that look obsolete. If they weren't 
                   marked obsolete on the flash at the time they _became_
@@ -527,7 +530,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
 
        spin_unlock(&c->erase_completion_lock);
 
-       if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) {
+       if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) ||
+               (c->flags & JFFS2_SB_FLAG_BUILDING)) {
                /* We didn't lock the erase_free_sem */
                return;
        }
@@ -590,11 +594,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                *p = ref->next_in_ino;
                ref->next_in_ino = NULL;
 
-               if (ic->nodes == (void *)ic) {
-                       D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
+               if (ic->nodes == (void *)ic && ic->nlink == 0)
                        jffs2_del_ino_cache(c, ic);
-                       jffs2_free_inode_cache(ic);
-               }
 
                spin_unlock(&c->erase_completion_lock);
        }
index 03b0acc37b736c93f3dfbbecad7c954dafc84790..5a2d2ee4f641776a566831e1bf5241c1cffe5f4a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.56 2005/05/03 15:19:00 dedekind Exp $
  *
  */
 
@@ -97,10 +97,13 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 #endif
 }
 
+
 #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
 
-#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
+#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
 #define jffs2_can_mark_obsolete(c) (1)
+#define jffs2_is_writebuffered(c) (0)
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
 
@@ -116,11 +119,14 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 #define jffs2_wbuf_timeout NULL
 #define jffs2_wbuf_process NULL
 #define jffs2_nor_ecc(c) (0)
+#define jffs2_dataflash(c) (0)
 #define jffs2_nor_ecc_flash_setup(c) (0)
 #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
 
 #else /* NAND and/or ECC'd NOR support present */
 
+#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
+#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
 #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM)
 #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
 
@@ -142,16 +148,16 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
 int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
 void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
-#ifdef CONFIG_JFFS2_FS_NOR_ECC
+
 #define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC))
 int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c);
 void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
-#else
-#define jffs2_nor_ecc(c) (0)
-#define jffs2_nor_ecc_flash_setup(c) (0)
-#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
-#endif /* NOR ECC */
-#endif /* NAND */
+
+#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH)
+int jffs2_dataflash_setup(struct jffs2_sb_info *c);
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
+
+#endif /* WRITEBUFFER */
 
 /* erase.c */
 static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
index eb493dc06db74ce553832a4fa598566e69214c2a..c7f9068907cfa6a6f4b13e2694b788ed389cdd11 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $
+ * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $
  *
  */
 
@@ -214,33 +214,3 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
        return 0;
 }
 
-/* Core function to read symlink target. */
-char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
-{
-       char *buf;
-       int ret;
-
-       down(&f->sem);
-
-       if (!f->metadata) {
-               printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino);
-               up(&f->sem);
-               return ERR_PTR(-EINVAL);
-       }
-       buf = kmalloc(f->metadata->size+1, GFP_USER);
-       if (!buf) {
-               up(&f->sem);
-               return ERR_PTR(-ENOMEM);
-       }
-       buf[f->metadata->size]=0;
-
-       ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size);
-
-       up(&f->sem);
-
-       if (ret) {
-               kfree(buf);
-               return ERR_PTR(ret);
-       }
-       return buf;
-}
index aca4a0b17bcd42975480273a19d3827197a8d926..ef552477c813f4d5a126f64c25a7fd3c320dca0b 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $
+ * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $
  *
  */
 
@@ -623,6 +623,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                   case. */
                if (!je32_to_cpu(latest_node->isize))
                        latest_node->isize = latest_node->dsize;
+
+               if (f->inocache->state != INO_STATE_CHECKING) {
+                       /* Symlink's inode data is the target path. Read it and
+                        * keep in RAM to facilitate quick follow symlink operation.
+                        * We use f->dents field to store the target path, which
+                        * is somewhat ugly. */
+                       f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
+                       if (!f->dents) {
+                               printk(KERN_WARNING "Can't allocate %d bytes of memory "
+                                               "for the symlink target path cache\n",
+                                               je32_to_cpu(latest_node->csize));
+                               up(&f->sem);
+                               jffs2_do_clear_inode(c, f);
+                               return -ENOMEM;
+                       }
+                       
+                       ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node),
+                                               je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents);
+                       
+                       if (ret  || retlen != je32_to_cpu(latest_node->csize)) {
+                               if (retlen != je32_to_cpu(latest_node->csize))
+                                       ret = -EIO;
+                               kfree(f->dents);
+                               f->dents = NULL;
+                               up(&f->sem);
+                               jffs2_do_clear_inode(c, f);
+                               return -ret;
+                       }
+
+                       ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0';
+                       D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n",
+                                               (char *)f->dents));
+               }
+               
                /* fall through... */
 
        case S_IFBLK:
@@ -672,6 +706,9 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
        down(&f->sem);
        deleted = f->inocache && !f->inocache->nlink;
 
+       if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
+               jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
+
        if (f->metadata) {
                if (deleted)
                        jffs2_mark_node_obsolete(c, f->metadata->raw);
@@ -680,16 +717,27 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
 
        jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
 
-       fds = f->dents;
+       /* For symlink inodes we us f->dents to store the target path name */
+       if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) {
+               if (f->dents) {
+                       kfree(f->dents);
+                       f->dents = NULL;
+               }
+       } else {
+               fds = f->dents;
 
-       while(fds) {
-               fd = fds;
-               fds = fd->next;
-               jffs2_free_full_dirent(fd);
+               while(fds) {
+                       fd = fds;
+                       fds = fd->next;
+                       jffs2_free_full_dirent(fd);
+               }
        }
 
-       if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
+       if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
                jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
+               if (f->inocache->nodes == (void *)f->inocache)
+                       jffs2_del_ino_cache(c, f->inocache);
+       }
 
        up(&f->sem);
 }
index ded53584a897dff6d0e93f3d005222288b442d6c..b63160f83bab8fe693d23025f275157840b0f2d6 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $
+ * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $
  *
  */
 #include <linux/kernel.h>
@@ -19,7 +19,7 @@
 #include <linux/compiler.h>
 #include "nodelist.h"
 
-#define EMPTY_SCAN_SIZE 1024
+#define DEFAULT_EMPTY_SCAN_SIZE 1024
 
 #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
                c->free_size -= _x; c->dirty_size += _x; \
@@ -68,13 +68,21 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
 static inline int min_free(struct jffs2_sb_info *c)
 {
        uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
                return c->wbuf_pagesize;
 #endif
        return min;
 
 }
+
+static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) {
+       if (sector_size < DEFAULT_EMPTY_SCAN_SIZE)
+               return sector_size;
+       else
+               return DEFAULT_EMPTY_SCAN_SIZE;
+}
+
 int jffs2_scan_medium(struct jffs2_sb_info *c)
 {
        int i, ret;
@@ -220,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                c->dirty_size -= c->nextblock->dirty_size;
                c->nextblock->dirty_size = 0;
        }
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
                /* If we're going to start writing into a block which already 
                   contains data, and the end of the data isn't page-aligned,
@@ -286,7 +294,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
        uint32_t hdr_crc, buf_ofs, buf_len;
        int err;
        int noise = 0;
-#ifdef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        int cleanmarkerfound = 0;
 #endif
 
@@ -295,7 +303,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
 
        D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));
 
-#ifdef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        if (jffs2_cleanmarker_oob(c)) {
                int ret = jffs2_check_nand_cleanmarker(c, jeb);
                D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
@@ -316,7 +324,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
        if (!buf_size) {
                buf_len = c->sector_size;
        } else {
-               buf_len = EMPTY_SCAN_SIZE;
+               buf_len = EMPTY_SCAN_SIZE(c->sector_size);
                err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
                if (err)
                        return err;
@@ -326,11 +334,11 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
        ofs = 0;
 
        /* Scan only 4KiB of 0xFF before declaring it's empty */
-       while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
+       while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
                ofs += 4;
 
-       if (ofs == EMPTY_SCAN_SIZE) {
-#ifdef CONFIG_JFFS2_FS_NAND
+       if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) {
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
                if (jffs2_cleanmarker_oob(c)) {
                        /* scan oob, take care of cleanmarker */
                        int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
@@ -343,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
                }
 #endif
                D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
-               return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
+               if (c->cleanmarker_size == 0)
+                       return BLK_STATE_CLEANMARKER;   /* don't bother with re-erase */
+               else
+                       return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
        }
        if (ofs) {
                D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
@@ -422,8 +433,8 @@ scan_more:
                        /* If we're only checking the beginning of a block with a cleanmarker,
                           bail now */
                        if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && 
-                           c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) {
-                               D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE));
+                           c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) {
+                               D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
                                return BLK_STATE_CLEANMARKER;
                        }
 
@@ -618,7 +629,7 @@ scan_more:
        }
 
        if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size 
-               && (!jeb->first_node || !jeb->first_node->next_in_ino) )
+               && (!jeb->first_node || !jeb->first_node->next_phys) )
                return BLK_STATE_CLEANMARKER;
                
        /* move blocks with max 4 byte dirty space to cleanlist */      
index 6b2a441d2766e63add98241621e13cb12752c05e..2cf14cf8b35aacb82e26fc39486a9f485b442160 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: super.c,v 1.104 2004/11/23 15:37:31 gleixner Exp $
+ * $Id: super.c,v 1.106 2005/05/18 11:37:25 dedekind Exp $
  *
  */
 
@@ -270,8 +270,6 @@ static void jffs2_put_super (struct super_block *sb)
 
        D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
 
-       if (!(sb->s_flags & MS_RDONLY))
-               jffs2_stop_garbage_collect_thread(c);
        down(&c->alloc_sem);
        jffs2_flush_wbuf_pad(c);
        up(&c->alloc_sem);
@@ -292,6 +290,8 @@ static void jffs2_put_super (struct super_block *sb)
 static void jffs2_kill_sb(struct super_block *sb)
 {
        struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
+       if (!(sb->s_flags & MS_RDONLY))
+               jffs2_stop_garbage_collect_thread(c);
        generic_shutdown_super(sb);
        put_mtd_device(c->mtd);
        kfree(c);
@@ -309,7 +309,7 @@ static int __init init_jffs2_fs(void)
        int ret;
 
        printk(KERN_INFO "JFFS2 version 2.2."
-#ifdef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
               " (NAND)"
 #endif
               " (C) 2001-2003 Red Hat, Inc.\n");
index 7b1820d13712040e0d1aadda20e4b8459e7f5e0a..65ab6b001dcac9d24d9d40aa8bc8527980a0587b 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $
+ * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $
  *
  */
 
 #include "nodelist.h"
 
 static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
-static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd);
 
 struct inode_operations jffs2_symlink_inode_operations =
 {      
        .readlink =     generic_readlink,
        .follow_link =  jffs2_follow_link,
-       .put_link =     jffs2_put_link,
        .setattr =      jffs2_setattr
 };
 
 static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-       unsigned char *buf;
-       buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
-       nd_set_link(nd, buf);
+       struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
+       
+       /*
+        * We don't acquire the f->sem mutex here since the only data we
+        * use is f->dents which in case of the symlink inode points to the
+        * symlink's target path.
+        *
+        * 1. If we are here the inode has already built and f->dents has
+        * to point to the target path.
+        * 2. Nobody uses f->dents (if the inode is symlink's inode). The
+        * exception is inode freeing function which frees f->dents. But
+        * it can't be called while we are here and before VFS has
+        * stopped using our f->dents string which we provide by means of
+        * nd_set_link() call.
+        */
+       
+       if (!f->dents) {
+               printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
+               return -EIO;
+       }
+       D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents));
+
+       nd_set_link(nd, (char *)f->dents);
+       
+       /*
+        * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe
+        * since the only way that may cause f->dents to be changed is iput() operation.
+        * But VFS will not use f->dents after iput() has been called.
+        */
        return 0;
 }
 
-static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd)
-{
-       char *s = nd_get_link(nd);
-       if (!IS_ERR(s))
-               kfree(s);
-}
index c8128069ecf0a8baff6020ce830a9bff87eb0102..996d922e503e188f2cbd502618833743a402bae0 100644 (file)
@@ -9,7 +9,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: wbuf.c,v 1.82 2004/11/20 22:08:31 dwmw2 Exp $
+ * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $
  *
  */
 
@@ -83,7 +83,7 @@ static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
        struct jffs2_inodirty *new;
 
        /* Mark the superblock dirty so that kupdated will flush... */
-       OFNI_BS_2SFFJ(c)->s_dirt = 1;
+       jffs2_erase_pending_trigger(c);
 
        if (jffs2_wbuf_pending_for_ino(c, ino))
                return;
@@ -130,7 +130,10 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
        }
 }
 
-static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+#define REFILE_NOTEMPTY 0
+#define REFILE_ANYWAY   1
+
+static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty)
 {
        D1(printk("About to refile bad block at %08x\n", jeb->offset));
 
@@ -144,7 +147,7 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock
                D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
                list_add(&jeb->list, &c->bad_used_list);
        } else {
-               BUG();
+               BUG_ON(allow_empty == REFILE_NOTEMPTY);
                /* It has to have had some nodes or we couldn't be here */
                D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
                list_add(&jeb->list, &c->erase_pending_list);
@@ -179,7 +182,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
        jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
 
-       jffs2_block_refile(c, jeb);
+       jffs2_block_refile(c, jeb, REFILE_NOTEMPTY);
 
        /* Find the first node to be recovered, by skipping over every
           node which ends before the wbuf starts, or which is obsolete. */
@@ -264,17 +267,16 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
        ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
        if (ret) {
                printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
-               if (buf)
-                       kfree(buf);
+               kfree(buf);
                return;
        }
        if (end-start >= c->wbuf_pagesize) {
-               /* Need to do another write immediately. This, btw,
-                means that we'll be writing from 'buf' and not from
-                the wbuf. Since if we're writing from the wbuf there
-                won't be more than a wbuf full of data, now will
-                there? :) */
-
+               /* Need to do another write immediately, but it's possible
+                  that this is just because the wbuf itself is completely
+                  full, and there's nothing earlier read back from the 
+                  flash. Hence 'buf' isn't necessarily what we're writing 
+                  from. */
+               unsigned char *rewrite_buf = buf?:c->wbuf;
                uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
 
                D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
@@ -292,9 +294,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 #endif
                if (jffs2_cleanmarker_oob(c))
                        ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
-                                               buf, NULL, c->oobinfo);
+                                               rewrite_buf, NULL, c->oobinfo);
                else
-                       ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf);
+                       ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf);
 
                if (ret || retlen != towrite) {
                        /* Argh. We tried. Really we did. */
@@ -321,10 +323,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
                c->wbuf_len = (end - start) - towrite;
                c->wbuf_ofs = ofs + towrite;
-               memcpy(c->wbuf, buf + towrite, c->wbuf_len);
+               memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
                /* Don't muck about with c->wbuf_inodes. False positives are harmless. */
-
-               kfree(buf);
+               if (buf)
+                       kfree(buf);
        } else {
                /* OK, now we're left with the dregs in whichever buffer we're using */
                if (buf) {
@@ -413,9 +415,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
        int ret;
        size_t retlen;
 
-       /* Nothing to do if not NAND flash. In particular, we shouldn't
+       /* Nothing to do if not write-buffering the flash. In particular, we shouldn't
           del_timer() the timer we never initialised. */
-       if (jffs2_can_mark_obsolete(c))
+       if (!jffs2_is_writebuffered(c))
                return 0;
 
        if (!down_trylock(&c->alloc_sem)) {
@@ -424,7 +426,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
                BUG();
        }
 
-       if(!c->wbuf || !c->wbuf_len)
+       if (!c->wbuf_len)       /* already checked c->wbuf above */
                return 0;
 
        /* claim remaining space on the page
@@ -433,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
           if we have a switch to next page, we will not have
           enough remaining space for this. 
        */
-       if (pad) {
+       if (pad && !jffs2_dataflash(c)) {
                c->wbuf_len = PAD(c->wbuf_len);
 
                /* Pad with JFFS2_DIRTY_BITMASK initially.  this helps out ECC'd NOR
@@ -484,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
        spin_lock(&c->erase_completion_lock);
 
        /* Adjust free size of the block if we padded. */
-       if (pad) {
+       if (pad && !jffs2_dataflash(c)) {
                struct jffs2_eraseblock *jeb;
 
                jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
@@ -532,6 +534,9 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
 
        D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
 
+       if (!c->wbuf)
+               return 0;
+
        down(&c->alloc_sem);
        if (!jffs2_wbuf_pending_for_ino(c, ino)) {
                D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
@@ -547,6 +552,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
                D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
                down_write(&c->wbuf_sem);
                ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+               /* retry flushing wbuf in case jffs2_wbuf_recover
+                  left some data in the wbuf */
+               if (ret)
+                       ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
                up_write(&c->wbuf_sem);
        } else while (old_wbuf_len &&
                      old_wbuf_ofs == c->wbuf_ofs) {
@@ -561,6 +570,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
                        down(&c->alloc_sem);
                        down_write(&c->wbuf_sem);
                        ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+                       /* retry flushing wbuf in case jffs2_wbuf_recover
+                          left some data in the wbuf */
+                       if (ret)
+                               ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
                        up_write(&c->wbuf_sem);
                        break;
                }
@@ -578,15 +591,27 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
 {
        int ret;
 
+       if (!c->wbuf)
+               return 0;
+
        down_write(&c->wbuf_sem);
        ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
+       /* retry - maybe wbuf recover left some data in wbuf. */
+       if (ret)
+               ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
        up_write(&c->wbuf_sem);
 
        return ret;
 }
 
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
+#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
+#else
 #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
 #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
+#endif
+
 int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
 {
        struct kvec outvecs[3];
@@ -601,7 +626,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
        uint32_t outvec_to = to;
 
        /* If not NAND flash, don't bother */
-       if (!c->wbuf)
+       if (!jffs2_is_writebuffered(c))
                return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
        
        down_write(&c->wbuf_sem);
@@ -630,7 +655,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
           erase block. Anything else, and you die.
           New block starts at xxx000c (0-b = block header)
        */
-       if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) {
+       if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
                /* It's a write to a new block */
                if (c->wbuf_len) {
                        D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
@@ -762,9 +787,18 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
                
                if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
                        /* At this point we have no problem,
-                          c->wbuf is empty. 
+                          c->wbuf is empty. However refile nextblock to avoid
+                          writing again to same address.
                        */
-                       *retlen = donelen;
+                       struct jffs2_eraseblock *jeb;
+
+                       spin_lock(&c->erase_completion_lock);
+
+                       jeb = &c->blocks[outvec_to / c->sector_size];
+                       jffs2_block_refile(c, jeb, REFILE_ANYWAY);
+
+                       *retlen = 0;
+                       spin_unlock(&c->erase_completion_lock);
                        goto exit;
                }
                
@@ -819,7 +853,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r
 {
        struct kvec vecs[1];
 
-       if (jffs2_can_mark_obsolete(c))
+       if (!jffs2_is_writebuffered(c))
                return c->mtd->write(c->mtd, ofs, len, retlen, buf);
 
        vecs[0].iov_base = (unsigned char *) buf;
@@ -835,39 +869,38 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
        loff_t  orbf = 0, owbf = 0, lwbf = 0;
        int     ret;
 
-       /* Read flash */
-       if (!jffs2_can_mark_obsolete(c)) {
-               down_read(&c->wbuf_sem);
-
-               if (jffs2_cleanmarker_oob(c))
-                       ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
-               else
-                       ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
-
-               if ( (ret == -EBADMSG) && (*retlen == len) ) {
-                       printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
-                              len, ofs);
-                       /* 
-                        * We have the raw data without ECC correction in the buffer, maybe 
-                        * we are lucky and all data or parts are correct. We check the node.
-                        * If data are corrupted node check will sort it out.
-                        * We keep this block, it will fail on write or erase and the we
-                        * mark it bad. Or should we do that now? But we should give him a chance.
-                        * Maybe we had a system crash or power loss before the ecc write or  
-                        * a erase was completed.
-                        * So we return success. :)
-                        */
-                       ret = 0;
-                }      
-       } else
+       if (!jffs2_is_writebuffered(c))
                return c->mtd->read(c->mtd, ofs, len, retlen, buf);
 
+       /* Read flash */
+       down_read(&c->wbuf_sem);
+       if (jffs2_cleanmarker_oob(c))
+               ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
+       else
+               ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
+
+       if ( (ret == -EBADMSG) && (*retlen == len) ) {
+               printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
+                      len, ofs);
+               /* 
+                * We have the raw data without ECC correction in the buffer, maybe 
+                * we are lucky and all data or parts are correct. We check the node.
+                * If data are corrupted node check will sort it out.
+                * We keep this block, it will fail on write or erase and the we
+                * mark it bad. Or should we do that now? But we should give him a chance.
+                * Maybe we had a system crash or power loss before the ecc write or  
+                * a erase was completed.
+                * So we return success. :)
+                */
+               ret = 0;
+       }       
+
        /* if no writebuffer available or write buffer empty, return */
        if (!c->wbuf_pagesize || !c->wbuf_len)
                goto exit;
 
        /* if we read in a different block, return */
-       if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) 
+       if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))
                goto exit;
 
        if (ofs >= c->wbuf_ofs) {
@@ -1161,7 +1194,27 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
        kfree(c->wbuf);
 }
 
-#ifdef CONFIG_JFFS2_FS_NOR_ECC
+int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
+       c->cleanmarker_size = 0;                /* No cleanmarkers needed */
+       
+       /* Initialize write buffer */
+       init_rwsem(&c->wbuf_sem);
+       c->wbuf_pagesize = c->sector_size;
+       c->wbuf_ofs = 0xFFFFFFFF;
+
+       c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+       if (!c->wbuf)
+               return -ENOMEM;
+
+       printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize);
+
+       return 0;
+}
+
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
+       kfree(c->wbuf);
+}
+
 int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
        /* Cleanmarker is actually larger on the flashes */
        c->cleanmarker_size = 16;
@@ -1181,4 +1234,3 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
 void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) {
        kfree(c->wbuf);
 }
-#endif
index 80a5db542629bbce99134bda6ad0f66bdd6712e2..69100615d9aef17535f808ed6e5e805b404f6eb2 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $
+ * $Id: write.c,v 1.92 2005/04/13 13:22:35 dwmw2 Exp $
  *
  */
 
@@ -35,13 +35,12 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
        f->inocache = ic;
        f->inocache->nlink = 1;
        f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
-       f->inocache->ino = ++c->highest_ino;
        f->inocache->state = INO_STATE_PRESENT;
 
-       ri->ino = cpu_to_je32(f->inocache->ino);
 
-       D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
        jffs2_add_ino_cache(c, f->inocache);
+       D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
+       ri->ino = cpu_to_je32(f->inocache->ino);
 
        ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
@@ -136,6 +135,15 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
        raw->__totlen = PAD(sizeof(*ri)+datalen);
        raw->next_phys = NULL;
 
+       if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) {
+               BUG_ON(!retried);
+               D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, "
+                               "highest version %d -> updating dnode\n", 
+                               je32_to_cpu(ri->version), f->highest_version));
+               ri->version = cpu_to_je32(++f->highest_version);
+               ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
+       }
+
        ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
                                 (alloc_mode==ALLOC_GC)?0:f->inocache->ino);
 
@@ -280,6 +288,16 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
        raw->__totlen = PAD(sizeof(*rd)+namelen);
        raw->next_phys = NULL;
 
+       if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) {
+               BUG_ON(!retried);
+               D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, "
+                                    "highest version %d -> updating dirent\n",
+                                    je32_to_cpu(rd->version), f->highest_version));
+               rd->version = cpu_to_je32(++f->highest_version);
+               fd->version = je32_to_cpu(rd->version);
+               rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
+       }
+
        ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
                                 (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
        if (ret || (retlen != sizeof(*rd) + namelen)) {
@@ -625,20 +643,23 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
 
                down(&dead_f->sem);
 
-               while (dead_f->dents) {
-                       /* There can be only deleted ones */
-                       fd = dead_f->dents;
-                       
-                       dead_f->dents = fd->next;
-                       
-                       if (fd->ino) {
-                               printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
-                                      dead_f->inocache->ino, fd->name, fd->ino);
-                       } else {
-                               D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino));
+               if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
+                       while (dead_f->dents) {
+                               /* There can be only deleted ones */
+                               fd = dead_f->dents;
+                               
+                               dead_f->dents = fd->next;
+                               
+                               if (fd->ino) {
+                                       printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
+                                              dead_f->inocache->ino, fd->name, fd->ino);
+                               } else {
+                                       D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
+                                               fd->name, dead_f->inocache->ino));
+                               }
+                               jffs2_mark_node_obsolete(c, fd->raw);
+                               jffs2_free_full_dirent(fd);
                        }
-                       jffs2_mark_node_obsolete(c, fd->raw);
-                       jffs2_free_full_dirent(fd);
                }
 
                dead_f->inocache->nlink--;
index 4afc8d8c2e9e11d0e57ea176989ce30783c9ed78..1e21546622de3b0bb2269550141774b5c5919402 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.48 2004/11/20 10:41:12 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.52 2005/05/19 16:12:17 gleixner Exp $ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
@@ -14,7 +14,8 @@
 #include <linux/rwsem.h>
 
 #define JFFS2_SB_FLAG_RO 1
-#define JFFS2_SB_FLAG_MOUNTING 2
+#define JFFS2_SB_FLAG_SCANNING 2 /* Flash scanning is in progress */
+#define JFFS2_SB_FLAG_BUILDING 4 /* File system building is in progress */
 
 struct jffs2_inodirty;
 
@@ -31,7 +32,7 @@ struct jffs2_sb_info {
        unsigned int flags;
 
        struct task_struct *gc_task;    /* GC task struct */
-       struct semaphore gc_thread_start; /* GC thread start mutex */
+       struct completion gc_thread_start; /* GC thread start completion */
        struct completion gc_thread_exit; /* GC thread exit completion port */
 
        struct semaphore alloc_sem;     /* Used to protect all the following 
@@ -94,7 +95,7 @@ struct jffs2_sb_info {
           to an obsoleted node. I don't like this. Alternatives welcomed. */
        struct semaphore erase_free_sem;
 
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        /* Write-behind buffer for NAND flash */
        unsigned char *wbuf;
        uint32_t wbuf_ofs;
index 2ed8c585021e2f28413f536b417883c2f50fd51a..66e0a32efbac1fa0fa7ad3ac76039fbbb6a1367c 100644 (file)
@@ -1,7 +1,7 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.50 2004/11/20 12:46:51 dwmw2 Exp $
+ * $Id: cfi.h,v 1.53 2005/03/15 19:03:13 gleixner Exp $
  */
 
 #ifndef __MTD_CFI_H__
@@ -148,6 +148,14 @@ struct cfi_pri_intelext {
        uint8_t  extra[0];
 } __attribute__((packed));
 
+struct cfi_intelext_otpinfo {
+       uint32_t ProtRegAddr;
+       uint16_t FactGroups;
+       uint8_t  FactProtRegSize;
+       uint16_t UserGroups;
+       uint8_t  UserProtRegSize;
+} __attribute__((packed));
+
 struct cfi_intelext_blockinfo {
        uint16_t NumIdentBlocks;
        uint16_t BlockSize;
@@ -244,7 +252,7 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int
  * It looks too long to be inline, but in the common case it should almost all
  * get optimised away. 
  */
-static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
 {
        map_word val = { {0} };
        int wordwidth, words_per_bus, chip_mode, chips_per_word;
@@ -307,6 +315,69 @@ static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cf
 }
 #define CMD(x)  cfi_build_cmd((x), map, cfi)
 
+
+static inline unsigned char cfi_merge_status(map_word val, struct map_info *map, 
+                                          struct cfi_private *cfi)
+{
+       int wordwidth, words_per_bus, chip_mode, chips_per_word;
+       unsigned long onestat, res = 0;
+       int i;
+
+       /* We do it this way to give the compiler a fighting chance 
+          of optimising away all the crap for 'bankwidth' larger than
+          an unsigned long, in the common case where that support is
+          disabled */
+       if (map_bankwidth_is_large(map)) {
+               wordwidth = sizeof(unsigned long);
+               words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
+       } else {
+               wordwidth = map_bankwidth(map);
+               words_per_bus = 1;
+       }
+       
+       chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
+       chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
+
+       onestat = val.x[0];
+       /* Or all status words together */
+       for (i=1; i < words_per_bus; i++) {
+               onestat |= val.x[i];
+       }
+
+       res = onestat;
+       switch(chips_per_word) {
+       default: BUG();
+#if BITS_PER_LONG >= 64
+       case 8:
+               res |= (onestat >> (chip_mode * 32));
+#endif
+       case 4:
+               res |= (onestat >> (chip_mode * 16));
+       case 2:
+               res |= (onestat >> (chip_mode * 8));
+       case 1:
+               ;
+       }
+
+       /* Last, determine what the bit-pattern should be for a single
+          device, according to chip mode and endianness... */
+       switch (chip_mode) {
+       case 1:
+               break;
+       case 2:
+               res = cfi16_to_cpu(res);
+               break;
+       case 4:
+               res = cfi32_to_cpu(res);
+               break;
+       default: BUG();
+       }
+       return res;
+}
+
+#define MERGESTATUS(x) cfi_merge_status((x), map, cfi)
+
+
 /*
  * Sends a CFI command to a bank of flash for the given geometry.
  *
index c66ba812bf90d447f3dd5f692d5f7c69aee1e842..675776fa3e27159a85b4a4792ca00986b4417eb1 100644 (file)
@@ -6,7 +6,7 @@
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.15 2004/11/05 22:41:06 nico Exp $
+ * $Id: flashchip.h,v 1.17 2005/03/14 18:27:15 bjd Exp $
  *
  */
 
@@ -29,6 +29,7 @@ typedef enum {
        FL_ERASE_SUSPENDED,
        FL_WRITING,
        FL_WRITING_TO_BUFFER,
+       FL_OTP_WRITE,
        FL_WRITE_SUSPENDING,
        FL_WRITE_SUSPENDED,
        FL_PM_SUSPENDED,
@@ -62,8 +63,8 @@ struct flchip {
        flstate_t state;
        flstate_t oldstate;
 
-       int write_suspended:1;
-       int erase_suspended:1;
+       unsigned int write_suspended:1;
+       unsigned int erase_suspended:1;
        unsigned long in_progress_block_addr;
 
        spinlock_t *mutex;
index f0268b99c900e53fced158d491637989365d1df1..142963f01d2947d9c4c2c52c84afc8a8d020f34e 100644 (file)
@@ -1,6 +1,6 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.46 2005/01/05 17:09:44 dwmw2 Exp $ */
+/* $Id: map.h,v 1.52 2005/05/25 10:29:41 gleixner Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #define __LINUX_MTD_MAP_H__
@@ -263,6 +263,17 @@ static inline map_word map_word_and(struct map_info *map, map_word val1, map_wor
        return r;
 }
 
+static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
+{
+       map_word r;
+       int i;
+
+       for (i=0; i<map_words(map); i++) {
+               r.x[i] = val1.x[i] & ~val2.x[i];
+       }
+       return r;
+}
+
 static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
 {
        map_word r;
@@ -273,6 +284,7 @@ static inline map_word map_word_or(struct map_info *map, map_word val1, map_word
        }
        return r;
 }
+
 #define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
 
 static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
@@ -328,16 +340,27 @@ static inline map_word map_word_load_partial(struct map_info *map, map_word orig
        return orig;
 }
 
+#if BITS_PER_LONG < 64
+#define MAP_FF_LIMIT 4
+#else
+#define MAP_FF_LIMIT 8
+#endif
+
 static inline map_word map_word_ff(struct map_info *map)
 {
        map_word r;
        int i;
-
-       for (i=0; i<map_words(map); i++) {
-               r.x[i] = ~0UL;
+       
+       if (map_bankwidth(map) < MAP_FF_LIMIT) {
+               int bw = 8 * map_bankwidth(map);
+               r.x[0] = (1 << bw) - 1;
+       } else {
+               for (i=0; i<map_words(map); i++)
+                       r.x[i] = ~0UL;
        }
        return r;
 }
+
 static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
 {
        map_word r;
@@ -405,7 +428,7 @@ extern void simple_map_init(struct map_info *);
 
 
 #define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth))
-#define map_is_linear(map) (1)
+#define map_is_linear(map) ({ (void)(map); 1; })
 
 #endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
 
index b3d134392b3128c5582185e468a35c909c9314df..c50c3f3927d959ceda9e1ad2539e9df785219139 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $
+ * $Id: mtd.h,v 1.59 2005/04/11 10:19:02 gleixner Exp $
  *
  * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
  *
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/uio.h>
+#include <linux/notifier.h>
 
 #include <linux/mtd/compatmac.h>
 #include <mtd/mtd-abi.h>
@@ -69,7 +70,6 @@ struct mtd_info {
 
        u_int32_t oobblock;  // Size of OOB blocks (e.g. 512)
        u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
-       u_int32_t oobavail;  // Number of bytes in OOB area available for fs 
        u_int32_t ecctype;
        u_int32_t eccsize;
        
@@ -80,6 +80,7 @@ struct mtd_info {
 
        // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO)
        struct nand_oobinfo oobinfo;
+       u_int32_t oobavail;  // Number of bytes in OOB area available for fs 
 
        /* Data for variable erase regions. If numeraseregions is zero,
         * it means that the whole device has erasesize as given above. 
@@ -113,12 +114,12 @@ struct mtd_info {
         * flash devices. The user data is one time programmable but the
         * factory data is read only. 
         */
-       int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
+       int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
        int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
-       /* This function is not yet implemented */
+       int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
+       int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+       int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
 
        /* kvec-based read/write methods. We need these especially for NAND flash,
           with its limited number of write cycles per erase.
@@ -147,6 +148,8 @@ struct mtd_info {
        int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
        int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
 
+       struct notifier_block reboot_notifier;  /* default mode before reboot */
+
        void *priv;
 
        struct module *owner;
index 9a19c65abd7495eb219ed2fff19d52a375c452a9..bee78969cb21b3e1d4671104dfbe7dc338fa033b 100644 (file)
@@ -5,7 +5,7 @@
  *                     Steven J. Hill <sjhill@realitydiluted.com>
  *                    Thomas Gleixner <tglx@linutronix.de>
  *
- * $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $
+ * $Id: nand.h,v 1.71 2005/02/09 12:12:59 gleixner Exp $
  *
  * 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
  *  02-08-2004 tglx    added option field to nand structure for chip anomalities
  *  05-25-2004 tglx    added bad block table support, ST-MICRO manufacturer id
  *                     update of nand_chip structure description
+ *  01-17-2005 dmarlin added extended commands for AG-AND device and added option 
+ *                     for BBT_AUTO_REFRESH.
+ *  01-20-2005 dmarlin added optional pointer to hardware specific callback for 
+ *                     extra error status checks.
  */
 #ifndef __LINUX_MTD_NAND_H
 #define __LINUX_MTD_NAND_H
@@ -115,6 +119,25 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
 #define NAND_CMD_READSTART     0x30
 #define NAND_CMD_CACHEDPROG    0x15
 
+/* Extended commands for AG-AND device */
+/* 
+ * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but 
+ *       there is no way to distinguish that from NAND_CMD_READ0
+ *       until the remaining sequence of commands has been completed
+ *       so add a high order bit and mask it off in the command.
+ */
+#define NAND_CMD_DEPLETE1      0x100
+#define NAND_CMD_DEPLETE2      0x38
+#define NAND_CMD_STATUS_MULTI  0x71
+#define NAND_CMD_STATUS_ERROR  0x72
+/* multi-bank error status (banks 0-3) */
+#define NAND_CMD_STATUS_ERROR0 0x73
+#define NAND_CMD_STATUS_ERROR1 0x74
+#define NAND_CMD_STATUS_ERROR2 0x75
+#define NAND_CMD_STATUS_ERROR3 0x76
+#define NAND_CMD_STATUS_RESET  0x7f
+#define NAND_CMD_STATUS_CLEAR  0xff
+
 /* Status bits */
 #define NAND_STATUS_FAIL       0x01
 #define NAND_STATUS_FAIL_N1    0x02
@@ -143,7 +166,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
 
 /*
  * Constants for Hardware ECC
-*/
+ */
 /* Reset Hardware ECC for read */
 #define NAND_ECC_READ          0
 /* Reset Hardware ECC for write */
@@ -151,6 +174,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
 /* Enable Hardware ECC before syndrom is read back from flash */
 #define NAND_ECC_READSYN       2
 
+/* Bit mask for flags passed to do_nand_read_ecc */
+#define NAND_GET_DEVICE                0x80
+
+
 /* Option constants for bizarre disfunctionality and real
 *  features
 */
@@ -170,6 +197,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
 /* Chip has a array of 4 pages which can be read without
  * additional ready /busy waits */
 #define NAND_4PAGE_ARRAY       0x00000040 
+/* Chip requires that BBT is periodically rewritten to prevent
+ * bits from adjacent blocks from 'leaking' in altering data.
+ * This happens with the Renesas AG-AND chips, possibly others.  */
+#define BBT_AUTO_REFRESH       0x00000080
 
 /* Options valid for Samsung large page devices */
 #define NAND_SAMSUNG_LP_OPTIONS \
@@ -192,7 +223,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
  * This can only work if we have the ecc bytes directly behind the 
  * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
 #define NAND_HWECC_SYNDROME    0x00020000
-
+/* This option skips the bbt scan during initialization. */
+#define NAND_SKIP_BBTSCAN      0x00040000
 
 /* Options set by nand scan */
 /* Nand scan has allocated oob_buf */
@@ -283,6 +315,8 @@ struct nand_hw_control {
  * @badblock_pattern:  [REPLACEABLE] bad block scan pattern used for initial bad block scan 
  * @controller:                [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
  * @priv:              [OPTIONAL] pointer to private chip date
+ * @errstat:           [OPTIONAL] hardware specific function to perform additional error status checks 
+ *                     (determine if errors are correctable)
  */
  
 struct nand_chip {
@@ -338,6 +372,7 @@ struct nand_chip {
        struct nand_bbt_descr   *badblock_pattern;
        struct nand_hw_control  *controller;
        void            *priv;
+       int             (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
 };
 
 /*
@@ -349,6 +384,7 @@ struct nand_chip {
 #define NAND_MFR_NATIONAL      0x8f
 #define NAND_MFR_RENESAS       0x07
 #define NAND_MFR_STMICRO       0x20
+#define NAND_MFR_HYNIX          0xad
 
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
@@ -459,6 +495,9 @@ extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
 extern int nand_default_bbt (struct mtd_info *mtd);
 extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
 extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
+extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+                             size_t * retlen, u_char * buf, u_char * oob_buf,
+                             struct nand_oobinfo *oobsel, int flags);
 
 /*
 * Constants for oob configuration
diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h
new file mode 100644 (file)
index 0000000..2332eda
--- /dev/null
@@ -0,0 +1,35 @@
+/* linux/include/mtd/plat-ram.h
+ *
+ * (c) 2004 Simtec Electronics
+ *     http://www.simtec.co.uk/products/SWLINUX/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * Generic platform device based RAM map
+ *
+ * $Id: plat-ram.h,v 1.2 2005/01/24 00:37:40 bjd Exp $
+ *
+ * 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.
+ *
+ */
+
+#ifndef __LINUX_MTD_PLATRAM_H
+#define __LINUX_MTD_PLATRAM_H __FILE__
+
+#define PLATRAM_RO (0)
+#define PLATRAM_RW (1)
+
+struct platdata_mtd_ram {
+       char                    *mapname;
+       char                   **probes;
+       struct mtd_partition    *partitions;
+       int                      nr_partitions;
+       int                      bankwidth;
+
+       /* control callbacks */
+
+       void    (*set_rw)(struct device *dev, int to);
+};
+
+#endif /* __LINUX_MTD_PLATRAM_H */
index a76ab898f4457a27a560cebb61f93a1372612597..428d9122940b131dd4450edbd45e614ba70de33d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $
+ * $Id: mtd-abi.h,v 1.11 2005/05/19 16:08:58 gleixner Exp $
  *
  * Portions of MTD ABI definition which are shared by kernel and user space 
  */
@@ -29,6 +29,7 @@ struct mtd_oob_buf {
 #define MTD_NORFLASH           3
 #define MTD_NANDFLASH          4
 #define MTD_PEROM              5
+#define MTD_DATAFLASH          6
 #define MTD_OTHER              14
 #define MTD_UNKNOWN            15
 
@@ -60,6 +61,12 @@ struct mtd_oob_buf {
 #define MTD_NANDECC_PLACE      1       // Use the given placement in the structure (YAFFS1 legacy mode)
 #define MTD_NANDECC_AUTOPLACE  2       // Use the default placement scheme
 #define MTD_NANDECC_PLACEONLY  3       // Use the given placement in the structure (Do not store ecc result on read)
+#define MTD_NANDECC_AUTOPL_USR         4       // Use the given autoplacement scheme rather than using the default
+
+/* OTP mode selection */
+#define MTD_OTP_OFF            0
+#define MTD_OTP_FACTORY                1
+#define MTD_OTP_USER           2
 
 struct mtd_info_user {
        uint8_t type;
@@ -80,6 +87,12 @@ struct region_info_user {
        uint32_t regionindex;
 };
 
+struct otp_info {
+       uint32_t start;
+       uint32_t length;
+       uint32_t locked;
+};
+
 #define MEMGETINFO              _IOR('M', 1, struct mtd_info_user)
 #define MEMERASE                _IOW('M', 2, struct erase_info_user)
 #define MEMWRITEOOB             _IOWR('M', 3, struct mtd_oob_buf)
@@ -92,6 +105,10 @@ struct region_info_user {
 #define MEMGETOOBSEL           _IOR('M', 10, struct nand_oobinfo)
 #define MEMGETBADBLOCK         _IOW('M', 11, loff_t)
 #define MEMSETBADBLOCK         _IOW('M', 12, loff_t)
+#define OTPSELECT              _IOR('M', 13, int)
+#define OTPGETREGIONCOUNT      _IOW('M', 14, int)
+#define OTPGETREGIONINFO       _IOW('M', 15, struct otp_info)
+#define OTPLOCK                _IOR('M', 16, struct otp_info)
 
 struct nand_oobinfo {
        uint32_t useecc;