]> err.no Git - linux-2.6/commitdiff
Merge master.kernel.org:/pub/scm/linux/kernel/git/tglx/mtd-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 7 Nov 2005 18:24:08 +0000 (10:24 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 7 Nov 2005 18:24:08 +0000 (10:24 -0800)
Some manual fixups for clashing kfree() cleanups etc.

192 files changed:
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/afs.c
drivers/mtd/chips/Kconfig
drivers/mtd/chips/Makefile
drivers/mtd/chips/amd_flash.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/chips/cfi_probe.c
drivers/mtd/chips/cfi_util.c
drivers/mtd/chips/chipreg.c
drivers/mtd/chips/fwh_lock.h
drivers/mtd/chips/gen_probe.c
drivers/mtd/chips/jedec.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/chips/map_absent.c
drivers/mtd/chips/sharp.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/blkmtd.c
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/doc2000.c
drivers/mtd/devices/doc2001.c
drivers/mtd/devices/doc2001plus.c
drivers/mtd/devices/docecc.c
drivers/mtd/devices/docprobe.c
drivers/mtd/devices/lart.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/pmc551.c
drivers/mtd/devices/slram.c
drivers/mtd/ftl.c
drivers/mtd/inftlcore.c
drivers/mtd/inftlmount.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/alchemy-flash.c
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/arctic-mtd.c
drivers/mtd/maps/autcpu12-nvram.c
drivers/mtd/maps/bast-flash.c
drivers/mtd/maps/beech-mtd.c
drivers/mtd/maps/cdb89712.c
drivers/mtd/maps/cfi_flagadm.c
drivers/mtd/maps/cstm_mips_ixx.c
drivers/mtd/maps/dbox2-flash.c
drivers/mtd/maps/dc21285.c
drivers/mtd/maps/dilnetpc.c
drivers/mtd/maps/dmv182.c
drivers/mtd/maps/ebony.c
drivers/mtd/maps/edb7312.c
drivers/mtd/maps/epxa10db-flash.c
drivers/mtd/maps/fortunet.c
drivers/mtd/maps/h720x-flash.c
drivers/mtd/maps/ichxrom.c
drivers/mtd/maps/impa7.c
drivers/mtd/maps/integrator-flash.c
drivers/mtd/maps/ipaq-flash.c
drivers/mtd/maps/iq80310.c
drivers/mtd/maps/ixp2000.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/l440gx.c
drivers/mtd/maps/lubbock-flash.c
drivers/mtd/maps/mainstone-flash.c
drivers/mtd/maps/mbx860.c
drivers/mtd/maps/mtx-1_flash.c [new file with mode: 0644]
drivers/mtd/maps/netsc520.c
drivers/mtd/maps/nettel.c
drivers/mtd/maps/ocelot.c
drivers/mtd/maps/octagon-5066.c
drivers/mtd/maps/omap-toto-flash.c
drivers/mtd/maps/omap_nor.c
drivers/mtd/maps/pci.c
drivers/mtd/maps/pcmciamtd.c
drivers/mtd/maps/physmap.c
drivers/mtd/maps/plat-ram.c
drivers/mtd/maps/pnc2000.c
drivers/mtd/maps/pq2fads.c [new file with mode: 0644]
drivers/mtd/maps/redwood.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/maps/sbc8240.c
drivers/mtd/maps/sbc_gxx.c
drivers/mtd/maps/sc520cdp.c
drivers/mtd/maps/scx200_docflash.c
drivers/mtd/maps/sharpsl-flash.c
drivers/mtd/maps/solutionengine.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/maps/tqm834x.c [new file with mode: 0644]
drivers/mtd/maps/tqm8xxl.c
drivers/mtd/maps/ts5500_flash.c
drivers/mtd/maps/tsunami_flash.c
drivers/mtd/maps/uclinux.c
drivers/mtd/maps/vmax301.c
drivers/mtd/maps/walnut.c
drivers/mtd/maps/wr_sbc82xx_flash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdblock.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdconcat.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/autcpu12.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/edb7312.c
drivers/mtd/nand/h1910.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_ecc.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/ppchameleonevb.c
drivers/mtd/nand/rtc_from4.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nand/spia.c
drivers/mtd/nand/toto.c
drivers/mtd/nftlcore.c
drivers/mtd/nftlmount.c
drivers/mtd/onenand/Kconfig [new file with mode: 0644]
drivers/mtd/onenand/Makefile [new file with mode: 0644]
drivers/mtd/onenand/generic.c [new file with mode: 0644]
drivers/mtd/onenand/onenand_base.c [new file with mode: 0644]
drivers/mtd/onenand/onenand_bbt.c [new file with mode: 0644]
drivers/mtd/redboot.c
drivers/mtd/rfd_ftl.c [new file with mode: 0644]
fs/Kconfig
fs/jffs2/Makefile
fs/jffs2/TODO
fs/jffs2/background.c
fs/jffs2/build.c
fs/jffs2/compr.c
fs/jffs2/compr.h
fs/jffs2/compr_rtime.c
fs/jffs2/compr_rubin.c
fs/jffs2/compr_rubin.h
fs/jffs2/compr_zlib.c
fs/jffs2/comprtest.c
fs/jffs2/debug.c [new file with mode: 0644]
fs/jffs2/debug.h [new file with mode: 0644]
fs/jffs2/dir.c
fs/jffs2/erase.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/histo.h
fs/jffs2/histo_mips.h
fs/jffs2/ioctl.c
fs/jffs2/malloc.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/summary.c [new file with mode: 0644]
fs/jffs2/summary.h [new file with mode: 0644]
fs/jffs2/super.c
fs/jffs2/symlink.c
fs/jffs2/wbuf.c
fs/jffs2/write.c
fs/jffs2/writev.c
include/linux/jffs2.h
include/linux/jffs2_fs_i.h
include/linux/jffs2_fs_sb.h
include/linux/mtd/bbm.h [new file with mode: 0644]
include/linux/mtd/blktrans.h
include/linux/mtd/cfi.h
include/linux/mtd/doc2000.h
include/linux/mtd/flashchip.h
include/linux/mtd/ftl.h
include/linux/mtd/gen_probe.h
include/linux/mtd/jedec.h
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/onenand.h [new file with mode: 0644]
include/linux/mtd/onenand_regs.h [new file with mode: 0644]
include/linux/mtd/partitions.h
include/linux/mtd/physmap.h
include/linux/mtd/pmc551.h
include/linux/mtd/xip.h
include/linux/rslib.h
include/mtd/inftl-user.h
include/mtd/mtd-abi.h
include/mtd/nftl-user.h
lib/reed_solomon/Makefile
lib/reed_solomon/decode_rs.c
lib/reed_solomon/encode_rs.c
lib/reed_solomon/reed_solomon.c

index 027054dea032bea6b909000b94228e218d64c190..f6b775e63ac8f07499767ae828f52cad418a067c 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Kconfig,v 1.7 2004/11/22 11:33:56 ijc Exp $
+# $Id: Kconfig,v 1.11 2005/11/07 11:14:19 gleixner Exp $
 
 menu "Memory Technology Devices (MTD)"
 
@@ -10,7 +10,7 @@ config MTD
          will provide the generic support for MTD drivers to register
          themselves with the kernel and for potential users of MTD devices
          to enumerate the devices which are present and obtain a handle on
-         them. It will also allow you to select individual drivers for 
+         them. It will also allow you to select individual drivers for
          particular hardware and users of MTD devices. If unsure, say N.
 
 config MTD_DEBUG
@@ -61,11 +61,11 @@ config MTD_REDBOOT_PARTS
 
          If you need code which can detect and parse this table, and register
          MTD 'partitions' corresponding to each image in the table, enable
-         this option. 
+         this option.
 
          You will still need the parsing functions to be called by the driver
-         for your particular device. It won't happen automatically. The 
-         SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
+         for your particular device. It won't happen automatically. The
+         SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
          example.
 
 config MTD_REDBOOT_DIRECTORY_BLOCK
@@ -81,10 +81,10 @@ config MTD_REDBOOT_DIRECTORY_BLOCK
          partition table.  A zero or positive value gives an absolete
          erase block number. A negative value specifies a number of
          sectors before the end of the device.
-         
+
          For example "2" means block number 2, "-1" means the last
          block and "-2" means the penultimate block.
-         
+
 config MTD_REDBOOT_PARTS_UNALLOCATED
        bool "  Include unallocated flash regions"
        depends on MTD_REDBOOT_PARTS
@@ -105,11 +105,11 @@ config MTD_CMDLINE_PARTS
        ---help---
          Allow generic configuration of the MTD paritition tables via the kernel
          command line. Multiple flash resources are supported for hardware where
-         different kinds of flash memory are available. 
+         different kinds of flash memory are available.
 
          You will still need the parsing functions to be called by the driver
-         for your particular device. It won't happen automatically. The 
-         SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
+         for your particular device. It won't happen automatically. The
+         SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
          example.
 
          The format for the command line is as follows:
@@ -118,12 +118,12 @@ config MTD_CMDLINE_PARTS
          <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
          <partdef> := <size>[@offset][<name>][ro]
          <mtd-id>  := unique id used in mapping driver/device
-         <size>    := standard linux memsize OR "-" to denote all 
+         <size>    := standard linux memsize OR "-" to denote all
          remaining space
          <name>    := (NAME)
 
-         Due to the way Linux handles the command line, no spaces are 
-         allowed in the partition definition, including mtd id's and partition 
+         Due to the way Linux handles the command line, no spaces are
+         allowed in the partition definition, including mtd id's and partition
          names.
 
          Examples:
@@ -240,7 +240,7 @@ config INFTL
        tristate "INFTL (Inverse NAND Flash Translation Layer) support"
        depends on MTD
        ---help---
-         This provides support for the Inverse NAND Flash Translation 
+         This provides support for the Inverse NAND Flash Translation
          Layer which is used on M-Systems' newer DiskOnChip devices. It
          uses a kind of pseudo-file system on a flash device to emulate
          a block device with 512-byte sectors, on top of which you put
@@ -253,6 +253,16 @@ config INFTL
          permitted to copy, modify and distribute the code as you wish. Just
          not use it.
 
+config RFD_FTL
+        tristate "Resident Flash Disk (Flash Translation Layer) support"
+       depends on MTD
+       ---help---
+         This provides support for the flash translation layer known
+         as the Resident Flash Disk (RFD), as used by the Embedded BIOS
+         of General Software. There is a blurb at:
+
+               http://www.gensw.com/pages/prod/bios/rfd.htm
+
 source "drivers/mtd/chips/Kconfig"
 
 source "drivers/mtd/maps/Kconfig"
@@ -261,5 +271,7 @@ source "drivers/mtd/devices/Kconfig"
 
 source "drivers/mtd/nand/Kconfig"
 
+source "drivers/mtd/onenand/Kconfig"
+
 endmenu
 
index e4ad588327f705aa4aa09fa7e5d82e369f299876..fc9374407c2bc7c6f5e57dd015e0d74e97b3fa8a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for the memory technology device drivers.
 #
-# $Id: Makefile.common,v 1.5 2004/08/10 20:51:49 dwmw2 Exp $
+# $Id: Makefile.common,v 1.7 2005/07/11 10:39:27 gleixner Exp $
 
 # Core functionality.
 mtd-y                          := mtdcore.o
@@ -20,8 +20,9 @@ obj-$(CONFIG_MTD_BLOCK_RO)    += mtdblock_ro.o mtd_blkdevs.o
 obj-$(CONFIG_FTL)              += ftl.o mtd_blkdevs.o
 obj-$(CONFIG_NFTL)             += nftl.o mtd_blkdevs.o
 obj-$(CONFIG_INFTL)            += inftl.o mtd_blkdevs.o
+obj-$(CONFIG_RFD_FTL)          += rfd_ftl.o mtd_blkdevs.o
 
 nftl-objs              := nftlcore.o nftlmount.o
 inftl-objs             := inftlcore.o inftlmount.o
 
-obj-y          += chips/ maps/ devices/ nand/
+obj-y          += chips/ maps/ devices/ nand/ onenand/
index 7363e101eb0f0958a8294831047ed191e18c0b93..6a45be04564b7cd6b92b4b7afab76696d50feb23 100644 (file)
@@ -1,27 +1,27 @@
 /*======================================================================
 
     drivers/mtd/afs.c: ARM Flash Layout/Partitioning
-  
+
     Copyright (C) 2000 ARM Limited
-  
+
    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
-  
-   This is access code for flashes using ARM's flash partitioning 
+
+   This is access code for flashes using ARM's flash partitioning
    standards.
 
-   $Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $
+   $Id: afs.c,v 1.15 2005/11/07 11:14:19 gleixner Exp $
 
 ======================================================================*/
 
@@ -163,7 +163,7 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
        return ret;
 }
 
-static int parse_afs_partitions(struct mtd_info *mtd, 
+static int parse_afs_partitions(struct mtd_info *mtd,
                          struct mtd_partition **pparts,
                          unsigned long origin)
 {
index df95d2158b167cef5946395e25778c323db6db13..eafa23f5cbd66e615c4b0f5025433f85267a35ff 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $
+# $Id: Kconfig,v 1.18 2005/11/07 11:14:22 gleixner Exp $
 
 menu "RAM/ROM/Flash chip drivers"
        depends on MTD!=n
@@ -39,7 +39,7 @@ config MTD_CFI_ADV_OPTIONS
          If you need to specify a specific endianness for access to flash
          chips, or if you wish to reduce the size of the kernel by including
          support for only specific arrangements of flash chips, say 'Y'. This
-         option does not directly affect the code, but will enable other 
+         option does not directly affect the code, but will enable other
          configuration options which allow you to do so.
 
          If unsure, say 'N'.
@@ -56,7 +56,7 @@ config MTD_CFI_NOSWAP
          data bits when writing the 'magic' commands to the chips. Saying
          'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't
          enabled, means that the CPU will not do any swapping; the chips
-         are expected to be wired to the CPU in 'host-endian' form. 
+         are expected to be wired to the CPU in 'host-endian' form.
          Specific arrangements are possible with the BIG_ENDIAN_BYTE and
          LITTLE_ENDIAN_BYTE, if the bytes are reversed.
 
@@ -79,10 +79,10 @@ config MTD_CFI_GEOMETRY
        bool "Specific CFI Flash geometry selection"
        depends on MTD_CFI_ADV_OPTIONS
        help
-         This option does not affect the code directly, but will enable 
+         This option does not affect the code directly, but will enable
          some other configuration options which would allow you to reduce
-         the size of the kernel by including support for only certain 
-         arrangements of CFI chips. If unsure, say 'N' and all options 
+         the size of the kernel by including support for only certain
+         arrangements of CFI chips. If unsure, say 'N' and all options
          which are supported by the current code will be enabled.
 
 config MTD_MAP_BANK_WIDTH_1
@@ -197,7 +197,7 @@ config MTD_CFI_AMDSTD
        help
          The Common Flash Interface defines a number of different command
          sets which a CFI-compliant chip may claim to implement. This code
-         provides support for one of those command sets, used on chips 
+         provides support for one of those command sets, used on chips
          including the AMD Am29LV320.
 
 config MTD_CFI_AMDSTD_RETRY
@@ -237,14 +237,14 @@ config MTD_RAM
        tristate "Support for RAM chips in bus mapping"
        depends on MTD
        help
-         This option enables basic support for RAM chips accessed through 
+         This option enables basic support for RAM chips accessed through
          a bus mapping driver.
 
 config MTD_ROM
        tristate "Support for ROM chips in bus mapping"
        depends on MTD
        help
-         This option enables basic support for ROM chips accessed through 
+         This option enables basic support for ROM chips accessed through
          a bus mapping driver.
 
 config MTD_ABSENT
@@ -275,7 +275,7 @@ config MTD_AMDSTD
        depends on MTD && MTD_OBSOLETE_CHIPS
        help
          This option enables support for flash chips using AMD-compatible
-         commands, including some which are not CFI-compatible and hence 
+         commands, including some which are not CFI-compatible and hence
          cannot be used with the CONFIG_MTD_CFI_AMDSTD option.
 
          It also works on AMD compatible chips that do conform to CFI.
@@ -285,7 +285,7 @@ config MTD_SHARP
        depends on MTD && MTD_OBSOLETE_CHIPS
        help
          This option enables support for flash chips using Sharp-compatible
-         commands, including some which are not CFI-compatible and hence 
+         commands, including some which are not CFI-compatible and hence
          cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
 
 config MTD_JEDEC
index 6830489828c604bac1a4c975217869da22d0d2d5..8afe3092c4e38ba73214c3f255006c3bced97a3a 100644 (file)
@@ -1,7 +1,7 @@
 #
 # linux/drivers/chips/Makefile
 #
-# $Id: Makefile.common,v 1.4 2004/07/12 16:07:30 dwmw2 Exp $
+# $Id: Makefile.common,v 1.5 2005/11/07 11:14:22 gleixner Exp $
 
 #                       *** BIG UGLY NOTE ***
 #
@@ -11,7 +11,7 @@
 # the CFI command set drivers are linked before gen_probe.o
 
 obj-$(CONFIG_MTD)              += chipreg.o
-obj-$(CONFIG_MTD_AMDSTD)       += amd_flash.o 
+obj-$(CONFIG_MTD_AMDSTD)       += amd_flash.o
 obj-$(CONFIG_MTD_CFI)          += cfi_probe.o
 obj-$(CONFIG_MTD_CFI_UTIL)     += cfi_util.o
 obj-$(CONFIG_MTD_CFI_STAA)     += cfi_cmdset_0020.o
index 2dafeba3f3d5afb9ce165794e86286da7b064e77..fdb91b6f1d979254e63b0256f7fbdf54fc3e1ac7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
+ * $Id: amd_flash.c,v 1.28 2005/11/07 11:14:22 gleixner Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
@@ -93,9 +93,9 @@
 #define D6_MASK        0x40
 
 struct amd_flash_private {
-       int device_type;        
-       int interleave; 
-       int numchips;   
+       int device_type;
+       int interleave;
+       int numchips;
        unsigned long chipshift;
 //     const char *im_name;
        struct flchip chips[0];
@@ -253,7 +253,7 @@ static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len,
        int i;
        int retval = 0;
        int lock_status;
-      
+
        map = mtd->priv;
 
        /* Pass the whole chip through sector by sector and check for each
@@ -273,7 +273,7 @@ static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len,
                                unlock_sector(map, eraseoffset, is_unlock);
 
                                lock_status = is_sector_locked(map, eraseoffset);
-                               
+
                                if (is_unlock && lock_status) {
                                        printk("Cannot unlock sector at address %x length %xx\n",
                                               eraseoffset, merip->erasesize);
@@ -305,7 +305,7 @@ static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 /*
  * Reads JEDEC manufacturer ID and device ID and returns the index of the first
  * matching table entry (-1 if not found or alias for already found chip).
- */ 
+ */
 static int probe_new_chip(struct mtd_info *mtd, __u32 base,
                          struct flchip *chips,
                          struct amd_flash_private *private,
@@ -636,7 +636,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
                        { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
                        { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks =  8 }
                }
-       } 
+       }
        };
 
        struct mtd_info *mtd;
@@ -701,7 +701,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
 
        mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) *
                                    mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) { 
+       if (!mtd->eraseregions) {
                printk(KERN_WARNING "%s: Failed to allocate "
                       "memory for MTD erase region info\n", map->name);
                kfree(mtd);
@@ -739,12 +739,12 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
        mtd->type = MTD_NORFLASH;
        mtd->flags = MTD_CAP_NORFLASH;
        mtd->name = map->name;
-       mtd->erase = amd_flash_erase;   
-       mtd->read = amd_flash_read;     
-       mtd->write = amd_flash_write;   
-       mtd->sync = amd_flash_sync;     
-       mtd->suspend = amd_flash_suspend;       
-       mtd->resume = amd_flash_resume; 
+       mtd->erase = amd_flash_erase;
+       mtd->read = amd_flash_read;
+       mtd->write = amd_flash_write;
+       mtd->sync = amd_flash_sync;
+       mtd->suspend = amd_flash_suspend;
+       mtd->resume = amd_flash_resume;
        mtd->lock = amd_flash_lock;
        mtd->unlock = amd_flash_unlock;
 
@@ -789,7 +789,7 @@ retry:
                       map->name, chip->state);
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
-                
+
                spin_unlock_bh(chip->mutex);
 
                schedule();
@@ -802,7 +802,7 @@ retry:
                timeo = jiffies + HZ;
 
                goto retry;
-       }       
+       }
 
        adr += chip->start;
 
@@ -889,7 +889,7 @@ retry:
                       map->name, chip->state);
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
-                
+
                spin_unlock_bh(chip->mutex);
 
                schedule();
@@ -901,7 +901,7 @@ retry:
                timeo = jiffies + HZ;
 
                goto retry;
-       }       
+       }
 
        chip->state = FL_WRITING;
 
@@ -911,7 +911,7 @@ retry:
        wide_write(map, datum, adr);
 
        times_left = 500000;
-       while (times_left-- && flash_is_busy(map, adr, private->interleave)) { 
+       while (times_left-- && flash_is_busy(map, adr, private->interleave)) {
                if (need_resched()) {
                        spin_unlock_bh(chip->mutex);
                        schedule();
@@ -989,7 +989,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
                if (ret) {
                        return ret;
                }
-               
+
                ofs += n;
                buf += n;
                (*retlen) += n;
@@ -1002,7 +1002,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
                        }
                }
        }
-       
+
        /* We are now aligned, write as much as possible. */
        while(len >= map->buswidth) {
                __u32 datum;
@@ -1063,7 +1063,7 @@ static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
                if (ret) {
                        return ret;
                }
-               
+
                (*retlen) += n;
        }
 
@@ -1085,7 +1085,7 @@ retry:
        if (chip->state != FL_READY){
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
-                
+
                spin_unlock_bh(chip->mutex);
 
                schedule();
@@ -1098,7 +1098,7 @@ retry:
                timeo = jiffies + HZ;
 
                goto retry;
-       }       
+       }
 
        chip->state = FL_ERASING;
 
@@ -1106,30 +1106,30 @@ retry:
        ENABLE_VPP(map);
        send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA);
        send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr);
-       
+
        timeo = jiffies + (HZ * 20);
 
        spin_unlock_bh(chip->mutex);
        msleep(1000);
        spin_lock_bh(chip->mutex);
-       
+
        while (flash_is_busy(map, adr, private->interleave)) {
 
                if (chip->state != FL_ERASING) {
                        /* Someone's suspended the erase. Sleep */
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&chip->wq, &wait);
-                       
+
                        spin_unlock_bh(chip->mutex);
                        printk(KERN_INFO "%s: erase suspended. Sleeping\n",
                               map->name);
                        schedule();
                        remove_wait_queue(&chip->wq, &wait);
-                       
+
                        if (signal_pending(current)) {
                                return -EINTR;
                        }
-                       
+
                        timeo = jiffies + (HZ*2); /* FIXME */
                        spin_lock_bh(chip->mutex);
                        continue;
@@ -1145,7 +1145,7 @@ retry:
 
                        return -EIO;
                }
-               
+
                /* Latency issues. Drop the lock, wait a while and retry */
                spin_unlock_bh(chip->mutex);
 
@@ -1153,7 +1153,7 @@ retry:
                        schedule();
                else
                        udelay(1);
-               
+
                spin_lock_bh(chip->mutex);
        }
 
@@ -1180,7 +1180,7 @@ retry:
                        return -EIO;
                }
        }
-       
+
        DISABLE_VPP(map);
        chip->state = FL_READY;
        wake_up(&chip->wq);
@@ -1246,7 +1246,7 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
         * with the erase region at that address.
         */
 
-       while ((i < mtd->numeraseregions) && 
+       while ((i < mtd->numeraseregions) &&
               ((instr->addr + instr->len) >= regions[i].offset)) {
                 i++;
        }
@@ -1293,10 +1293,10 @@ static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
                        }
                }
        }
-               
+
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
-       
+
        return 0;
 }
 
@@ -1324,7 +1324,7 @@ static void amd_flash_sync(struct mtd_info *mtd)
                case FL_JEDEC_QUERY:
                        chip->oldstate = chip->state;
                        chip->state = FL_SYNCING;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
@@ -1335,13 +1335,13 @@ static void amd_flash_sync(struct mtd_info *mtd)
                default:
                        /* Not an idle state */
                        add_wait_queue(&chip->wq, &wait);
-                       
+
                        spin_unlock_bh(chip->mutex);
 
                        schedule();
 
                        remove_wait_queue(&chip->wq, &wait);
-                       
+
                        goto retry;
                }
        }
@@ -1351,7 +1351,7 @@ static void amd_flash_sync(struct mtd_info *mtd)
                chip = &private->chips[i];
 
                spin_lock_bh(chip->mutex);
-               
+
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
                        wake_up(&chip->wq);
index c3fc9b2f21fbd5988a39dd2c9c0f12d0fd69190f..143f01a4c1705343a2406c53f1aff0f71b4feb28 100644 (file)
@@ -4,9 +4,9 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.185 2005/11/07 11:14:22 gleixner Exp $
+ *
  *
- * 
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
  *     - completely revamped method functions so they are aware and
  *       independent of the flash geometry (buswidth, interleave, etc.)
@@ -51,6 +51,7 @@
 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *);
 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);
@@ -105,6 +106,7 @@ static struct mtd_chip_driver cfi_intelext_chipdrv = {
 static void cfi_tell_features(struct cfi_pri_intelext *extp)
 {
        int i;
+       printk("  Extended Query version %c.%c\n", extp->MajorVersion, extp->MinorVersion);
        printk("  Feature/Command Support:      %4.4X\n", extp->FeatureSupport);
        printk("     - Chip Erase:              %s\n", extp->FeatureSupport&1?"supported":"unsupported");
        printk("     - Suspend Erase:           %s\n", extp->FeatureSupport&2?"supported":"unsupported");
@@ -116,36 +118,43 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
        printk("     - Page-mode read:          %s\n", extp->FeatureSupport&128?"supported":"unsupported");
        printk("     - Synchronous read:        %s\n", extp->FeatureSupport&256?"supported":"unsupported");
        printk("     - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported");
-       for (i=10; i<32; i++) {
-               if (extp->FeatureSupport & (1<<i)) 
+       printk("     - Extended Flash Array:    %s\n", extp->FeatureSupport&1024?"supported":"unsupported");
+       for (i=11; i<32; i++) {
+               if (extp->FeatureSupport & (1<<i))
                        printk("     - Unknown Bit %X:      supported\n", i);
        }
-       
+
        printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
        printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
        for (i=1; i<8; i++) {
                if (extp->SuspendCmdSupport & (1<<i))
                        printk("     - Unknown Bit %X:               supported\n", i);
        }
-       
+
        printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
        printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
-       printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
-       for (i=2; i<16; i++) {
+       printk("     - Lock-Down Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no");
+       for (i=2; i<3; i++) {
                if (extp->BlkStatusRegMask & (1<<i))
                        printk("     - Unknown Bit %X Active: yes\n",i);
        }
-       
-       printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+       printk("     - EFA Lock Bit:         %s\n", extp->BlkStatusRegMask&16?"yes":"no");
+       printk("     - EFA Lock-Down Bit:    %s\n", extp->BlkStatusRegMask&32?"yes":"no");
+       for (i=6; i<16; i++) {
+               if (extp->BlkStatusRegMask & (1<<i))
+                       printk("     - Unknown Bit %X Active: yes\n",i);
+       }
+
+       printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
               extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
        if (extp->VppOptimal)
-               printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+               printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
                       extp->VppOptimal >> 4, extp->VppOptimal & 0xf);
 }
 #endif
 
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ 
+/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */
 static void fixup_intel_strataflash(struct mtd_info *mtd, void* param)
 {
        struct map_info *map = mtd->priv;
@@ -176,7 +185,7 @@ static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       
+
        cfi->cfiq->BufWriteTimeoutTyp = 0;      /* Not supported */
        cfi->cfiq->BufWriteTimeoutMax = 0;      /* Not supported */
 }
@@ -185,7 +194,7 @@ static void fixup_st_m28w320cb(struct mtd_info *mtd, void* param)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       
+
        /* Note this is done after the region info is endian swapped */
        cfi->cfiq->EraseRegionInfo[1] =
                (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
@@ -207,12 +216,13 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
        if (cfi->cfiq->BufWriteTimeoutTyp) {
                printk(KERN_INFO "Using buffer write method\n" );
                mtd->write = cfi_intelext_write_buffers;
+               mtd->writev = cfi_intelext_writev;
        }
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-       { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, 
+       { CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL },
 #endif
 #ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
        { CFI_MFR_ANY, CFI_ID_ANY, fixup_no_write_suspend, NULL },
@@ -252,12 +262,21 @@ read_pri_intelext(struct map_info *map, __u16 adr)
        if (!extp)
                return NULL;
 
+       if (extp->MajorVersion != '1' ||
+           (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
+               printk(KERN_ERR "  Unknown Intel/Sharp Extended Query "
+                      "version %c.%c.\n",  extp->MajorVersion,
+                      extp->MinorVersion);
+               kfree(extp);
+               return NULL;
+       }
+
        /* Do some byteswapping if necessary */
        extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
        extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
        extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
 
-       if (extp->MajorVersion == '1' && extp->MinorVersion == '3') {
+       if (extp->MajorVersion == '1' && extp->MinorVersion >= '3') {
                unsigned int extra_size = 0;
                int nb_parts, i;
 
@@ -266,7 +285,10 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                              sizeof(struct cfi_intelext_otpinfo);
 
                /* Burst Read info */
-               extra_size += 6;
+               extra_size += 2;
+               if (extp_size < sizeof(*extp) + extra_size)
+                       goto need_more;
+               extra_size += extp->extra[extra_size-1];
 
                /* Number of hardware-partitions */
                extra_size += 1;
@@ -274,6 +296,10 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                        goto need_more;
                nb_parts = extp->extra[extra_size - 1];
 
+               /* skip the sizeof(partregion) field in CFI 1.4 */
+               if (extp->MinorVersion >= '4')
+                       extra_size += 2;
+
                for (i = 0; i < nb_parts; i++) {
                        struct cfi_intelext_regioninfo *rinfo;
                        rinfo = (struct cfi_intelext_regioninfo *)&extp->extra[extra_size];
@@ -285,6 +311,9 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                                      * sizeof(struct cfi_intelext_blockinfo);
                }
 
+               if (extp->MinorVersion >= '4')
+                       extra_size += sizeof(struct cfi_intelext_programming_regioninfo);
+
                if (extp_size < sizeof(*extp) + extra_size) {
                        need_more:
                        extp_size = sizeof(*extp) + extra_size;
@@ -298,7 +327,7 @@ read_pri_intelext(struct map_info *map, __u16 adr)
                        goto again;
                }
        }
-               
+
        return extp;
 }
 
@@ -339,7 +368,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
        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
                 * routine faked a CFI structure. So we read the feature
                 * table from it.
@@ -354,14 +383,14 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
                }
 
                /* Install our own private info structure */
-               cfi->cmdset_priv = extp;        
+               cfi->cmdset_priv = extp;
 
                cfi_fixup(mtd, cfi_fixup_table);
 
 #ifdef DEBUG_CFI_FEATURES
                /* Tell the user about it in lots of lovely detail */
                cfi_tell_features(extp);
-#endif 
+#endif
 
                if(extp->SuspendCmdSupport & 1) {
                        printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
@@ -379,10 +408,10 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
                cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
                cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
                cfi->chips[i].ref_point_counter = 0;
-       }               
+       }
 
        map->fldrv = &cfi_intelext_chipdrv;
-       
+
        return cfi_intelext_setup(mtd);
 }
 
@@ -399,13 +428,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
        mtd->size = devsize * cfi->numchips;
 
        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
-       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 
+       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                        * mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) { 
+       if (!mtd->eraseregions) {
                printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
                goto setup_err;
        }
-       
+
        for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
                unsigned long ernum, ersize;
                ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
@@ -429,7 +458,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
        }
 
        for (i=0; i<mtd->numeraseregions;i++){
-               printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n",
+               printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n",
                       i,mtd->eraseregions[i].offset,
                       mtd->eraseregions[i].erasesize,
                       mtd->eraseregions[i].numblocks);
@@ -480,7 +509,7 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
         * arrangement at this point. This can be rearranged in the future
         * if someone feels motivated enough.  --nico
         */
-       if (extp && extp->MajorVersion == '1' && extp->MinorVersion == '3'
+       if (extp && extp->MajorVersion == '1' && extp->MinorVersion >= '3'
            && extp->FeatureSupport & (1 << 9)) {
                struct cfi_private *newcfi;
                struct flchip *chip;
@@ -492,12 +521,16 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                       sizeof(struct cfi_intelext_otpinfo);
 
                /* Burst Read info */
-               offs += 6;
+               offs += extp->extra[offs+1]+2;
 
                /* Number of partition regions */
                numregions = extp->extra[offs];
                offs += 1;
 
+               /* skip the sizeof(partregion) field in CFI 1.4 */
+               if (extp->MinorVersion >= '4')
+                       offs += 2;
+
                /* Number of hardware partitions */
                numparts = 0;
                for (i = 0; i < numregions; i++) {
@@ -509,6 +542,20 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
                                  sizeof(struct cfi_intelext_blockinfo);
                }
 
+               /* Programming Region info */
+               if (extp->MinorVersion >= '4') {
+                       struct cfi_intelext_programming_regioninfo *prinfo;
+                       prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
+                       MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift;
+                       MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid;
+                       MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid;
+                       mtd->flags |= MTD_PROGRAM_REGIONS;
+                       printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
+                              map->name, MTD_PROGREGION_SIZE(mtd),
+                              MTD_PROGREGION_CTRLMODE_VALID(mtd),
+                              MTD_PROGREGION_CTRLMODE_INVALID(mtd));
+               }
+
                /*
                 * All functions below currently rely on all chips having
                 * the same geometry so we'll just assume that all hardware
@@ -653,8 +700,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                                break;
 
                        if (time_after(jiffies, timeo)) {
-                               printk(KERN_ERR "Waiting for chip to be ready timed out. Status %lx\n", 
-                                      status.x[0]);
+                               printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n",
+                                      map->name, status.x[0]);
                                return -EIO;
                        }
                        spin_unlock(chip->mutex);
@@ -663,7 +710,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                        /* Someone else might have been playing with it. */
                        goto retry;
                }
-                               
+
        case FL_READY:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
@@ -701,8 +748,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                                map_write(map, CMD(0x70), adr);
                                chip->state = FL_ERASING;
                                chip->oldstate = FL_READY;
-                               printk(KERN_ERR "Chip not ready after erase "
-                                      "suspended: status = 0x%lx\n", status.x[0]);
+                               printk(KERN_ERR "%s: Chip not ready after erase "
+                                      "suspended: status = 0x%lx\n", map->name, status.x[0]);
                                return -EIO;
                        }
 
@@ -782,14 +829,14 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
        switch(chip->oldstate) {
        case FL_ERASING:
                chip->state = chip->oldstate;
-               /* What if one interleaved chip has finished and the 
+               /* What if one interleaved chip has finished and the
                   other hasn't? The old code would leave the finished
-                  one in READY mode. That's bad, and caused -EROFS 
+                  one in READY mode. That's bad, and caused -EROFS
                   errors to be returned from do_erase_oneblock because
                   that's the only bit it checked for at the time.
-                  As the state machine appears to explicitly allow 
+                  As the state machine appears to explicitly allow
                   sending the 0x70 (Read Status) command to an erasing
-                  chip and expecting it to be ignored, that's what we 
+                  chip and expecting it to be ignored, that's what we
                   do. */
                map_write(map, CMD(0xd0), adr);
                map_write(map, CMD(0x70), adr);
@@ -809,7 +856,7 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
                DISABLE_VPP(map);
                break;
        default:
-               printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate);
+               printk(KERN_ERR "%s: put_chip() called with oldstate %d!!\n", map->name, chip->oldstate);
        }
        wake_up(&chip->wq);
 }
@@ -1025,8 +1072,8 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
 
        adr += chip->start;
 
-       /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(map_bankwidth(map)-1); 
+       /* Ensure cmd read/writes are aligned. */
+       cmd_addr = adr & ~(map_bankwidth(map)-1);
 
        spin_lock(chip->mutex);
 
@@ -1054,7 +1101,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
 
        if (!map->virt || (from + len > mtd->size))
                return -EINVAL;
-       
+
        *mtdbuf = (void *)map->virt + from;
        *retlen = 0;
 
@@ -1081,7 +1128,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
 
                *retlen += thislen;
                len -= thislen;
-               
+
                ofs = 0;
                chipnum++;
        }
@@ -1120,7 +1167,7 @@ static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t fro
                        if(chip->ref_point_counter == 0)
                                chip->state = FL_READY;
                } else
-                       printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */
+                       printk(KERN_ERR "%s: Warning: unpoint called on non pointed region\n", map->name); /* Should this give an error? */
 
                put_chip(map, chip, chip->start);
                spin_unlock(chip->mutex);
@@ -1139,8 +1186,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
 
        adr += chip->start;
 
-       /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(map_bankwidth(map)-1); 
+       /* Ensure cmd read/writes are aligned. */
+       cmd_addr = adr & ~(map_bankwidth(map)-1);
 
        spin_lock(chip->mutex);
        ret = get_chip(map, chip, cmd_addr, FL_READY);
@@ -1195,7 +1242,7 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
                *retlen += thislen;
                len -= thislen;
                buf += thislen;
-               
+
                ofs = 0;
                chipnum++;
        }
@@ -1212,12 +1259,17 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
 
        adr += chip->start;
 
-       /* Let's determine this according to the interleave only once */
+       /* Let's determine those 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;
+       case FL_WRITING:
+               write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
+               break;
+       case FL_OTP_WRITE:
+               write_cmd = CMD(0xc0);
+               break;
+       default:
+               return -EINVAL;
        }
 
        spin_lock(chip->mutex);
@@ -1258,12 +1310,13 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
+                       map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
                        xip_enable(map, chip, adr);
-                       printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
+                       printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
                        ret = -EIO;
                        goto out;
                }
@@ -1275,27 +1328,39 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
        if (!z) {
                chip->word_write_time--;
                if (!chip->word_write_time)
-                       chip->word_write_time++;
+                       chip->word_write_time = 1;
        }
-       if (z > 1) 
+       if (z > 1)
                chip->word_write_time++;
 
        /* Done and happy. */
        chip->state = FL_STATUS;
 
-       /* check for lock bit */
-       if (map_word_bitsset(map, status, CMD(0x02))) {
-               /* clear status */
+       /* check for errors */
+       if (map_word_bitsset(map, status, CMD(0x1a))) {
+               unsigned long chipstatus = MERGESTATUS(status);
+
+               /* reset status */
                map_write(map, CMD(0x50), adr);
-               /* put back into read status register mode */
                map_write(map, CMD(0x70), adr);
-               ret = -EROFS;
+               xip_enable(map, chip, adr);
+
+               if (chipstatus & 0x02) {
+                       ret = -EROFS;
+               } else if (chipstatus & 0x08) {
+                       printk(KERN_ERR "%s: word write error (bad VPP)\n", map->name);
+                       ret = -EIO;
+               } else {
+                       printk(KERN_ERR "%s: word write error (status 0x%lx)\n", map->name, chipstatus);
+                       ret = -EINVAL;
+               }
+
+               goto out;
        }
 
        xip_enable(map, chip, adr);
  out:  put_chip(map, chip, adr);
        spin_unlock(chip->mutex);
-
        return ret;
 }
 
@@ -1328,7 +1393,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
                                               bus_ofs, datum, FL_WRITING);
-               if (ret) 
+               if (ret)
                        return ret;
 
                len -= n;
@@ -1337,13 +1402,13 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                (*retlen) += n;
 
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                }
        }
-       
+
        while(len >= map_bankwidth(map)) {
                map_word datum = map_word_load(map, buf);
 
@@ -1358,7 +1423,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                len -= map_bankwidth(map);
 
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
@@ -1373,9 +1438,9 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
                                       ofs, datum, FL_WRITING);
-               if (ret) 
+               if (ret)
                        return ret;
-               
+
                (*retlen) += len;
        }
 
@@ -1383,20 +1448,24 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
 }
 
 
-static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, 
-                                   unsigned long adr, const u_char *buf, int len)
+static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
+                                   unsigned long adr, const struct kvec **pvec,
+                                   unsigned long *pvec_seek, int len)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       map_word status, status_OK;
+       map_word status, status_OK, write_cmd, datum;
        unsigned long cmd_adr, timeo;
-       int wbufsize, z, ret=0, bytes, words;
+       int wbufsize, z, ret=0, word_gap, words;
+       const struct kvec *vec;
+       unsigned long vec_seek;
 
        wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        adr += chip->start;
        cmd_adr = adr & ~(wbufsize-1);
-       
+
        /* Let's determine this according to the interleave only once */
        status_OK = CMD(0x80);
+       write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
 
        spin_lock(chip->mutex);
        ret = get_chip(map, chip, cmd_adr, FL_WRITING);
@@ -1410,7 +1479,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        xip_disable(map, chip, cmd_adr);
 
        /* Â§4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
-          [...], the device will not accept any more Write to Buffer commands". 
+          [...], the device will not accept any more Write to Buffer commands".
           So we must check here and reset those bits if they're set. Otherwise
           we're just pissing in the wind */
        if (chip->state != FL_STATUS)
@@ -1428,7 +1497,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 
        z = 0;
        for (;;) {
-               map_write(map, CMD(0xe8), cmd_adr);
+               map_write(map, write_cmd, cmd_adr);
 
                status = map_read(map, cmd_adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
@@ -1446,41 +1515,66 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                        map_write(map, CMD(0x50), cmd_adr);
                        map_write(map, CMD(0x70), cmd_adr);
                        xip_enable(map, chip, cmd_adr);
-                       printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
-                              status.x[0], Xstatus.x[0]);
+                       printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
+                              map->name, status.x[0], Xstatus.x[0]);
                        ret = -EIO;
                        goto out;
                }
        }
 
+       /* Figure out the number of words to write */
+       word_gap = (-adr & (map_bankwidth(map)-1));
+       words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
+       if (!word_gap) {
+               words--;
+       } else {
+               word_gap = map_bankwidth(map) - word_gap;
+               adr -= word_gap;
+               datum = map_word_ff(map);
+       }
+
        /* Write length of data to come */
-       bytes = len & (map_bankwidth(map)-1);
-       words = len / map_bankwidth(map);
-       map_write(map, CMD(words - !bytes), cmd_adr );
+       map_write(map, CMD(words), cmd_adr );
 
        /* Write data */
-       z = 0;
-       while(z < words * map_bankwidth(map)) {
-               map_word datum = map_word_load(map, buf);
-               map_write(map, datum, adr+z);
+       vec = *pvec;
+       vec_seek = *pvec_seek;
+       do {
+               int n = map_bankwidth(map) - word_gap;
+               if (n > vec->iov_len - vec_seek)
+                       n = vec->iov_len - vec_seek;
+               if (n > len)
+                       n = len;
 
-               z += map_bankwidth(map);
-               buf += map_bankwidth(map);
-       }
+               if (!word_gap && len < map_bankwidth(map))
+                       datum = map_word_ff(map);
 
-       if (bytes) {
-               map_word datum;
+               datum = map_word_load_partial(map, datum,
+                                             vec->iov_base + vec_seek,
+                                             word_gap, n);
 
-               datum = map_word_ff(map);
-               datum = map_word_load_partial(map, datum, buf, 0, bytes);
-               map_write(map, datum, adr+z);
-       }
+               len -= n;
+               word_gap += n;
+               if (!len || word_gap == map_bankwidth(map)) {
+                       map_write(map, datum, adr);
+                       adr += map_bankwidth(map);
+                       word_gap = 0;
+               }
+
+               vec_seek += n;
+               if (vec_seek == vec->iov_len) {
+                       vec++;
+                       vec_seek = 0;
+               }
+       } while (len);
+       *pvec = vec;
+       *pvec_seek = vec_seek;
 
        /* GO GO GO */
        map_write(map, CMD(0xd0), cmd_adr);
        chip->state = FL_WRITING;
 
-       INVALIDATE_CACHE_UDELAY(map, chip, 
+       INVALIDATE_CACHE_UDELAY(map, chip,
                                cmd_adr, len,
                                chip->buffer_write_time);
 
@@ -1506,13 +1600,14 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
 
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
+                       map_write(map, CMD(0x70), cmd_adr);
                        chip->state = FL_STATUS;
                        xip_enable(map, chip, cmd_adr);
-                       printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
+                       printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
                        ret = -EIO;
                        goto out;
                }
-               
+
                /* Latency issues. Drop the lock, wait a while and retry */
                z++;
                UDELAY(map, chip, cmd_adr, 1);
@@ -1520,21 +1615,34 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        if (!z) {
                chip->buffer_write_time--;
                if (!chip->buffer_write_time)
-                       chip->buffer_write_time++;
+                       chip->buffer_write_time = 1;
        }
-       if (z > 1) 
+       if (z > 1)
                chip->buffer_write_time++;
 
        /* Done and happy. */
        chip->state = FL_STATUS;
 
-       /* check for lock bit */
-       if (map_word_bitsset(map, status, CMD(0x02))) {
-               /* clear status */
+       /* check for errors */
+       if (map_word_bitsset(map, status, CMD(0x1a))) {
+               unsigned long chipstatus = MERGESTATUS(status);
+
+               /* reset status */
                map_write(map, CMD(0x50), cmd_adr);
-               /* put back into read status register mode */
-               map_write(map, CMD(0x70), adr);
-               ret = -EROFS;
+               map_write(map, CMD(0x70), cmd_adr);
+               xip_enable(map, chip, cmd_adr);
+
+               if (chipstatus & 0x02) {
+                       ret = -EROFS;
+               } else if (chipstatus & 0x08) {
+                       printk(KERN_ERR "%s: buffer write error (bad VPP)\n", map->name);
+                       ret = -EIO;
+               } else {
+                       printk(KERN_ERR "%s: buffer write error (status 0x%lx)\n", map->name, chipstatus);
+                       ret = -EINVAL;
+               }
+
+               goto out;
        }
 
        xip_enable(map, chip, cmd_adr);
@@ -1543,70 +1651,65 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        return ret;
 }
 
-static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, 
-                                      size_t len, size_t *retlen, const u_char *buf)
+static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,
+                               unsigned long count, loff_t to, size_t *retlen)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
        int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        int ret = 0;
        int chipnum;
-       unsigned long ofs;
+       unsigned long ofs, vec_seek, i;
+       size_t len = 0;
+
+       for (i = 0; i < count; i++)
+               len += vecs[i].iov_len;
 
        *retlen = 0;
        if (!len)
                return 0;
 
        chipnum = to >> cfi->chipshift;
-       ofs = to  - (chipnum << cfi->chipshift);
-
-       /* If it's not bus-aligned, do the first word write */
-       if (ofs & (map_bankwidth(map)-1)) {
-               size_t local_len = (-ofs)&(map_bankwidth(map)-1);
-               if (local_len > len)
-                       local_len = len;
-               ret = cfi_intelext_write_words(mtd, to, local_len,
-                                              retlen, buf);
-               if (ret)
-                       return ret;
-               ofs += local_len;
-               buf += local_len;
-               len -= local_len;
-
-               if (ofs >> cfi->chipshift) {
-                       chipnum ++;
-                       ofs = 0;
-                       if (chipnum == cfi->numchips)
-                               return 0;
-               }
-       }
+       ofs = to - (chipnum << cfi->chipshift);
+       vec_seek = 0;
 
-       while(len) {
+       do {
                /* We must not cross write block boundaries */
                int size = wbufsize - (ofs & (wbufsize-1));
 
                if (size > len)
                        size = len;
-               ret = do_write_buffer(map, &cfi->chips[chipnum], 
-                                     ofs, buf, size);
+               ret = do_write_buffer(map, &cfi->chips[chipnum],
+                                     ofs, &vecs, &vec_seek, size);
                if (ret)
                        return ret;
 
                ofs += size;
-               buf += size;
                (*retlen) += size;
                len -= size;
 
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                }
-       }
+       } while (len);
+
        return 0;
 }
 
+static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
+                                      size_t len, size_t *retlen, const u_char *buf)
+{
+       struct kvec vec;
+
+       vec.iov_base = (void *) buf;
+       vec.iov_len = len;
+
+       return cfi_intelext_writev(mtd, &vec, 1, to, retlen);
+}
+
 static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
                                      unsigned long adr, int len, void *thunk)
 {
@@ -1672,23 +1775,17 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       map_word Xstatus;
                        map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       Xstatus = map_read(map, adr);
-                       /* Clear status bits */
-                       map_write(map, CMD(0x50), adr);
-                       map_write(map, CMD(0x70), adr);
                        xip_enable(map, chip, adr);
-                       printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n",
-                              adr, status.x[0], Xstatus.x[0]);
+                       printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
                        ret = -EIO;
                        goto out;
                }
-               
+
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1000000/HZ);
        }
@@ -1698,43 +1795,40 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
        chip->state = FL_STATUS;
        status = map_read(map, adr);
 
-       /* check for lock bit */
+       /* check for errors */
        if (map_word_bitsset(map, status, CMD(0x3a))) {
-               unsigned long chipstatus;
+               unsigned long chipstatus = MERGESTATUS(status);
 
                /* Reset the error bits */
                map_write(map, CMD(0x50), adr);
                map_write(map, CMD(0x70), adr);
                xip_enable(map, chip, adr);
 
-               chipstatus = MERGESTATUS(status);
-
                if ((chipstatus & 0x30) == 0x30) {
-                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus);
-                       ret = -EIO;
+                       printk(KERN_ERR "%s: block erase error: (bad command sequence, status 0x%lx)\n", map->name, chipstatus);
+                       ret = -EINVAL;
                } 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%lx\n", chipstatus);
+                       printk(KERN_ERR "%s: block erase error: (bad VPP)\n", map->name);
                        ret = -EIO;
-               } else if (chipstatus & 0x20) {
-                       if (retries--) {
-                               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%lx\n", adr, chipstatus);
+               } else if (chipstatus & 0x20 && retries--) {
+                       printk(KERN_DEBUG "block 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;
+               } else {
+                       printk(KERN_ERR "%s: block erase failed at 0x%08lx (status 0x%lx)\n", map->name, adr, chipstatus);
                        ret = -EIO;
                }
-       } else {
-               xip_enable(map, chip, adr);
-               ret = 0;
+
+               goto out;
        }
 
+       xip_enable(map, chip, adr);
  out:  put_chip(map, chip, adr);
        spin_unlock(chip->mutex);
        return ret;
@@ -1754,7 +1848,7 @@ int cfi_intelext_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
 
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
-       
+
        return 0;
 }
 
@@ -1775,7 +1869,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
                if (!ret) {
                        chip->oldstate = chip->state;
                        chip->state = FL_SYNCING;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
@@ -1789,7 +1883,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
                chip = &cfi->chips[i];
 
                spin_lock(chip->mutex);
-               
+
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
                        chip->oldstate = FL_READY;
@@ -1846,7 +1940,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
 
        ENABLE_VPP(map);
        xip_disable(map, chip, adr);
-       
+
        map_write(map, CMD(0x60), adr);
        if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
                map_write(map, CMD(0x01), adr);
@@ -1874,25 +1968,22 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       map_word Xstatus;
                        map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       Xstatus = map_read(map, adr);
                        xip_enable(map, chip, adr);
-                       printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n",
-                              status.x[0], Xstatus.x[0]);
+                       printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
                        put_chip(map, chip, adr);
                        spin_unlock(chip->mutex);
                        return -EIO;
                }
-               
+
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1);
        }
-       
+
        /* Done and happy. */
        chip->state = FL_STATUS;
        xip_enable(map, chip, adr);
@@ -1912,9 +2003,9 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
                ofs, len, 0);
 #endif
 
-       ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, 
+       ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
                ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
-       
+
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
               __FUNCTION__, ret);
@@ -1938,20 +2029,20 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
 
        ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
                                        ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
-       
+
 #ifdef DEBUG_LOCK_BITS
        printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
               __FUNCTION__, ret);
-       cfi_varsize_frob(mtd, do_printlockstatus_oneblock, 
+       cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
                ofs, len, 0);
 #endif
-       
+
        return ret;
 }
 
 #ifdef CONFIG_MTD_OTP
 
-typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, 
+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);
 
@@ -2002,7 +2093,7 @@ do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
 
                datum = map_word_load_partial(map, datum, buf, gap, n);
                ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
-               if (ret) 
+               if (ret)
                        return ret;
 
                offset += n;
@@ -2195,7 +2286,7 @@ static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
                                     NULL, do_otp_lock, 1);
 }
 
-static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, 
+static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
                                           struct otp_info *buf, size_t len)
 {
        size_t retlen;
@@ -2238,7 +2329,7 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
                        if (chip->oldstate == FL_READY) {
                                chip->oldstate = chip->state;
                                chip->state = FL_PM_SUSPENDED;
-                               /* No need to wake_up() on this state change - 
+                               /* No need to wake_up() on this state change -
                                 * as the whole point is that nobody can do anything
                                 * with the chip now anyway.
                                 */
@@ -2266,9 +2357,9 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
        if (ret) {
                for (i--; i >=0; i--) {
                        chip = &cfi->chips[i];
-                       
+
                        spin_lock(chip->mutex);
-                       
+
                        if (chip->state == FL_PM_SUSPENDED) {
                                /* No need to force it into a known state here,
                                   because we're returning failure, and it didn't
@@ -2279,8 +2370,8 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
                        }
                        spin_unlock(chip->mutex);
                }
-       } 
-       
+       }
+
        return ret;
 }
 
@@ -2292,11 +2383,11 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
        struct flchip *chip;
 
        for (i=0; i<cfi->numchips; i++) {
-       
+
                chip = &cfi->chips[i];
 
                spin_lock(chip->mutex);
-               
+
                /* Go to known state. Chip may have been power cycled */
                if (chip->state == FL_PM_SUSPENDED) {
                        map_write(map, CMD(0xFF), cfi->chips[i].start);
@@ -2318,7 +2409,7 @@ static int cfi_intelext_reset(struct mtd_info *mtd)
                struct flchip *chip = &cfi->chips[i];
 
                /* force the completion of any ongoing operation
-                  and switch to array mode so any bootloader in 
+                  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);
@@ -2355,20 +2446,23 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
        kfree(mtd->eraseregions);
 }
 
-static char im_name_1[]="cfi_cmdset_0001";
-static char im_name_3[]="cfi_cmdset_0003";
+static char im_name_0001[] = "cfi_cmdset_0001";
+static char im_name_0003[] = "cfi_cmdset_0003";
+static char im_name_0200[] = "cfi_cmdset_0200";
 
 static int __init cfi_intelext_init(void)
 {
-       inter_module_register(im_name_1, THIS_MODULE, &cfi_cmdset_0001);
-       inter_module_register(im_name_3, THIS_MODULE, &cfi_cmdset_0001);
+       inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001);
+       inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001);
+       inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001);
        return 0;
 }
 
 static void __exit cfi_intelext_exit(void)
 {
-       inter_module_unregister(im_name_1);
-       inter_module_unregister(im_name_3);
+       inter_module_unregister(im_name_0001);
+       inter_module_unregister(im_name_0003);
+       inter_module_unregister(im_name_0200);
 }
 
 module_init(cfi_intelext_init);
index 0e6475050da91b90c47a78c8d6532395c55c482d..aed10bd5c3c3869cb52732d764004753a30aa319 100644 (file)
  *
  * 4_by_16 work by Carolyn J. Smith
  *
- * XIP support hooks by Vitaly Wool (based on code for Intel flash 
+ * XIP support hooks by Vitaly Wool (based on code for Intel flash
  * by Nicolas Pitre)
- * 
+ *
  * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
  *
  * This code is GPL
  *
- * $Id: cfi_cmdset_0002.c,v 1.118 2005/07/04 22:34:29 gleixner Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.122 2005/11/07 11:14:22 gleixner Exp $
  *
  */
 
@@ -93,7 +93,7 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp)
        };
 
        printk("  Silicon revision: %d\n", extp->SiliconRevision >> 1);
-       printk("  Address sensitive unlock: %s\n", 
+       printk("  Address sensitive unlock: %s\n",
               (extp->SiliconRevision & 1) ? "Not required" : "Required");
 
        if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
@@ -118,9 +118,9 @@ static void cfi_tell_features(struct cfi_pri_amdstd *extp)
        else
                printk("  Page mode: %d word page\n", extp->PageMode << 2);
 
-       printk("  Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", 
+       printk("  Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n",
               extp->VppMin >> 4, extp->VppMin & 0xf);
-       printk("  Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", 
+       printk("  Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n",
               extp->VppMax >> 4, extp->VppMax & 0xf);
 
        if (extp->TopBottom < ARRAY_SIZE(top_bottom))
@@ -177,7 +177,7 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param)
                ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
                mtd->erase = cfi_amdstd_erase_chip;
        }
-       
+
 }
 
 static struct cfi_fixup cfi_fixup_table[] = {
@@ -239,7 +239,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 
        if (cfi->cfi_mode==CFI_MODE_CFI){
                unsigned char bootloc;
-               /* 
+               /*
                 * It's a real CFI chip, not one for which the probe
                 * routine faked a CFI structure. So we read the feature
                 * table from it.
@@ -253,8 +253,18 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
                        return NULL;
                }
 
+               if (extp->MajorVersion != '1' ||
+                   (extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
+                       printk(KERN_ERR "  Unknown Amd/Fujitsu Extended Query "
+                              "version %c.%c.\n",  extp->MajorVersion,
+                              extp->MinorVersion);
+                       kfree(extp);
+                       kfree(mtd);
+                       return NULL;
+               }
+
                /* Install our own private info structure */
-               cfi->cmdset_priv = extp;        
+               cfi->cmdset_priv = extp;
 
                /* Apply cfi device specific fixups */
                cfi_fixup(mtd, cfi_fixup_table);
@@ -262,7 +272,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 #ifdef DEBUG_CFI_FEATURES
                /* Tell the user about it in lots of lovely detail */
                cfi_tell_features(extp);
-#endif 
+#endif
 
                bootloc = extp->TopBottom;
                if ((bootloc != 2) && (bootloc != 3)) {
@@ -273,11 +283,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 
                if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
                        printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
-                       
+
                        for (i=0; i<cfi->cfiq->NumEraseRegions / 2; i++) {
                                int j = (cfi->cfiq->NumEraseRegions-1)-i;
                                __u32 swap;
-                               
+
                                swap = cfi->cfiq->EraseRegionInfo[i];
                                cfi->cfiq->EraseRegionInfo[i] = cfi->cfiq->EraseRegionInfo[j];
                                cfi->cfiq->EraseRegionInfo[j] = swap;
@@ -288,11 +298,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
                cfi->addr_unlock2 = 0x2aa;
                /* Modify the unlock address if we are in compatibility mode */
                if (    /* x16 in x8 mode */
-                       ((cfi->device_type == CFI_DEVICETYPE_X8) && 
+                       ((cfi->device_type == CFI_DEVICETYPE_X8) &&
                                (cfi->cfiq->InterfaceDesc == 2)) ||
                        /* x32 in x16 mode */
                        ((cfi->device_type == CFI_DEVICETYPE_X16) &&
-                               (cfi->cfiq->InterfaceDesc == 4))) 
+                               (cfi->cfiq->InterfaceDesc == 4)))
                {
                        cfi->addr_unlock1 = 0xaaa;
                        cfi->addr_unlock2 = 0x555;
@@ -310,10 +320,10 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
                cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
                cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
                cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
-       }               
-       
+       }
+
        map->fldrv = &cfi_amdstd_chipdrv;
-       
+
        return cfi_amdstd_setup(mtd);
 }
 
@@ -326,24 +336,24 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
        unsigned long offset = 0;
        int i,j;
 
-       printk(KERN_NOTICE "number of %s chips: %d\n", 
+       printk(KERN_NOTICE "number of %s chips: %d\n",
               (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
-       /* Select the correct geometry setup */ 
+       /* Select the correct geometry setup */
        mtd->size = devsize * cfi->numchips;
 
        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
        mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                                    * mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) { 
+       if (!mtd->eraseregions) {
                printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
                goto setup_err;
        }
-                       
+
        for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
                unsigned long ernum, ersize;
                ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
                ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
-                       
+
                if (mtd->erasesize < ersize) {
                        mtd->erasesize = ersize;
                }
@@ -429,7 +439,7 @@ static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word
        oldd = map_read(map, addr);
        curd = map_read(map, addr);
 
-       return  map_word_equal(map, oldd, curd) && 
+       return  map_word_equal(map, oldd, curd) &&
                map_word_equal(map, curd, expected);
 }
 
@@ -461,7 +471,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                        /* Someone else might have been playing with it. */
                        goto retry;
                }
-                               
+
        case FL_READY:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
@@ -504,7 +514,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                                printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
                                return -EIO;
                        }
-                       
+
                        spin_unlock(chip->mutex);
                        cfi_udelay(1);
                        spin_lock(chip->mutex);
@@ -607,7 +617,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
  * When a delay is required for the flash operation to complete, the
  * xip_udelay() function is polling for both the given timeout and pending
  * (but still masked) hardware interrupts.  Whenever there is an interrupt
- * pending then the flash erase operation is suspended, array mode restored 
+ * pending then the flash erase operation is suspended, array mode restored
  * and interrupts unmasked.  Task scheduling might also happen at that
  * point.  The CPU eventually returns from the interrupt or the call to
  * schedule() and the suspended flash operation is resumed for the remaining
@@ -631,9 +641,9 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
                    ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) &&
                    (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
                        /*
-                        * Let's suspend the erase operation when supported.  
-                        * Note that we currently don't try to suspend 
-                        * interleaved chips if there is already another 
+                        * Let's suspend the erase operation when supported.
+                        * Note that we currently don't try to suspend
+                        * interleaved chips if there is already another
                         * operation suspended (imagine what happens
                         * when one chip was already done with the current
                         * operation while another chip suspended it, then
@@ -769,8 +779,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
 
        adr += chip->start;
 
-       /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(map_bankwidth(map)-1); 
+       /* Ensure cmd read/writes are aligned. */
+       cmd_addr = adr & ~(map_bankwidth(map)-1);
 
        spin_lock(chip->mutex);
        ret = get_chip(map, chip, cmd_addr, FL_READY);
@@ -850,7 +860,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
 #endif
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
-               
+
                spin_unlock(chip->mutex);
 
                schedule();
@@ -862,7 +872,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
                timeo = jiffies + HZ;
 
                goto retry;
-       }       
+       }
 
        adr += chip->start;
 
@@ -871,14 +881,14 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-       
+
        map_copy_from(map, buf, adr, len);
 
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
-       
+
        wake_up(&chip->wq);
        spin_unlock(chip->mutex);
 
@@ -987,7 +997,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
                                chip->word_write_time);
 
        /* See comment above for timeout value. */
-       timeo = jiffies + uWriteTimeout; 
+       timeo = jiffies + uWriteTimeout;
        for (;;) {
                if (chip->state != FL_WRITING) {
                        /* Someone's suspended the write. Sleep */
@@ -1003,16 +1013,16 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
                        continue;
                }
 
-               if (chip_ready(map, adr))
-                       break;
-
-               if (time_after(jiffies, timeo)) {
+               if (time_after(jiffies, timeo) && !chip_ready(map, adr)){
                        xip_enable(map, chip, adr);
                        printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
                        xip_disable(map, chip, adr);
-                        break;
+                       break;
                }
 
+               if (chip_ready(map, adr))
+                       break;
+
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1);
        }
@@ -1022,7 +1032,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
                map_write( map, CMD(0xF0), chip->start );
                /* FIXME - should have reset delay before continuing */
 
-               if (++retry_cnt <= MAX_WORD_RETRIES) 
+               if (++retry_cnt <= MAX_WORD_RETRIES)
                        goto retry;
 
                ret = -EIO;
@@ -1090,27 +1100,27 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
 
                /* Number of bytes to copy from buffer */
                n = min_t(int, len, map_bankwidth(map)-i);
-               
+
                tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
 
-               ret = do_write_oneword(map, &cfi->chips[chipnum], 
+               ret = do_write_oneword(map, &cfi->chips[chipnum],
                                       bus_ofs, tmp_buf);
-               if (ret) 
+               if (ret)
                        return ret;
-               
+
                ofs += n;
                buf += n;
                (*retlen) += n;
                len -= n;
 
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                }
        }
-       
+
        /* We are now aligned, write as much as possible */
        while(len >= map_bankwidth(map)) {
                map_word datum;
@@ -1128,7 +1138,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
                len -= map_bankwidth(map);
 
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
@@ -1166,12 +1176,12 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
                spin_unlock(cfi->chips[chipnum].mutex);
 
                tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
-       
-               ret = do_write_oneword(map, &cfi->chips[chipnum], 
+
+               ret = do_write_oneword(map, &cfi->chips[chipnum],
                                ofs, tmp_buf);
-               if (ret) 
+               if (ret)
                        return ret;
-               
+
                (*retlen) += len;
        }
 
@@ -1183,7 +1193,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
  * FIXME: interleaved mode not tested, and probably not supported!
  */
 static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
-                                   unsigned long adr, const u_char *buf, 
+                                   unsigned long adr, const u_char *buf,
                                    int len)
 {
        struct cfi_private *cfi = map->fldrv_priv;
@@ -1213,7 +1223,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        XIP_INVAL_CACHED_RANGE(map, adr, len);
        ENABLE_VPP(map);
        xip_disable(map, chip, cmd_adr);
-       
+
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -1247,8 +1257,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                                adr, map_bankwidth(map),
                                chip->word_write_time);
 
-       timeo = jiffies + uWriteTimeout; 
-               
+       timeo = jiffies + uWriteTimeout;
+
        for (;;) {
                if (chip->state != FL_WRITING) {
                        /* Someone's suspended the write. Sleep */
@@ -1264,13 +1274,13 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
                        continue;
                }
 
+               if (time_after(jiffies, timeo) && !chip_ready(map, adr))
+                       break;
+
                if (chip_ready(map, adr)) {
                        xip_enable(map, chip, adr);
                        goto op_done;
                }
-                   
-               if( time_after(jiffies, timeo))
-                       break;
 
                /* Latency issues. Drop the lock, wait a while and retry */
                UDELAY(map, chip, adr, 1);
@@ -1342,7 +1352,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
                if (size % map_bankwidth(map))
                        size -= size % map_bankwidth(map);
 
-               ret = do_write_buffer(map, &cfi->chips[chipnum], 
+               ret = do_write_buffer(map, &cfi->chips[chipnum],
                                      ofs, buf, size);
                if (ret)
                        return ret;
@@ -1353,7 +1363,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
                len -= size;
 
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
@@ -1570,7 +1580,7 @@ int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
 
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
-       
+
        return 0;
 }
 
@@ -1593,7 +1603,7 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
 
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
-       
+
        return 0;
 }
 
@@ -1620,7 +1630,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
                case FL_JEDEC_QUERY:
                        chip->oldstate = chip->state;
                        chip->state = FL_SYNCING;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
@@ -1631,13 +1641,13 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
                default:
                        /* Not an idle state */
                        add_wait_queue(&chip->wq, &wait);
-                       
+
                        spin_unlock(chip->mutex);
 
                        schedule();
 
                        remove_wait_queue(&chip->wq, &wait);
-                       
+
                        goto retry;
                }
        }
@@ -1648,7 +1658,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
                chip = &cfi->chips[i];
 
                spin_lock(chip->mutex);
-               
+
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
                        wake_up(&chip->wq);
@@ -1678,7 +1688,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
                case FL_JEDEC_QUERY:
                        chip->oldstate = chip->state;
                        chip->state = FL_PM_SUSPENDED;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
@@ -1699,7 +1709,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
                        chip = &cfi->chips[i];
 
                        spin_lock(chip->mutex);
-               
+
                        if (chip->state == FL_PM_SUSPENDED) {
                                chip->state = chip->oldstate;
                                wake_up(&chip->wq);
@@ -1707,7 +1717,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
                        spin_unlock(chip->mutex);
                }
        }
-       
+
        return ret;
 }
 
@@ -1720,11 +1730,11 @@ static void cfi_amdstd_resume(struct mtd_info *mtd)
        struct flchip *chip;
 
        for (i=0; i<cfi->numchips; i++) {
-       
+
                chip = &cfi->chips[i];
 
                spin_lock(chip->mutex);
-               
+
                if (chip->state == FL_PM_SUSPENDED) {
                        chip->state = FL_READY;
                        map_write(map, CMD(0xF0), chip->start);
index c894f880157831f1d1c3524aa77d9a462d77dd60..c4a19d2dc67f6aabdc88977311dbd4ba2fa109ce 100644 (file)
@@ -4,8 +4,8 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0020.c,v 1.19 2005/07/13 15:52:45 dwmw2 Exp $
- * 
+ * $Id: cfi_cmdset_0020.c,v 1.22 2005/11/07 11:14:22 gleixner Exp $
+ *
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
  *     - completely revamped method functions so they are aware and
  *       independent of the flash geometry (buswidth, interleave, etc.)
@@ -81,17 +81,17 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
        printk("     - Page-mode read:     %s\n", extp->FeatureSupport&128?"supported":"unsupported");
        printk("     - Synchronous read:   %s\n", extp->FeatureSupport&256?"supported":"unsupported");
        for (i=9; i<32; i++) {
-               if (extp->FeatureSupport & (1<<i)) 
+               if (extp->FeatureSupport & (1<<i))
                        printk("     - Unknown Bit %X:      supported\n", i);
        }
-       
+
        printk("  Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport);
        printk("     - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported");
        for (i=1; i<8; i++) {
                if (extp->SuspendCmdSupport & (1<<i))
                        printk("     - Unknown Bit %X:               supported\n", i);
        }
-       
+
        printk("  Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask);
        printk("     - Lock Bit Active:      %s\n", extp->BlkStatusRegMask&1?"yes":"no");
        printk("     - Valid Bit Active:     %s\n", extp->BlkStatusRegMask&2?"yes":"no");
@@ -99,11 +99,11 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
                if (extp->BlkStatusRegMask & (1<<i))
                        printk("     - Unknown Bit %X Active: yes\n",i);
        }
-       
-       printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+
+       printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n",
               extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
        if (extp->VppOptimal)
-               printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
+               printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n",
                       extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
 }
 #endif
@@ -121,7 +121,7 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
        int i;
 
        if (cfi->cfi_mode) {
-               /* 
+               /*
                 * It's a real CFI chip, not one for which the probe
                 * routine faked a CFI structure. So we read the feature
                 * table from it.
@@ -133,24 +133,33 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
                if (!extp)
                        return NULL;
 
+               if (extp->MajorVersion != '1' ||
+                   (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
+                       printk(KERN_ERR "  Unknown ST Microelectronics"
+                              " Extended Query version %c.%c.\n",
+                              extp->MajorVersion, extp->MinorVersion);
+                       kfree(extp);
+                       return NULL;
+               }
+
                /* Do some byteswapping if necessary */
                extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
                extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
-               
+
 #ifdef DEBUG_CFI_FEATURES
                /* Tell the user about it in lots of lovely detail */
                cfi_tell_features(extp);
-#endif 
+#endif
 
                /* Install our own private info structure */
                cfi->cmdset_priv = extp;
-       }       
+       }
 
        for (i=0; i< cfi->numchips; i++) {
                cfi->chips[i].word_write_time = 128;
                cfi->chips[i].buffer_write_time = 128;
                cfi->chips[i].erase_time = 1024;
-       }               
+       }
 
        return cfi_staa_setup(map);
 }
@@ -178,15 +187,15 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
        mtd->size = devsize * cfi->numchips;
 
        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
-       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) 
+       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                        * mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) { 
+       if (!mtd->eraseregions) {
                printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
                kfree(cfi->cmdset_priv);
                kfree(mtd);
                return NULL;
        }
-       
+
        for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
                unsigned long ernum, ersize;
                ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
@@ -219,7 +228,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
                               mtd->eraseregions[i].numblocks);
                }
 
-       /* Also select the correct geometry setup too */ 
+       /* Also select the correct geometry setup too */
        mtd->erase = cfi_staa_erase_varsize;
        mtd->read = cfi_staa_read;
         mtd->write = cfi_staa_write_buffers;
@@ -250,8 +259,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
 
        adr += chip->start;
 
-       /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(map_bankwidth(map)-1); 
+       /* Ensure cmd read/writes are aligned. */
+       cmd_addr = adr & ~(map_bankwidth(map)-1);
 
        /* Let's determine this according to the interleave only once */
        status_OK = CMD(0x80);
@@ -267,7 +276,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
        case FL_ERASING:
                if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
                        goto sleep; /* We don't support erase suspend */
-               
+
                map_write (map, CMD(0xb0), cmd_addr);
                /* If the flash has finished erasing, then 'erase suspend'
                 * appears to make some (28F320) flash devices switch to
@@ -282,7 +291,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
                        status = map_read(map, cmd_addr);
                        if (map_word_andequal(map, status, status_OK, status_OK))
                                break;
-                       
+
                        if (time_after(jiffies, timeo)) {
                                /* Urgh */
                                map_write(map, CMD(0xd0), cmd_addr);
@@ -294,17 +303,17 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
                                       "suspended: status = 0x%lx\n", status.x[0]);
                                return -EIO;
                        }
-                       
+
                        spin_unlock_bh(chip->mutex);
                        cfi_udelay(1);
                        spin_lock_bh(chip->mutex);
                }
-               
+
                suspended = 1;
                map_write(map, CMD(0xff), cmd_addr);
                chip->state = FL_READY;
                break;
-       
+
 #if 0
        case FL_WRITING:
                /* Not quite yet */
@@ -325,7 +334,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
                        chip->state = FL_READY;
                        break;
                }
-               
+
                /* Urgh. Chip not yet ready to talk to us. */
                if (time_after(jiffies, timeo)) {
                        spin_unlock_bh(chip->mutex);
@@ -355,17 +364,17 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
 
        if (suspended) {
                chip->state = chip->oldstate;
-               /* What if one interleaved chip has finished and the 
+               /* What if one interleaved chip has finished and the
                   other hasn't? The old code would leave the finished
-                  one in READY mode. That's bad, and caused -EROFS 
+                  one in READY mode. That's bad, and caused -EROFS
                   errors to be returned from do_erase_oneblock because
                   that's the only bit it checked for at the time.
-                  As the state machine appears to explicitly allow 
+                  As the state machine appears to explicitly allow
                   sending the 0x70 (Read Status) command to an erasing
-                  chip and expecting it to be ignored, that's what we 
+                  chip and expecting it to be ignored, that's what we
                   do. */
                map_write(map, CMD(0xd0), cmd_addr);
-               map_write(map, CMD(0x70), cmd_addr);            
+               map_write(map, CMD(0x70), cmd_addr);
        }
 
        wake_up(&chip->wq);
@@ -405,14 +414,14 @@ static int cfi_staa_read (struct mtd_info *mtd, loff_t from, size_t len, size_t
                *retlen += thislen;
                len -= thislen;
                buf += thislen;
-               
+
                ofs = 0;
                chipnum++;
        }
        return ret;
 }
 
-static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 
+static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                                  unsigned long adr, const u_char *buf, int len)
 {
        struct cfi_private *cfi = map->fldrv_priv;
@@ -420,7 +429,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        unsigned long cmd_adr, timeo;
        DECLARE_WAITQUEUE(wait, current);
        int wbufsize, z;
-        
+
         /* M58LW064A requires bus alignment for buffer wriets -- saw */
         if (adr & (map_bankwidth(map)-1))
             return -EINVAL;
@@ -428,10 +437,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
         wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
         adr += chip->start;
        cmd_adr = adr & ~(wbufsize-1);
-       
+
        /* Let's determine this according to the interleave only once */
         status_OK = CMD(0x80);
-        
+
        timeo = jiffies + HZ;
  retry:
 
@@ -439,7 +448,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state);
 #endif
        spin_lock_bh(chip->mutex);
+
        /* Check that the chip's ready to talk to us.
         * Later, we can actually think about interrupting it
         * if it's in FL_ERASING state.
@@ -448,7 +457,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        switch (chip->state) {
        case FL_READY:
                break;
-               
+
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
                map_write(map, CMD(0x70), cmd_adr);
@@ -513,7 +522,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
 
        /* Write length of data to come */
        map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr );
-        
+
        /* Write data */
        for (z = 0; z < len;
             z += map_bankwidth(map), buf += map_bankwidth(map)) {
@@ -560,7 +569,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                        printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
                        return -EIO;
                }
-               
+
                /* Latency issues. Drop the lock, wait a while and retry */
                spin_unlock_bh(chip->mutex);
                cfi_udelay(1);
@@ -572,9 +581,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                if (!chip->buffer_write_time)
                        chip->buffer_write_time++;
        }
-       if (z > 1) 
+       if (z > 1)
                chip->buffer_write_time++;
-        
+
        /* Done and happy. */
        DISABLE_VPP(map);
        chip->state = FL_STATUS;
@@ -598,7 +607,7 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
         return 0;
 }
 
-static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to, 
+static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
                                       size_t len, size_t *retlen, const u_char *buf)
 {
        struct map_info *map = mtd->priv;
@@ -620,7 +629,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
         printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize);
         printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len);
 #endif
-        
+
         /* Write buffer is worth it only if more than one word to write... */
         while (len > 0) {
                /* We must not cross write block boundaries */
@@ -629,7 +638,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
                 if (size > len)
                     size = len;
 
-                ret = do_write_buffer(map, &cfi->chips[chipnum], 
+                ret = do_write_buffer(map, &cfi->chips[chipnum],
                                      ofs, buf, size);
                if (ret)
                        return ret;
@@ -640,13 +649,13 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
                len -= size;
 
                if (ofs >> cfi->chipshift) {
-                       chipnum ++; 
+                       chipnum ++;
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                }
        }
-        
+
        return 0;
 }
 
@@ -756,7 +765,7 @@ retry:
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* Urgh. Chip not yet ready to talk to us. */
                if (time_after(jiffies, timeo)) {
                        spin_unlock_bh(chip->mutex);
@@ -789,7 +798,7 @@ retry:
        map_write(map, CMD(0x20), adr);
        map_write(map, CMD(0xD0), adr);
        chip->state = FL_ERASING;
-       
+
        spin_unlock_bh(chip->mutex);
        msleep(1000);
        spin_lock_bh(chip->mutex);
@@ -814,7 +823,7 @@ retry:
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
                        map_write(map, CMD(0x70), adr);
@@ -824,13 +833,13 @@ retry:
                        spin_unlock_bh(chip->mutex);
                        return -EIO;
                }
-               
+
                /* Latency issues. Drop the lock, wait a while and retry */
                spin_unlock_bh(chip->mutex);
                cfi_udelay(1);
                spin_lock_bh(chip->mutex);
        }
-       
+
        DISABLE_VPP(map);
        ret = 0;
 
@@ -855,7 +864,7 @@ retry:
                /* Reset the error bits */
                map_write(map, CMD(0x50), adr);
                map_write(map, CMD(0x70), adr);
-               
+
                if ((chipstatus & 0x30) == 0x30) {
                        printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
                        ret = -EIO;
@@ -904,17 +913,17 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
 
        i = 0;
 
-       /* Skip all erase regions which are ended before the start of 
+       /* Skip all erase regions which are ended before the start of
           the requested erase. Actually, to save on the calculations,
           we skip to the first erase region which starts after the
           start of the requested erase, and then go back one.
        */
-       
+
        while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
               i++;
        i--;
 
-       /* OK, now i is pointing at the erase region in which this 
+       /* OK, now i is pointing at the erase region in which this
           erase request starts. Check the start of the requested
           erase range is aligned with the erase size which is in
           effect here.
@@ -937,7 +946,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
           the address actually falls
        */
        i--;
-       
+
        if ((instr->addr + instr->len) & (regions[i].erasesize-1))
                return -EINVAL;
 
@@ -949,7 +958,7 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
 
        while(len) {
                ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
-               
+
                if (ret)
                        return ret;
 
@@ -962,15 +971,15 @@ int cfi_staa_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
                if (adr >> cfi->chipshift) {
                        adr = 0;
                        chipnum++;
-                       
+
                        if (chipnum >= cfi->numchips)
                        break;
                }
        }
-               
+
        instr->state = MTD_ERASE_DONE;
        mtd_erase_callback(instr);
-       
+
        return 0;
 }
 
@@ -996,7 +1005,7 @@ static void cfi_staa_sync (struct mtd_info *mtd)
                case FL_JEDEC_QUERY:
                        chip->oldstate = chip->state;
                        chip->state = FL_SYNCING;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
@@ -1007,11 +1016,11 @@ static void cfi_staa_sync (struct mtd_info *mtd)
                default:
                        /* Not an idle state */
                        add_wait_queue(&chip->wq, &wait);
-                       
+
                        spin_unlock_bh(chip->mutex);
                        schedule();
                        remove_wait_queue(&chip->wq, &wait);
-                       
+
                        goto retry;
                }
        }
@@ -1022,7 +1031,7 @@ static void cfi_staa_sync (struct mtd_info *mtd)
                chip = &cfi->chips[i];
 
                spin_lock_bh(chip->mutex);
-               
+
                if (chip->state == FL_SYNCING) {
                        chip->state = chip->oldstate;
                        wake_up(&chip->wq);
@@ -1057,9 +1066,9 @@ retry:
 
        case FL_STATUS:
                status = map_read(map, adr);
-               if (map_word_andequal(map, status, status_OK, status_OK)) 
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* Urgh. Chip not yet ready to talk to us. */
                if (time_after(jiffies, timeo)) {
                        spin_unlock_bh(chip->mutex);
@@ -1088,7 +1097,7 @@ retry:
        map_write(map, CMD(0x60), adr);
        map_write(map, CMD(0x01), adr);
        chip->state = FL_LOCKING;
-       
+
        spin_unlock_bh(chip->mutex);
        msleep(1000);
        spin_lock_bh(chip->mutex);
@@ -1102,7 +1111,7 @@ retry:
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
                        map_write(map, CMD(0x70), adr);
@@ -1112,13 +1121,13 @@ retry:
                        spin_unlock_bh(chip->mutex);
                        return -EIO;
                }
-               
+
                /* Latency issues. Drop the lock, wait a while and retry */
                spin_unlock_bh(chip->mutex);
                cfi_udelay(1);
                spin_lock_bh(chip->mutex);
        }
-       
+
        /* Done and happy. */
        chip->state = FL_STATUS;
        DISABLE_VPP(map);
@@ -1162,8 +1171,8 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
                cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
                printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
                cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-#endif 
-               
+#endif
+
                if (ret)
                        return ret;
 
@@ -1173,7 +1182,7 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
                if (adr >> cfi->chipshift) {
                        adr = 0;
                        chipnum++;
-                       
+
                        if (chipnum >= cfi->numchips)
                        break;
                }
@@ -1208,7 +1217,7 @@ retry:
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* Urgh. Chip not yet ready to talk to us. */
                if (time_after(jiffies, timeo)) {
                        spin_unlock_bh(chip->mutex);
@@ -1237,7 +1246,7 @@ retry:
        map_write(map, CMD(0x60), adr);
        map_write(map, CMD(0xD0), adr);
        chip->state = FL_UNLOCKING;
-       
+
        spin_unlock_bh(chip->mutex);
        msleep(1000);
        spin_lock_bh(chip->mutex);
@@ -1251,7 +1260,7 @@ retry:
                status = map_read(map, adr);
                if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
-               
+
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
                        map_write(map, CMD(0x70), adr);
@@ -1261,13 +1270,13 @@ retry:
                        spin_unlock_bh(chip->mutex);
                        return -EIO;
                }
-               
+
                /* Latency issues. Drop the unlock, wait a while and retry */
                spin_unlock_bh(chip->mutex);
                cfi_udelay(1);
                spin_lock_bh(chip->mutex);
        }
-       
+
        /* Done and happy. */
        chip->state = FL_STATUS;
        DISABLE_VPP(map);
@@ -1292,7 +1301,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
        {
                unsigned long temp_adr = adr;
                unsigned long temp_len = len;
-                 
+
                cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
                 while (temp_len) {
                        printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor)));
@@ -1310,7 +1319,7 @@ static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
        printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor)));
        cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
 #endif
-       
+
        return ret;
 }
 
@@ -1334,7 +1343,7 @@ static int cfi_staa_suspend(struct mtd_info *mtd)
                case FL_JEDEC_QUERY:
                        chip->oldstate = chip->state;
                        chip->state = FL_PM_SUSPENDED;
-                       /* No need to wake_up() on this state change - 
+                       /* No need to wake_up() on this state change -
                         * as the whole point is that nobody can do anything
                         * with the chip now anyway.
                         */
@@ -1353,9 +1362,9 @@ static int cfi_staa_suspend(struct mtd_info *mtd)
        if (ret) {
                for (i--; i >=0; i--) {
                        chip = &cfi->chips[i];
-                       
+
                        spin_lock_bh(chip->mutex);
-                       
+
                        if (chip->state == FL_PM_SUSPENDED) {
                                /* No need to force it into a known state here,
                                   because we're returning failure, and it didn't
@@ -1365,8 +1374,8 @@ static int cfi_staa_suspend(struct mtd_info *mtd)
                        }
                        spin_unlock_bh(chip->mutex);
                }
-       } 
-       
+       }
+
        return ret;
 }
 
@@ -1378,11 +1387,11 @@ static void cfi_staa_resume(struct mtd_info *mtd)
        struct flchip *chip;
 
        for (i=0; i<cfi->numchips; i++) {
-       
+
                chip = &cfi->chips[i];
 
                spin_lock_bh(chip->mutex);
-               
+
                /* Go to known state. Chip may have been power cycled */
                if (chip->state == FL_PM_SUSPENDED) {
                        map_write(map, CMD(0xFF), 0);
index cf750038ce6af9645df83ff320a35200c6598168..90eb30e06b7c9322fd4e71b81a794976d5f95c4a 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: cfi_probe.c,v 1.83 2004/11/16 18:19:02 nico Exp $
+   $Id: cfi_probe.c,v 1.84 2005/11/07 11:14:23 gleixner Exp $
 */
 
 #include <linux/config.h>
@@ -20,7 +20,7 @@
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/gen_probe.h>
 
-//#define DEBUG_CFI 
+//#define DEBUG_CFI
 
 #ifdef DEBUG_CFI
 static void print_cfi_ident(struct cfi_ident *);
@@ -103,7 +103,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
                                   unsigned long *chip_map, struct cfi_private *cfi)
 {
        int i;
-       
+
        if ((base + 0) >= map->size) {
                printk(KERN_NOTICE
                        "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n",
@@ -128,7 +128,7 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
        }
 
        if (!cfi->numchips) {
-               /* This is the first time we're called. Set up the CFI 
+               /* This is the first time we're called. Set up the CFI
                   stuff accordingly and return */
                return cfi_chip_setup(map, cfi);
        }
@@ -138,13 +138,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
                unsigned long start;
                if(!test_bit(i, chip_map)) {
                        /* Skip location; no valid chip at this address */
-                       continue; 
+                       continue;
                }
                start = i << cfi->chipshift;
                /* This chip should be in read mode if it's one
                   we've already touched. */
                if (qry_present(map, start, cfi)) {
-                       /* Eep. This chip also had the QRY marker. 
+                       /* Eep. This chip also had the QRY marker.
                         * Is it an alias for the new one? */
                        cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL);
                        cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
@@ -156,13 +156,13 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
                                       map->name, base, start);
                                return 0;
                        }
-                       /* Yes, it's actually got QRY for data. Most 
+                       /* Yes, it's actually got QRY for data. Most
                         * unfortunate. Stick the new chip in read mode
                         * too and if it's the same, assume it's an alias. */
                        /* FIXME: Use other modes to do a proper check */
                        cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
                        cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
-                       
+
                        if (qry_present(map, base, cfi)) {
                                xip_allowed(base, map);
                                printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
@@ -171,12 +171,12 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
                        }
                }
        }
-       
+
        /* OK, if we got to here, then none of the previous chips appear to
           be aliases for the current one. */
        set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
        cfi->numchips++;
-       
+
        /* Put it back into Read Mode */
        cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
@@ -185,11 +185,11 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
        printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
               map->name, cfi->interleave, cfi->device_type*8, base,
               map->bankwidth*8);
-       
+
        return 1;
 }
 
-static int __xipram cfi_chip_setup(struct map_info *map, 
+static int __xipram cfi_chip_setup(struct map_info *map,
                                   struct cfi_private *cfi)
 {
        int ofs_factor = cfi->interleave*cfi->device_type;
@@ -209,11 +209,11 @@ static int __xipram cfi_chip_setup(struct map_info *map,
                printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
                return 0;
        }
-       
-       memset(cfi->cfiq,0,sizeof(struct cfi_ident));   
-       
+
+       memset(cfi->cfiq,0,sizeof(struct cfi_ident));
+
        cfi->cfi_mode = CFI_MODE_CFI;
-       
+
        /* Read the CFI info structure */
        xip_disable_qry(base, map, cfi);
        for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++)
@@ -231,7 +231,7 @@ static int __xipram cfi_chip_setup(struct map_info *map,
        cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
        cfi->mfr = cfi_read_query(map, base);
-       cfi->id = cfi_read_query(map, base + ofs_factor);    
+       cfi->id = cfi_read_query(map, base + ofs_factor);
 
        /* Put it back into Read Mode */
        cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
@@ -255,10 +255,10 @@ static int __xipram cfi_chip_setup(struct map_info *map,
 
        for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
                cfi->cfiq->EraseRegionInfo[i] = le32_to_cpu(cfi->cfiq->EraseRegionInfo[i]);
-               
-#ifdef DEBUG_CFI               
+
+#ifdef DEBUG_CFI
                printk("  Erase Region #%d: BlockSize 0x%4.4X bytes, %d blocks\n",
-                      i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff, 
+                      i, (cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff,
                       (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
 #endif
        }
@@ -271,33 +271,33 @@ static int __xipram cfi_chip_setup(struct map_info *map,
 }
 
 #ifdef DEBUG_CFI
-static char *vendorname(__u16 vendor) 
+static char *vendorname(__u16 vendor)
 {
        switch (vendor) {
        case P_ID_NONE:
                return "None";
-               
+
        case P_ID_INTEL_EXT:
                return "Intel/Sharp Extended";
-               
+
        case P_ID_AMD_STD:
                return "AMD/Fujitsu Standard";
-               
+
        case P_ID_INTEL_STD:
                return "Intel/Sharp Standard";
-               
+
        case P_ID_AMD_EXT:
                return "AMD/Fujitsu Extended";
 
        case P_ID_WINBOND:
                return "Winbond Standard";
-               
+
        case P_ID_ST_ADV:
                return "ST Advanced";
 
        case P_ID_MITSUBISHI_STD:
                return "Mitsubishi Standard";
-               
+
        case P_ID_MITSUBISHI_EXT:
                return "Mitsubishi Extended";
 
@@ -306,13 +306,13 @@ static char *vendorname(__u16 vendor)
 
        case P_ID_INTEL_PERFORMANCE:
                return "Intel Performance Code";
-               
+
        case P_ID_INTEL_DATA:
                return "Intel Data";
-               
+
        case P_ID_RESERVED:
                return "Not Allowed / Reserved for Future Use";
-               
+
        default:
                return "Unknown";
        }
@@ -325,21 +325,21 @@ static void print_cfi_ident(struct cfi_ident *cfip)
        if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') {
                printk("Invalid CFI ident structure.\n");
                return;
-       }       
-#endif         
+       }
+#endif
        printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID));
        if (cfip->P_ADR)
                printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR);
        else
                printk("No Primary Algorithm Table\n");
-       
+
        printk("Alternative Vendor Command Set: %4.4X (%s)\n", cfip->A_ID, vendorname(cfip->A_ID));
        if (cfip->A_ADR)
                printk("Alternate Algorithm Table at %4.4X\n", cfip->A_ADR);
        else
                printk("No Alternate Algorithm Table\n");
-               
-               
+
+
        printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
        printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
        if (cfip->VppMin) {
@@ -348,61 +348,61 @@ static void print_cfi_ident(struct cfi_ident *cfip)
        }
        else
                printk("No Vpp line\n");
-       
+
        printk("Typical byte/word write timeout: %d Âµs\n", 1<<cfip->WordWriteTimeoutTyp);
        printk("Maximum byte/word write timeout: %d Âµs\n", (1<<cfip->WordWriteTimeoutMax) * (1<<cfip->WordWriteTimeoutTyp));
-       
+
        if (cfip->BufWriteTimeoutTyp || cfip->BufWriteTimeoutMax) {
                printk("Typical full buffer write timeout: %d Âµs\n", 1<<cfip->BufWriteTimeoutTyp);
                printk("Maximum full buffer write timeout: %d Âµs\n", (1<<cfip->BufWriteTimeoutMax) * (1<<cfip->BufWriteTimeoutTyp));
        }
        else
                printk("Full buffer write not supported\n");
-       
+
        printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp);
        printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp));
        if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) {
-               printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); 
+               printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp);
                printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp));
        }
        else
                printk("Chip erase not supported\n");
-       
+
        printk("Device size: 0x%X bytes (%d MiB)\n", 1 << cfip->DevSize, 1<< (cfip->DevSize - 20));
        printk("Flash Device Interface description: 0x%4.4X\n", cfip->InterfaceDesc);
        switch(cfip->InterfaceDesc) {
        case 0:
                printk("  - x8-only asynchronous interface\n");
                break;
-               
+
        case 1:
                printk("  - x16-only asynchronous interface\n");
                break;
-               
+
        case 2:
                printk("  - supports x8 and x16 via BYTE# with asynchronous interface\n");
                break;
-               
+
        case 3:
                printk("  - x32-only asynchronous interface\n");
                break;
-               
+
        case 4:
                printk("  - supports x16 and x32 via Word# with asynchronous interface\n");
                break;
-               
+
        case 65535:
                printk("  - Not Allowed / Reserved\n");
                break;
-               
+
        default:
                printk("  - Unknown\n");
                break;
        }
-       
+
        printk("Max. bytes in buffer write: 0x%x\n", 1<< cfip->MaxBufWriteSize);
        printk("Number of Erase Block Regions: %d\n", cfip->NumEraseRegions);
-       
+
 }
 #endif /* DEBUG_CFI */
 
index 2b2ede2bfccaeca3f9e0e47f2869d501b1633abf..d8e7a026ba5ae945a83da21485f4a34dac71ef2d 100644 (file)
@@ -7,7 +7,7 @@
  *
  * This code is covered by the GPL.
  *
- * $Id: cfi_util.c,v 1.8 2004/12/14 19:55:56 nico Exp $
+ * $Id: cfi_util.c,v 1.10 2005/11/07 11:14:23 gleixner Exp $
  *
  */
 
@@ -56,7 +56,7 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n
 
        /* Read in the Extended Query Table */
        for (i=0; i<size; i++) {
-               ((unsigned char *)extp)[i] = 
+               ((unsigned char *)extp)[i] =
                        cfi_read_query(map, base+((adr+i)*ofs_factor));
        }
 
@@ -70,15 +70,6 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n
        local_irq_enable();
 #endif
 
-       if (extp->MajorVersion != '1' || 
-           (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
-               printk(KERN_WARNING "  Unknown %s Extended Query "
-                      "version %c.%c.\n",  name, extp->MajorVersion,
-                      extp->MinorVersion);
-               kfree(extp);
-               extp = NULL;
-       }
-
  out:  return extp;
 }
 
@@ -122,17 +113,17 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
 
        i = 0;
 
-       /* Skip all erase regions which are ended before the start of 
+       /* Skip all erase regions which are ended before the start of
           the requested erase. Actually, to save on the calculations,
           we skip to the first erase region which starts after the
           start of the requested erase, and then go back one.
        */
-       
+
        while (i < mtd->numeraseregions && ofs >= regions[i].offset)
               i++;
        i--;
 
-       /* OK, now i is pointing at the erase region in which this 
+       /* OK, now i is pointing at the erase region in which this
           erase request starts. Check the start of the requested
           erase range is aligned with the erase size which is in
           effect here.
@@ -155,7 +146,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
           the address actually falls
        */
        i--;
-       
+
        if ((ofs + len) & (regions[i].erasesize-1))
                return -EINVAL;
 
@@ -168,7 +159,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
                int size = regions[i].erasesize;
 
                ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
-               
+
                if (ret)
                        return ret;
 
@@ -182,7 +173,7 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
                if (adr >> cfi->chipshift) {
                        adr = 0;
                        chipnum++;
-                       
+
                        if (chipnum >= cfi->numchips)
                        break;
                }
index d7d739a108ae5367788f6825b93925f4034e07f4..c2127840a183007b57976d9a611ab96789656c36 100644 (file)
@@ -41,7 +41,7 @@ static struct mtd_chip_driver *get_mtd_chip_driver (const char *name)
 
        list_for_each(pos, &chip_drvs_list) {
                this = list_entry(pos, typeof(*this), list);
-               
+
                if (!strcmp(this->name, name)) {
                        ret = this;
                        break;
@@ -73,7 +73,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map)
 
        ret = drv->probe(map);
 
-       /* We decrease the use count here. It may have been a 
+       /* We decrease the use count here. It may have been a
           probe-only module, which is no longer required from this
           point, having given us a handle on (and increased the use
           count of) the actual driver code.
@@ -82,7 +82,7 @@ struct mtd_info *do_map_probe(const char *name, struct map_info *map)
 
        if (ret)
                return ret;
-       
+
        return NULL;
 }
 /*
index e1a5b76596c577a2b2325071cc8988755772449e..77303ce5dcf1699d3097a76a25935d884f515fb3 100644 (file)
@@ -25,7 +25,7 @@ struct fwh_xxlock_thunk {
  * so this code has not been tested with interleaved chips,
  * and will likely fail in that context.
  */
-static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, 
+static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
        unsigned long adr, int len, void *thunk)
 {
        struct cfi_private *cfi = map->fldrv_priv;
@@ -44,7 +44,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
         * - on 64k boundariesand
         * - bit 1 set high
         * - block lock registers are 4MiB lower - overflow subtract (danger)
-        * 
+        *
         * The address manipulation is first done on the logical address
         * which is 0 at the start of the chip, and then the offset of
         * the individual chip is addted to it.  Any other order a weird
@@ -93,7 +93,7 @@ static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
 
        ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
                (void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK);
-       
+
        return ret;
 }
 
index dc065b22f79ece4ee37440038c965766cfcaa8d4..41bd59d20d85f38229e1b9056e9e87d4598474c2 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.22 2005/01/24 23:49:50 rmk Exp $
+ * $Id: gen_probe.c,v 1.24 2005/11/07 11:14:23 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -26,7 +26,7 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
 
        /* First probe the map to see if we have CFI stuff there. */
        cfi = genprobe_ident_chips(map, cp);
-       
+
        if (!cfi)
                return NULL;
 
@@ -36,12 +36,12 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
        mtd = check_cmd_set(map, 1); /* First the primary cmdset */
        if (!mtd)
                mtd = check_cmd_set(map, 0); /* Then the secondary */
-       
+
        if (mtd)
                return mtd;
 
        printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n");
-       
+
        kfree(cfi->cfiq);
        kfree(cfi);
        map->fldrv_priv = NULL;
@@ -60,14 +60,14 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
 
        memset(&cfi, 0, sizeof(cfi));
 
-       /* Call the probetype-specific code with all permutations of 
+       /* Call the probetype-specific code with all permutations of
           interleave and device type, etc. */
        if (!genprobe_new_chip(map, cp, &cfi)) {
                /* The probe didn't like it */
                printk(KERN_DEBUG "%s: Found no %s device at location zero\n",
                       cp->name, map->name);
                return NULL;
-       }               
+       }
 
 #if 0 /* Let the CFI probe routine do this sanity check. The Intel and AMD
         probe routines won't ever return a broken CFI structure anyway,
@@ -92,13 +92,13 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
        } else {
                BUG();
        }
-               
+
        cfi.numchips = 1;
 
-       /* 
-        * Allocate memory for bitmap of valid chips. 
-        * Align bitmap storage size to full byte. 
-        */ 
+       /*
+        * Allocate memory for bitmap of valid chips.
+        * Align bitmap storage size to full byte.
+        */
        max_chips = map->size >> cfi.chipshift;
        mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
        chip_map = kmalloc(mapsize, GFP_KERNEL);
@@ -122,7 +122,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
        }
 
        /*
-        * Now allocate the space for the structures we need to return to 
+        * Now allocate the space for the structures we need to return to
         * our caller, and copy the appropriate data into them.
         */
 
@@ -154,7 +154,7 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
        return retcfi;
 }
 
-       
+
 static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
                             struct cfi_private *cfi)
 {
@@ -189,7 +189,7 @@ extern cfi_cmdset_fn_t cfi_cmdset_0001;
 extern cfi_cmdset_fn_t cfi_cmdset_0002;
 extern cfi_cmdset_fn_t cfi_cmdset_0020;
 
-static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, 
+static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
                                                  int primary)
 {
        struct cfi_private *cfi = map->fldrv_priv;
@@ -199,7 +199,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
        cfi_cmdset_fn_t *probe_function;
 
        sprintf(probename, "cfi_cmdset_%4.4X", type);
-               
+
        probe_function = inter_module_get_request(probename, probename);
 
        if (probe_function) {
@@ -221,7 +221,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID;
-       
+
        if (type == P_ID_NONE || type == P_ID_RESERVED)
                return NULL;
 
@@ -235,6 +235,7 @@ static struct mtd_info *check_cmd_set(struct map_info *map, int primary)
 #ifdef CONFIG_MTD_CFI_INTELEXT
        case 0x0001:
        case 0x0003:
+       case 0x0200:
                return cfi_cmdset_0001(map, primary);
 #endif
 #ifdef CONFIG_MTD_CFI_AMDSTD
index 4f6778f3ee3e2a9d9714389805a56b6311111e3c..c40b48dabed362c00a5bc2c001a75d2131a6b05c 100644 (file)
@@ -1,6 +1,6 @@
 
 /* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is 
+ * This is an older type of interface for self programming flash. It is
  * commonly use in older AMD chips and is obsolete compared with CFI.
  * It is called JEDEC because the JEDEC association distributes the ID codes
  * for the chips.
@@ -88,9 +88,9 @@ static const struct JEDECTable JEDEC_table[] = {
 
 static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id);
 static void jedec_sync(struct mtd_info *mtd) {};
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, 
+static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
                      size_t *retlen, u_char *buf);
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, 
+static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
                             size_t *retlen, u_char *buf);
 
 static struct mtd_info *jedec_probe(struct map_info *map);
@@ -122,7 +122,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
 
    memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private));
    priv = (struct jedec_private *)&MTD[1];
-   
+
    my_bank_size = map->size;
 
    if (map->size/my_bank_size > MAX_JEDEC_CHIPS)
@@ -131,13 +131,13 @@ static struct mtd_info *jedec_probe(struct map_info *map)
       kfree(MTD);
       return NULL;
    }
-   
+
    for (Base = 0; Base < map->size; Base += my_bank_size)
    {
       // Perhaps zero could designate all tests?
       if (map->buswidth == 0)
         map->buswidth = 1;
-      
+
       if (map->buswidth == 1){
         if (jedec_probe8(map,Base,priv) == 0) {
                 printk("did recognize jedec chip\n");
@@ -150,7 +150,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
       if (map->buswidth == 4)
         jedec_probe32(map,Base,priv);
    }
-   
+
    // Get the biggest sector size
    SectorSize = 0;
    for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
@@ -160,7 +160,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
       if (priv->chips[I].sectorsize > SectorSize)
         SectorSize = priv->chips[I].sectorsize;
    }
-   
+
    // Quickly ensure that the other sector sizes are factors of the largest
    for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
    {
@@ -169,9 +169,9 @@ static struct mtd_info *jedec_probe(struct map_info *map)
         printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
         kfree(MTD);
         return NULL;
-      }      
+      }
    }
-   
+
    /* Generate a part name that includes the number of different chips and
       other configuration information */
    count = 1;
@@ -181,13 +181,13 @@ static struct mtd_info *jedec_probe(struct map_info *map)
    for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
    {
       const struct JEDECTable *JEDEC;
-      
+
       if (priv->chips[I+1].jedec == priv->chips[I].jedec)
       {
         count++;
         continue;
       }
-      
+
       // Locate the chip in the jedec table
       JEDEC = jedec_idtoinf(priv->chips[I].jedec >> 8,priv->chips[I].jedec);
       if (JEDEC == 0)
@@ -196,11 +196,11 @@ static struct mtd_info *jedec_probe(struct map_info *map)
         kfree(MTD);
         return NULL;
       }
-      
+
       if (Uniq != 0)
         strcat(Part,",");
       Uniq++;
-      
+
       if (count != 1)
         sprintf(Part+strlen(Part),"%x*[%s]",count,JEDEC->name);
       else
@@ -208,7 +208,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
       if (strlen(Part) > sizeof(Part)*2/3)
         break;
       count = 1;
-   }   
+   }
 
    /* Determine if the chips are organized in a linear fashion, or if there
       are empty banks. Note, the last bank does not count here, only the
@@ -233,7 +233,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
                   {
                      if (priv->bank_fill[I] != my_bank_size)
                         priv->is_banked = 1;
-                     
+
                      /* This even could be eliminated, but new de-optimized read/write
                         functions have to be written */
                      printk("priv->bank_fill[%d] is %lx, priv->bank_fill[0] is %lx\n",I,priv->bank_fill[I],priv->bank_fill[0]);
@@ -242,7 +242,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
                         printk("mtd: Failed. Cannot handle unsymmetric banking\n");
                         kfree(MTD);
                         return NULL;
-                     }      
+                     }
                   }
           }
    }
@@ -250,7 +250,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
       strcat(Part,", banked");
 
    //   printk("Part: '%s'\n",Part);
-   
+
    memset(MTD,0,sizeof(*MTD));
   // strlcpy(MTD->name,Part,sizeof(MTD->name));
    MTD->name = map->name;
@@ -291,7 +291,7 @@ static int checkparity(u_char C)
 
 /* Take an array of JEDEC numbers that represent interleved flash chips
    and process them. Check to make sure they are good JEDEC numbers, look
-   them up and then add them to the chip list */   
+   them up and then add them to the chip list */
 static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
                  unsigned long base,struct jedec_private *priv)
 {
@@ -306,16 +306,16 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
       if (checkparity(Mfg[I]) == 0 || checkparity(Id[I]) == 0)
         return 0;
    }
-   
+
    // Finally, just make sure all the chip sizes are the same
    JEDEC = jedec_idtoinf(Mfg[0],Id[0]);
-   
+
    if (JEDEC == 0)
    {
       printk("mtd: Found JEDEC flash chip, but do not have a table entry for %x:%x\n",Mfg[0],Mfg[1]);
       return 0;
    }
-   
+
    Size = JEDEC->size;
    SectorSize = JEDEC->sectorsize;
    for (I = 0; I != Count; I++)
@@ -331,7 +331,7 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
       {
         printk("mtd: Failed. Interleved flash does not have matching characteristics\n");
         return 0;
-      }      
+      }
    }
 
    // Load the Chips
@@ -345,13 +345,13 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
    {
       printk("mtd: Device has too many chips. Increase MAX_JEDEC_CHIPS\n");
       return 0;
-   }      
-   
+   }
+
    // Add them to the table
    for (J = 0; J != Count; J++)
    {
       unsigned long Bank;
-        
+
       JEDEC = jedec_idtoinf(Mfg[J],Id[J]);
       priv->chips[I].jedec = (Mfg[J] << 8) | Id[J];
       priv->chips[I].size = JEDEC->size;
@@ -364,17 +364,17 @@ static int handle_jedecs(struct map_info *map,__u8 *Mfg,__u8 *Id,unsigned Count,
       // log2 n :|
       priv->chips[I].addrshift = 0;
       for (Bank = Count; Bank != 1; Bank >>= 1, priv->chips[I].addrshift++);
-      
+
       // Determine how filled this bank is.
       Bank = base & (~(my_bank_size-1));
-      if (priv->bank_fill[Bank/my_bank_size] < base + 
+      if (priv->bank_fill[Bank/my_bank_size] < base +
          (JEDEC->size << priv->chips[I].addrshift) - Bank)
         priv->bank_fill[Bank/my_bank_size] =  base + (JEDEC->size << priv->chips[I].addrshift) - Bank;
       I++;
    }
 
    priv->size += priv->chips[I-1].size*Count;
-        
+
    return priv->chips[I-1].size;
 }
 
@@ -392,7 +392,7 @@ static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id)
 // Look for flash using an 8 bit bus interface
 static int jedec_probe8(struct map_info *map,unsigned long base,
                  struct jedec_private *priv)
-{ 
+{
    #define flread(x) map_read8(map,base+x)
    #define flwrite(v,x) map_write8(map,v,base+x)
 
@@ -410,20 +410,20 @@ static int jedec_probe8(struct map_info *map,unsigned long base,
    OldVal = flread(base);
    for (I = 0; OldVal != flread(base) && I < 10000; I++)
       OldVal = flread(base);
-   
+
    // Reset the chip
-   flwrite(Reset,0x555); 
-   
+   flwrite(Reset,0x555);
+
    // Send the sequence
    flwrite(AutoSel1,0x555);
    flwrite(AutoSel2,0x2AA);
    flwrite(AutoSel3,0x555);
-   
+
    //  Get the JEDEC numbers
    Mfg[0] = flread(0);
    Id[0] = flread(1);
    //   printk("Mfg is %x, Id is %x\n",Mfg[0],Id[0]);
-      
+
    Size = handle_jedecs(map,Mfg,Id,1,base,priv);
    //   printk("handle_jedecs Size is %x\n",(unsigned int)Size);
    if (Size == 0)
@@ -431,13 +431,13 @@ static int jedec_probe8(struct map_info *map,unsigned long base,
       flwrite(Reset,0x555);
       return 0;
    }
-   
+
 
    // Reset.
    flwrite(Reset,0x555);
-   
+
    return 1;
-   
+
    #undef flread
    #undef flwrite
 }
@@ -470,17 +470,17 @@ static int jedec_probe32(struct map_info *map,unsigned long base,
    OldVal = flread(base);
    for (I = 0; OldVal != flread(base) && I < 10000; I++)
       OldVal = flread(base);
-   
+
    // Reset the chip
-   flwrite(Reset,0x555); 
-   
+   flwrite(Reset,0x555);
+
    // Send the sequence
    flwrite(AutoSel1,0x555);
    flwrite(AutoSel2,0x2AA);
    flwrite(AutoSel3,0x555);
-   
+
    // Test #1, JEDEC numbers are readable from 0x??00/0x??01
-   if (flread(0) != flread(0x100) || 
+   if (flread(0) != flread(0x100) ||
        flread(1) != flread(0x101))
    {
       flwrite(Reset,0x555);
@@ -494,14 +494,14 @@ static int jedec_probe32(struct map_info *map,unsigned long base,
    OldVal = flread(1);
    for (I = 0; I != 4; I++)
       Id[I] = (OldVal >> (I*8));
-      
+
    Size = handle_jedecs(map,Mfg,Id,4,base,priv);
    if (Size == 0)
    {
       flwrite(Reset,0x555);
       return 0;
    }
-   
+
    /* Check if there is address wrap around within a single bank, if this
       returns JEDEC numbers then we assume that it is wrap around. Notice
       we call this routine with the JEDEC return still enabled, if two or
@@ -519,27 +519,27 @@ static int jedec_probe32(struct map_info *map,unsigned long base,
 
    // Reset.
    flwrite(0xF0F0F0F0,0x555);
-   
+
    return 1;
-   
+
    #undef flread
    #undef flwrite
 }
 
 /* Linear read. */
-static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len, 
+static int jedec_read(struct mtd_info *mtd, loff_t from, size_t len,
                      size_t *retlen, u_char *buf)
 {
    struct map_info *map = mtd->priv;
-   
+
    map_copy_from(map, buf, from, len);
    *retlen = len;
-   return 0;   
+   return 0;
 }
 
 /* Banked read. Take special care to jump past the holes in the bank
    mapping. This version assumes symetry in the holes.. */
-static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len, 
+static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
                             size_t *retlen, u_char *buf)
 {
    struct map_info *map = mtd->priv;
@@ -555,17 +555,17 @@ static int jedec_read_banked(struct mtd_info *mtd, loff_t from, size_t len,
       if (priv->bank_fill[0] - offset < len)
         get = priv->bank_fill[0] - offset;
 
-      bank /= priv->bank_fill[0];      
+      bank /= priv->bank_fill[0];
       map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get);
-      
+
       len -= get;
       *retlen += get;
       from += get;
-   }   
-   return 0;   
+   }
+   return 0;
 }
 
-/* Pass the flags value that the flash return before it re-entered read 
+/* Pass the flags value that the flash return before it re-entered read
    mode. */
 static void jedec_flash_failed(unsigned char code)
 {
@@ -579,17 +579,17 @@ static void jedec_flash_failed(unsigned char code)
    printk("mtd: Programming didn't take\n");
 }
 
-/* This uses the erasure function described in the AMD Flash Handbook, 
+/* This uses the erasure function described in the AMD Flash Handbook,
    it will work for flashes with a fixed sector size only. Flashes with
    a selection of sector sizes (ie the AMD Am29F800B) will need a different
-   routine. This routine tries to parallize erasing multiple chips/sectors 
+   routine. This routine tries to parallize erasing multiple chips/sectors
    where possible */
 static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
    // Does IO to the currently selected chip
    #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift))
    #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift))
-   
+
    unsigned long Time = 0;
    unsigned long NoTime = 0;
    unsigned long start = instr->addr, len = instr->len;
@@ -603,7 +603,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
        (len % mtd->erasesize) != 0 ||
        (len/mtd->erasesize) == 0)
       return -EINVAL;
-   
+
    jedec_flash_chip_scan(priv,start,len);
 
    // Start the erase sequence on each chip
@@ -611,16 +611,16 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
    {
       unsigned long off;
       struct jedec_flash_chip *chip = priv->chips + I;
-      
+
       if (chip->length == 0)
         continue;
-      
+
       if (chip->start + chip->length > chip->size)
       {
         printk("DIE\n");
         return -EIO;
-      }     
-      
+      }
+
       flwrite(0xF0,chip->start + 0x555);
       flwrite(0xAA,chip->start + 0x555);
       flwrite(0x55,chip->start + 0x2AA);
@@ -628,8 +628,8 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
       flwrite(0xAA,chip->start + 0x555);
       flwrite(0x55,chip->start + 0x2AA);
 
-      /* Once we start selecting the erase sectors the delay between each 
-         command must not exceed 50us or it will immediately start erasing 
+      /* Once we start selecting the erase sectors the delay between each
+         command must not exceed 50us or it will immediately start erasing
          and ignore the other sectors */
       for (off = 0; off < len; off += chip->sectorsize)
       {
@@ -641,19 +641,19 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
         {
            printk("mtd: Ack! We timed out the erase timer!\n");
            return -EIO;
-        }               
+        }
       }
-   }   
+   }
 
    /* We could split this into a timer routine and return early, performing
       background erasure.. Maybe later if the need warrents */
 
    /* Poll the flash for erasure completion, specs say this can take as long
-      as 480 seconds to do all the sectors (for a 2 meg flash). 
+      as 480 seconds to do all the sectors (for a 2 meg flash).
       Erasure time is dependent on chip age, temp and wear.. */
-   
+
    /* This being a generic routine assumes a 32 bit bus. It does read32s
-      and bundles interleved chips into the same grouping. This will work 
+      and bundles interleved chips into the same grouping. This will work
       for all bus widths */
    Time = 0;
    NoTime = 0;
@@ -664,20 +664,20 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
       unsigned todo[4] = {0,0,0,0};
       unsigned todo_left = 0;
       unsigned J;
-      
+
       if (chip->length == 0)
         continue;
 
-      /* Find all chips in this data line, realistically this is all 
+      /* Find all chips in this data line, realistically this is all
          or nothing up to the interleve count */
       for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
       {
-        if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) == 
+        if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
             (chip->base & (~((1<<chip->addrshift)-1))))
         {
            todo_left++;
            todo[priv->chips[J].base & ((1<<chip->addrshift)-1)] = 1;
-        }       
+        }
       }
 
       /*      printk("todo: %x %x %x %x\n",(short)todo[0],(short)todo[1],
@@ -687,7 +687,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
       {
         __u32 Last[4];
         unsigned long Count = 0;
-        
+
         /* During erase bit 7 is held low and bit 6 toggles, we watch this,
            should it stop toggling or go high then the erase is completed,
            or this is not really flash ;> */
@@ -718,23 +718,23 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
               __u8 Byte3 = (Last[(Count-3)%4] >> (J*8)) & 0xFF;
               if (todo[J] == 0)
                  continue;
-              
+
               if ((Byte1 & (1 << 7)) == 0 && Byte1 != Byte2)
               {
 //               printk("Check %x %x %x\n",(short)J,(short)Byte1,(short)Byte2);
                  continue;
               }
-              
+
               if (Byte1 == Byte2)
               {
                  jedec_flash_failed(Byte3);
                  return -EIO;
               }
-              
+
               todo[J] = 0;
               todo_left--;
            }
-           
+
 /*         if (NoTime == 0)
               Time += HZ/10 - schedule_timeout(HZ/10);*/
            NoTime = 0;
@@ -751,7 +751,7 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
              break;
            }
            Count++;
-           
+
 /*         // Count time, max of 15s per sector (according to AMD)
            if (Time > 15*len/mtd->erasesize*HZ)
            {
@@ -759,38 +759,38 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr)
               return -EIO;
            }       */
         }
-                
+
         // Skip to the next chip if we used chip erase
         if (chip->length == chip->size)
            off = chip->size;
         else
            off += chip->sectorsize;
-        
+
         if (off >= chip->length)
            break;
         NoTime = 1;
       }
-      
+
       for (J = 0; priv->chips[J].jedec != 0 && J < MAX_JEDEC_CHIPS; J++)
       {
         if ((priv->chips[J].base & (~((1<<chip->addrshift)-1))) ==
             (chip->base & (~((1<<chip->addrshift)-1))))
            priv->chips[J].length = 0;
-      }      
+      }
    }
-                   
+
    //printk("done\n");
    instr->state = MTD_ERASE_DONE;
    mtd_erase_callback(instr);
    return 0;
-   
+
    #undef flread
    #undef flwrite
 }
 
 /* This is the simple flash writing function. It writes to every byte, in
    sequence. It takes care of how to properly address the flash if
-   the flash is interleved. It can only be used if all the chips in the 
+   the flash is interleved. It can only be used if all the chips in the
    array are identical!*/
 static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
                       size_t *retlen, const u_char *buf)
@@ -800,25 +800,25 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
       of addrshift (interleave index) and then adds the control register index. */
    #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
    #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift))
-   
+
    struct map_info *map = mtd->priv;
    struct jedec_private *priv = map->fldrv_priv;
    unsigned long base;
    unsigned long off;
    size_t save_len = len;
-   
+
    if (start + len > mtd->size)
       return -EIO;
-   
+
    //printk("Here");
-   
+
    //printk("flash_write: start is %x, len is %x\n",start,(unsigned long)len);
    while (len != 0)
    {
       struct jedec_flash_chip *chip = priv->chips;
       unsigned long bank;
       unsigned long boffset;
-        
+
       // Compute the base of the flash.
       off = ((unsigned long)start) % (chip->size << chip->addrshift);
       base = start - off;
@@ -828,10 +828,10 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
       boffset = base & (priv->bank_fill[0]-1);
       bank = (bank/priv->bank_fill[0])*my_bank_size;
       base = bank + boffset;
-      
+
     //  printk("Flasing %X %X %X\n",base,chip->size,len);
      // printk("off is %x, compare with %x\n",off,chip->size << chip->addrshift);
-      
+
       // Loop over this page
       for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++)
       {
@@ -845,7 +845,7 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
         }
         if (((~oldbyte) & *buf) != 0)
            printk("mtd: warn: Trying to set a 0 to a 1\n");
-            
+
         // Write
         flwrite(0xAA,0x555);
         flwrite(0x55,0x2AA);
@@ -854,10 +854,10 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
         Last[0] = map_read8(map,base + off);
         Last[1] = map_read8(map,base + off);
         Last[2] = map_read8(map,base + off);
-        
+
         /* Wait for the flash to finish the operation. We store the last 4
            status bytes that have been retrieved so we can determine why
-           it failed. The toggle bits keep toggling when there is a 
+           it failed. The toggle bits keep toggling when there is a
            failure */
         for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] &&
              Count < 10000; Count++)
@@ -866,7 +866,7 @@ static int flash_write(struct mtd_info *mtd, loff_t start, size_t len,
         {
            jedec_flash_failed(Last[(Count - 3) % 4]);
            return -EIO;
-        }       
+        }
       }
    }
    *retlen = save_len;
@@ -885,24 +885,24 @@ static void jedec_flash_chip_scan(struct jedec_private *priv,unsigned long start
    // Zero the records
    for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
       priv->chips[I].start = priv->chips[I].length = 0;
-   
+
    // Intersect the region with each chip
    for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++)
    {
       struct jedec_flash_chip *chip = priv->chips + I;
       unsigned long ByteStart;
       unsigned long ChipEndByte = chip->offset + (chip->size << chip->addrshift);
-      
+
       // End is before this chip or the start is after it
       if (start+len < chip->offset ||
          ChipEndByte - (1 << chip->addrshift) < start)
         continue;
-      
+
       if (start < chip->offset)
       {
         ByteStart = chip->offset;
         chip->start = 0;
-      }      
+      }
       else
       {
         chip->start = (start - chip->offset + (1 << chip->addrshift)-1) >> chip->addrshift;
index 30da428eb7b99e0c9a265928d8d4303654a21264..edb306c03c0a14b8f1e9b0f50382f05a08e5d4d2 100644 (file)
@@ -1,7 +1,7 @@
-/* 
+/*
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $
+   $Id: jedec_probe.c,v 1.66 2005/11/07 11:14:23 gleixner Exp $
    See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
    for the standard this probe goes back to.
 
@@ -1719,7 +1719,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
 
 static struct mtd_info *jedec_probe(struct map_info *map);
 
-static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, 
+static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
        struct cfi_private *cfi)
 {
        map_word result;
@@ -1730,7 +1730,7 @@ static inline u32 jedec_read_mfr(struct map_info *map, __u32 base,
        return result.x[0] & mask;
 }
 
-static inline u32 jedec_read_id(struct map_info *map, __u32 base, 
+static inline u32 jedec_read_id(struct map_info *map, __u32 base,
        struct cfi_private *cfi)
 {
        map_word result;
@@ -1741,7 +1741,7 @@ static inline u32 jedec_read_id(struct map_info *map, __u32 base,
        return result.x[0] & mask;
 }
 
-static inline void jedec_reset(u32 base, struct map_info *map, 
+static inline void jedec_reset(u32 base, struct map_info *map,
        struct cfi_private *cfi)
 {
        /* Reset */
@@ -1765,7 +1765,7 @@ static inline void jedec_reset(u32 base, struct map_info *map,
         * so ensure we're in read mode.  Send both the Intel and the AMD command
         * for this.  Intel uses 0xff for this, AMD uses 0xff for NOP, so
         * this should be safe.
-        */ 
+        */
        cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
        /* FIXME - should have reset delay before continuing */
 }
@@ -1807,14 +1807,14 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
        printk("Found: %s\n",jedec_table[index].name);
 
        num_erase_regions = jedec_table[index].NumEraseRegions;
-       
+
        p_cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
        if (!p_cfi->cfiq) {
                //xx printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
                return 0;
        }
 
-       memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); 
+       memset(p_cfi->cfiq,0,sizeof(struct cfi_ident));
 
        p_cfi->cfiq->P_ID = jedec_table[index].CmdSet;
        p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions;
@@ -1969,7 +1969,7 @@ static inline int jedec_match( __u32 base,
        cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
        /* FIXME - should have a delay before continuing */
 
- match_done:   
+ match_done:
        return rc;
 }
 
@@ -1998,23 +1998,23 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                        "Probe at base(0x%08x) past the end of the map(0x%08lx)\n",
                        base, map->size -1);
                return 0;
-               
+
        }
        /* Ensure the unlock addresses we try stay inside the map */
        probe_offset1 = cfi_build_cmd_addr(
-               cfi->addr_unlock1, 
-               cfi_interleave(cfi), 
+               cfi->addr_unlock1,
+               cfi_interleave(cfi),
                cfi->device_type);
        probe_offset2 = cfi_build_cmd_addr(
-               cfi->addr_unlock1, 
-               cfi_interleave(cfi), 
+               cfi->addr_unlock1,
+               cfi_interleave(cfi),
                cfi->device_type);
        if (    ((base + probe_offset1 + map_bankwidth(map)) >= map->size) ||
                ((base + probe_offset2 + map_bankwidth(map)) >= map->size))
        {
                goto retry;
        }
-               
+
        /* Reset */
        jedec_reset(base, map, cfi);
 
@@ -2027,13 +2027,13 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
        /* FIXME - should have a delay before continuing */
 
        if (!cfi->numchips) {
-               /* This is the first time we're called. Set up the CFI 
+               /* This is the first time we're called. Set up the CFI
                   stuff accordingly and return */
-               
+
                cfi->mfr = jedec_read_mfr(map, base, cfi);
                cfi->id = jedec_read_id(map, base, cfi);
                DEBUG(MTD_DEBUG_LEVEL3,
-                     "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
+                     "Search for id:(%02x %02x) interleave(%d) type(%d)\n",
                        cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type);
                for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
                        if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
@@ -2062,7 +2062,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                        return 0;
                }
        }
-       
+
        /* Check each previous chip locations to see if it's an alias */
        for (i=0; i < (base >> cfi->chipshift); i++) {
                unsigned long start;
@@ -2083,7 +2083,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                                       map->name, base, start);
                                return 0;
                        }
-                       
+
                        /* Yes, it's actually got the device IDs as data. Most
                         * unfortunate. Stick the new chip in read mode
                         * too and if it's the same, assume it's an alias. */
@@ -2097,20 +2097,20 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                        }
                }
        }
-               
+
        /* OK, if we got to here, then none of the previous chips appear to
           be aliases for the current one. */
        set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
        cfi->numchips++;
-               
+
 ok_out:
        /* Put it back into Read Mode */
        jedec_reset(base, map, cfi);
 
        printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
-              map->name, cfi_interleave(cfi), cfi->device_type*8, base, 
+              map->name, cfi_interleave(cfi), cfi->device_type*8, base,
               map->bankwidth*8);
-       
+
        return 1;
 }
 
index c6c83833cc32311ccb14fda47cbf685480f05a20..a611de9b15159349116d78d28fdb2968b29f2c62 100644 (file)
@@ -1,11 +1,11 @@
 /*
  * Common code to handle absent "placeholder" devices
  * Copyright 2001 Resilience Corporation <ebrower@resilience.com>
- * $Id: map_absent.c,v 1.5 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: map_absent.c,v 1.6 2005/11/07 11:14:23 gleixner Exp $
  *
  * This map driver is used to allocate "placeholder" MTD
- * devices on systems that have socketed/removable media. 
- * Use of this driver as a fallback preserves the expected 
+ * devices on systems that have socketed/removable media.
+ * Use of this driver as a fallback preserves the expected
  * registration of MTD device nodes regardless of probe outcome.
  * A usage example is as follows:
  *
@@ -80,7 +80,7 @@ static int map_absent_read(struct mtd_info *mtd, loff_t from, size_t len, size_t
 static int map_absent_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
 {
        *retlen = 0;
-       return -ENODEV; 
+       return -ENODEV;
 }
 
 static int map_absent_erase(struct mtd_info *mtd, struct erase_info *instr)
index c3cf0f63bc93639ad151a35b8867e554452548a7..2d26bdef82d5c9fe4fe64ad4406719edcb5b12c0 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
  *           2000,2001 Lineo, Inc.
  *
- * $Id: sharp.c,v 1.14 2004/08/09 13:19:43 dwmw2 Exp $
+ * $Id: sharp.c,v 1.16 2005/11/07 11:14:23 gleixner Exp $
  *
  * Devices supported:
  *   LH28F016SCT Symmetrical block flash memory, 2Mx8
@@ -31,6 +31,7 @@
 #include <linux/mtd/cfi.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 
 #define CMD_RESET              0xffffffff
 #define CMD_READ_ID            0x90909090
@@ -214,7 +215,7 @@ static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd)
 /* This function returns with the chip->mutex lock held. */
 static int sharp_wait(struct map_info *map, struct flchip *chip)
 {
-       __u16 status;
+       int status, i;
        unsigned long timeo = jiffies + HZ;
        DECLARE_WAITQUEUE(wait, current);
        int adr = 0;
@@ -227,13 +228,11 @@ retry:
                map_write32(map,CMD_READ_STATUS,adr);
                chip->state = FL_STATUS;
        case FL_STATUS:
-               status = map_read32(map,adr);
-//printk("status=%08x\n",status);
-
-               udelay(100);
-               if((status & SR_READY)!=SR_READY){
-//printk(".status=%08x\n",status);
-                       udelay(100);
+               for(i=0;i<100;i++){
+                       status = map_read32(map,adr);
+                       if((status & SR_READY)==SR_READY)
+                               break;
+                       udelay(1);
                }
                break;
        default:
@@ -460,12 +459,12 @@ static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
                remove_wait_queue(&chip->wq, &wait);
 
                //spin_lock_bh(chip->mutex);
-               
+
                if (signal_pending(current)){
                        ret = -EINTR;
                        goto out;
                }
-               
+
        }
        ret = -ETIME;
 out:
@@ -564,7 +563,7 @@ static int sharp_suspend(struct mtd_info *mtd)
 static void sharp_resume(struct mtd_info *mtd)
 {
        printk("sharp_resume()\n");
-       
+
 }
 
 static void sharp_destroy(struct mtd_info *mtd)
index ef24837019d3e4e8f4961035a62d1198beb039fb..6b8bb2e4dcfde7ca5dbf8cb6bd1f4abc13c78c6f 100644 (file)
@@ -1,24 +1,24 @@
 /*
- * $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $
+ * $Id: cmdlinepart.c,v 1.19 2005/11/07 11:14:19 gleixner Exp $
  *
  * Read flash partition table from command line
  *
  * Copyright 2002 SYSGO Real-Time Solutions GmbH
  *
  * The format for the command line is as follows:
- * 
+ *
  * mtdparts=<mtddef>[;<mtddef]
  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
  * <partdef> := <size>[@offset][<name>][ro]
  * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
  * <size>    := standard linux memsize OR "-" to denote all remaining space
  * <name>    := '(' NAME ')'
- * 
+ *
  * Examples:
- * 
+ *
  * 1 NOR Flash, with 1 single writable partition:
  * edb7312-nor:-
- * 
+ *
  * 1 NOR Flash with 2 partitions, 1 NAND with one
  * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
  */
@@ -60,17 +60,17 @@ static int cmdline_parsed = 0;
 
 /*
  * Parse one partition definition for an MTD. Since there can be many
- * comma separated partition definitions, this function calls itself 
+ * comma separated partition definitions, this function calls itself
  * recursively until no more partition definitions are found. Nice side
  * effect: the memory to keep the mtd_partition structs and the names
  * is allocated upon the last definition being found. At that point the
  * syntax has been verified ok.
  */
-static struct mtd_partition * newpart(char *s, 
+static struct mtd_partition * newpart(char *s,
                                       char **retptr,
                                       int *num_parts,
-                                      int this_part, 
-                                      unsigned char **extra_mem_ptr, 
+                                      int this_part,
+                                      unsigned char **extra_mem_ptr,
                                       int extra_mem_size)
 {
        struct mtd_partition *parts;
@@ -102,7 +102,7 @@ static struct mtd_partition * newpart(char *s,
        mask_flags = 0; /* this is going to be a regular partition */
        delim = 0;
         /* check for offset */
-        if (*s == '@') 
+        if (*s == '@')
        {
                 s++;
                 offset = memparse(s, &s);
@@ -112,7 +112,7 @@ static struct mtd_partition * newpart(char *s,
        {
                delim = ')';
        }
-               
+
        if (delim)
        {
                char *p;
@@ -131,12 +131,12 @@ static struct mtd_partition * newpart(char *s,
                name = NULL;
                name_len = 13; /* Partition_000 */
        }
-   
+
        /* record name length for memory allocation later */
        extra_mem_size += name_len + 1;
 
         /* test for options */
-        if (strncmp(s, "ro", 2) == 0) 
+        if (strncmp(s, "ro", 2) == 0)
        {
                mask_flags |= MTD_WRITEABLE;
                s += 2;
@@ -151,7 +151,7 @@ static struct mtd_partition * newpart(char *s,
                        return NULL;
                }
                /* more partitions follow, parse them */
-               if ((parts = newpart(s + 1, &s, num_parts, 
+               if ((parts = newpart(s + 1, &s, num_parts,
                                     this_part + 1, &extra_mem, extra_mem_size)) == 0)
                  return NULL;
        }
@@ -187,7 +187,7 @@ static struct mtd_partition * newpart(char *s,
        extra_mem += name_len + 1;
 
        dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
-            this_part, 
+            this_part,
             parts[this_part].name,
             parts[this_part].offset,
             parts[this_part].size,
@@ -204,8 +204,8 @@ static struct mtd_partition * newpart(char *s,
        return parts;
 }
 
-/* 
- * Parse the command line. 
+/*
+ * Parse the command line.
  */
 static int mtdpart_setup_real(char *s)
 {
@@ -230,7 +230,7 @@ static int mtdpart_setup_real(char *s)
 
                dbg(("parsing <%s>\n", p+1));
 
-               /* 
+               /*
                 * parse one mtd. have it reserve memory for the
                 * struct cmdline_mtd_partition and the mtd-id string.
                 */
@@ -239,7 +239,7 @@ static int mtdpart_setup_real(char *s)
                                &num_parts,     /* out: number of parts */
                                0,              /* first partition */
                                (unsigned char**)&this_mtd, /* out: extra mem */
-                               mtd_id_len + 1 + sizeof(*this_mtd) + 
+                               mtd_id_len + 1 + sizeof(*this_mtd) +
                                sizeof(void*)-1 /*alignment*/);
                if(!parts)
                {
@@ -254,21 +254,21 @@ static int mtdpart_setup_real(char *s)
                 }
 
                /* align this_mtd */
-               this_mtd = (struct cmdline_mtd_partition *) 
+               this_mtd = (struct cmdline_mtd_partition *)
                        ALIGN((unsigned long)this_mtd, sizeof(void*));
-               /* enter results */         
+               /* enter results */
                this_mtd->parts = parts;
                this_mtd->num_parts = num_parts;
                this_mtd->mtd_id = (char*)(this_mtd + 1);
                strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
 
                /* link into chain */
-               this_mtd->next = partitions;            
+               this_mtd->next = partitions;
                partitions = this_mtd;
 
-               dbg(("mtdid=<%s> num_parts=<%d>\n", 
+               dbg(("mtdid=<%s> num_parts=<%d>\n",
                     this_mtd->mtd_id, this_mtd->num_parts));
-               
+
 
                /* EOS - we're done */
                if (*s == 0)
@@ -292,7 +292,7 @@ static int mtdpart_setup_real(char *s)
  * information. It returns partitions for the requested mtd device, or
  * the first one in the chain if a NULL mtd_id is passed in.
  */
-static int parse_cmdline_partitions(struct mtd_info *master, 
+static int parse_cmdline_partitions(struct mtd_info *master,
                              struct mtd_partition **pparts,
                              unsigned long origin)
 {
@@ -322,7 +322,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
                                  part->parts[i].size = master->size - offset;
                                if (offset + part->parts[i].size > master->size)
                                {
-                                       printk(KERN_WARNING ERRP 
+                                       printk(KERN_WARNING ERRP
                                               "%s: partitioning exceeds flash size, truncating\n",
                                               part->mtd_id);
                                        part->parts[i].size = master->size - offset;
@@ -338,8 +338,8 @@ static int parse_cmdline_partitions(struct mtd_info *master,
 }
 
 
-/* 
- * This is the handler for our kernel parameter, called from 
+/*
+ * This is the handler for our kernel parameter, called from
  * main.c::checksetup(). Note that we can not yet kmalloc() anything,
  * so we only save the commandline for later processing.
  *
index c4a56a4ac5e20dfe1df3960ea800d851ff1333c6..9a2aa4033c6a6e37ea60ade60a4f67c70613ccc5 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.15 2004/12/22 17:51:15 joern Exp $
+# $Id: Kconfig,v 1.18 2005/11/07 11:14:24 gleixner Exp $
 
 menu "Self-contained MTD device drivers"
        depends on MTD!=n
@@ -110,7 +110,7 @@ config MTDRAM_ABS_POS
          If you have system RAM accessible by the CPU but not used by Linux
          in normal operation, you can give the physical address at which the
          available RAM starts, and the MTDRAM driver will use it instead of
-         allocating space from Linux's available memory. Otherwise, leave 
+         allocating space from Linux's available memory. Otherwise, leave
          this set to zero. Most people will want to leave this as zero.
 
 config MTD_BLKMTD
@@ -165,7 +165,7 @@ config MTD_DOC2001
        select MTD_DOCPROBE
        select MTD_NAND_IDS
        ---help---
-         This provides an alternative MTD device driver for the M-Systems 
+         This provides an alternative MTD device driver for the M-Systems
          DiskOnChip Millennium devices.  Use this if you have problems with
          the combined DiskOnChip 2000 and Millennium driver above.  To get
          the DiskOnChip probe code to load and use this driver instead of
@@ -192,7 +192,7 @@ config MTD_DOC2001PLUS
 
          If you use this device, you probably also want to enable the INFTL
          'Inverse NAND Flash Translation Layer' option below, which is used
-         to emulate a block device by using a kind of file system on the 
+         to emulate a block device by using a kind of file system on the
          flash chips.
 
          NOTE: This driver will soon be replaced by the new DiskOnChip driver
index 59a29e616a226f82112851ef76ae8a57ca1db012..f9db52f6bf00f40156ece013ffd6f37e60769aee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: blkmtd.c,v 1.24 2004/11/16 18:29:01 dwmw2 Exp $
+ * $Id: blkmtd.c,v 1.27 2005/11/07 11:14:24 gleixner Exp $
  *
  * blkmtd.c - use a block device as a fake MTD
  *
@@ -39,7 +39,7 @@
 
 /* Default erase size in K, always make it a multiple of PAGE_SIZE */
 #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)        /* 128KiB */
-#define VERSION "$Revision: 1.24 $"
+#define VERSION "$Revision: 1.27 $"
 
 /* Info for the block device */
 struct blkmtd_dev {
@@ -117,7 +117,7 @@ static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error
                unlock_page(page);
                page_cache_release(page);
        } while (bvec >= bio->bi_io_vec);
-       
+
        complete((struct completion*)bio->bi_private);
        return 0;
 }
@@ -135,7 +135,7 @@ static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page)
                unlock_page(page);
                return 0;
        }
-       
+
        ClearPageUptodate(page);
        ClearPageError(page);
 
@@ -707,7 +707,7 @@ static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size
                     dev->mtd_info.erasesize >> 10,
                     readonly ? "(read-only)" : "");
        }
-       
+
        return dev;
 
  devinit_err:
index 4a7a805e7564c4d359f9049daf1ebc54a284c39b..0aaa0ced9aba0acd7d5105d16a4fe90b4323be73 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $
+ * $Id: block2mtd.c,v 1.29 2005/11/07 11:14:24 gleixner Exp $
  *
  * block2mtd.c - create an mtd from a block device
  *
@@ -19,7 +19,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/buffer_head.h>
 
-#define VERSION "$Revision: 1.28 $"
+#define VERSION "$Revision: 1.29 $"
 
 
 #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
@@ -111,7 +111,7 @@ static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
                        return PTR_ERR(page);
 
                max = (u_long*)page_address(page) + PAGE_SIZE;
-               for (p=(u_long*)page_address(page); p<max; p++) 
+               for (p=(u_long*)page_address(page); p<max; p++)
                        if (*p != -1UL) {
                                lock_page(page);
                                memset(page_address(page), 0xff, PAGE_SIZE);
@@ -206,7 +206,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
        if (retlen)
                *retlen = 0;
        while (len) {
-               if ((offset+len) > PAGE_SIZE) 
+               if ((offset+len) > PAGE_SIZE)
                        cpylen = PAGE_SIZE - offset;    // multiple pages
                else
                        cpylen = len;                   // this page
index 5fc532895a24eb37b7b859ea8e767e8f50812071..be5e88b3888daf727404fa12c5cb22bb77b01b40 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2000.c,v 1.66 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.67 2005/11/07 11:14:24 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -58,7 +58,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
                         size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
-static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, 
+static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
                          unsigned long count, loff_t to, size_t *retlen,
                          u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -76,14 +76,14 @@ static void DoC_Delay(struct DiskOnChip *doc, unsigned short cycles)
 {
        volatile char dummy;
        int i;
-       
+
        for (i = 0; i < cycles; i++) {
                if (DoC_is_Millennium(doc))
                        dummy = ReadDOC(doc->virtadr, NOP);
                else
                        dummy = ReadDOC(doc->virtadr, DOCStatus);
        }
-       
+
 }
 
 /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
@@ -220,8 +220,8 @@ static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
                WriteDOC(ofs & 0xff, docptr, WritePipeTerm);
 
        DoC_Delay(doc, 2);      /* Needed for some slow flash chips. mf. */
-       
-       /* FIXME: The SlowIO's for millennium could be replaced by 
+
+       /* FIXME: The SlowIO's for millennium could be replaced by
           a single WritePipeTerm here. mf. */
 
        /* Lower the ALE line */
@@ -377,9 +377,9 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
        if (mfr == 0xff || mfr == 0)
                return 0;
 
-       /* Check it's the same as the first chip we identified. 
+       /* Check it's the same as the first chip we identified.
         * M-Systems say that any given DiskOnChip device should only
-        * contain _one_ type of flash part, although that's not a 
+        * contain _one_ type of flash part, although that's not a
         * hardware restriction. */
        if (doc->mfr) {
                if (doc->mfr == mfr && doc->id == id)
@@ -397,7 +397,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                        for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
                                if (nand_manuf_ids[j].id == mfr)
                                        break;
-                       }       
+                       }
                        printk(KERN_INFO
                               "Flash chip found: Manufacturer ID: %2.2X, "
                               "Chip ID: %2.2X (%s:%s)\n", mfr, id,
@@ -405,7 +405,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                        if (!doc->mfr) {
                                doc->mfr = mfr;
                                doc->id = id;
-                               doc->chipshift = 
+                               doc->chipshift =
                                        ffs((nand_flash_ids[i].chipsize << 20)) - 1;
                                doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0;
                                doc->pageadrlen = doc->chipshift > 25 ? 3 : 2;
@@ -467,7 +467,7 @@ static void DoC_ScanChips(struct DiskOnChip *this, int maxchips)
 
        ret = 0;
 
-       /* Fill out the chip array with {floor, chipno} for each 
+       /* Fill out the chip array with {floor, chipno} for each
         * detected chip in the device. */
        for (floor = 0; floor < MAX_FLOORS; floor++) {
                for (chip = 0; chip < numchips[floor]; chip++) {
@@ -757,12 +757,12 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                                     (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
                                     eccbuf[3], eccbuf[4], eccbuf[5]);
 #endif
-               
+
                        /* disable the ECC engine */
                        WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
                }
 
-               /* according to 11.4.1, we need to wait for the busy line 
+               /* according to 11.4.1, we need to wait for the busy line
                 * drop if we read to the end of the page.  */
                if(0 == ((from + len) & 0x1ff))
                {
@@ -941,7 +941,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
 
                /* Let the caller know we completed it */
                *retlen += len;
-               
+
                if (eccbuf) {
                        unsigned char x[8];
                        size_t dummy;
@@ -950,10 +950,10 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
                        /* Write the ECC data to flash */
                        for (di=0; di<6; di++)
                                x[di] = eccbuf[di];
-               
+
                        x[6]=0x55;
                        x[7]=0x55;
-               
+
                        ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
                        if (ret) {
                                up(&this->lock);
@@ -970,7 +970,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
        return 0;
 }
 
-static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, 
+static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
                          unsigned long count, loff_t to, size_t *retlen,
                          u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
@@ -1022,7 +1022,7 @@ static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
                        break;
 
                to += thislen;
-       }               
+       }
 
        up(&writev_buf_sem);
        *retlen = totretlen;
@@ -1080,7 +1080,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
        /* Reading the full OOB data drops us off of the end of the page,
          * causing the flash device to go into busy mode, so we need
          * to wait until ready 11.4.1 and Toshiba TC58256FT docs */
-       
+
        ret = DoC_WaitReady(this);
 
        up(&this->lock);
@@ -1190,7 +1190,7 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
        return 0;
 
 }
+
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                         size_t * retlen, const u_char * buf)
 {
@@ -1222,7 +1222,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
        }
 
        instr->state = MTD_ERASING;
-               
+
        /* FIXME: Do this in the background. Use timers or schedule_task() */
        while(len) {
                mychip = &this->chips[ofs >> this->chipshift];
index 1e704915ef0880d6c8325bacd64f1c8977bea3df..fcb28a6fd89f8dc011698b828b0c046b23aeb382 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001.c,v 1.48 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: doc2001.c,v 1.49 2005/11/07 11:14:24 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -196,10 +196,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
        DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP);
        DoC_WaitReady(doc->virtadr);
 
-       /* Read the NAND chip ID: 1. Send ReadID command */ 
+       /* Read the NAND chip ID: 1. Send ReadID command */
        DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP);
 
-       /* Read the NAND chip ID: 2. Send address byte zero */ 
+       /* Read the NAND chip ID: 2. Send address byte zero */
        DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00);
 
        /* Read the manufacturer and device id codes of the flash device through
@@ -223,7 +223,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                        for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
                                if (nand_manuf_ids[j].id == mfr)
                                        break;
-                       }       
+                       }
                        printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, "
                               "Chip ID: %2.2X (%s:%s)\n",
                               mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
@@ -275,7 +275,7 @@ static void DoC_ScanChips(struct DiskOnChip *this)
                return;
        }
 
-       /* Fill out the chip array with {floor, chipno} for each 
+       /* Fill out the chip array with {floor, chipno} for each
         * detected chip in the device. */
        for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) {
                for (chip = 0 ; chip < numchips[floor] ; chip++) {
@@ -309,7 +309,7 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
        tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
        if (tmp1 != tmp2)
                return 0;
-       
+
        WriteDOC((tmp1+1) % 0xff, doc1->virtadr, AliasResolution);
        tmp2 = ReadDOC(doc2->virtadr, AliasResolution);
        if (tmp2 == (tmp1+1) % 0xff)
@@ -425,7 +425,7 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                return -EINVAL;
 
        /* Don't allow a single read to cross a 512-byte block boundary */
-       if (from + len > ((from | 0x1ff) + 1)) 
+       if (from + len > ((from | 0x1ff) + 1))
                len = ((from | 0x1ff) + 1) - from;
 
        /* Find the chip which is to be used and select it */
@@ -552,7 +552,7 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
 
 #if 0
        /* Don't allow a single write to cross a 512-byte block boundary */
-       if (to + len > ( (to | 0x1ff) + 1)) 
+       if (to + len > ( (to | 0x1ff) + 1))
                len = ((to | 0x1ff) + 1) - to;
 #else
        /* Don't allow writes which aren't exactly one block */
@@ -632,7 +632,7 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
 
                /* write the block status BLOCK_USED (0x5555) at the end of ECC data
                   FIXME: this is only a hack for programming the IPL area for LinuxBIOS
-                  and should be replace with proper codes in user space utilities */ 
+                  and should be replace with proper codes in user space utilities */
                WriteDOC(0x55, docptr, Mil_CDSN_IO);
                WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
 
@@ -802,7 +802,7 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr)
        void __iomem *docptr = this->virtadr;
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
 
-       if (len != mtd->erasesize) 
+       if (len != mtd->erasesize)
                printk(KERN_WARNING "Erase not right size (%x != %x)n",
                       len, mtd->erasesize);
 
@@ -870,9 +870,9 @@ static void __exit cleanup_doc2001(void)
        while ((mtd=docmillist)) {
                this = mtd->priv;
                docmillist = this->nextdoc;
-                       
+
                del_mtd_device(mtd);
-                       
+
                iounmap(this->virtadr);
                kfree(this->chips);
                kfree(mtd);
index ed47bafb2ce2f9380d4e2bf9f516022e0735936d..0595cc7324b257d7f95a147c618df5af9f6bf73f 100644 (file)
@@ -6,7 +6,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001plus.c,v 1.13 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: doc2001plus.c,v 1.14 2005/11/07 11:14:24 gleixner Exp $
  *
  * Released under GPL
  */
@@ -293,10 +293,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
        DoC_Command(docptr, NAND_CMD_RESET, 0);
        DoC_WaitReady(docptr);
 
-       /* Read the NAND chip ID: 1. Send ReadID command */ 
+       /* Read the NAND chip ID: 1. Send ReadID command */
        DoC_Command(docptr, NAND_CMD_READID, 0);
 
-       /* Read the NAND chip ID: 2. Send address byte zero */ 
+       /* Read the NAND chip ID: 2. Send address byte zero */
        DoC_Address(doc, 1, 0x00, 0, 0x00);
 
        WriteDOC(0, docptr, Mplus_FlashControl);
@@ -365,7 +365,7 @@ static void DoC_ScanChips(struct DiskOnChip *this)
                this->interleave = 1;
 
        /* Check the ASIC agrees */
-       if ( (this->interleave << 2) != 
+       if ( (this->interleave << 2) !=
             (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) {
                u_char conf = ReadDOC(this->virtadr, Mplus_Configuration);
                printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n",
@@ -398,7 +398,7 @@ static void DoC_ScanChips(struct DiskOnChip *this)
                return;
        }
 
-       /* Fill out the chip array with {floor, chipno} for each 
+       /* Fill out the chip array with {floor, chipno} for each
         * detected chip in the device. */
        for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) {
                for (chip = 0 ; chip < numchips[floor] ; chip++) {
@@ -432,7 +432,7 @@ static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2)
        tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
        if (tmp1 != tmp2)
                return 0;
-       
+
        WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution);
        tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution);
        if (tmp2 == (tmp1+1) % 0xff)
@@ -624,7 +624,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                return -EINVAL;
 
        /* Don't allow a single read to cross a 512-byte block boundary */
-       if (from + len > ((from | 0x1ff) + 1)) 
+       if (from + len > ((from | 0x1ff) + 1))
                len = ((from | 0x1ff) + 1) - from;
 
        DoC_CheckASIC(docptr);
@@ -1066,7 +1066,7 @@ int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
 
        DoC_CheckASIC(docptr);
 
-       if (len != mtd->erasesize) 
+       if (len != mtd->erasesize)
                printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n",
                       len, mtd->erasesize);
 
@@ -1136,9 +1136,9 @@ static void __exit cleanup_doc2001plus(void)
        while ((mtd=docmilpluslist)) {
                this = mtd->priv;
                docmilpluslist = this->nextdoc;
-                       
+
                del_mtd_device(mtd);
-                       
+
                iounmap(this->virtadr);
                kfree(this->chips);
                kfree(mtd);
index 24f670b5a4f34e4b36751fe66479ada3d78843f6..cd3db72bef96ae92cfd9a69ee688d20d5759bc33 100644 (file)
@@ -4,10 +4,10 @@
  * GNU GPL License. The rest is simply to convert the disk on chip
  * syndrom into a standard syndom.
  *
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 Exp $
+ * $Id: docecc.c,v 1.7 2005/11/07 11:14:25 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
@@ -122,7 +122,7 @@ for(ci=(n)-1;ci >=0;ci--)\
         a(0) + a(1) @ + a(2) @^2 + ... + a(m-1) @^(m-1)
    we consider the integer "i" whose binary representation with a(0) being LSB
    and a(m-1) MSB is (a(0),a(1),...,a(m-1)) and locate the entry
-   "index_of[i]". Now, @^index_of[i] is that element whose polynomial 
+   "index_of[i]". Now, @^index_of[i] is that element whose polynomial
     representation is (a(0),a(1),a(2),...,a(m-1)).
    NOTE:
         The element alpha_to[2^m-1] = 0 always signifying that the
@@ -130,7 +130,7 @@ for(ci=(n)-1;ci >=0;ci--)\
         Similarily, the element index_of[0] = A0 always signifying
    that the power of alpha which has the polynomial representation
    (0,0,...,0) is "infinity".
+
 */
 
 static void
@@ -176,7 +176,7 @@ generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
  * are written back. NOTE! This array must be at least NN-KK elements long.
  * The corrected data are written in eras_val[]. They must be xor with the data
  * to retrieve the correct data : data[erase_pos[i]] ^= erase_val[i] .
- * 
+ *
  * First "no_eras" erasures are declared by the calling program. Then, the
  * maximum # of errors correctable is t_after_eras = floor((NN-KK-no_eras)/2).
  * If the number of channel errors is not greater than "t_after_eras" the
@@ -189,7 +189,7 @@ generate_gf(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1])
  * */
 static int
 eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
-            gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK], 
+            gf bb[NN - KK + 1], gf eras_val[NN-KK], int eras_pos[NN-KK],
             int no_eras)
 {
   int deg_lambda, el, deg_omega;
@@ -212,7 +212,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
     count = 0;
     goto finish;
   }
-  
+
   for(i=1;i<=NN-KK;i++){
     s[i] = bb[0];
   }
@@ -220,7 +220,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
     if(bb[j] == 0)
       continue;
     tmp = Index_of[bb[j]];
-    
+
     for(i=1;i<=NN-KK;i++)
       s[i] ^= Alpha_to[modnn(tmp + (B0+i-1)*PRIM*j)];
   }
@@ -234,7 +234,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
           tmp = modnn(tmp + 2 * KK * (B0+i-1)*PRIM);
       s[i] = tmp;
   }
-  
+
   CLEAR(&lambda[1],NN-KK);
   lambda[0] = 1;
 
@@ -252,7 +252,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
 #if DEBUG_ECC >= 1
     /* Test code that verifies the erasure locator polynomial just constructed
        Needed only for decoder debugging. */
-    
+
     /* find roots of the erasure location polynomial */
     for(i=1;i<=no_eras;i++)
       reg[i] = Index_of[lambda[i]];
@@ -286,7 +286,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
   }
   for(i=0;i<NN-KK+1;i++)
     b[i] = Index_of[lambda[i]];
-  
+
   /*
    * Begin Berlekamp-Massey algorithm to determine error+erasure
    * locator polynomial
@@ -389,7 +389,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
     omega[i] = Index_of[tmp];
   }
   omega[NN-KK] = A0;
-  
+
   /*
    * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
    * inv(X(l))**(B0-1) and den = lambda_pr(inv(X(l))) all in poly-form
@@ -402,7 +402,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
     }
     num2 = Alpha_to[modnn(root[j] * (B0 - 1) + NN)];
     den = 0;
-    
+
     /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
     for (i = min(deg_lambda,NN-KK-1) & ~1; i >= 0; i -=2) {
       if(lambda[i+1] != A0)
@@ -436,11 +436,11 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1],
 /* The sector bytes are packed into NB_DATA MM bits words */
 #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / MM)
 
-/* 
+/*
  * Correct the errors in 'sector[]' by using 'ecc1[]' which is the
  * content of the feedback shift register applyied to the sector and
  * the ECC. Return the number of errors corrected (and correct them in
- * sector), or -1 if error 
+ * sector), or -1 if error
  */
 int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
 {
@@ -454,7 +454,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
     Alpha_to = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
     if (!Alpha_to)
         return -1;
-    
+
     Index_of = kmalloc((NN + 1) * sizeof(dtype), GFP_KERNEL);
     if (!Index_of) {
         kfree(Alpha_to);
@@ -470,7 +470,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
     bb[2] = ((ecc1[2] & 0xf0) >> 4) | ((ecc1[3] & 0x3f) << 4);
     bb[3] = ((ecc1[3] & 0xc0) >> 6) | ((ecc1[0] & 0xff) << 2);
 
-    nb_errors = eras_dec_rs(Alpha_to, Index_of, bb, 
+    nb_errors = eras_dec_rs(Alpha_to, Index_of, bb,
                             error_val, error_pos, 0);
     if (nb_errors <= 0)
         goto the_end;
@@ -489,7 +489,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
                can be modified since pos is even */
             index = (pos >> 3) ^ 1;
             bitpos = pos & 7;
-            if ((index >= 0 && index < SECTOR_SIZE) || 
+            if ((index >= 0 && index < SECTOR_SIZE) ||
                 index == (SECTOR_SIZE + 1)) {
                 val = error_val[i] >> (2 + bitpos);
                 parity ^= val;
@@ -500,7 +500,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
             bitpos = (bitpos + 10) & 7;
             if (bitpos == 0)
                 bitpos = 8;
-            if ((index >= 0 && index < SECTOR_SIZE) || 
+            if ((index >= 0 && index < SECTOR_SIZE) ||
                 index == (SECTOR_SIZE + 1)) {
                 val = error_val[i] << (8 - bitpos);
                 parity ^= val;
@@ -509,7 +509,7 @@ int doc_decode_ecc(unsigned char sector[SECTOR_SIZE], unsigned char ecc1[6])
             }
         }
     }
-    
+
     /* use parity to test extra errors */
     if ((parity & 0xff) != 0)
         nb_errors = -1;
index 197d67045e1e754e60424fcd2dd180d206336618..13178b9dd00aa1db3a72a3a9a87100efff547029 100644 (file)
@@ -4,22 +4,22 @@
 /* (C) 1999 Machine Vision Holdings, Inc.                      */
 /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>         */
 
-/* $Id: docprobe.c,v 1.44 2005/01/05 12:40:36 dwmw2 Exp $      */
+/* $Id: docprobe.c,v 1.46 2005/11/07 11:14:25 gleixner Exp $   */
 
 
 
 /* DOC_PASSIVE_PROBE:
-   In order to ensure that the BIOS checksum is correct at boot time, and 
-   hence that the onboard BIOS extension gets executed, the DiskOnChip 
-   goes into reset mode when it is read sequentially: all registers 
-   return 0xff until the chip is woken up again by writing to the 
-   DOCControl register. 
-
-   Unfortunately, this means that the probe for the DiskOnChip is unsafe, 
-   because one of the first things it does is write to where it thinks 
-   the DOCControl register should be - which may well be shared memory 
-   for another device. I've had machines which lock up when this is 
-   attempted. Hence the possibility to do a passive probe, which will fail 
+   In order to ensure that the BIOS checksum is correct at boot time, and
+   hence that the onboard BIOS extension gets executed, the DiskOnChip
+   goes into reset mode when it is read sequentially: all registers
+   return 0xff until the chip is woken up again by writing to the
+   DOCControl register.
+
+   Unfortunately, this means that the probe for the DiskOnChip is unsafe,
+   because one of the first things it does is write to where it thinks
+   the DOCControl register should be - which may well be shared memory
+   for another device. I've had machines which lock up when this is
+   attempted. Hence the possibility to do a passive probe, which will fail
    to detect a chip in reset mode, but is at least guaranteed not to lock
    the machine.
 
@@ -33,9 +33,9 @@
 
    The old Millennium-only driver has been retained just in case there
    are problems with the new code. If the combined driver doesn't work
-   for you, you can try the old one by undefining DOC_SINGLE_DRIVER 
+   for you, you can try the old one by undefining DOC_SINGLE_DRIVER
    below and also enabling it in your configuration. If this fixes the
-   problems, please send a report to the MTD mailing list at 
+   problems, please send a report to the MTD mailing list at
    <linux-mtd@lists.infradead.org>.
 */
 #define DOC_SINGLE_DRIVER
@@ -68,16 +68,16 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe
 static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
 #ifdef CONFIG_MTD_DOCPROBE_HIGH
-       0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
+       0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
        0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
-       0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
-       0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 
+       0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
+       0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
        0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
 #else /*  CONFIG_MTD_DOCPROBE_HIGH */
-       0xc8000, 0xca000, 0xcc000, 0xce000, 
+       0xc8000, 0xca000, 0xcc000, 0xce000,
        0xd0000, 0xd2000, 0xd4000, 0xd6000,
-       0xd8000, 0xda000, 0xdc000, 0xde000, 
-       0xe0000, 0xe2000, 0xe4000, 0xe6000, 
+       0xd8000, 0xda000, 0xdc000, 0xde000,
+       0xe0000, 0xe2000, 0xe4000, 0xe6000,
        0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
 #elif defined(__PPC__)
@@ -111,35 +111,35 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr
                return 0;
 #endif /* CONFIG_MTD_DOCPROBE_55AA */
 
-#ifndef DOC_PASSIVE_PROBE      
+#ifndef DOC_PASSIVE_PROBE
        /* It's not possible to cleanly detect the DiskOnChip - the
         * bootup procedure will put the device into reset mode, and
         * it's not possible to talk to it without actually writing
         * to the DOCControl register. So we store the current contents
         * of the DOCControl register's location, in case we later decide
         * that it's not a DiskOnChip, and want to put it back how we
-        * found it. 
+        * found it.
         */
        tmp2 = ReadDOC(window, DOCControl);
-       
+
        /* Reset the DiskOnChip ASIC */
-       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
                 window, DOCControl);
-       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
                 window, DOCControl);
-       
+
        /* Enable the DiskOnChip ASIC */
-       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
                 window, DOCControl);
-       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
                 window, DOCControl);
-#endif /* !DOC_PASSIVE_PROBE */        
+#endif /* !DOC_PASSIVE_PROBE */
 
        /* We need to read the ChipID register four times. For some
           newer DiskOnChip 2000 units, the first three reads will
           return the DiskOnChip Millennium ident. Don't ask. */
        ChipID = ReadDOC(window, ChipID);
-  
+
        switch (ChipID) {
        case DOC_ChipID_Doc2k:
                /* Check the TOGGLE bit in the ECC register */
@@ -149,7 +149,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr
                if (tmp != tmpb && tmp == tmpc)
                                return ChipID;
                break;
-               
+
        case DOC_ChipID_DocMil:
                /* Check for the new 2000 with Millennium ASIC */
                ReadDOC(window, ChipID);
@@ -164,7 +164,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr
                if (tmp != tmpb && tmp == tmpc)
                                return ChipID;
                break;
-               
+
        case DOC_ChipID_DocMilPlus16:
        case DOC_ChipID_DocMilPlus32:
        case 0:
@@ -179,7 +179,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr
                        DOC_MODE_BDECT;
                WriteDOC(tmp, window, Mplus_DOCControl);
                WriteDOC(~tmp, window, Mplus_CtrlConfirm);
-       
+
                mdelay(1);
                /* Enable the DiskOnChip ASIC */
                tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
@@ -187,7 +187,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr
                WriteDOC(tmp, window, Mplus_DOCControl);
                WriteDOC(~tmp, window, Mplus_CtrlConfirm);
                mdelay(1);
-#endif /* !DOC_PASSIVE_PROBE */        
+#endif /* !DOC_PASSIVE_PROBE */
 
                ChipID = ReadDOC(window, ChipID);
 
@@ -227,7 +227,7 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr
        WriteDOC(tmp2, window, DOCControl);
 #endif
        return 0;
-}   
+}
 
 static int docfound;
 
@@ -244,10 +244,10 @@ static void __init DoC_Probe(unsigned long physadr)
        void (*initroutine)(struct mtd_info *) = NULL;
 
        docptr = ioremap(physadr, DOC_IOREMAP_LEN);
-       
+
        if (!docptr)
                return;
-       
+
        if ((ChipID = doccheck(docptr, physadr))) {
                if (ChipID == DOC_ChipID_Doc2kTSOP) {
                        /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
@@ -263,9 +263,9 @@ static void __init DoC_Probe(unsigned long physadr)
                        iounmap(docptr);
                        return;
                }
-               
+
                this = (struct DiskOnChip *)(&mtd[1]);
-               
+
                memset((char *)mtd,0, sizeof(struct mtd_info));
                memset((char *)this, 0, sizeof(struct DiskOnChip));
 
@@ -281,13 +281,13 @@ static void __init DoC_Probe(unsigned long physadr)
                        im_funcname = "DoC2k_init";
                        im_modname = "doc2000";
                        break;
-                       
+
                case DOC_ChipID_Doc2k:
                        name="2000";
                        im_funcname = "DoC2k_init";
                        im_modname = "doc2000";
                        break;
-                       
+
                case DOC_ChipID_DocMil:
                        name="Millennium";
 #ifdef DOC_SINGLE_DRIVER
@@ -331,7 +331,7 @@ static void __init DoC_Probe(unsigned long physadr)
 static int __init init_doc(void)
 {
        int i;
-       
+
        if (doc_config_location) {
                printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
                DoC_Probe(doc_config_location);
index df987a53ed9cf918c5c8d318e0dc8b1267f2a96e..1e876fcb04084ca43ff366803973fad01ee9b833 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
  *
- * $Id: lart.c,v 1.7 2004/08/09 13:19:44 dwmw2 Exp $
+ * $Id: lart.c,v 1.9 2005/11/07 11:14:25 gleixner Exp $
  *
  * Author: Abraham vd Merwe <abraham@2d3d.co.za>
  *
@@ -122,7 +122,7 @@ static char module_name[] = "lart";
 
 /*
  * The data line mapping on LART is as follows:
- * 
+ *
  *      U2  CPU |   U3  CPU
  *      -------------------
  *       0  20  |   0   12
@@ -181,7 +181,7 @@ static char module_name[] = "lart";
                (((x) & 0x00004000) >> 13)              \
        )
 
-/* 
+/*
  * The address line mapping on LART is as follows:
  *
  *      U3  CPU |   U2  CPU
@@ -204,7 +204,7 @@ static char module_name[] = "lart";
  *      12  15  |   12  15
  *      13  14  |   13  14
  *      14  16  |   14  16
- * 
+ *
  *      MAIN BLOCK BOUNDARY
  *
  *      15  17  |   15  18
index 765c0179c8df9097e476982c57131edea2399647..e8685ee6c1e425f202b8ca2b91ea6de05dc8c8ae 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $
+ * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $
  *
  * Copyright (c) ????          Jochen Schäuble <psionic@psionic.de>
  * Copyright (c) 2003-2004     Jörn Engel <joern@wh.fh-wedel.de>
@@ -41,10 +41,10 @@ static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
 
        if (instr->addr + instr->len > mtd->size)
                return -EINVAL;
-       
+
        memset(start + instr->addr, 0xff, instr->len);
 
-       /* This'll catch a few races. Free the thing before returning :) 
+       /* This'll catch a few races. Free the thing before returning :)
         * I don't feel at all ashamed. This kind of thing is possible anyway
         * with flash, but unlikely.
         */
@@ -63,7 +63,7 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
 
        if (from + len > mtd->size)
                return -EINVAL;
-       
+
        *mtdbuf = start + from;
        *retlen = len;
        return 0;
@@ -84,7 +84,7 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
 
        if (len > mtd->size - from)
                len = mtd->size - from;
-       
+
        memcpy(buf, start + from, len);
 
        *retlen = len;
@@ -101,7 +101,7 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
 
        if (len > mtd->size - to)
                len = mtd->size - to;
-       
+
        memcpy(start + to, buf, len);
 
        *retlen = len;
@@ -159,7 +159,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
        }
 
        list_add_tail(&new->list, &phram_list);
-       return 0;       
+       return 0;
 
 out2:
        iounmap(new->mtd.priv);
index 5b3defadf884d264b6920648feb2a83a65d576d9..de48b35f5609e96957b2a7ec0e71de2572ca0236 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.c,v 1.30 2005/01/05 18:05:13 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.32 2005/11/07 11:14:25 gleixner Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
@@ -27,7 +27,7 @@
  *      it as high speed swap or for a high speed disk device of some
  *      sort.  Which becomes very useful on diskless systems in the
  *      embedded market I might add.
- *      
+ *
  * Notes:
  *      Due to what I assume is more buggy SROM, the 64M PMC551 I
  *      have available claims that all 4 of it's DRAM banks have 64M
  *       Minyard set up the card to utilize a 1M sliding apature.
  *
  *      Corey Minyard <minyard@nortelnetworks.com>
- *       * Modified driver to utilize a sliding aperture instead of 
+ *       * Modified driver to utilize a sliding aperture instead of
  *         mapping all memory into kernel space which turned out to
  *         be very wasteful.
- *       * Located a bug in the SROM's initialization sequence that 
+ *       * Located a bug in the SROM's initialization sequence that
  *         made the memory unusable, added a fix to code to touch up
  *         the DRAM some.
  *
@@ -390,7 +390,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev)
        bcmd |= (0x40|0x20);
        pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
 
-        /* 
+        /*
         * Take care and turn off the memory on the device while we
         * tweak the configurations
         */
@@ -408,7 +408,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev)
         * Grab old BAR0 config so that we can figure out memory size
         * This is another bit of kludge going on.  The reason for the
         * redundancy is I am hoping to retain the original configuration
-        * previously assigned to the card by the BIOS or some previous 
+        * previously assigned to the card by the BIOS or some previous
         * fixup routine in the kernel.  So we read the old config into cfg,
         * then write all 1's to the memory space, read back the result into
         * "size", and then write back all the old config.
@@ -480,7 +480,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev)
         } while ( (PCI_COMMAND_IO) & cmd );
 
         /*
-        * Turn on auto refresh 
+        * Turn on auto refresh
         * The loop is taken directly from Ramix's example code.  I assume that
         * this must be held high for some duration of time, but I can find no
         * documentation refrencing the reasons why.
@@ -615,7 +615,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev)
        pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
        printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n"
                           "pmc551: System Control Register is %slocked to PCI access\n"
-                          "pmc551: System Control Register is %slocked to EEPROM access\n", 
+                          "pmc551: System Control Register is %slocked to EEPROM access\n",
                (bcmd&0x1)?"software":"hardware",
                (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un");
 #endif
@@ -744,7 +744,7 @@ static int __init init_pmc551(void)
                 priv->start = ioremap(((PCI_Device->resource[0].start)
                                        & PCI_BASE_ADDRESS_MEM_MASK),
                                       priv->asize);
-               
+
                if (!priv->start) {
                        printk(KERN_NOTICE "pmc551: Unable to map IO space\n");
                         kfree(mtd->priv);
@@ -765,7 +765,7 @@ static int __init init_pmc551(void)
                                          priv->curr_map0 );
 
 #ifdef CONFIG_MTD_PMC551_DEBUG
-               printk( KERN_DEBUG "pmc551: aperture set to %d\n", 
+               printk( KERN_DEBUG "pmc551: aperture set to %d\n",
                        (priv->base_map0 & 0xF0)>>4 );
 #endif
 
@@ -823,13 +823,13 @@ static void __exit cleanup_pmc551(void)
        while((mtd=pmc551list)) {
                priv = mtd->priv;
                pmc551list = priv->nextpmc551;
-               
+
                if(priv->start) {
                        printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n",
                                priv->asize>>20, priv->start);
                        iounmap (priv->start);
                }
-               
+
                kfree (mtd->priv);
                del_mtd_device (mtd);
                kfree (mtd);
index 84fa91392a8c7180b5113a15a290e76f49f4a50a..6faee6c6958c2a7bc709b53df6cf61ff6c507369 100644 (file)
@@ -1,6 +1,6 @@
 /*======================================================================
 
-  $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $
+  $Id: slram.c,v 1.36 2005/11/07 11:14:25 gleixner 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
   <start>: start of the memory region, decimal or hex (0xabcdef)
   <end/offset>: end of the memory region. It's possible to use +0x1234
                 to specify the offset instead of the absolute address
-    
+
   NOTE:
   With slram it's only possible to map a contigous memory region. Therfore
   if there's a device mapped somewhere in the region specified slram will
   fail to load (see kernel log if modprobe fails).
 
   -
-  
+
   Jochen Schaeuble <psionic@psionic.de>
 
 ======================================================================*/
@@ -89,10 +89,10 @@ static int slram_erase(struct mtd_info *mtd, struct erase_info *instr)
        if (instr->addr + instr->len > mtd->size) {
                return(-EINVAL);
        }
-       
+
        memset(priv->start + instr->addr, 0xff, instr->len);
 
-       /* This'll catch a few races. Free the thing before returning :) 
+       /* This'll catch a few races. Free the thing before returning :)
         * I don't feel at all ashamed. This kind of thing is possible anyway
         * with flash, but unlikely.
         */
@@ -170,12 +170,12 @@ static int register_device(char *name, unsigned long start, unsigned long length
        }
        (*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
        (*curmtd)->next = NULL;
-       
+
        if ((*curmtd)->mtdinfo) {
                memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info));
                (*curmtd)->mtdinfo->priv =
                        kmalloc(sizeof(slram_priv_t), GFP_KERNEL);
-               
+
                if (!(*curmtd)->mtdinfo->priv) {
                        kfree((*curmtd)->mtdinfo);
                        (*curmtd)->mtdinfo = NULL;
@@ -188,7 +188,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
                E("slram: Cannot allocate new MTD device.\n");
                return(-ENOMEM);
        }
-       
+
        if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start =
                                ioremap(start, length))) {
                E("slram: ioremap failed\n");
@@ -223,7 +223,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
        T("slram: Mapped from 0x%p to 0x%p\n",
                        ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start,
                        ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end);
-       return(0);      
+       return(0);
 }
 
 static void unregister_devices(void)
@@ -256,7 +256,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
        char *buffer;
        unsigned long devstart;
        unsigned long devlength;
-       
+
        if ((!devname) || (!szstart) || (!szlength)) {
                unregister_devices();
                return(-EINVAL);
@@ -264,7 +264,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
 
        devstart = simple_strtoul(szstart, &buffer, 0);
        devstart = handle_unit(devstart, buffer);
-       
+
        if (*(szlength) != '+') {
                devlength = simple_strtoul(szlength, &buffer, 0);
                devlength = handle_unit(devlength, buffer) - devstart;
@@ -278,7 +278,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
                E("slram: Illegal start / length parameter.\n");
                return(-EINVAL);
        }
-       
+
        if ((devstart = register_device(devname, devstart, devlength))){
                unregister_devices();
                return((int)devstart);
@@ -335,7 +335,7 @@ static int init_slram(void)
        }
 #else
        int count;
-       
+
        for (count = 0; (map[count]) && (count < SLRAM_MAX_DEVICES_PARAMS);
                        count++) {
        }
@@ -350,10 +350,10 @@ static int init_slram(void)
                if (parse_cmdline(devname, map[i * 3 + 1], map[i * 3 + 2])!=0) {
                        return(-EINVAL);
                }
-               
+
        }
 #endif /* !MODULE */
-       
+
        return(0);
 }
 
index d32c1b3a8ce34422bd7c476b80299beef40ebb67..de7e231d6d180deb3528caeb62593555ba09f363 100644 (file)
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
+ * $Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -53,7 +53,7 @@
     Use of the FTL format for non-PCMCIA applications may be an
     infringement of these patents.  For additional information,
     contact M-Systems (http://www.m-sys.com) directly.
-      
+
 ======================================================================*/
 #include <linux/mtd/blktrans.h>
 #include <linux/module.h>
@@ -160,7 +160,7 @@ static void ftl_erase_callback(struct erase_info *done);
     Scan_header() checks to see if a memory region contains an FTL
     partition.  build_maps() reads all the erase unit headers, builds
     the erase unit map, and then builds the virtual page map.
-    
+
 ======================================================================*/
 
 static int scan_header(partition_t *part)
@@ -176,10 +176,10 @@ static int scan_header(partition_t *part)
         (offset + sizeof(header)) < max_offset;
         offset += part->mbd.mtd->erasesize ? : 0x2000) {
 
-       err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, 
+       err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret,
                              (unsigned char *)&header);
-       
-       if (err) 
+
+       if (err)
            return err;
 
        if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
@@ -232,10 +232,10 @@ static int build_maps(partition_t *part)
     for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) {
        offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN))
                      << part->header.EraseUnitSize);
-       ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, 
+       ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval,
                              (unsigned char *)&header);
-       
-       if (ret) 
+
+       if (ret)
            goto out_XferInfo;
 
        ret = -1;
@@ -274,7 +274,7 @@ static int build_maps(partition_t *part)
               "don't add up!\n");
        goto out_XferInfo;
     }
-    
+
     /* Set up virtual page map */
     blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize;
     part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t));
@@ -296,12 +296,12 @@ static int build_maps(partition_t *part)
        part->EUNInfo[i].Free = 0;
        part->EUNInfo[i].Deleted = 0;
        offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset);
-       
-       ret = part->mbd.mtd->read(part->mbd.mtd, offset,  
-                             part->BlocksPerUnit * sizeof(u_int32_t), &retval, 
+
+       ret = part->mbd.mtd->read(part->mbd.mtd, offset,
+                             part->BlocksPerUnit * sizeof(u_int32_t), &retval,
                              (unsigned char *)part->bam_cache);
-       
-       if (ret) 
+
+       if (ret)
                goto out_bam_cache;
 
        for (j = 0; j < part->BlocksPerUnit; j++) {
@@ -316,7 +316,7 @@ static int build_maps(partition_t *part)
                part->EUNInfo[i].Deleted++;
        }
     }
-    
+
     ret = 0;
     goto out;
 
@@ -336,7 +336,7 @@ out:
 
     Erase_xfer() schedules an asynchronous erase operation for a
     transfer unit.
-    
+
 ======================================================================*/
 
 static int erase_xfer(partition_t *part,
@@ -351,10 +351,10 @@ static int erase_xfer(partition_t *part,
     xfer->state = XFER_ERASING;
 
     /* Is there a free erase slot? Always in MTD. */
-    
-    
+
+
     erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
-    if (!erase) 
+    if (!erase)
             return -ENOMEM;
 
     erase->mtd = part->mbd.mtd;
@@ -362,7 +362,7 @@ static int erase_xfer(partition_t *part,
     erase->addr = xfer->Offset;
     erase->len = 1 << part->header.EraseUnitSize;
     erase->priv = (u_long)part;
-    
+
     ret = part->mbd.mtd->erase(part->mbd.mtd, erase);
 
     if (!ret)
@@ -377,7 +377,7 @@ static int erase_xfer(partition_t *part,
 
     Prepare_xfer() takes a freshly erased transfer unit and gives
     it an appropriate header.
-    
+
 ======================================================================*/
 
 static void ftl_erase_callback(struct erase_info *erase)
@@ -385,7 +385,7 @@ static void ftl_erase_callback(struct erase_info *erase)
     partition_t *part;
     struct xfer_info_t *xfer;
     int i;
-    
+
     /* Look up the transfer unit */
     part = (partition_t *)(erase->priv);
 
@@ -422,7 +422,7 @@ static int prepare_xfer(partition_t *part, int i)
 
     xfer = &part->XferInfo[i];
     xfer->state = XFER_FAILED;
-    
+
     DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
 
     /* Write the transfer unit header */
@@ -446,7 +446,7 @@ static int prepare_xfer(partition_t *part, int i)
 
     for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) {
 
-       ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), 
+       ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t),
                               &retlen, (u_char *)&ctl);
 
        if (ret)
@@ -454,7 +454,7 @@ static int prepare_xfer(partition_t *part, int i)
     }
     xfer->state = XFER_PREPARED;
     return 0;
-    
+
 } /* prepare_xfer */
 
 /*======================================================================
@@ -466,7 +466,7 @@ static int prepare_xfer(partition_t *part, int i)
     All data blocks are copied to the corresponding blocks in the
     target unit, so the virtual block map does not need to be
     updated.
-    
+
 ======================================================================*/
 
 static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
@@ -486,14 +486,14 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     xfer = &part->XferInfo[xferunit];
     DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
          eun->Offset, xfer->Offset);
-       
-    
+
+
     /* Read current BAM */
     if (part->bam_index != srcunit) {
 
        offset = eun->Offset + le32_to_cpu(part->header.BAMOffset);
 
-       ret = part->mbd.mtd->read(part->mbd.mtd, offset, 
+       ret = part->mbd.mtd->read(part->mbd.mtd, offset,
                              part->BlocksPerUnit * sizeof(u_int32_t),
                              &retlen, (u_char *) (part->bam_cache));
 
@@ -501,11 +501,11 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
        part->bam_index = 0xffff;
 
        if (ret) {
-           printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");                
+           printk( KERN_WARNING "ftl: Failed to read BAM cache in copy_erase_unit()!\n");
            return ret;
        }
     }
-    
+
     /* Write the LogicalEUN for the transfer unit */
     xfer->state = XFER_UNKNOWN;
     offset = xfer->Offset + 20; /* Bad! */
@@ -513,12 +513,12 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
 
     ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t),
                           &retlen, (u_char *) &unit);
-    
+
     if (ret) {
        printk( KERN_WARNING "ftl: Failed to write back to BAM cache in copy_erase_unit()!\n");
        return ret;
     }
-    
+
     /* Copy all data blocks from source unit to transfer unit */
     src = eun->Offset; dest = xfer->Offset;
 
@@ -558,15 +558,15 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     }
 
     /* Write the BAM to the transfer unit */
-    ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), 
-                    part->BlocksPerUnit * sizeof(int32_t), &retlen, 
+    ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset),
+                    part->BlocksPerUnit * sizeof(int32_t), &retlen,
                    (u_char *)part->bam_cache);
     if (ret) {
        printk( KERN_WARNING "ftl: Error writing BAM in copy_erase_unit\n");
        return ret;
     }
 
-    
+
     /* All clear? Then update the LogicalEUN again */
     ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t),
                           &retlen, (u_char *)&srcunitswap);
@@ -574,9 +574,9 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     if (ret) {
        printk(KERN_WARNING "ftl: Error writing new LogicalEUN in copy_erase_unit\n");
        return ret;
-    }    
-    
-    
+    }
+
+
     /* Update the maps and usage stats*/
     i = xfer->EraseCount;
     xfer->EraseCount = eun->EraseCount;
@@ -588,10 +588,10 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     part->FreeTotal += free;
     eun->Free = free;
     eun->Deleted = 0;
-    
+
     /* Now, the cache should be valid for the new block */
     part->bam_index = srcunit;
-    
+
     return 0;
 } /* copy_erase_unit */
 
@@ -608,7 +608,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit,
     oldest data unit instead.  This means that we generally postpone
     the next reclaimation as long as possible, but shuffle static
     stuff around a bit for wear leveling.
-    
+
 ======================================================================*/
 
 static int reclaim_block(partition_t *part)
@@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part)
                else
                    DEBUG(1, "ftl_cs: reclaim failed: no "
                          "suitable transfer units!\n");
-                       
+
                return -EIO;
            }
        }
@@ -715,7 +715,7 @@ static int reclaim_block(partition_t *part)
     returns the block index -- the erase unit is just the currently
     cached unit.  If there are no free blocks, it returns 0 -- this
     is never a valid data block because it contains the header.
-    
+
 ======================================================================*/
 
 #ifdef PSYCHO_DEBUG
@@ -737,7 +737,7 @@ static u_int32_t find_free(partition_t *part)
     u_int32_t blk;
     size_t retlen;
     int ret;
-    
+
     /* Find an erase unit with some free space */
     stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
     eun = stop;
@@ -749,17 +749,17 @@ static u_int32_t find_free(partition_t *part)
 
     if (part->EUNInfo[eun].Free == 0)
        return 0;
-    
+
     /* Is this unit's BAM cached? */
     if (eun != part->bam_index) {
        /* Invalidate cache */
        part->bam_index = 0xffff;
 
-       ret = part->mbd.mtd->read(part->mbd.mtd, 
+       ret = part->mbd.mtd->read(part->mbd.mtd,
                       part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset),
                       part->BlocksPerUnit * sizeof(u_int32_t),
                       &retlen, (u_char *) (part->bam_cache));
-       
+
        if (ret) {
            printk(KERN_WARNING"ftl: Error reading BAM in find_free\n");
            return 0;
@@ -781,14 +781,14 @@ static u_int32_t find_free(partition_t *part)
     }
     DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
     return blk;
-    
+
 } /* find_free */
 
 
 /*======================================================================
 
     Read a series of sectors from an FTL partition.
-    
+
 ======================================================================*/
 
 static int ftl_read(partition_t *part, caddr_t buffer,
@@ -798,7 +798,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,
     u_long i;
     int ret;
     size_t offset, retlen;
-    
+
     DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
          part, sector, nblocks);
     if (!(part->state & FTL_FORMATTED)) {
@@ -834,7 +834,7 @@ static int ftl_read(partition_t *part, caddr_t buffer,
 /*======================================================================
 
     Write a series of sectors to an FTL partition
-    
+
 ======================================================================*/
 
 static int set_bam_entry(partition_t *part, u_int32_t log_addr,
@@ -855,7 +855,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr,
     blk = (log_addr % bsize) / SECTOR_SIZE;
     offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) +
                  le32_to_cpu(part->header.BAMOffset));
-    
+
 #ifdef PSYCHO_DEBUG
     ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t),
                         &retlen, (u_char *)&old_addr);
@@ -925,7 +925,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
        if (ret)
            return ret;
     }
-    
+
     bsize = 1 << part->header.EraseUnitSize;
 
     virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
@@ -949,12 +949,12 @@ static int ftl_write(partition_t *part, caddr_t buffer,
        log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
        part->EUNInfo[part->bam_index].Free--;
        part->FreeTotal--;
-       if (set_bam_entry(part, log_addr, 0xfffffffe)) 
+       if (set_bam_entry(part, log_addr, 0xfffffffe))
            return -EIO;
        part->EUNInfo[part->bam_index].Deleted++;
        offset = (part->EUNInfo[part->bam_index].Offset +
                      blk * SECTOR_SIZE);
-       ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, 
+       ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen,
                                      buffer);
 
        if (ret) {
@@ -964,7 +964,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
                   offset);
            return -EIO;
        }
-       
+
        /* Only delete the old entry when the new entry is ready */
        old_addr = part->VirtualBlockMap[sector+i];
        if (old_addr != 0xffffffff) {
@@ -979,7 +979,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
            return -EIO;
        part->VirtualBlockMap[sector+i] = log_addr;
        part->EUNInfo[part->bam_index].Deleted--;
-       
+
        buffer += SECTOR_SIZE;
        virt_addr += SECTOR_SIZE;
     }
@@ -1034,20 +1034,20 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        partition_t *partition;
 
        partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
-               
+
        if (!partition) {
                printk(KERN_WARNING "No memory to scan for FTL on %s\n",
                       mtd->name);
                return;
-       }    
+       }
 
        memset(partition, 0, sizeof(partition_t));
 
        partition->mbd.mtd = mtd;
 
-       if ((scan_header(partition) == 0) && 
+       if ((scan_header(partition) == 0) &&
            (build_maps(partition) == 0)) {
-               
+
                partition->state = FTL_FORMATTED;
 #ifdef PCMCIA_DEBUG
                printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n",
@@ -1086,7 +1086,7 @@ struct mtd_blktrans_ops ftl_tr = {
 
 int init_ftl(void)
 {
-       DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
+       DEBUG(0, "$Id: ftl.c,v 1.58 2005/11/07 11:14:19 gleixner Exp $\n");
 
        return register_mtd_blktrans(&ftl_tr);
 }
index 8db65bf029ea6db3ed59f30a568d5434e1b8c067..8a544890173d3c857c953eb149c68b14b145ba90 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
  *
  * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
@@ -7,7 +7,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * Author: David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: inftlcore.c,v 1.18 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 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
@@ -113,14 +113,14 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 
        if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
                /*
-                 Oh no we don't have 
+                 Oh no we don't have
                   mbd.size == heads * cylinders * sectors
                */
                printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
                       "match size of 0x%lx.\n", inftl->mbd.size);
                printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
                        "(== 0x%lx sects)\n",
-                       inftl->cylinders, inftl->heads , inftl->sectors, 
+                       inftl->cylinders, inftl->heads , inftl->sectors,
                        (long)inftl->cylinders * (long)inftl->heads *
                        (long)inftl->sectors );
        }
@@ -219,7 +219,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                       "Virtual Unit Chain %d!\n", thisVUC);
                return BLOCK_NIL;
        }
-       
+
        /*
         * Scan to find the Erase Unit which holds the actual data for each
         * 512-byte block within the Chain.
@@ -260,7 +260,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                                "Unit Chain 0x%x\n", thisVUC);
                        return BLOCK_NIL;
                }
-               
+
                thisEUN = inftl->PUtable[thisEUN];
        }
 
@@ -291,15 +291,15 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                 */
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
-                
+
                 ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
                        BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
-                       &retlen, movebuf); 
+                       &retlen, movebuf);
                 if (ret < 0) {
                        ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
                                BlockMap[block]) + (block * SECTORSIZE),
                                SECTORSIZE, &retlen, movebuf);
-                       if (ret != -EIO) 
+                       if (ret != -EIO)
                                DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
                                        "away on retry?\n");
                 }
@@ -351,7 +351,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
 static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
 {
        /*
-        * This is the part that needs some cleverness applied. 
+        * This is the part that needs some cleverness applied.
         * For now, I'm doing the minimum applicable to actually
         * get the thing to work.
         * Wear-levelling and other clever stuff needs to be implemented
@@ -410,7 +410,7 @@ static int nrbits(unsigned int val, int bitcount)
 }
 
 /*
- * INFTL_findwriteunit: Return the unit number into which we can write 
+ * INFTL_findwriteunit: Return the unit number into which we can write
  *                      for this block. Make it available if it isn't already.
  */
 static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
@@ -459,10 +459,10 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
                                 * Invalid block. Don't use it any more.
                                 * Must implement.
                                 */
-                               break;                  
+                               break;
                        }
-                       
-                       if (!silly--) { 
+
+                       if (!silly--) {
                                printk(KERN_WARNING "INFTL: infinite loop in "
                                        "Virtual Unit Chain 0x%x\n", thisVUC);
                                return 0xffff;
@@ -478,7 +478,7 @@ hitused:
 
 
                /*
-                * OK. We didn't find one in the existing chain, or there 
+                * OK. We didn't find one in the existing chain, or there
                 * is no existing chain. Allocate a new one.
                 */
                writeEUN = INFTL_findfreeblock(inftl, 0);
@@ -502,8 +502,8 @@ hitused:
                        if (writeEUN == BLOCK_NIL) {
                                /*
                                 * Ouch. This should never happen - we should
-                                * always be able to make some room somehow. 
-                                * If we get here, we've allocated more storage 
+                                * always be able to make some room somehow.
+                                * If we get here, we've allocated more storage
                                 * space than actual media, or our makefreeblock
                                 * routine is missing something.
                                 */
@@ -514,7 +514,7 @@ hitused:
                                INFTL_dumpVUchains(inftl);
 #endif
                                return BLOCK_NIL;
-                       }                       
+                       }
                }
 
                /*
@@ -539,7 +539,7 @@ hitused:
                parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
                parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
                parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
+
                oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
                oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
                oob.u.a.ANAC = anac;
@@ -558,7 +558,7 @@ hitused:
                oob.u.b.parityPerField = parity;
                oob.u.b.discarded = 0xaa;
 
-               MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 
+               MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
                        SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
 
                inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
@@ -598,7 +598,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
                       "Virtual Unit Chain %d!\n", thisVUC);
                return;
        }
-       
+
        /*
         * Scan through the Erase Units to determine whether any data is in
         * each of the 512-byte blocks within the Chain.
@@ -638,7 +638,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
                                "Unit Chain 0x%x\n", thisVUC);
                        return;
                }
-               
+
                thisEUN = inftl->PUtable[thisEUN];
        }
 
@@ -754,7 +754,7 @@ foundit:
        return 0;
 }
 
-static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, 
+static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
                            char *buffer)
 {
        struct INFTLrecord *inftl = (void *)mbd;
@@ -889,7 +889,7 @@ extern char inftlmountrev[];
 
 static int __init init_inftl(void)
 {
-       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.18 $, "
+       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, "
                "inftlmount.c %s\n", inftlmountrev);
 
        return register_mtd_blktrans(&inftl_tr);
index 3dac53feeee27561a28b8cc6c35a1bd313ebb17a..43fdc943388241bcceeacd66b410ec15612699d2 100644 (file)
@@ -1,14 +1,14 @@
-/* 
+/*
  * inftlmount.c -- INFTL mount code with extensive checks.
  *
  * Author: Greg Ungerer (gerg@snapgear.com)
  * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com)
  *
  * Based heavily on the nftlmount.c code which is:
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev Exp $
+ * $Id: inftlmount.c,v 1.18 2005/11/07 11:14:20 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
@@ -41,7 +41,7 @@
 #include <linux/mtd/inftl.h>
 #include <linux/mtd/compatmac.h>
 
-char inftlmountrev[]="$Revision: 1.16 $";
+char inftlmountrev[]="$Revision: 1.18 $";
 
 /*
  * find_boot_record: Find the INFTL Media Header and its Spare copy which
@@ -273,7 +273,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
                                inftl->nb_boot_blocks);
                        return -1;
                }
-               
+
                inftl->mbd.size  = inftl->numvunits *
                        (inftl->EraseSize / SECTORSIZE);
 
@@ -302,7 +302,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
                                inftl->nb_blocks * sizeof(u16));
                        return -ENOMEM;
                }
-               
+
                /* Mark the blocks before INFTL MediaHeader as reserved */
                for (i = 0; i < inftl->nb_boot_blocks; i++)
                        inftl->PUtable[i] = BLOCK_RESERVED;
@@ -380,7 +380,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
  *
  * Return: 0 when succeed, -1 on error.
  *
- * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
+ * ToDo: 1. Is it neceressary to check_free_sector after erasing ??
  */
 int INFTL_formatblock(struct INFTLrecord *inftl, int block)
 {
@@ -563,7 +563,7 @@ int INFTL_mount(struct INFTLrecord *s)
        /* Search for INFTL MediaHeader and Spare INFTL Media Header */
        if (find_boot_record(s) < 0) {
                printk(KERN_WARNING "INFTL: could not find valid boot record?\n");
-               return -1;
+               return -ENXIO;
        }
 
        /* Init the logical to physical table */
@@ -601,7 +601,7 @@ int INFTL_mount(struct INFTLrecord *s)
 
                for (chain_length = 0; ; chain_length++) {
 
-                       if ((chain_length == 0) && 
+                       if ((chain_length == 0) &&
                            (s->PUtable[block] != BLOCK_NOTEXPLORED)) {
                                /* Nothing to do here, onto next block */
                                break;
@@ -748,7 +748,7 @@ int INFTL_mount(struct INFTLrecord *s)
                                        "in virtual chain %d\n",
                                        s->PUtable[block], logical_block);
                                s->PUtable[block] = BLOCK_NIL;
-                                       
+
                        }
                        if (ANACtable[block] != ANAC) {
                                /*
index 44781a83b2e78b79b953d21f60bbf4fe12294466..48638c8097a56b9204bcec9dad9019121b681d40 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.55 2005/07/02 01:53:24 tpoynor Exp $
+# $Id: Kconfig,v 1.61 2005/11/07 11:14:26 gleixner Exp $
 
 menu "Mapping drivers for chip access"
        depends on MTD!=n
@@ -64,9 +64,9 @@ config MTD_SUN_UFLASH
        tristate "Sun Microsystems userflash support"
        depends on (SPARC32 || SPARC64) && MTD_CFI
        help
-         This provides a 'mapping' driver which supports the way in 
-         which user-programmable flash chips are connected on various 
-         Sun Microsystems boardsets.  This driver will require CFI support 
+         This provides a 'mapping' driver which supports the way in
+         which user-programmable flash chips are connected on various
+         Sun Microsystems boardsets.  This driver will require CFI support
          in the kernel, so if you did not enable CFI previously, do that now.
 
 config MTD_PNC2000
@@ -89,22 +89,22 @@ config MTD_NETSC520
        depends on X86 && MTD_CFI && MTD_PARTITIONS
        help
          This enables access routines for the flash chips on the AMD NetSc520
-         demonstration board. If you have one of these boards and would like 
+         demonstration board. If you have one of these boards and would like
          to use the flash chips on it, say 'Y'.
 
 config MTD_TS5500
        tristate "JEDEC Flash device mapped on Technologic Systems TS-5500"
-       depends on X86 && MTD_JEDECPROBE && MTD_PARTITIONS
+       depends on ELAN
+       select MTD_PARTITIONS
+       select MTD_JEDECPROBE
+       select MTD_CFI_AMDSTD
        help
          This provides a driver for the on-board flash of the Technologic
-         System's TS-5500 board. The flash is split into 3 partitions
+         System's TS-5500 board. The 2MB flash is split into 3 partitions
          which are accessed as separate MTD devices.
 
-         mtd0 and mtd2 are the two BIOS drives. Unfortunately the BIOS
-         uses a proprietary flash translation layer from General Software,
-         which is not supported (the drives cannot be mounted). You can
-         create your own file system (jffs for example), but the BIOS
-         won't be able to boot from it.
+         mtd0 and mtd2 are the two BIOS drives, which use the resident
+         flash disk (RFD) flash translation layer.
 
          mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL.
 
@@ -212,11 +212,18 @@ config MTD_NETtel
          Support for flash chips on NETtel/SecureEdge/SnapGear boards.
 
 config MTD_ALCHEMY
-       tristate '  AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' 
-       depends on MIPS && SOC_AU1X00
+       tristate '  AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support'
+       depends on SOC_AU1X00
        help
          Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
 
+config MTD_MTX1
+       tristate "4G Systems MTX-1 Flash device"
+       depends on MIPS && MIPS_MTX1
+       help
+         Flash memory access on 4G Systems MTX-1 Board. If you have one of
+         these boards and would like to use the flash chips on it, say 'Y'.
+
 config MTD_DILNETPC
        tristate "CFI Flash device mapped on DIL/Net PC"
        depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT
@@ -244,14 +251,14 @@ config MTD_L440GX
 
 config MTD_SBC8240
        tristate "Flash device on SBC8240"
-       depends on PPC32 && MTD_JEDECPROBE && 6xx && 8260
+       depends on MTD_JEDECPROBE && 8260
        help
           Flash access on the SBC8240 board from Wind River.  See
           <http://www.windriver.com/products/sbc8240/>
 
 config MTD_TQM8XXL
        tristate "CFI Flash device mapped on TQM8XXL"
-       depends on MTD_CFI && PPC32 && 8xx && TQM8xxL
+       depends on MTD_CFI && TQM8xxL
        help
          The TQM8xxL PowerPC board has up to two banks of CFI-compliant
          chips, currently uses AMD one. This 'mapping' driver supports
@@ -261,7 +268,7 @@ config MTD_TQM8XXL
 
 config MTD_RPXLITE
        tristate "CFI Flash device mapped on RPX Lite or CLLF"
-       depends on MTD_CFI && PPC32 && 8xx && (RPXCLASSIC || RPXLITE)
+       depends on MTD_CFI && (RPXCLASSIC || RPXLITE)
        help
          The RPXLite PowerPC board has CFI-compliant chips mapped in
          a strange sparse mapping. This 'mapping' driver supports that
@@ -271,7 +278,7 @@ config MTD_RPXLITE
 
 config MTD_MBX860
        tristate "System flash on MBX860 board"
-       depends on MTD_CFI && PPC32 && 8xx && MBX
+       depends on MTD_CFI && MBX
        help
          This enables access routines for the flash chips on the Motorola
          MBX860 board. If you have one of these boards and would like
@@ -279,7 +286,7 @@ config MTD_MBX860
 
 config MTD_DBOX2
        tristate "CFI Flash device mapped on D-Box2"
-       depends on PPC32 && 8xx && DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
+       depends on DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
        help
          This enables access routines for the flash chips on the Nokia/Sagem
          D-Box 2 board. If you have one of these boards and would like to use
@@ -287,14 +294,14 @@ config MTD_DBOX2
 
 config MTD_CFI_FLAGADM
        tristate "CFI Flash device mapping on FlagaDM"
-       depends on PPC32 && 8xx && MTD_CFI
+       depends on 8xx && MTD_CFI
        help
          Mapping for the Flaga digital module. If you don't have one, ignore
          this setting.
 
 config MTD_BEECH
        tristate "CFI Flash device mapped on IBM 405LP Beech"
-       depends on MTD_CFI && PPC32 && 40x && BEECH
+       depends on MTD_CFI && BEECH
        help
          This enables access routines for the flash chips on the IBM
          405LP Beech board. If you have one of these boards and would like
@@ -302,7 +309,7 @@ config MTD_BEECH
 
 config MTD_ARCTIC
        tristate "CFI Flash device mapped on IBM 405LP Arctic"
-       depends on MTD_CFI && PPC32 && 40x && ARCTIC2
+       depends on MTD_CFI && ARCTIC2
        help
          This enables access routines for the flash chips on the IBM 405LP
          Arctic board. If you have one of these boards and would like to
@@ -310,7 +317,7 @@ config MTD_ARCTIC
 
 config MTD_WALNUT
        tristate "Flash device mapped on IBM 405GP Walnut"
-       depends on MTD_JEDECPROBE && PPC32 && 40x && WALNUT
+       depends on MTD_JEDECPROBE && WALNUT
        help
          This enables access routines for the flash chips on the IBM 405GP
          Walnut board. If you have one of these boards and would like to
@@ -318,7 +325,7 @@ config MTD_WALNUT
 
 config MTD_EBONY
        tristate "Flash devices mapped on IBM 440GP Ebony"
-       depends on MTD_JEDECPROBE && PPC32 && 44x && EBONY
+       depends on MTD_JEDECPROBE && EBONY
        help
          This enables access routines for the flash chips on the IBM 440GP
          Ebony board. If you have one of these boards and would like to
@@ -326,7 +333,7 @@ config MTD_EBONY
 
 config MTD_OCOTEA
        tristate "Flash devices mapped on IBM 440GX Ocotea"
-       depends on MTD_CFI && PPC32 && 44x && OCOTEA
+       depends on MTD_CFI && OCOTEA
        help
          This enables access routines for the flash chips on the IBM 440GX
          Ocotea board. If you have one of these boards and would like to
@@ -334,12 +341,20 @@ config MTD_OCOTEA
 
 config MTD_REDWOOD
        tristate "CFI Flash devices mapped on IBM Redwood"
-       depends on MTD_CFI && PPC32 && 4xx && 40x && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 )
+       depends on MTD_CFI && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 )
        help
          This enables access routines for the flash chips on the IBM
          Redwood board. If you have one of these boards and would like to
          use the flash chips on it, say 'Y'.
 
+config MTD_TQM834x
+       tristate "Flash device mapped on TQ Components TQM834x Boards"
+       depends on MTD_CFI && TQM834x
+       help
+         This enables access routines for the flash chips on the
+         TQ Components TQM834x boards. If you have one of these boards
+         and would like to use the flash chips on it, say 'Y'.
+
 config MTD_CSTM_MIPS_IXX
        tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board"
        depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS
@@ -362,8 +377,8 @@ config MTD_CSTM_MIPS_IXX_START
        default "0x8000000"
        help
          This is the physical memory location that the MTD driver will
-         use for the flash chips on your particular target board. 
-         Refer to the memory map which should hopefully be in the 
+         use for the flash chips on your particular target board.
+         Refer to the memory map which should hopefully be in the
          documentation for your board.
 
 config MTD_CSTM_MIPS_IXX_LEN
@@ -371,7 +386,7 @@ config MTD_CSTM_MIPS_IXX_LEN
        depends on MTD_CSTM_MIPS_IXX
        default "0x4000000"
        help
-         This is the total length that the MTD driver will use for the 
+         This is the total length that the MTD driver will use for the
          flash chips on your particular board.  Refer to the memory
          map which should hopefully be in the documentation for your
          board.
@@ -405,14 +420,14 @@ config MTD_ARM_INTEGRATOR
 
 config MTD_CDB89712
        tristate "Cirrus CDB89712 evaluation board mappings"
-       depends on ARM && MTD_CFI && ARCH_CDB89712
+       depends on MTD_CFI && ARCH_CDB89712
        help
          This enables access to the flash or ROM chips on the CDB89712 board.
          If you have such a board, say 'Y'.
 
 config MTD_SA1100
        tristate "CFI Flash device mapped on StrongARM SA11x0"
-       depends on ARM && MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS
+       depends on MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS
        help
          This enables access to the flash chips on most platforms based on
          the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
@@ -420,13 +435,13 @@ config MTD_SA1100
 
 config MTD_IPAQ
        tristate "CFI Flash device mapped on Compaq/HP iPAQ"
-       depends on ARM && IPAQ_HANDHELD && MTD_CFI
+       depends on IPAQ_HANDHELD && MTD_CFI
        help
          This provides a driver for the on-board flash of the iPAQ.
 
 config MTD_DC21285
        tristate "CFI Flash device mapped on DC21285 Footbridge"
-       depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS
+       depends on MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS
        help
          This provides a driver for the flash accessed using Intel's
          21285 bridge used with Intel's StrongARM processors. More info at
@@ -434,33 +449,33 @@ config MTD_DC21285
 
 config MTD_IQ80310
        tristate "CFI Flash device mapped on the XScale IQ80310 board"
-       depends on ARM && MTD_CFI && ARCH_IQ80310
+       depends on MTD_CFI && ARCH_IQ80310
        help
          This enables access routines for the flash chips on the Intel XScale
-         IQ80310 evaluation board. If you have one of these boards and would 
+         IQ80310 evaluation board. If you have one of these boards and would
          like to use the flash chips on it, say 'Y'.
 
 config MTD_IXP4XX
        tristate "CFI Flash device mapped on Intel IXP4xx based systems"
-       depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX
+       depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX
        help
-         This enables MTD access to flash devices on platforms based 
+         This enables MTD access to flash devices on platforms based
          on Intel's IXP4xx family of network processors such as the
          IXDP425 and Coyote. If you have an IXP4xx based board and
          would like to use the flash chips on it, say 'Y'.
 
 config MTD_IXP2000
        tristate "CFI Flash device mapped on Intel IXP2000 based systems"
-       depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000
+       depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000
        help
-         This enables MTD access to flash devices on platforms based 
+         This enables MTD access to flash devices on platforms based
          on Intel's IXP2000 family of network processors such as the
          IXDP425 and Coyote. If you have an IXP2000 based board and
          would like to use the flash chips on it, say 'Y'.
 
 config MTD_EPXA10DB
        tristate "CFI Flash device mapped on Epxa10db"
-       depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT
+       depends on MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT
        help
          This enables support for the flash devices on the Altera
          Excalibur XA10 Development Board. If you are building a kernel
@@ -468,21 +483,21 @@ config MTD_EPXA10DB
 
 config MTD_FORTUNET
        tristate "CFI Flash device mapped on the FortuNet board"
-       depends on ARM && MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET
+       depends on MTD_CFI && MTD_PARTITIONS && SA1100_FORTUNET
        help
          This enables access to the Flash on the FortuNet board.  If you
          have such a board, say 'Y'.
 
 config MTD_AUTCPU12
        tristate "NV-RAM mapping AUTCPU12 board"
-       depends on ARM && ARCH_AUTCPU12
+       depends on ARCH_AUTCPU12
        help
          This enables access to the NV-RAM on autronix autcpu12 board.
          If you have such a board, say 'Y'.
 
 config MTD_EDB7312
        tristate "CFI Flash device mapped on EDB7312"
-       depends on ARM && MTD_CFI
+       depends on ARCH_EDB7312 && MTD_CFI
        help
          This enables access to the CFI Flash on the Cogent EDB7312 board.
          If you have such a board, say 'Y' here.
@@ -496,7 +511,7 @@ config MTD_IMPA7
 
 config MTD_CEIVA
        tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame"
-       depends on ARM && MTD_JEDECPROBE && ARCH_CEIVA
+       depends on MTD_JEDECPROBE && ARCH_CEIVA
        help
          This enables access to the flash chips on the Ceiva/Polaroid
          PhotoMax Digital Picture Frame.
@@ -504,25 +519,31 @@ config MTD_CEIVA
 
 config MTD_NOR_TOTO
        tristate "NOR Flash device on TOTO board"
-       depends on ARM && ARCH_OMAP && OMAP_TOTO
+       depends on ARCH_OMAP && OMAP_TOTO
        help
          This enables access to the NOR flash on the Texas Instruments
          TOTO board.
 
 config MTD_H720X
        tristate "Hynix evaluation board mappings"
-       depends on ARM && MTD_CFI && ( ARCH_H7201 || ARCH_H7202 )
+       depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 )
        help
          This enables access to the flash chips on the Hynix evaluation boards.
          If you have such a board, say 'Y'.
 
 config MTD_MPC1211
        tristate "CFI Flash device mapped on Interface MPC-1211"
-       depends on SUPERH && SH_MPC1211 && MTD_CFI
+       depends on SH_MPC1211 && MTD_CFI
        help
          This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02).
          If you have such a board, say 'Y'.
 
+config MTD_PQ2FADS
+       tristate "JEDEC flash SIMM mapped on PQ2FADS and 8272ADS boards"
+       depends on (ADS8272 || PQ2FADS) && MTD_PARTITIONS && MTD_JEDECPROBE && MTD_PHYSMAP && MTD_CFI_GEOMETRY && MTD_CFI_INTELEXT
+       help
+        This enables access to flash SIMM on PQ2FADS-like boards
+
 config MTD_OMAP_NOR
        tristate "TI OMAP board mappings"
        depends on MTD_CFI && ARCH_OMAP
index 7bcbc49e329f24c94ec7d1ee714c29e8ecab1a5f..7d9e940a1dcd7e5ddc20621bcae3ece4f5f0739e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile.common,v 1.30 2005/07/02 01:53:24 tpoynor Exp $
+# $Id: Makefile.common,v 1.34 2005/11/07 11:14:26 gleixner Exp $
 
 ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
 obj-$(CONFIG_MTD)              += map_funcs.o
@@ -26,7 +26,7 @@ obj-$(CONFIG_MTD_MAINSTONE)   += mainstone-flash.o
 obj-$(CONFIG_MTD_MBX860)       += mbx860.o
 obj-$(CONFIG_MTD_CEIVA)                += ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)      += octagon-5066.o
-obj-$(CONFIG_MTD_PHYSMAP)      += physmap.o 
+obj-$(CONFIG_MTD_PHYSMAP)      += physmap.o
 obj-$(CONFIG_MTD_PNC2000)      += pnc2000.o
 obj-$(CONFIG_MTD_PCMCIA)       += pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)      += rpxlite.o
@@ -70,3 +70,6 @@ obj-$(CONFIG_MTD_DMV182)      += dmv182.o
 obj-$(CONFIG_MTD_SHARP_SL)     += sharpsl-flash.o
 obj-$(CONFIG_MTD_PLATRAM)      += plat-ram.o
 obj-$(CONFIG_MTD_OMAP_NOR)     += omap_nor.o
+obj-$(CONFIG_MTD_PQ2FADS)      += pq2fads.o
+obj-$(CONFIG_MTD_MTX1)         += mtx-1_flash.o
+obj-$(CONFIG_MTD_TQM834x)      += tqm834x.o
index 27fd2a3c3b600721264419a81110c440b665d25b..a57791a6ce402a754e32f6dec0b40523ffe11eda 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * Flash memory access on AMD Alchemy evaluation boards
- * 
- * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $
+ *
+ * $Id: alchemy-flash.c,v 1.2 2005/11/07 11:14:26 gleixner Exp $
  *
  * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
- * 
+ *
  */
 
 #include <linux/config.h>
@@ -22,7 +22,7 @@
 #ifdef         DEBUG_RW
 #define        DBG(x...)       printk(x)
 #else
-#define        DBG(x...)       
+#define        DBG(x...)
 #endif
 
 #ifdef CONFIG_MIPS_PB1000
@@ -136,7 +136,7 @@ int __init alchemy_mtd_init(void)
        int nb_parts = 0;
        unsigned long window_addr;
        unsigned long window_size;
-       
+
        /* Default flash buswidth */
        alchemy_map.bankwidth = BOARD_FLASH_WIDTH;
 
@@ -161,7 +161,7 @@ int __init alchemy_mtd_init(void)
         * 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", 
+       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);
index 9a64149f431d2a547383bd97b1861e81fafd2596..c350878d4592978ffece3fe1b1e97cb4caae5187 100644 (file)
@@ -2,7 +2,7 @@
  * amd76xrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $
+ * $Id: amd76xrom.c,v 1.21 2005/11/07 11:14:26 gleixner Exp $
  */
 
 #include <linux/module.h>
@@ -70,7 +70,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window)
                list_del(&map->list);
                kfree(map);
        }
-       if (window->rsrc.parent) 
+       if (window->rsrc.parent)
                release_resource(&window->rsrc);
 
        if (window->virt) {
@@ -107,7 +107,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
                window->phys = 0xffff0000; /* 64KiB */
        }
        window->size = 0xffffffffUL - window->phys + 1UL;
-       
+
        /*
         * Try to reserve the window mem region.  If this fails then
         * it is likely due to a fragment of the window being
@@ -138,7 +138,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
        /* Enable writes through the rom window */
        pci_read_config_byte(pdev, 0x40, &byte);
        pci_write_config_byte(pdev, 0x40, byte | 1);
-       
+
        /* FIXME handle registers 0x80 - 0x8C the bios region locks */
 
        /* For write accesses caches are useless */
@@ -186,7 +186,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
                        MOD_NAME, map->map.phys);
 
                /* There is no generic VPP support */
-               for(map->map.bankwidth = 32; map->map.bankwidth; 
+               for(map->map.bankwidth = 32; map->map.bankwidth;
                        map->map.bankwidth >>= 1)
                {
                        char **probe_type;
@@ -239,7 +239,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
                for(i = 0; i < cfi->numchips; i++) {
                        cfi->chips[i].start += offset;
                }
-               
+
                /* Now that the mtd devices is complete claim and export it */
                map->mtd->owner = THIS_MODULE;
                if (add_mtd_device(map->mtd)) {
@@ -277,9 +277,9 @@ static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
 }
 
 static struct pci_device_id amd76xrom_pci_tbl[] = {
-       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,  
+       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410,
                PCI_ANY_ID, PCI_ANY_ID, },
-       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,  
+       { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440,
                PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */
        { 0, }
index 777276fd0e151ff04f068a066d628f57b1050855..d95ae582fbe9a4cc275919153fac944e56e4b664 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: arctic-mtd.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
- * 
- * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for 
+ * $Id: arctic-mtd.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
+ *
+ * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for
  *                              IBM 405LP Arctic boards.
  *
  * This program is free software; you can redistribute it and/or modify
index cf362ccc3c8ed57c029dd8dbd8aaadbb69a5a451..7ed3424dd959bb2aa3ce42af93a4dc25ad74f25f 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * NV-RAM memory access on autcpu12 
+ * NV-RAM memory access on autcpu12
  * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
  *
- * $Id: autcpu12-nvram.c,v 1.8 2004/11/04 13:24:14 gleixner Exp $ 
+ * $Id: autcpu12-nvram.c,v 1.9 2005/11/07 11:14:26 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
@@ -55,10 +55,10 @@ static int __init init_autcpu12_sram (void)
        }
        simple_map_init(&autcpu_sram_map);
 
-       /* 
-        * Check for 32K/128K 
-        * read ofs 0 
-        * read ofs 0x10000 
+       /*
+        * Check for 32K/128K
+        * read ofs 0
+        * read ofs 0x10000
         * Write complement to ofs 0x100000
         * Read and check result on ofs 0x0
         * Restore contents
@@ -66,7 +66,7 @@ static int __init init_autcpu12_sram (void)
        save0 = map_read32(&autcpu12_sram_map,0);
        save1 = map_read32(&autcpu12_sram_map,0x10000);
        map_write32(&autcpu12_sram_map,~save0,0x10000);
-       /* if we find this pattern on 0x0, we have 32K size 
+       /* if we find this pattern on 0x0, we have 32K size
         * restore contents and exit
         */
        if ( map_read32(&autcpu12_sram_map,0) != save0) {
@@ -89,7 +89,7 @@ map:
 
        sram_mtd->owner = THIS_MODULE;
        sram_mtd->erasesize = 16;
-       
+
        if (add_mtd_device(sram_mtd)) {
                printk("NV-RAM device addition failed\n");
                err = -ENOMEM;
@@ -97,7 +97,7 @@ map:
        }
 
        printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
-               
+
        return 0;
 
 out_probe:
index 8c19d722ac796178c9d0cda7ecd3de29c8223927..b7858eb935347acb767d2961de8896027b4b1674 100644 (file)
@@ -9,7 +9,7 @@
  *     20-Sep-2004  BJD  Initial version
  *     17-Jan-2005  BJD  Add whole device if no partitions found
  *
- * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $
+ * $Id: bast-flash.c,v 1.5 2005/11/07 11:14:26 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
@@ -75,7 +75,7 @@ static void bast_flash_setrw(int to)
 
        local_irq_save(flags);
        val = __raw_readb(BAST_VA_CTRL3);
-       
+
        if (to)
                val |= BAST_CPLD_CTRL3_ROMWEN;
        else
@@ -93,7 +93,7 @@ static int bast_flash_remove(struct device *dev)
 
        dev_set_drvdata(dev, NULL);
 
-       if (info == NULL) 
+       if (info == NULL)
                return 0;
 
        if (info->map.virt != NULL)
@@ -110,7 +110,7 @@ static int bast_flash_remove(struct device *dev)
                release_resource(info->area);
                kfree(info->area);
        }
-       
+
        kfree(info);
 
        return 0;
@@ -137,15 +137,15 @@ static int bast_flash_probe(struct device *dev)
 
        info->map.phys = res->start;
        info->map.size = res->end - res->start + 1;
-       info->map.name = dev->bus_id;   
+       info->map.name = dev->bus_id;
        info->map.bankwidth = 2;
-       
+
        if (info->map.size > AREA_MAXSIZE)
                info->map.size = AREA_MAXSIZE;
 
        pr_debug("%s: area %08lx, size %ld\n", __FUNCTION__,
                 info->map.phys, info->map.size);
-       
+
        info->area = request_mem_region(res->start, info->map.size,
                                        pdev->name);
        if (info->area == NULL) {
@@ -162,7 +162,7 @@ static int bast_flash_probe(struct device *dev)
                err = -EIO;
                goto exit_error;
        }
+
        simple_map_init(&info->map);
 
        /* enable the write to the flash area */
@@ -187,7 +187,7 @@ static int bast_flash_probe(struct device *dev)
        err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
        if (err > 0) {
                err = add_mtd_partitions(info->mtd, info->partitions, err);
-               if (err) 
+               if (err)
                        printk(KERN_ERR PFX "cannot add/parse partitions\n");
        } else {
                err = add_mtd_device(info->mtd);
@@ -205,6 +205,7 @@ static int bast_flash_probe(struct device *dev)
 
 static struct device_driver bast_flash_driver = {
        .name           = "bast-nor",
+       .owner          = THIS_MODULE,
        .bus            = &platform_bus_type,
        .probe          = bast_flash_probe,
        .remove         = bast_flash_remove,
index 5e79c9d5da2b3a4537bbb516c2c59127dc7b12c3..5df7361d14079e2d8aae78ea02b76ac59555d038 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: beech-mtd.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $
- * 
- * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for 
+ * $Id: beech-mtd.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $
+ *
+ * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for
  *                              IBM 405LP Beech boards.
  *
  * This program is free software; you can redistribute it and/or modify
index ab15dac2f9360168ab3893499c3ef8ca0f1a103a..9f17bb6c5a9d388714c8822ea412230d918b6b38 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Flash on Cirrus CDB89712
  *
- * $Id: cdb89712.c,v 1.10 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: cdb89712.c,v 1.11 2005/11/07 11:14:26 gleixner Exp $
  */
 
 #include <linux/module.h>
@@ -37,13 +37,13 @@ struct resource cdb89712_flash_resource = {
 static int __init init_cdb89712_flash (void)
 {
        int err;
-       
+
        if (request_resource (&ioport_resource, &cdb89712_flash_resource)) {
                printk(KERN_NOTICE "Failed to reserve Cdb89712 FLASH space\n");
                err = -EBUSY;
                goto out;
        }
-       
+
        cdb89712_flash_map.virt = ioremap(FLASH_START, FLASH_SIZE);
        if (!cdb89712_flash_map.virt) {
                printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n");
@@ -64,13 +64,13 @@ static int __init init_cdb89712_flash (void)
        }
 
        flash_mtd->owner = THIS_MODULE;
-       
+
        if (add_mtd_device(flash_mtd)) {
                printk("FLASH device addition failed\n");
                err = -ENOMEM;
                goto out_probe;
        }
-               
+
        return 0;
 
 out_probe:
@@ -107,13 +107,13 @@ struct resource cdb89712_sram_resource = {
 static int __init init_cdb89712_sram (void)
 {
        int err;
-       
+
        if (request_resource (&ioport_resource, &cdb89712_sram_resource)) {
                printk(KERN_NOTICE "Failed to reserve Cdb89712 SRAM space\n");
                err = -EBUSY;
                goto out;
        }
-       
+
        cdb89712_sram_map.virt = ioremap(SRAM_START, SRAM_SIZE);
        if (!cdb89712_sram_map.virt) {
                printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n");
@@ -130,13 +130,13 @@ static int __init init_cdb89712_sram (void)
 
        sram_mtd->owner = THIS_MODULE;
        sram_mtd->erasesize = 16;
-       
+
        if (add_mtd_device(sram_mtd)) {
                printk("SRAM device addition failed\n");
                err = -ENOMEM;
                goto out_probe;
        }
-               
+
        return 0;
 
 out_probe:
@@ -175,13 +175,13 @@ struct resource cdb89712_bootrom_resource = {
 static int __init init_cdb89712_bootrom (void)
 {
        int err;
-       
+
        if (request_resource (&ioport_resource, &cdb89712_bootrom_resource)) {
                printk(KERN_NOTICE "Failed to reserve Cdb89712 BOOTROM space\n");
                err = -EBUSY;
                goto out;
        }
-       
+
        cdb89712_bootrom_map.virt = ioremap(BOOTROM_START, BOOTROM_SIZE);
        if (!cdb89712_bootrom_map.virt) {
                printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n");
@@ -198,13 +198,13 @@ static int __init init_cdb89712_bootrom (void)
 
        bootrom_mtd->owner = THIS_MODULE;
        bootrom_mtd->erasesize = 0x10000;
-       
+
        if (add_mtd_device(bootrom_mtd)) {
                printk("BootROM device addition failed\n");
                err = -ENOMEM;
                goto out_probe;
        }
-               
+
        return 0;
 
 out_probe:
@@ -225,16 +225,16 @@ out:
 static int __init init_cdb89712_maps(void)
 {
 
-               printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n  Flash 0x%x at 0x%x\n  SRAM 0x%x at 0x%x\n  BootROM 0x%x at 0x%x\n", 
+               printk(KERN_INFO "Cirrus CDB89712 MTD mappings:\n  Flash 0x%x at 0x%x\n  SRAM 0x%x at 0x%x\n  BootROM 0x%x at 0x%x\n",
               FLASH_SIZE, FLASH_START, SRAM_SIZE, SRAM_START, BOOTROM_SIZE, BOOTROM_START);
 
        init_cdb89712_flash();
        init_cdb89712_sram();
        init_cdb89712_bootrom();
-       
+
        return 0;
 }
-       
+
 
 static void __exit cleanup_cdb89712_maps(void)
 {
@@ -244,7 +244,7 @@ static void __exit cleanup_cdb89712_maps(void)
                iounmap((void *)cdb89712_sram_map.virt);
                release_resource (&cdb89712_sram_resource);
        }
-       
+
        if (flash_mtd) {
                del_mtd_device(flash_mtd);
                map_destroy(flash_mtd);
index f72e4f894b321efeb2a457d59c8be45733abc28f..6a8c0415bde87b6c7432f5307d84e8a301f0990e 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *  Copyright Â© 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is>
  *
- *  $Id: cfi_flagadm.c,v 1.14 2004/11/04 13:24:14 gleixner Exp $
- *  
+ *  $Id: cfi_flagadm.c,v 1.15 2005/11/07 11:14:26 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
@@ -42,7 +42,7 @@
  */
 
 #define FLASH_PHYS_ADDR 0x40000000
-#define FLASH_SIZE 0x400000  
+#define FLASH_SIZE 0x400000
 
 #define FLASH_PARTITION0_ADDR 0x00000000
 #define FLASH_PARTITION0_SIZE 0x00020000
@@ -79,7 +79,7 @@ struct mtd_partition flagadm_parts[] = {
                .offset =       FLASH_PARTITION2_ADDR,
                .size =         FLASH_PARTITION2_SIZE
        },
-       {       
+       {
                .name =         "Persistant storage",
                .offset =       FLASH_PARTITION3_ADDR,
                .size =         FLASH_PARTITION3_SIZE
@@ -91,10 +91,10 @@ struct mtd_partition flagadm_parts[] = {
 static struct mtd_info *mymtd;
 
 int __init init_flagadm(void)
-{      
+{
        printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n",
                        FLASH_SIZE, FLASH_PHYS_ADDR);
-       
+
        flagadm_map.phys = FLASH_PHYS_ADDR;
        flagadm_map.virt = ioremap(FLASH_PHYS_ADDR,
                                        FLASH_SIZE);
index ae9252fbf1760461f05217aa3d33adca8dba78b7..a370953c1513a2a6c1a24a9f551d7300ea52b47b 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * $Id: cstm_mips_ixx.c,v 1.12 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: cstm_mips_ixx.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
  *
  * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
  * Config with both CFI and JEDEC device support.
  *
- * Basically physmap.c with the addition of partitions and 
+ * Basically physmap.c with the addition of partitions and
  * an array of mapping info to accomodate more than one flash type per board.
  *
  * Copyright 2000 MontaVista Software Inc.
@@ -69,7 +69,7 @@ void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
                        __u16   data;
                        __u8    data1;
                        static u8 first = 1;
-               
+
                        // Set GPIO port B pin3 to high
                        data = *(__u16 *)(CC_GPBCR);
                        data = (data & 0xff0f) | 0x0040;
@@ -85,7 +85,7 @@ void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
        } else {
                if (!--vpp_count) {
                        __u16   data;
-               
+
                        // Set GPIO port B pin3 to high
                        data = *(__u16 *)(CC_GPBCR);
                        data = (data & 0xff3f) | 0x0040;
@@ -109,8 +109,8 @@ struct cstm_mips_ixx_info {
 };
 
 #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
-#define PHYSMAP_NUMBER  1  // number of board desc structs needed, one per contiguous flash type 
-const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = 
+#define PHYSMAP_NUMBER  1  // number of board desc structs needed, one per contiguous flash type
+const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
 {
     {   // 28F128J3A in 2x16 configuration
         "big flash",     // name
@@ -131,10 +131,10 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP
 },
 };
 #else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
-#define PHYSMAP_NUMBER  1  // number of board desc structs needed, one per contiguous flash type 
-const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] = 
+#define PHYSMAP_NUMBER  1  // number of board desc structs needed, one per contiguous flash type
+const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
 {
-    {  
+    {
         "MTD flash",                   // name
        CONFIG_MTD_CSTM_MIPS_IXX_START,      // window_addr
        CONFIG_MTD_CSTM_MIPS_IXX_LEN,        // window_size
@@ -144,7 +144,7 @@ const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
 
 };
 static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
-{ 
+{
        {
                .name = "main partition",
                .size =  CONFIG_MTD_CSTM_MIPS_IXX_LEN,
@@ -165,7 +165,7 @@ int __init init_cstm_mips_ixx(void)
 
        /* Initialize mapping */
        for (i=0;i<PHYSMAP_NUMBER;i++) {
-               printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", 
+               printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n",
                       cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
 
 
@@ -235,7 +235,7 @@ void PCISetULongByOffset(__u32 DevNumber, __u32 FuncNumber, __u32 Offset, __u32
 
        offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ;
 
-       *(__u32 *)CC_CONFADDR = offset; 
+       *(__u32 *)CC_CONFADDR = offset;
        *(__u32 *)CC_CONFDATA = data;
 }
 void setup_ITE_IVR_flash()
index d850a27a4b59e4b7a44f4b34f837110b65a7f954..49d90542fc752859bd0f80ec083ae75044997c03 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dbox2-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: dbox2-flash.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
  *
  * D-Box 2 flash driver
  */
 static struct mtd_partition partition_info[]= {
        {
        .name           = "BR bootloader",
-       .size           = 128 * 1024, 
-       .offset         = 0,                  
+       .size           = 128 * 1024,
+       .offset         = 0,
        .mask_flags     = MTD_WRITEABLE
        },
        {
        .name           = "FLFS (U-Boot)",
-       .size           = 128 * 1024, 
-       .offset         = MTDPART_OFS_APPEND, 
+       .size           = 128 * 1024,
+       .offset         = MTDPART_OFS_APPEND,
        .mask_flags     = 0
        },
        {
-       .name           = "Root (SquashFS)",    
-       .size           = 7040 * 1024, 
-       .offset         = MTDPART_OFS_APPEND, 
+       .name           = "Root (SquashFS)",
+       .size           = 7040 * 1024,
+       .offset         = MTDPART_OFS_APPEND,
        .mask_flags     = 0
        },
        {
        .name           = "var (JFFS2)",
-       .size           = 896 * 1024, 
-       .offset         = MTDPART_OFS_APPEND, 
+       .size           = 896 * 1024,
+       .offset         = MTDPART_OFS_APPEND,
        .mask_flags     = 0
        },
        {
-       .name           = "Flash without bootloader",   
-       .size           = MTDPART_SIZ_FULL, 
-       .offset         = 128 * 1024, 
+       .name           = "Flash without bootloader",
+       .size           = MTDPART_SIZ_FULL,
+       .offset         = 128 * 1024,
        .mask_flags     = 0
        },
        {
-       .name           = "Complete Flash",     
-       .size           = MTDPART_SIZ_FULL, 
-       .offset         = 0, 
+       .name           = "Complete Flash",
+       .size           = MTDPART_SIZ_FULL,
+       .offset         = 0,
        .mask_flags     = MTD_WRITEABLE
        }
 };
@@ -88,16 +88,16 @@ int __init init_dbox2_flash(void)
        if (!mymtd) {
            // Probe for single Intel 28F640
            dbox2_flash_map.bankwidth = 2;
-       
+
            mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
        }
-           
+
        if (mymtd) {
                mymtd->owner = THIS_MODULE;
 
                 /* Create MTD devices for each partition. */
                add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
-               
+
                return 0;
        }
 
index e5b74169fde621167b96aa47cb127f7b098296a8..701620b6baede850569e5516a1d2683a86323d6f 100644 (file)
@@ -4,8 +4,8 @@
  * (C) 2000  Nicolas Pitre <nico@cam.org>
  *
  * This code is GPL
- * 
- * $Id: dc21285.c,v 1.22 2004/11/01 13:39:21 rmk Exp $
+ *
+ * $Id: dc21285.c,v 1.24 2005/11/07 11:14:26 gleixner Exp $
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -27,9 +27,9 @@
 static struct mtd_info *dc21285_mtd;
 
 #ifdef CONFIG_ARCH_NETWINDER
-/* 
+/*
  * This is really ugly, but it seams to be the only
- * realiable way to do it, as the cpld state machine 
+ * realiable way to do it, as the cpld state machine
  * is unpredictible. So we have a 25us penalty per
  * write access.
  */
@@ -150,7 +150,7 @@ static struct map_info dc21285_map = {
 static struct mtd_partition *dc21285_parts;
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 #endif
-  
+
 static int __init init_dc21285(void)
 {
 
@@ -160,20 +160,20 @@ static int __init init_dc21285(void)
 
        /* Determine bankwidth */
        switch (*CSR_SA110_CNTL & (3<<14)) {
-               case SA110_CNTL_ROMWIDTH_8: 
+               case SA110_CNTL_ROMWIDTH_8:
                        dc21285_map.bankwidth = 1;
                        dc21285_map.read = dc21285_read8;
                        dc21285_map.write = dc21285_write8;
                        dc21285_map.copy_to = dc21285_copy_to_8;
                        break;
-               case SA110_CNTL_ROMWIDTH_16: 
-                       dc21285_map.bankwidth = 2; 
+               case SA110_CNTL_ROMWIDTH_16:
+                       dc21285_map.bankwidth = 2;
                        dc21285_map.read = dc21285_read16;
                        dc21285_map.write = dc21285_write16;
                        dc21285_map.copy_to = dc21285_copy_to_16;
                        break;
-               case SA110_CNTL_ROMWIDTH_32: 
-                       dc21285_map.bankwidth = 4; 
+               case SA110_CNTL_ROMWIDTH_32:
+                       dc21285_map.bankwidth = 4;
                        dc21285_map.read = dc21285_read32;
                        dc21285_map.write = dc21285_write32;
                        dc21285_map.copy_to = dc21285_copy_to_32;
@@ -201,20 +201,20 @@ static int __init init_dc21285(void)
        if (!dc21285_mtd) {
                iounmap(dc21285_map.virt);
                return -ENXIO;
-       }       
-       
+       }
+
        dc21285_mtd->owner = THIS_MODULE;
 
 #ifdef CONFIG_MTD_PARTITIONS
        nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0);
        if (nrparts > 0)
                add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts);
-       else    
-#endif 
+       else
+#endif
                add_mtd_device(dc21285_mtd);
-                       
+
        if(machine_is_ebsa285()) {
-               /* 
+               /*
                 * Flash timing is determined with bits 19-16 of the
                 * CSR_SA110_CNTL.  The value is the number of wait cycles, or
                 * 0 for 16 cycles (the default).  Cycles are 20 ns.
@@ -227,7 +227,7 @@ static int __init init_dc21285(void)
                /* tristate time */
                *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
        }
-       
+
        return 0;
 }
 
index f99519692cb7815d369577c0c54ede59e7332f1f..b51c757817d819c3cc4352ed773df591a905222d 100644 (file)
@@ -14,7 +14,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: dilnetpc.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: dilnetpc.c,v 1.20 2005/11/07 11:14:26 gleixner Exp $
  *
  * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
  * featuring the AMD Elan SC410 processor. There are two variants of this
@@ -272,13 +272,13 @@ static struct map_info dnpc_map = {
 
 static struct mtd_partition partition_info[]=
 {
-       { 
-               .name =         "ADNP boot", 
-               .offset =       0, 
+       {
+               .name =         "ADNP boot",
+               .offset =       0,
                .size =         0xf0000,
        },
-       { 
-               .name =         "ADNP system BIOS", 
+       {
+               .name =         "ADNP system BIOS",
                .offset =       MTDPART_OFS_NXTBLK,
                .size =         0x10000,
 #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
@@ -291,7 +291,7 @@ static struct mtd_partition partition_info[]=
                .size =         0x2f0000,
        },
        {
-               .name =         "ADNP system BIOS entry", 
+               .name =         "ADNP system BIOS entry",
                .offset =       MTDPART_OFS_NXTBLK,
                .size =         MTDPART_SIZ_FULL,
 #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
@@ -325,9 +325,9 @@ static struct mtd_info *merged_mtd;
 
 static struct mtd_partition higlvl_partition_info[]=
 {
-       { 
-               .name =         "ADNP boot block", 
-               .offset =       0, 
+       {
+               .name =         "ADNP boot block",
+               .offset =       0,
                .size =         CONFIG_MTD_DILNETPC_BOOTSIZE,
        },
        {
@@ -335,8 +335,8 @@ static struct mtd_partition higlvl_partition_info[]=
                .offset =       MTDPART_OFS_NXTBLK,
                .size =         ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000,
        },
-       { 
-               .name =         "ADNP system BIOS + BIOS Entry", 
+       {
+               .name =         "ADNP system BIOS + BIOS Entry",
                .offset =       MTDPART_OFS_NXTBLK,
                .size =         MTDPART_SIZ_FULL,
 #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED
@@ -371,7 +371,7 @@ static int __init init_dnpc(void)
 
        /*
        ** determine hardware (DNP/ADNP/invalid)
-       */      
+       */
        if((is_dnp = dnp_adnp_probe()) < 0)
                return -ENXIO;
 
@@ -397,13 +397,13 @@ static int __init init_dnpc(void)
                ++dnpc_map.name;
                for(i = 0; i < NUM_PARTITIONS; i++)
                        ++partition_info[i].name;
-               higlvl_partition_info[1].size = DNP_WINDOW_SIZE - 
+               higlvl_partition_info[1].size = DNP_WINDOW_SIZE -
                        CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000;
                for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++)
                        ++higlvl_partition_info[i].name;
        }
 
-       printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", 
+       printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n",
                is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys);
 
        dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size);
@@ -436,7 +436,7 @@ static int __init init_dnpc(void)
                iounmap(dnpc_map.virt);
                return -ENXIO;
        }
-               
+
        mymtd->owner = THIS_MODULE;
 
        /*
index b9bc63503e268c6f0c308215ca5e9119d24fa70c..b993ac01a9a5f8b10b6048e1e9ab75454cf3cddf 100644 (file)
@@ -1,10 +1,10 @@
 
 /*
  * drivers/mtd/maps/svme182.c
- * 
+ *
  * Flash map driver for the Dy4 SVME182 board
- * 
- * $Id: dmv182.c,v 1.5 2004/11/04 13:24:14 gleixner Exp $
+ *
+ * $Id: dmv182.c,v 1.6 2005/11/07 11:14:26 gleixner Exp $
  *
  * Copyright 2003-2004, TimeSys Corporation
  *
@@ -104,7 +104,7 @@ static int __init init_svme182(void)
        partitions = svme182_partitions;
 
        svme182_map.virt = ioremap(FLASH_BASE_ADDR, svme182_map.size);
-               
+
        if (svme182_map.virt == 0) {
                printk("Failed to ioremap FLASH memory area.\n");
                return -EIO;
index b9d9cf4854b62e5f17abdc9b0f5597a5b1ea19f0..c0daf58357cacaba92fcf0550bac25d84e286eaf 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * $Id: ebony.c,v 1.15 2004/12/09 18:39:54 holindho Exp $
- * 
+ * $Id: ebony.c,v 1.16 2005/11/07 11:14:26 gleixner Exp $
+ *
  * Mapping for Ebony user flash
  *
  * Matt Porter <mporter@kernel.crashing.org>
@@ -85,7 +85,7 @@ int __init init_ebony(void)
                small_flash_base = EBONY_SMALL_FLASH_LOW2;
        else
                small_flash_base = EBONY_SMALL_FLASH_LOW1;
-                       
+
        if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
                        !EBONY_ONBRD_FLASH_EN(fpga0_reg))
                large_flash_base = EBONY_LARGE_FLASH_LOW;
index 8b0da394f3fa5224274fa30896711925cc8ad5aa..b48a3473ffc16103f65947f471e5d35169118966 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * $Id: edb7312.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: edb7312.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $
  *
  * Handle mapping of the NOR flash on Cogent EDB7312 boards
  *
  * Copyright 2002 SYSGO Real-Time Solutions GmbH
- * 
+ *
  * 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.
@@ -46,7 +46,7 @@ struct map_info edb7312nor_map = {
 #ifdef CONFIG_MTD_PARTITIONS
 
 /*
- * MTD partitioning stuff 
+ * MTD partitioning stuff
  */
 static struct mtd_partition static_partitions[3] =
 {
@@ -80,7 +80,7 @@ int __init init_edb7312nor(void)
        const char **type;
        const char *part_type = 0;
 
-               printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", 
+               printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n",
               WINDOW_SIZE, WINDOW_ADDR);
        edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
@@ -88,7 +88,7 @@ int __init init_edb7312nor(void)
                printk(MSG_PREFIX "failed to ioremap\n");
                return -EIO;
        }
-       
+
        simple_map_init(&edb7312nor_map);
 
        mymtd = 0;
index 1df6188926b3aa81e99b402bdaa265d4fa666d16..265b079fe93466d91f0a966524e155cc3d5fff32 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 2001 Altera Corporation
  *  Copyright (C) 2001 Red Hat, Inc.
  *
- * $Id: epxa10db-flash.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ 
+ * $Id: epxa10db-flash.c,v 1.15 2005/11/07 11:14: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
@@ -62,7 +62,7 @@ static const char *probes[] = { "RedBoot", "afs", NULL };
 static int __init epxa_mtd_init(void)
 {
        int i;
-       
+
        printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
 
        epxa_map.virt = ioremap(FLASH_START, FLASH_SIZE);
@@ -126,8 +126,8 @@ static void __exit epxa_mtd_cleanup(void)
 }
 
 
-/* 
- * This will do for now, once we decide which bootldr we're finally 
+/*
+ * This will do for now, once we decide which bootldr we're finally
  * going to use then we'll remove this function and do it properly
  *
  * Partions are currently (as offsets from base of flash):
@@ -140,7 +140,7 @@ static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_pa
        struct mtd_partition *parts;
        int ret, i;
        int npartitions = 0;
-       char *names; 
+       char *names;
        const char *name = "jffs";
 
        printk("Using default partitions for %s\n",BOARD_NAME);
@@ -152,7 +152,7 @@ static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_pa
                goto out;
        }
        i=0;
-       names = (char *)&parts[npartitions];    
+       names = (char *)&parts[npartitions];
        parts[i].name = names;
        names += strlen(name) + 1;
        strcpy(parts[i].name, name);
index 00f7bbe5479e47d74aa5570e6d85d103d26f750d..c6bf4e1219ef116c9a5e6cb488fa8ece0d47315c 100644 (file)
@@ -1,6 +1,6 @@
 /* fortunet.c memory map
  *
- * $Id: fortunet.c,v 1.9 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: fortunet.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $
  */
 
 #include <linux/module.h>
@@ -212,7 +212,7 @@ int __init init_fortunet(void)
 
                        map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical,
 
-                       map_regions[ix].map_info.virt = 
+                       map_regions[ix].map_info.virt =
                                ioremap_nocache(
                                map_regions[ix].window_addr_physical,
                                map_regions[ix].map_info.size);
index c73828171d9b303566962a21b0c541c7d29daf58..3190948211011b16211950cba7e7dab9c4b89251 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * Flash memory access on Hynix GMS30C7201/HMS30C7202 based 
+ * Flash memory access on Hynix GMS30C7201/HMS30C7202 based
  * evaluation boards
- * 
- * $Id: h720x-flash.c,v 1.11 2004/11/04 13:24:14 gleixner Exp $
+ *
+ * $Id: h720x-flash.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $
  *
  * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com>
- *     2003 Thomas Gleixner <tglx@linutronix.de>       
+ *     2003 Thomas Gleixner <tglx@linutronix.de>
  */
 
 #include <linux/config.h>
@@ -72,7 +72,7 @@ int __init h720x_mtd_init(void)
 {
 
        char    *part_type = NULL;
-       
+
        h720x_map.virt = ioremap(FLASH_PHYS, FLASH_SIZE);
 
        if (!h720x_map.virt) {
@@ -91,7 +91,7 @@ int __init h720x_mtd_init(void)
            h720x_map.bankwidth = 2;
            mymtd = do_map_probe("cfi_probe", &h720x_map);
        }
-           
+
        if (mymtd) {
                mymtd->owner = THIS_MODULE;
 
@@ -124,11 +124,11 @@ static void __exit h720x_mtd_cleanup(void)
                del_mtd_partitions(mymtd);
                map_destroy(mymtd);
        }
-       
+
        /* Free partition info, if commandline partition was used */
        if (mtd_parts && (mtd_parts != h720x_partitions))
                kfree (mtd_parts);
-       
+
        if (h720x_map.virt) {
                iounmap((void *)h720x_map.virt);
                h720x_map.virt = 0;
index c5e2111ba146df5535e0b90f451cc5c55d99ac63..ea5073781b3a38265053e2710606d5ef26464854 100644 (file)
@@ -2,7 +2,7 @@
  * ichxrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: ichxrom.c,v 1.18 2005/07/07 10:26:20 dwmw2 Exp $
+ * $Id: ichxrom.c,v 1.19 2005/11/07 11:14:27 gleixner Exp $
  */
 
 #include <linux/module.h>
@@ -101,7 +101,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
         * you can only really attach a FWH to an ICHX there
         * a number of simplifications you can make.
         *
-        * Also you can page firmware hubs if an 8MB window isn't enough 
+        * Also you can page firmware hubs if an 8MB window isn't enough
         * but don't currently handle that case either.
         */
        window->pdev = pdev;
@@ -144,7 +144,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
                window->phys = 0xfff00000;
        }
        else if ((byte & 0x80) == 0x80) {
-               window->phys = 0xfff80000; 
+               window->phys = 0xfff80000;
        }
 
        if (window->phys == 0) {
@@ -233,7 +233,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
                 * in a factory setting.  So in-place programming
                 * needs to use a different method.
                 */
-               for(map->map.bankwidth = 32; map->map.bankwidth; 
+               for(map->map.bankwidth = 32; map->map.bankwidth;
                        map->map.bankwidth >>= 1)
                {
                        char **probe_type;
@@ -286,7 +286,7 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
                for(i = 0; i < cfi->numchips; i++) {
                        cfi->chips[i].start += offset;
                }
-               
+
                /* Now that the mtd devices is complete claim and export it */
                map->mtd->owner = THIS_MODULE;
                if (add_mtd_device(map->mtd)) {
@@ -324,11 +324,11 @@ static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
 }
 
 static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
-       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
          PCI_ANY_ID, PCI_ANY_ID, },
-       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, 
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
          PCI_ANY_ID, PCI_ANY_ID, },
-       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, 
+       { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
          PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
          PCI_ANY_ID, PCI_ANY_ID, },
index cb39172c81d23fbe2803937badce1dd37ebcc221..ba7f40311a7e359352156b2d9e51738b6cd7e55c 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * $Id: impa7.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: impa7.c,v 1.14 2005/11/07 11:14:27 gleixner Exp $
  *
  * Handle mapping of the NOR flash on implementa A7 boards
  *
  * Copyright 2002 SYSGO Real-Time Solutions GmbH
- * 
+ *
  * 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.
@@ -55,7 +55,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = {
 #ifdef CONFIG_MTD_PARTITIONS
 
 /*
- * MTD partitioning stuff 
+ * MTD partitioning stuff
  */
 static struct mtd_partition static_partitions[] =
 {
@@ -108,9 +108,9 @@ int __init init_impa7(void)
                        impa7_mtd[i]->owner = THIS_MODULE;
                        devicesfound++;
 #ifdef CONFIG_MTD_PARTITIONS
-                       mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], 
+                       mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i],
                                                               probes,
-                                                              &mtd_parts[i], 
+                                                              &mtd_parts[i],
                                                               0);
                        if (mtd_parts_nb[i] > 0) {
                                part_type = "command line";
@@ -121,16 +121,16 @@ int __init init_impa7(void)
                        }
 
                        printk(KERN_NOTICE MSG_PREFIX
-                              "using %s partition definition\n", 
+                              "using %s partition definition\n",
                               part_type);
-                       add_mtd_partitions(impa7_mtd[i], 
+                       add_mtd_partitions(impa7_mtd[i],
                                           mtd_parts[i], mtd_parts_nb[i]);
 #else
                        add_mtd_device(impa7_mtd[i]);
 
 #endif
                }
-               else 
+               else
                        iounmap((void *)impa7_map[i].virt);
        }
        return devicesfound == 0 ? -ENXIO : 0;
index 93f50d6d5488817cd4d2af10072a7acddd6a12a2..fe738fd8d6f89f068910a82cd636a4bb431eb4c9 100644 (file)
@@ -1,28 +1,28 @@
 /*======================================================================
 
     drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver
-  
+
     Copyright (C) 2000 ARM Limited
     Copyright (C) 2003 Deep Blue Solutions 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
-  
-   This is access code for flashes using ARM's flash partitioning 
+
+   This is access code for flashes using ARM's flash partitioning
    standards.
 
-   $Id: integrator-flash.c,v 1.18 2004/11/01 13:26:15 rmk Exp $
+   $Id: integrator-flash.c,v 1.20 2005/11/07 11:14:27 gleixner Exp $
 
 ======================================================================*/
 
index 70b0e0b82c34f8e7384b2fb0bae3ea51503dc10d..35097c9bbf50c5bb560fe5fce3b039a3a4c4eba3 100644 (file)
@@ -1,11 +1,11 @@
 /*
  * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based)
- * 
+ *
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com>
  * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes
- * 
- * $Id: ipaq-flash.c,v 1.3 2004/11/04 13:24:15 gleixner Exp $
+ *
+ * $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $
  */
 
 #include <linux/config.h>
@@ -107,7 +107,7 @@ static struct mtd_partition h3xxx_partitions[] = {
 #ifndef CONFIG_LAB
                mask_flags:     MTD_WRITEABLE,  /* force read-only */
 #endif
-       }, 
+       },
        {
                name:           "H3XXX root jffs2",
 #ifndef CONFIG_LAB
@@ -148,7 +148,7 @@ static DEFINE_SPINLOCK(ipaq_vpp_lock);
 static void h3xxx_set_vpp(struct map_info *map, int vpp)
 {
        static int nest = 0;
-       
+
        spin_lock(&ipaq_vpp_lock);
        if (vpp)
                nest++;
@@ -191,7 +191,7 @@ static unsigned long cs_phys[] = {
        SA1100_CS3_PHYS,
        SA1100_CS4_PHYS,
        SA1100_CS5_PHYS,
-#else 
+#else
        PXA_CS0_PHYS,
        PXA_CS1_PHYS,
        PXA_CS2_PHYS,
@@ -216,7 +216,7 @@ int __init ipaq_mtd_init(void)
 
        /* Default flash bankwidth */
        // ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
-       
+
        if (machine_is_h1900())
        {
                /* For our intents, the h1900 is not a real iPAQ, so we special-case it. */
@@ -229,7 +229,7 @@ int __init ipaq_mtd_init(void)
        else
                for(i=0; i<MAX_IPAQ_CS; i++)
                        ipaq_map[i].bankwidth = 4;
-                       
+
        /*
         * Static partition definition selection
         */
@@ -309,7 +309,7 @@ int __init ipaq_mtd_init(void)
                                        return -ENXIO;
                        } else
                                printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size);
-                       
+
                        /* do we really need this debugging? --joshua 20030703 */
                        // printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]);
                        my_sub_mtd[i]->owner = THIS_MODULE;
@@ -333,11 +333,11 @@ int __init ipaq_mtd_init(void)
 #else
                mymtd = my_sub_mtd[0];
 
-               /* 
+               /*
                 *In the very near future, command line partition parsing
                 * will use the device name as 'mtd-id' instead of a value
                 * passed to the parse_cmdline_partitions() routine. Since
-                * the bootldr says 'ipaq', make sure it continues to work. 
+                * the bootldr says 'ipaq', make sure it continues to work.
                 */
                mymtd->name = "ipaq";
 
@@ -385,7 +385,7 @@ int __init ipaq_mtd_init(void)
         */
 
         i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0);
-                       
+
         if (i > 0) {
                 nb_parts = parsed_nr_parts = i;
                 parts = parsed_parts;
@@ -423,10 +423,10 @@ static void __exit ipaq_mtd_cleanup(void)
 #endif
                map_destroy(mymtd);
 #ifdef CONFIG_MTD_CONCAT
-               for(i=0; i<MAX_IPAQ_CS; i++) 
+               for(i=0; i<MAX_IPAQ_CS; i++)
 #else
-                       for(i=1; i<MAX_IPAQ_CS; i++) 
-#endif           
+                       for(i=1; i<MAX_IPAQ_CS; i++)
+#endif
                        {
                                if (my_sub_mtd[i])
                                        map_destroy(my_sub_mtd[i]);
@@ -444,14 +444,14 @@ static int __init h1900_special_case(void)
        ipaq_map[0].phys = 0x0;
        ipaq_map[0].virt = __ioremap(0x0, 0x04000000, 0, 1);
        ipaq_map[0].bankwidth = 2;
-       
+
        printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
        mymtd = do_map_probe("jedec_probe", &ipaq_map[0]);
        if (!mymtd)
                return -ENODEV;
        add_mtd_device(mymtd);
        printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n");
-       
+
        return 0;
 }
 
index 2e7577492a2c3602b135386f0ac0f4b6d122214d..62d9e87d84e2863edc3690075d717d86b998ace8 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * $Id: iq80310.c,v 1.20 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: iq80310.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
  *
  * Mapping for the Intel XScale IQ80310 evaluation board
  *
  * Author:     Nicolas Pitre
  * Copyright:  (C) 2001 MontaVista Software Inc.
- * 
+ *
  * 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.
index 6f36497022d19bed60f57e78bd8882bf21b7dedb..641eb2b55e9f4733b6cbc1d8ad8ef8e21e05b962 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $
+ * $Id: ixp2000.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $
  *
  * drivers/mtd/maps/ixp2000.c
  *
@@ -14,7 +14,7 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- * 
+ *
  */
 
 #include <linux/module.h>
@@ -46,8 +46,8 @@ struct ixp2000_flash_info {
 };
 
 static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
-{      
-       unsigned long (*set_bank)(unsigned long) = 
+{
+       unsigned long (*set_bank)(unsigned long) =
                (unsigned long(*)(unsigned long))map->map_priv_2;
 
        return (set_bank ? set_bank(ofs) : ofs);
@@ -55,8 +55,8 @@ static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long
 
 #ifdef __ARMEB__
 /*
- * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which 
- * causes the lower address bits to be XORed with 0x11 on 8 bit accesses 
+ * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which
+ * causes the lower address bits to be XORed with 0x11 on 8 bit accesses
  * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44.
  */
 static int erratum44_workaround = 0;
@@ -90,7 +90,7 @@ static void ixp2000_flash_copy_from(struct map_info *map, void *to,
                              unsigned long from, ssize_t len)
 {
        from = flash_bank_setup(map, from);
-       while(len--) 
+       while(len--)
                *(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++);
 }
 
@@ -148,11 +148,11 @@ static int ixp2000_flash_probe(struct device *_dev)
        static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
        struct platform_device *dev = to_platform_device(_dev);
        struct ixp2000_flash_data *ixp_data = dev->dev.platform_data;
-       struct flash_platform_data *plat; 
+       struct flash_platform_data *plat;
        struct ixp2000_flash_info *info;
        unsigned long window_size;
        int err = -1;
-       
+
        if (!ixp_data)
                return -ENODEV;
 
@@ -161,7 +161,7 @@ static int ixp2000_flash_probe(struct device *_dev)
                return -ENODEV;
 
        window_size = dev->resource->end - dev->resource->start + 1;
-       dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", 
+       dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n",
                        ixp_data->nr_banks, ((u32)window_size >> 20));
 
        if (plat->width != 1) {
@@ -174,7 +174,7 @@ static int ixp2000_flash_probe(struct device *_dev)
        if(!info) {
                err = -ENOMEM;
                goto Error;
-       }       
+       }
        memzero(info, sizeof(struct ixp2000_flash_info));
 
        dev_set_drvdata(&dev->dev, info);
@@ -184,7 +184,7 @@ static int ixp2000_flash_probe(struct device *_dev)
         * not attempt to do a direct access on us.
         */
        info->map.phys = NO_XIP;
-       
+
        info->nr_banks = ixp_data->nr_banks;
        info->map.size = ixp_data->nr_banks * window_size;
        info->map.bankwidth = 1;
@@ -192,7 +192,7 @@ static int ixp2000_flash_probe(struct device *_dev)
        /*
         * map_priv_2 is used to store a ptr to to the bank_setup routine
         */
-       info->map.map_priv_2 = (void __iomem *) ixp_data->bank_setup;
+       info->map.map_priv_2 = (unsigned long) ixp_data->bank_setup;
 
        info->map.name = dev->dev.bus_id;
        info->map.read = ixp2000_flash_read8;
@@ -200,8 +200,8 @@ static int ixp2000_flash_probe(struct device *_dev)
        info->map.copy_from = ixp2000_flash_copy_from;
        info->map.copy_to = ixp2000_flash_copy_to;
 
-       info->res = request_mem_region(dev->resource->start, 
-                       dev->resource->end - dev->resource->start + 1, 
+       info->res = request_mem_region(dev->resource->start,
+                       dev->resource->end - dev->resource->start + 1,
                        dev->dev.bus_id);
        if (!info->res) {
                dev_err(_dev, "Could not reserve memory region\n");
@@ -209,7 +209,7 @@ static int ixp2000_flash_probe(struct device *_dev)
                goto Error;
        }
 
-       info->map.map_priv_1 = ioremap(dev->resource->start, 
+       info->map.map_priv_1 = (unsigned long) ioremap(dev->resource->start,
                                dev->resource->end - dev->resource->start + 1);
        if (!info->map.map_priv_1) {
                dev_err(_dev, "Failed to ioremap flash region\n");
index 0d87c02dee046f32070427b8e743ac550fa1f8ed..56b3a355bf7b83f934a77eeca368b2cdfa25d96c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ixp4xx.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: ixp4xx.c,v 1.12 2005/11/07 11:14:27 gleixner Exp $
  *
  * drivers/mtd/maps/ixp4xx.c
  *
@@ -45,7 +45,7 @@
 static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
 {
        map_word val;
-       val.x[0] = *(__u16 *) (map->map_priv_1 + ofs);
+       val.x[0] = le16_to_cpu(readw(map->virt + ofs));
        return val;
 }
 
@@ -59,35 +59,35 @@ static void ixp4xx_copy_from(struct map_info *map, void *to,
 {
        int i;
        u8 *dest = (u8 *) to;
-       u16 *src = (u16 *) (map->map_priv_1 + from);
+       void __iomem *src = map->virt + from;
        u16 data;
 
        for (i = 0; i < (len / 2); i++) {
-               data = src[i];
+               data = le16_to_cpu(readw(src + 2*i));
                dest[i * 2] = BYTE0(data);
                dest[i * 2 + 1] = BYTE1(data);
        }
 
        if (len & 1)
-               dest[len - 1] = BYTE0(src[i]);
+               dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i)));
 }
 
-/* 
+/*
  * Unaligned writes are ignored, causing the 8-bit
  * probe to fail and proceed to the 16-bit probe (which succeeds).
  */
 static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
 {
        if (!(adr & 1))
-              *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
+               writew(cpu_to_le16(d.x[0]), map->virt + adr);
 }
 
-/* 
+/*
  * Fast write16 function without the probing check above
  */
 static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
 {
-       *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
+       writew(cpu_to_le16(d.x[0]), map->virt + adr);
 }
 
 struct ixp4xx_flash_info {
@@ -104,25 +104,18 @@ static int ixp4xx_flash_remove(struct device *_dev)
        struct platform_device *dev = to_platform_device(_dev);
        struct flash_platform_data *plat = dev->dev.platform_data;
        struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev);
-       map_word d;
 
        dev_set_drvdata(&dev->dev, NULL);
 
        if(!info)
                return 0;
 
-       /*
-        * This is required for a soft reboot to work.
-        */
-       d.x[0] = 0xff;
-       ixp4xx_write16(&info->map, d, 0x55 * 0x2);
-
        if (info->mtd) {
                del_mtd_partitions(info->mtd);
                map_destroy(info->mtd);
        }
-       if (info->map.map_priv_1)
-               iounmap((void *) info->map.map_priv_1);
+       if (info->map.virt)
+               iounmap(info->map.virt);
 
        kfree(info->partitions);
 
@@ -134,9 +127,6 @@ static int ixp4xx_flash_remove(struct device *_dev)
        if (plat->exit)
                plat->exit();
 
-       /* Disable flash write */
-       *IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE;
-
        return 0;
 }
 
@@ -160,17 +150,11 @@ static int ixp4xx_flash_probe(struct device *_dev)
        if(!info) {
                err = -ENOMEM;
                goto Error;
-       }       
+       }
        memzero(info, sizeof(struct ixp4xx_flash_info));
 
        dev_set_drvdata(&dev->dev, info);
 
-       /* 
-        * Enable flash write 
-        * TODO: Move this out to board specific code
-        */
-       *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
-
        /*
         * Tell the MTD layer we're not 1:1 mapped so that it does
         * not attempt to do a direct access on us.
@@ -189,8 +173,8 @@ static int ixp4xx_flash_probe(struct device *_dev)
        info->map.write = ixp4xx_probe_write16,
        info->map.copy_from = ixp4xx_copy_from,
 
-       info->res = request_mem_region(dev->resource->start, 
-                       dev->resource->end - dev->resource->start + 1, 
+       info->res = request_mem_region(dev->resource->start,
+                       dev->resource->end - dev->resource->start + 1,
                        "IXP4XXFlash");
        if (!info->res) {
                printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n");
@@ -198,9 +182,9 @@ static int ixp4xx_flash_probe(struct device *_dev)
                goto Error;
        }
 
-       info->map.map_priv_1 = ioremap(dev->resource->start,
-                           dev->resource->end - dev->resource->start + 1);
-       if (!info->map.map_priv_1) {
+       info->map.virt = ioremap(dev->resource->start,
+                                dev->resource->end - dev->resource->start + 1);
+       if (!info->map.virt) {
                printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
                err = -EIO;
                goto Error;
@@ -213,7 +197,7 @@ static int ixp4xx_flash_probe(struct device *_dev)
                goto Error;
        }
        info->mtd->owner = THIS_MODULE;
-       
+
        /* Use the fast version */
        info->map.write = ixp4xx_write16,
 
@@ -258,4 +242,3 @@ module_exit(ixp4xx_flash_exit);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems");
 MODULE_AUTHOR("Deepak Saxena");
-
index b08668212ab7401a0640e15f9fab420431d93499..851bf957605205c66ed3a7fe0d0777e83b44e4f6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: l440gx.c,v 1.18 2005/11/07 11:14:27 gleixner Exp $
  *
  * BIOS Flash chip on Intel 440GX board.
  *
@@ -49,7 +49,7 @@ static struct map_info l440gx_map = {
        .bankwidth = BUSWIDTH,
        .phys = WINDOW_ADDR,
 #if 0
-       /* FIXME verify that this is the 
+       /* FIXME verify that this is the
         * appripriate code for vpp enable/disable
         */
        .set_vpp = l440gx_set_vpp
@@ -62,10 +62,10 @@ static int __init init_l440gx(void)
        struct resource *pm_iobase;
        __u16 word;
 
-       dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
+       dev = pci_find_device(PCI_VENDOR_ID_INTEL,
                PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
 
-       pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, 
+       pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
                PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
 
        if (!dev || !pm_dev) {
@@ -82,10 +82,10 @@ static int __init init_l440gx(void)
        simple_map_init(&l440gx_map);
        printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt);
 
-       /* Setup the pm iobase resource 
+       /* Setup the pm iobase resource
         * This code should move into some kind of generic bridge
         * driver but for the moment I'm content with getting the
-        * allocation correct. 
+        * allocation correct.
         */
        pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE];
        if (!(pm_iobase->flags & IORESOURCE_IO)) {
@@ -110,7 +110,7 @@ static int __init init_l440gx(void)
        /* Set the iobase */
        iobase = pm_iobase->start;
        pci_write_config_dword(pm_dev, 0x40, iobase | 1);
-       
+
 
        /* Set XBCS# */
        pci_read_config_word(dev, 0x4e, &word);
@@ -122,7 +122,7 @@ static int __init init_l440gx(void)
 
        /* Enable the gate on the WE line */
        outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT);
-       
+
                printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n");
 
        mymtd = do_map_probe("jedec_probe", &l440gx_map);
@@ -145,7 +145,7 @@ static void __exit cleanup_l440gx(void)
 {
        del_mtd_device(mymtd);
        map_destroy(mymtd);
-       
+
        iounmap(l440gx_map.virt);
 }
 
index 2b4c5058787d76426b536d304374cb82ae92b82d..1aa0447c5e66a2430ec9dd42bf5b86fba8549f16 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * $Id: lubbock-flash.c,v 1.19 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: lubbock-flash.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
  *
  * Map driver for the Lubbock developer platform.
  *
  * Author:     Nicolas Pitre
  * Copyright:  (C) 2001 MontaVista Software Inc.
- * 
+ *
  * 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.
@@ -76,7 +76,7 @@ static int __init init_lubbock(void)
        int flashboot = (LUB_CONF_SWITCHES & 1);
        int ret = 0, i;
 
-       lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = 
+       lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth =
                (BOOT_DEF & 1) ? 2 : 4;
 
        /* Compensate for the nROMBT switch which swaps the flash banks */
@@ -100,11 +100,11 @@ static int __init init_lubbock(void)
                simple_map_init(&lubbock_maps[i]);
 
                printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
-                      lubbock_maps[i].name, lubbock_maps[i].phys, 
+                      lubbock_maps[i].name, lubbock_maps[i].phys,
                       lubbock_maps[i].bankwidth * 8);
 
                mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
-               
+
                if (!mymtds[i]) {
                        iounmap((void *)lubbock_maps[i].virt);
                        if (lubbock_maps[i].cached)
@@ -124,7 +124,7 @@ static int __init init_lubbock(void)
 
        if (!mymtds[0] && !mymtds[1])
                return ret;
-       
+
        for (i = 0; i < 2; i++) {
                if (!mymtds[i]) {
                        printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name);
@@ -151,7 +151,7 @@ static void __exit cleanup_lubbock(void)
                if (nr_parsed_parts[i] || !i)
                        del_mtd_partitions(mymtds[i]);
                else
-                       del_mtd_device(mymtds[i]);                      
+                       del_mtd_device(mymtds[i]);
 
                map_destroy(mymtds[i]);
                iounmap((void *)lubbock_maps[i].virt);
index da0f8a692628a253f7a95831d8d44cb9664683d6..eaa4bbb868a32855adef0adcb9e7f4ca7d492f2d 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Author:     Nicolas Pitre
  * Copyright:  (C) 2001 MontaVista Software Inc.
- * 
+ *
  * 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.
@@ -91,27 +91,27 @@ static int __init init_mainstone(void)
                mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys,
                                                 WINDOW_SIZE);
                if (!mainstone_maps[i].virt) {
-                       printk(KERN_WARNING "Failed to ioremap %s\n", 
+                       printk(KERN_WARNING "Failed to ioremap %s\n",
                               mainstone_maps[i].name);
                        if (!ret)
                                ret = -ENOMEM;
                        continue;
                }
-               mainstone_maps[i].cached = 
+               mainstone_maps[i].cached =
                        ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE);
                if (!mainstone_maps[i].cached)
                        printk(KERN_WARNING "Failed to ioremap cached %s\n",
                               mainstone_maps[i].name);
                simple_map_init(&mainstone_maps[i]);
 
-               printk(KERN_NOTICE 
+               printk(KERN_NOTICE
                       "Probing %s at physical address 0x%08lx"
                       " (%d-bit bankwidth)\n",
-                      mainstone_maps[i].name, mainstone_maps[i].phys, 
+                      mainstone_maps[i].name, mainstone_maps[i].phys,
                       mainstone_maps[i].bankwidth * 8);
 
                mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]);
-               
+
                if (!mymtds[i]) {
                        iounmap((void *)mainstone_maps[i].virt);
                        if (mainstone_maps[i].cached)
@@ -131,21 +131,21 @@ static int __init init_mainstone(void)
 
        if (!mymtds[0] && !mymtds[1])
                return ret;
-       
+
        for (i = 0; i < 2; i++) {
                if (!mymtds[i]) {
-                       printk(KERN_WARNING "%s is absent. Skipping\n", 
+                       printk(KERN_WARNING "%s is absent. Skipping\n",
                               mainstone_maps[i].name);
                } else if (nr_parsed_parts[i]) {
-                       add_mtd_partitions(mymtds[i], parsed_parts[i], 
+                       add_mtd_partitions(mymtds[i], parsed_parts[i],
                                           nr_parsed_parts[i]);
                } else if (!i) {
                        printk("Using static partitions on %s\n",
                               mainstone_maps[i].name);
-                       add_mtd_partitions(mymtds[i], mainstone_partitions, 
+                       add_mtd_partitions(mymtds[i], mainstone_partitions,
                                           ARRAY_SIZE(mainstone_partitions));
                } else {
-                       printk("Registering %s as whole device\n", 
+                       printk("Registering %s as whole device\n",
                               mainstone_maps[i].name);
                        add_mtd_device(mymtds[i]);
                }
index c5c6901a476318d63d86c14d06e9d5f92d081026..06b1187278468bb4e0392b8a70edc1b32842c3f3 100644 (file)
@@ -1,11 +1,11 @@
 /*
- * $Id: mbx860.c,v 1.8 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: mbx860.c,v 1.9 2005/11/07 11:14:27 gleixner Exp $
  *
  * Handle mapping of the flash on MBX860 boards
  *
  * Author:     Anton Todorov
  * Copyright:  (C) 2001 Emness Technology
- * 
+ *
  * 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.
@@ -46,7 +46,7 @@ static struct mtd_partition partition_info[]={
        { .name = "MBX flash APPLICATION partition",
        .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 }
 };
-                                  
+
 
 static struct mtd_info *mymtd;
 
diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c
new file mode 100644 (file)
index 0000000..d1e66e1
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Flash memory access on 4G Systems MTX-1 boards
+ *
+ * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $
+ *
+ * (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz>
+ * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de>
+ *
+ */
+
+#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>
+
+static struct map_info mtx1_map = {
+       .name = "MTX-1 flash",
+       .bankwidth = 4,
+       .size = 0x2000000,
+       .phys = 0x1E000000,
+};
+
+static struct mtd_partition mtx1_partitions[] = {
+        {
+                .name = "filesystem",
+                .size = 0x01C00000,
+                .offset = 0,
+        },{
+                .name = "yamon",
+                .size = 0x00100000,
+                .offset = MTDPART_OFS_APPEND,
+                .mask_flags = MTD_WRITEABLE,
+        },{
+                .name = "kernel",
+                .size = 0x002c0000,
+                .offset = MTDPART_OFS_APPEND,
+        },{
+                .name = "yamon env",
+                .size = 0x00040000,
+                .offset = MTDPART_OFS_APPEND,
+        }
+};
+
+static struct mtd_info *mtx1_mtd;
+
+int __init mtx1_mtd_init(void)
+{
+       int ret = -ENXIO;
+
+       simple_map_init(&mtx1_map);
+
+       mtx1_map.virt = ioremap(mtx1_map.phys, mtx1_map.size);
+       if (!mtx1_map.virt)
+               return -EIO;
+
+       mtx1_mtd = do_map_probe("cfi_probe", &mtx1_map);
+       if (!mtx1_mtd)
+               goto err;
+
+       mtx1_mtd->owner = THIS_MODULE;
+
+       ret = add_mtd_partitions(mtx1_mtd, mtx1_partitions,
+                       ARRAY_SIZE(mtx1_partitions));
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       iounmap(mtx1_map.virt);
+       return ret;
+}
+
+static void __exit mtx1_mtd_cleanup(void)
+{
+       if (mtx1_mtd) {
+               del_mtd_partitions(mtx1_mtd);
+               map_destroy(mtx1_mtd);
+       }
+       if (mtx1_map.virt)
+               iounmap(mtx1_map.virt);
+}
+
+module_init(mtx1_mtd_init);
+module_exit(mtx1_mtd_cleanup);
+
+MODULE_AUTHOR("Bruno Randolf <bruno.randolf@4g-systems.biz>");
+MODULE_DESCRIPTION("MTX-1 flash map");
+MODULE_LICENSE("GPL");
index ab7e6358d281b35edccb08006062964f0d53723a..33060a31572217b6feb25ba8d288323fbc492555 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
  *     based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
  *
- * $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: netsc520.c,v 1.14 2005/11/07 11:14: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
@@ -38,7 +38,7 @@
 ** The single, 16 megabyte flash bank is divided into four virtual
 ** partitions.  The first partition is 768 KiB and is intended to
 ** store the kernel image loaded by the bootstrap loader.  The second
-** partition is 256 KiB and holds the BIOS image.  The third 
+** partition is 256 KiB and holds the BIOS image.  The third
 ** partition is 14.5 MiB and is intended for the flash file system
 ** image.  The last partition is 512 KiB and contains another copy
 ** of the BIOS image and the reset vector.
 ** recoverable afterwards.
 */
 
-/* partition_info gives details on the logical partitions that the split the 
+/* 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 = "NetSc520 boot kernel", 
-           .offset = 0, 
+    {
+           .name = "NetSc520 boot kernel",
+           .offset = 0,
            .size = 0xc0000
     },
-    { 
-           .name = "NetSc520 Low BIOS", 
-           .offset = 0xc0000, 
+    {
+           .name = "NetSc520 Low BIOS",
+           .offset = 0xc0000,
            .size = 0x40000
     },
-    { 
-           .name = "NetSc520 file system", 
-           .offset = 0x100000, 
+    {
+           .name = "NetSc520 file system",
+           .offset = 0x100000,
            .size = 0xe80000
     },
-    { 
-           .name = "NetSc520 High BIOS", 
-           .offset = 0xf80000, 
+    {
+           .name = "NetSc520 High BIOS",
+           .offset = 0xf80000,
            .size = 0x80000
     },
 };
@@ -114,7 +114,7 @@ static int __init init_netsc520(void)
                iounmap(netsc520_map.virt);
                return -ENXIO;
        }
-               
+
        mymtd->owner = THIS_MODULE;
        add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS );
        return 0;
index 61be5a4148c9abdae5d56e02b99fe709a9862eb2..f00ee7e54dba7dbdaa17a30d3e2ff013d3f3eb6d 100644 (file)
@@ -6,7 +6,7 @@
  *      (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
  *      (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
  *
- *     $Id: nettel.c,v 1.10 2005/01/05 17:11:29 dwmw2 Exp $
+ *     $Id: nettel.c,v 1.11 2005/11/07 11:14:27 gleixner Exp $
  */
 
 /****************************************************************************/
@@ -143,7 +143,7 @@ static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val,
 {
        struct cfi_private *cfi = nettel_intel_map.fldrv_priv;
        unsigned long b;
-       
+
        /* Make sure all FLASH chips are put back into read mode */
        for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) {
                cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi,
@@ -199,7 +199,7 @@ int nettel_eraseconfig(void)
 
                schedule();  /* Wait for erase to finish. */
                remove_wait_queue(&wait_q, &wait);
-               
+
                put_mtd_device(mtd);
        }
 
@@ -430,7 +430,7 @@ int __init nettel_init(void)
                nettel_intel_partitions[1].size = (intel0size + intel1size) -
                        (1024*1024 + intel_mtd->erasesize);
                nettel_intel_partitions[3].size = intel0size + intel1size;
-               nettel_intel_partitions[4].offset = 
+               nettel_intel_partitions[4].offset =
                        (intel0size + intel1size) - intel_mtd->erasesize;
                nettel_intel_partitions[4].size = intel_mtd->erasesize;
                nettel_intel_partitions[5].offset =
index 82c3070678c5111b4abb69a212dee60f43046ec1..6977963d789708c1e060e0990843b1a4e602eb52 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ocelot.c,v 1.16 2005/01/05 18:05:13 dwmw2 Exp $
+ * $Id: ocelot.c,v 1.17 2005/11/07 11:14:27 gleixner Exp $
  *
  * Flash on Momenco Ocelot
  */
@@ -31,7 +31,7 @@ static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t
         struct map_info *map = mtd->priv;
        size_t done = 0;
 
-       /* If we use memcpy, it does word-wide writes. Even though we told the 
+       /* If we use memcpy, it does word-wide writes. Even though we told the
           GT64120A that it's an 8-bit wide region, word-wide writes don't work.
           We end up just writing the first byte of the four to all four bytes.
           So we have this loop instead */
@@ -68,7 +68,7 @@ static int __init init_ocelot_maps(void)
        int nr_parts;
        unsigned char brd_status;
 
-               printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n", 
+               printk(KERN_INFO "Momenco Ocelot MTD mappings: Flash 0x%x at 0x%x, NVRAM 0x%x at 0x%x\n",
               FLASH_WINDOW_SIZE, FLASH_WINDOW_ADDR, NVRAM_WINDOW_SIZE, NVRAM_WINDOW_ADDR);
 
        /* First check whether the flash jumper is present */
@@ -138,8 +138,8 @@ static int __init init_ocelot_maps(void)
                add_mtd_device(flash_mtd);
 
        return 0;
-       
- fail3:        
+
+ fail3:
        iounmap((void *)ocelot_flash_map.virt);
        if (ocelot_flash_map.cached)
                        iounmap((void *)ocelot_flash_map.cached);
index e5ff83de420ee9ecb808de973db51133471185a1..a6642db3d325e19e6418ce0675fdd0f596e1f522 100644 (file)
@@ -1,12 +1,12 @@
-// $Id: octagon-5066.c,v 1.26 2004/07/12 22:38:29 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.28 2005/11/07 11:14:27 gleixner Exp $
 /* ######################################################################
 
-   Octagon 5066 MTD Driver. 
-  
+   Octagon 5066 MTD Driver.
+
    The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
    comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
    is replacable by flash. Both units are mapped through a multiplexer
-   into a 32k memory window at 0xe8000. The control register for the 
+   into a 32k memory window at 0xe8000. The control register for the
    multiplexing unit is located at IO 0x208 with a bit map of
      0-5 Page Selection in 32k increments
      6-7 Device selection:
         01 SSD 0 (Socket)
         10 SSD 1 (Flash chip)
         11 undefined
-  
+
    On each SSD, the first 128k is reserved for use by the bios
-   (actually it IS the bios..) This only matters if you are booting off the 
+   (actually it IS the bios..) This only matters if you are booting off the
    flash, you must not put a file system starting there.
-   
+
    The driver tries to do a detection algorithm to guess what sort of devices
    are plugged into the sockets.
-   
+
    ##################################################################### */
 
 #include <linux/module.h>
@@ -56,7 +56,7 @@ static void __oct5066_page(struct map_info *map, __u8 byte)
 static inline void oct5066_page(struct map_info *map, unsigned long ofs)
 {
        __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
-       
+
        if (page_n_dev != byte)
                __oct5066_page(map, byte);
 }
@@ -78,7 +78,7 @@ static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from
                unsigned long thislen = len;
                if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
                        thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-               
+
                spin_lock(&oct5066_spin);
                oct5066_page(map, from);
                memcpy_fromio(to, iomapadr + from, thislen);
@@ -103,7 +103,7 @@ static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *
                unsigned long thislen = len;
                if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
                        thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-               
+
                spin_lock(&oct5066_spin);
                oct5066_page(map, to);
                memcpy_toio(iomapadr + to, from, thislen);
@@ -144,7 +144,7 @@ static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
 // OctProbe - Sense if this is an octagon card
 // ---------------------------------------------------------------------
 /* Perform a simple validity test, we map the window select SSD0 and
-   change pages while monitoring the window. A change in the window, 
+   change pages while monitoring the window. A change in the window,
    controlled by the PAGE_IO port is a functioning 5066 board. This will
    fail if the thing in the socket is set to a uniform value. */
 static int __init OctProbe(void)
@@ -161,13 +161,13 @@ static int __init OctProbe(void)
         Values[I%10] = readl(iomapadr);
         if (I > 0 && Values[I%10] == Values[0])
            return -EAGAIN;
-      }      
+      }
       else
       {
         // Make sure we get the same values on the second pass
         if (Values[I%10] != readl(iomapadr))
            return -EAGAIN;
-      }      
+      }
    }
    return 0;
 }
@@ -207,11 +207,11 @@ int __init init_oct5066(void)
                ret = -EAGAIN;
                goto out_unmap;
        }
-       
+
        // Print out our little header..
        printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
               WINDOW_START+WINDOW_LENGTH);
-       
+
        for (i=0; i<2; i++) {
                oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
                if (!oct5066_mtd[i])
@@ -225,11 +225,11 @@ int __init init_oct5066(void)
                        add_mtd_device(oct5066_mtd[i]);
                }
        }
-       
+
        if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
                cleanup_oct5066();
                return -ENXIO;
-       }         
+       }
 
        return 0;
 
index 763304154a923364151b7b4b789bf7db2e0ebbff..dc37652700570e3c6899fb881f1269fc17e8d270 100644 (file)
@@ -5,7 +5,7 @@
  *
  *  (C) 2002 MontVista Software, Inc.
  *
- * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $
+ * $Id: omap-toto-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $
  */
 
 #include <linux/config.h>
@@ -38,7 +38,7 @@ static struct map_info omap_toto_map_flash = {
        .virt =         (void __iomem *)OMAP_TOTO_FLASH_BASE,
 };
 
+
 static struct mtd_partition toto_flash_partitions[] = {
        {
                .name =         "BootLoader",
@@ -54,21 +54,21 @@ static struct mtd_partition toto_flash_partitions[] = {
                .name =         "EnvArea",      /* bottom 64KiB for env vars */
                .size =         MTDPART_SIZ_FULL,
                .offset =       MTDPART_OFS_APPEND,
-       } 
+       }
 };
 
 static struct mtd_partition *parsed_parts;
 
 static struct mtd_info *flash_mtd;
-static int __init init_flash (void)   
+
+static int __init init_flash (void)
 {
 
        struct mtd_partition *parts;
        int nb_parts = 0;
        int parsed_nr_parts = 0;
        const char *part_type;
+
        /*
         * Static partition definition selection
         */
@@ -89,7 +89,7 @@ static int __init init_flash (void)
        flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash);
        if (!flash_mtd)
                return -ENXIO;
+
        if (parsed_nr_parts > 0) {
                parts = parsed_parts;
                nb_parts = parsed_nr_parts;
@@ -108,8 +108,8 @@ static int __init init_flash (void)
        }
        return 0;
 }
-int __init omap_toto_mtd_init(void)  
+
+int __init omap_toto_mtd_init(void)
 {
        int status;
 
@@ -119,7 +119,7 @@ int __init omap_toto_mtd_init(void)
     return status;
 }
 
-static void  __exit omap_toto_mtd_cleanup(void)  
+static void  __exit omap_toto_mtd_cleanup(void)
 {
        if (flash_mtd) {
                del_mtd_partitions(flash_mtd);
index 7f370bb794fefae45e192df190d657e7bcd13110..fd3b4a5fc2072653a6f2c919d5c9984004a87a04 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2001-2002 MontaVista Software Inc.
  * Copyright (C) 2003-2004 Texas Instruments
- * Copyright (C) 2004 Nokia Corporation 
+ * Copyright (C) 2004 Nokia Corporation
  *
  *     Assembled using driver code copyright the companies above
  *     and written by David Brownell, Jian Zhang <jzhang@ti.com>,
index d9c64e99ee32a7ae466499f0b053df0908dcefd6..8b3570b090954bd27f8034d69620d0dc9baf2fd3 100644 (file)
@@ -7,8 +7,8 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $
- * 
+ *  $Id: pci.c,v 1.13 2005/11/07 11:14:27 gleixner Exp $
+ *
  * Generic PCI memory map driver.  We support the following boards:
  *  - Intel IQ80310 ATU.
  *  - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001
@@ -38,7 +38,7 @@ struct map_pci_info {
        void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
        unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
        struct pci_dev *dev;
-};     
+};
 
 static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs)
 {
index ff7c50d101802333bf7a9b452ab60212a103cf57..af24216a06264bcbd58631c701be6e431dda3f9b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: pcmciamtd.c,v 1.51 2004/07/12 22:38:29 dwmw2 Exp $
+ * $Id: pcmciamtd.c,v 1.55 2005/11/07 11:14:28 gleixner Exp $
  *
  * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
  *
@@ -48,7 +48,7 @@ static const int debug = 0;
 
 
 #define DRIVER_DESC    "PCMCIA Flash memory card driver"
-#define DRIVER_VERSION "$Revision: 1.51 $"
+#define DRIVER_VERSION "$Revision: 1.55 $"
 
 /* Size of the PCMCIA address space: 26 bits = 64 MB */
 #define MAX_PCMCIA_ADDR        0x4000000
@@ -176,7 +176,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long
 
                if(toread > len)
                        toread = len;
-               
+
                addr = remap_window(map, from);
                if(!addr)
                        return;
@@ -386,7 +386,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
                        cs_error(link->handle, ParseTuple, rc);
                        break;
                }
-               
+
                switch(tuple.TupleCode) {
                case  CISTPL_FORMAT: {
                        cistpl_format_t *t = &parse.format;
@@ -394,9 +394,9 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
                        DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u",
                              t->type, t->edc, t->offset, t->length);
                        break;
-                       
+
                }
-                       
+
                case CISTPL_DEVICE: {
                        cistpl_device_t *t = &parse.device;
                        int i;
@@ -410,7 +410,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
                        }
                        break;
                }
-                       
+
                case CISTPL_VERS_1: {
                        cistpl_vers_1_t *t = &parse.version_1;
                        int i;
@@ -425,7 +425,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
                        DEBUG(2, "Found name: %s", dev->mtd_name);
                        break;
                }
-                       
+
                case CISTPL_JEDEC_C: {
                        cistpl_jedec_t *t = &parse.jedec;
                        int i;
@@ -434,7 +434,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
                        }
                        break;
                }
-                       
+
                case CISTPL_DEVICE_GEO: {
                        cistpl_device_geo_t *t = &parse.device_geo;
                        int i;
@@ -449,11 +449,11 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
                        }
                        break;
                }
-                       
+
                default:
                        DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
                }
-               
+
                rc = pcmcia_get_next_tuple(link->handle, &tuple);
        }
        if(!dev->pcmcia_map.size)
@@ -470,7 +470,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
        if(bankwidth) {
                dev->pcmcia_map.bankwidth = bankwidth;
                DEBUG(2, "bankwidth forced to %d", bankwidth);
-       }               
+       }
 
        dev->pcmcia_map.name = dev->mtd_name;
        if(!dev->mtd_name[0]) {
@@ -568,7 +568,7 @@ static void pcmciamtd_config(dev_link_t *link)
                return;
        }
        DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10);
-               
+
        /* Get write protect status */
        CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status));
        DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
@@ -624,11 +624,11 @@ static void pcmciamtd_config(dev_link_t *link)
                        mtd = do_map_probe(probes[i], &dev->pcmcia_map);
                        if(mtd)
                                break;
-                       
+
                        DEBUG(1, "FAILED: %s", probes[i]);
                }
        }
-       
+
        if(!mtd) {
                DEBUG(1, "Cant find an MTD");
                pcmciamtd_release(link);
index b853670bfb81d6b4ffc6d58d5aa62a2d00c5669d..9ee760f97bc6ae58da80183fe3de17cdc77e80d4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: physmap.c,v 1.38 2005/11/07 11:14:28 gleixner Exp $
  *
  * Normal mappings of chips in physical memory
  *
@@ -69,7 +69,7 @@ static int __init init_physmap(void)
                mymtd->owner = THIS_MODULE;
 
 #ifdef CONFIG_MTD_PARTITIONS
-               mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, 
+               mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes,
                                                    &mtd_parts, 0);
 
                if (mtd_parts_nb > 0)
@@ -78,9 +78,9 @@ static int __init init_physmap(void)
                        return 0;
                }
 
-               if (num_physmap_partitions != 0) 
+               if (num_physmap_partitions != 0)
                {
-                       printk(KERN_NOTICE 
+                       printk(KERN_NOTICE
                               "Using physmap partition definition\n");
                        add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions);
                        return 0;
index 104576b5be3480cf238f1f4c3ac0a6c9bbfeca8f..a02eed94a231ecbf39686d2db1733b65a3fdfd4c 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generic platfrom device based RAM map
  *
- * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $
+ * $Id: plat-ram.c,v 1.7 2005/11/07 11:14:28 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
@@ -91,7 +91,7 @@ static int platram_remove(struct device *dev)
 
        dev_dbg(dev, "removing device\n");
 
-       if (info == NULL) 
+       if (info == NULL)
                return 0;
 
        if (info->mtd) {
@@ -118,7 +118,7 @@ static int platram_remove(struct device *dev)
 
        if (info->map.virt != NULL)
                iounmap(info->map.virt);
-       
+
        kfree(info);
 
        return 0;
@@ -139,7 +139,7 @@ static int platram_probe(struct device *dev)
        int err = 0;
 
        dev_dbg(dev, "probe entered\n");
-       
+
        if (dev->platform_data == NULL) {
                dev_err(dev, "no platform data supplied\n");
                err = -ENOENT;
@@ -177,7 +177,7 @@ static int platram_probe(struct device *dev)
 
        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.name = pdata->mapname != NULL ? pdata->mapname : (char *)pd->name;
        info->map.bankwidth = pdata->bankwidth;
 
        /* register our usage of the memory area */
@@ -240,7 +240,7 @@ static int platram_probe(struct device *dev)
                dev_err(dev, "add_mtd_device() failed\n");
                err = -ENOMEM;
        }
-       
+
        dev_info(dev, "registered mtd device\n");
        return err;
 
@@ -254,6 +254,7 @@ static int platram_probe(struct device *dev)
 
 static struct device_driver platram_driver = {
        .name           = "mtd-ram",
+       .owner          = THIS_MODULE,
        .bus            = &platform_bus_type,
        .probe          = platram_probe,
        .remove         = platram_remove,
index a0f43dad898507877d026d82754e2d92634b8f94..d7e16c2d5c4441efd0bf8bf129a1050dfb514d42 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: pnc2000.c,v 1.17 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: pnc2000.c,v 1.18 2005/11/07 11:14:28 gleixner Exp $
  */
 
 #include <linux/module.h>
@@ -21,7 +21,7 @@
 #define WINDOW_ADDR 0xbf000000
 #define WINDOW_SIZE 0x00400000
 
-/* 
+/*
  * MAP DRIVER STUFF
  */
 
@@ -36,7 +36,7 @@ static struct map_info pnc_map = {
 
 
 /*
- * MTD 'PARTITIONING' STUFF 
+ * MTD 'PARTITIONING' STUFF
  */
 static struct mtd_partition pnc_partitions[3] = {
        {
@@ -56,7 +56,7 @@ static struct mtd_partition pnc_partitions[3] = {
        }
 };
 
-/* 
+/*
  * This is the master MTD device for which all the others are just
  * auto-relocating aliases.
  */
diff --git a/drivers/mtd/maps/pq2fads.c b/drivers/mtd/maps/pq2fads.c
new file mode 100644 (file)
index 0000000..fb78d87
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * drivers/mtd/maps/pq2fads.c
+ *
+ * Mapping for the flash SIMM on 8272ADS and PQ2FADS board
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/ppcboot.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+
+/*
+  NOTE: bank width and interleave relative to the installed flash
+  should have been chosen within MTD_CFI_GEOMETRY options.
+  */
+#define PQ2FADS_BANK_WIDTH 4
+
+static struct mtd_partition pq2fads_partitions[] = {
+       {
+#ifdef CONFIG_ADS8272
+               .name           = "HRCW",
+               .size           = 0x40000,
+               .offset         = 0,
+               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
+       }, {
+               .name           = "User FS",
+               .size           = 0x5c0000,
+               .offset         = 0x40000,
+#else
+               .name           = "User FS",
+               .size           = 0x600000,
+               .offset         = 0,
+#endif
+       }, {
+               .name           = "uImage",
+               .size           = 0x100000,
+               .offset         = 0x600000,
+               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
+       }, {
+               .name           = "bootloader",
+               .size           = 0x40000,
+               .offset         = 0x700000,
+               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
+       }, {
+               .name           = "bootloader env",
+               .size           = 0x40000,
+               .offset         = 0x740000,
+               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
+       }
+};
+
+
+/* pointer to MPC885ADS board info data */
+extern unsigned char __res[];
+
+static int __init init_pq2fads_mtd(void)
+{
+       bd_t *bd = (bd_t *)__res;
+       physmap_configure(bd->bi_flashstart, bd->bi_flashsize, PQ2FADS_BANK_WIDTH, NULL);
+
+       physmap_set_partitions(pq2fads_partitions,
+                               sizeof (pq2fads_partitions) /
+                               sizeof (pq2fads_partitions[0]));
+       return 0;
+}
+
+static void __exit cleanup_pq2fads_mtd(void)
+{
+}
+
+module_init(init_pq2fads_mtd);
+module_exit(cleanup_pq2fads_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MTD map and partitions for MPC8272ADS boards");
index edd01ee4f90be1232c16c4a524fea994994fb2a7..5b76ed8861859d7ce47305de56b35ec991f4a11a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: redwood.c,v 1.10 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: redwood.c,v 1.11 2005/11/07 11:14:28 gleixner Exp $
  *
  * drivers/mtd/maps/redwood.c
  *
@@ -79,7 +79,7 @@ static struct mtd_partition redwood_flash_partitions[] = {
 
 #define RW_PART0_OF    0
 #define RW_PART0_SZ    0x400000        /* 4 MiB data */
-#define RW_PART1_OF    RW_PART0_OF + RW_PART0_SZ 
+#define RW_PART1_OF    RW_PART0_OF + RW_PART0_SZ
 #define RW_PART1_SZ    0x10000         /* 64K VPD */
 #define RW_PART2_OF    RW_PART1_OF + RW_PART1_SZ
 #define RW_PART2_SZ    0x400000 - (0x10000 + 0x20000)
index a31f6ee8a4be5834d5d2f7ff9b583c236ba121f1..9e8bb1782be00318ab3eb58264ccf087e3761c8d 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * Flash memory access on SA11x0 based devices
- * 
+ *
  * (C) 2000 Nicolas Pitre <nico@cam.org>
- * 
- * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $
+ *
+ * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $
  */
 #include <linux/config.h>
 #include <linux/module.h>
index da684d3384e923a37ec9e819c9ecc1e5e3a40840..225cdd9ba5b2f2d84054686d826e8cfff028b75b 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPLed
  *
- * $Id: sbc8240.c,v 1.4 2004/07/12 22:38:29 dwmw2 Exp $
+ * $Id: sbc8240.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $
  *
  */
 
@@ -205,7 +205,7 @@ int __init init_sbc8240_mtd (void)
                } else {
                        printk (KERN_NOTICE MSG_PREFIX
                                "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name);
-                       add_mtd_partitions (sbc8240_mtd[i], 
+                       add_mtd_partitions (sbc8240_mtd[i],
                                            sbc8240_part_banks[i].mtd_part,
                                            sbc8240_part_banks[i].nums);
                }
index 65add28bde14ce40d562aa2df5a6edb7a235dca9..7cc4041d096d6eaf5fb9e351760a95e1f1d2382c 100644 (file)
@@ -1,35 +1,35 @@
 /* sbc_gxx.c -- MTD map driver for Arcom Control Systems SBC-MediaGX,
                 SBC-GXm and SBC-GX1 series boards.
+
    Copyright (C) 2001 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: sbc_gxx.c,v 1.33 2004/11/28 09:40:40 dwmw2 Exp $
+   $Id: sbc_gxx.c,v 1.35 2005/11/07 11:14:28 gleixner Exp $
 
-The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
-Intel StrataFlash (28F320/28F640) in x8 mode.  
+The SBC-MediaGX / SBC-GXx has up to 16 MiB of
+Intel StrataFlash (28F320/28F640) in x8 mode.
 
 This driver uses the CFI probe and Intel Extended Command Set drivers.
 
 The flash is accessed as follows:
 
    16 KiB memory window at 0xdc000-0xdffff
-   
+
    Two IO address locations for paging
-   
+
    0x258
        bit 0-7: address bit 14-21
    0x259
@@ -37,7 +37,7 @@ The flash is accessed as follows:
        bit 7:   0 - reset/powered down
                 1 - device enabled
 
-The single flash device is divided into 3 partition which appear as 
+The single flash device is divided into 3 partition which appear as
 separate MTD devices.
 
 25/04/2001 AJL (Arcom)  Modified signon strings and partition sizes
@@ -87,17 +87,17 @@ static volatile int page_in_window = -1; // Current page in window.
 static void __iomem *iomapadr;
 static DEFINE_SPINLOCK(sbc_gxx_spin);
 
-/* partition_info gives details on the logical partitions that the split the 
+/* 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 = "SBC-GXx flash boot partition", 
-      .offset = 0, 
+    { .name = "SBC-GXx flash boot partition",
+      .offset = 0,
       .size =   BOOT_PARTITION_SIZE_KiB*1024 },
-    { .name = "SBC-GXx flash data partition", 
-      .offset = BOOT_PARTITION_SIZE_KiB*1024, 
+    { .name = "SBC-GXx flash data partition",
+      .offset = BOOT_PARTITION_SIZE_KiB*1024,
       .size = (DATA_PARTITION_SIZE_KiB)*1024 },
-    { .name = "SBC-GXx flash application partition", 
+    { .name = "SBC-GXx flash application partition",
       .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 }
 };
 
@@ -130,7 +130,7 @@ static void sbc_gxx_copy_from(struct map_info *map, void *to, unsigned long from
                unsigned long thislen = len;
                if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
                        thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-               
+
                spin_lock(&sbc_gxx_spin);
                sbc_gxx_page(map, from);
                memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
@@ -150,12 +150,12 @@ static void sbc_gxx_write8(struct map_info *map, map_word d, unsigned long adr)
 }
 
 static void sbc_gxx_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(&sbc_gxx_spin);
                sbc_gxx_page(map, to);
                memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen);
@@ -201,7 +201,7 @@ static int __init init_sbc_gxx(void)
                        sbc_gxx_map.name );
                return -EIO;
        }
-       
+
        if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) {
                printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n",
                        sbc_gxx_map.name,
@@ -209,8 +209,8 @@ static int __init init_sbc_gxx(void)
                iounmap(iomapadr);
                return -EAGAIN;
        }
-               
-       
+
+
        printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
                sbc_gxx_map.name,
                PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1,
@@ -222,7 +222,7 @@ static int __init init_sbc_gxx(void)
                cleanup_sbc_gxx();
                return -ENXIO;
        }
-       
+
        all_mtd->owner = THIS_MODULE;
 
        /* Create MTD devices for each partition. */
index a06ed21e7ed1b85f9799a08f87b821947f261c42..6fb9f3c57aabe1fc9fc443675d0bd82c5dd741ff 100644 (file)
@@ -16,7 +16,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: sc520cdp.c,v 1.21 2004/12/13 10:27:08 dedekind Exp $
+ * $Id: sc520cdp.c,v 1.22 2005/11/07 11:14:28 gleixner Exp $
  *
  *
  * The SC520CDP is an evaluation board for the Elan SC520 processor available
@@ -231,7 +231,7 @@ static void sc520cdp_setup_par(void)
 static int __init init_sc520cdp(void)
 {
        int i, devices_found = 0;
-       
+
 #ifdef REPROGRAM_PAR
        /* reprogram PAR registers so flash appears at the desired addresses */
        sc520cdp_setup_par();
@@ -278,7 +278,7 @@ static int __init init_sc520cdp(void)
 static void __exit cleanup_sc520cdp(void)
 {
        int i;
-       
+
        if (merged_mtd) {
                del_mtd_device(merged_mtd);
                mtd_concat_destroy(merged_mtd);
index 0ece3786d6ea5a179ebda4b43a8fbe0396653e73..2c91dff8bb60c881e015d9e8e6d53b6bba3c669c 100644 (file)
@@ -1,8 +1,8 @@
-/* linux/drivers/mtd/maps/scx200_docflash.c 
+/* linux/drivers/mtd/maps/scx200_docflash.c
 
    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
 
-   $Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $ 
+   $Id: scx200_docflash.c,v 1.12 2005/11/07 11:14:28 gleixner Exp $
 
    National Semiconductor SCx200 flash mapped with DOCCS
 */
@@ -49,23 +49,23 @@ static struct mtd_info *mymtd;
 
 #ifdef CONFIG_MTD_PARTITIONS
 static struct mtd_partition partition_info[] = {
-       { 
-               .name   = "DOCCS Boot kernel", 
-               .offset = 0, 
+       {
+               .name   = "DOCCS Boot kernel",
+               .offset = 0,
                .size   = 0xc0000
        },
-       { 
-               .name   = "DOCCS Low BIOS", 
-               .offset = 0xc0000, 
+       {
+               .name   = "DOCCS Low BIOS",
+               .offset = 0xc0000,
                .size   = 0x40000
        },
-       { 
-               .name   = "DOCCS File system", 
-               .offset = 0x100000, 
+       {
+               .name   = "DOCCS File system",
+               .offset = 0x100000,
                .size   = ~0    /* calculate from flash size */
        },
-       { 
-               .name   = "DOCCS High BIOS", 
+       {
+               .name   = "DOCCS High BIOS",
                .offset = ~0,   /* calculate from flash size */
                .size   = 0x80000
        },
@@ -88,7 +88,7 @@ static int __init init_scx200_docflash(void)
 
        printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
 
-       if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
+       if ((bridge = pci_find_device(PCI_VENDOR_ID_NS,
                                      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
                                      NULL)) == NULL)
                return -ENODEV;
@@ -134,28 +134,28 @@ static int __init init_scx200_docflash(void)
                        printk(KERN_ERR NAME ": invalid size for flash mapping\n");
                        return -EINVAL;
                }
-               
+
                if (width != 8 && width != 16) {
                        printk(KERN_ERR NAME ": invalid bus width for flash mapping\n");
                        return -EINVAL;
                }
-               
-               if (allocate_resource(&iomem_resource, &docmem, 
+
+               if (allocate_resource(&iomem_resource, &docmem,
                                      size,
-                                     0xc0000000, 0xffffffff, 
+                                     0xc0000000, 0xffffffff,
                                      size, NULL, NULL)) {
                        printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
                        return -ENOMEM;
                }
-               
+
                ctrl = 0x07000000 | ((size-1) >> 13);
 
                printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl);
-               
+
                pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start);
                pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl);
                pmr = inl(scx200_cb_base + SCx200_PMR);
-               
+
                if (width == 8) {
                        pmr &= ~(1<<6);
                } else {
@@ -163,8 +163,8 @@ static int __init init_scx200_docflash(void)
                }
                outl(pmr, scx200_cb_base + SCx200_PMR);
        }
-       
-               printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", 
+
+               printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n",
               docmem.start, docmem.end, width);
 
        scx200_docflash_map.size = size;
index b7f093fbf9b05396dc1f54a6c14bb3b0c501268e..999f4bb3d845ce475322c88db98f774036dbcbfb 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * sharpsl-flash.c
- * 
+ *
  * Copyright (C) 2001 Lineo Japan, Inc.
  * Copyright (C) 2002  SHARP
  *
- * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $
+ * $Id: sharpsl-flash.c,v 1.7 2005/11/07 11:14:28 gleixner 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
@@ -57,7 +57,7 @@ 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", 
+       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) {
@@ -75,7 +75,7 @@ int __init init_sharpsl(void)
 
        mymtd->owner = THIS_MODULE;
 
-       if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() 
+       if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky()
                || machine_is_poodle()) {
                sharpsl_partitions[0].size=0x006d0000;
                sharpsl_partitions[0].offset=0x00120000;
@@ -87,10 +87,10 @@ int __init init_sharpsl(void)
                sharpsl_partitions[0].offset=0x00140000;
        } else {
                map_destroy(mymtd);
-               iounmap(sharpsl_map.virt);      
+               iounmap(sharpsl_map.virt);
                return -ENODEV;
        }
-       
+
        parts = sharpsl_partitions;
        nb_parts = NB_OF(sharpsl_partitions);
 
index 8ce5d897645c71b450f6cc1b2120f2921fa1dad2..c53c2c369c9d5dcc2df5aec29b26c48c3e6157ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: solutionengine.c,v 1.14 2004/09/16 23:27:14 gleixner Exp $
+ * $Id: solutionengine.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $
  *
  * Flash and EPROM on Hitachi Solution Engine and similar boards.
  *
@@ -67,7 +67,7 @@ static int __init init_soleng_maps(void)
        soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000);
        simple_map_init(&soleng_eprom_map);
        simple_map_init(&soleng_flash_map);
-       
+
        printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
        flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map);
        if (!flash_mtd) {
index 1355c28f90a4d7432a59171a9622dfc710a92dea..0758cb1d01056568dfda74d55297f7e9a6daa791 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sun_uflash.c,v 1.11 2004/11/04 13:24:15 gleixner Exp $
+/* $Id: sun_uflash.c,v 1.13 2005/11/07 11:14:28 gleixner Exp $
  *
  * sun_uflash - Driver implementation for user-programmable flash
  * present on many Sun Microsystems SME boardsets.
@@ -63,7 +63,7 @@ int uflash_devinit(struct linux_ebus_device* edev)
        iTmp = prom_getproperty(
                edev->prom_node, "reg", (void *)regs, sizeof(regs));
        if ((iTmp % sizeof(regs[0])) != 0) {
-               printk("%s: Strange reg property size %d\n", 
+               printk("%s: Strange reg property size %d\n",
                        UFLASH_DEVNAME, iTmp);
                return -ENODEV;
        }
@@ -75,7 +75,7 @@ int uflash_devinit(struct linux_ebus_device* edev)
                 * can work on supporting it.
                 */
                printk("%s: unsupported device at 0x%lx (%d regs): " \
-                       "email ebrower@usa.net\n", 
+                       "email ebrower@usa.net\n",
                        UFLASH_DEVNAME, edev->resource[0].start, nregs);
                return -ENODEV;
        }
@@ -84,7 +84,7 @@ int uflash_devinit(struct linux_ebus_device* edev)
                printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME);
                return(-ENOMEM);
        }
-       
+
        /* copy defaults and tweak parameters */
        memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ));
        pdev->map.size = regs[0].reg_size;
@@ -155,7 +155,7 @@ static void __exit uflash_cleanup(void)
 
        list_for_each(udevlist, &device_list) {
                udev = list_entry(udevlist, struct uflash_dev, list);
-               DEBUG(2, "%s: removing device %s\n", 
+               DEBUG(2, "%s: removing device %s\n",
                        UFLASH_DEVNAME, udev->name);
 
                if(0 != udev->mtd) {
@@ -168,7 +168,7 @@ static void __exit uflash_cleanup(void)
                }
                kfree(udev->name);
                kfree(udev);
-       }       
+       }
 }
 
 module_init(uflash_init);
diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c
new file mode 100644 (file)
index 0000000..c7ae9a5
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * drivers/mtd/maps/tqm834x.c
+ *
+ * MTD mapping driver for TQM834x boards
+ *
+ * Copyright 2005 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <asm/io.h>
+#include <asm/ppcboot.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define FLASH_BANK_MAX 2
+
+extern unsigned char __res[];
+
+/* trivial struct to describe partition information */
+struct mtd_part_def
+{
+       int nums;
+       unsigned char *type;
+       struct mtd_partition* mtd_part;
+};
+
+static struct mtd_info* mtd_banks[FLASH_BANK_MAX];
+static struct map_info* map_banks[FLASH_BANK_MAX];
+static struct mtd_part_def part_banks[FLASH_BANK_MAX];
+
+static unsigned long num_banks;
+static unsigned long start_scan_addr;
+
+#ifdef CONFIG_MTD_PARTITIONS
+/*
+ * The following defines the partition layout of TQM834x boards.
+ *
+ * See include/linux/mtd/partitions.h for definition of the
+ * mtd_partition structure.
+ *
+ * Assume minimal initial size of 4 MiB per bank, will be updated
+ * later in init_tqm834x_mtd() routine.
+ */
+
+/* Partition definition for the first flash bank which is always present. */
+static struct mtd_partition tqm834x_partitions_bank1[] = {
+       {
+               .name   = "u-boot",             /* u-boot firmware      */
+               .offset = 0x00000000,
+               .size   = 0x00040000,           /* 256 KiB              */
+               /*mask_flags: MTD_WRITEABLE,     * force read-only      */
+       },
+       {
+               .name   = "env",                /* u-boot environment   */
+               .offset = 0x00040000,
+               .size   = 0x00020000,           /* 128 KiB              */
+               /*mask_flags: MTD_WRITEABLE,     * force read-only      */
+       },
+       {
+               .name   = "kernel",             /* linux kernel image   */
+               .offset = 0x00060000,
+               .size   = 0x00100000,           /* 1 MiB                */
+               /*mask_flags: MTD_WRITEABLE,     * force read-only      */
+       },
+       {
+               .name   = "initrd",             /* ramdisk image        */
+               .offset = 0x00160000,
+               .size   = 0x00200000,           /* 2 MiB                */
+       },
+       {
+               .name   = "user",               /* user data            */
+               .offset = 0x00360000,
+               .size   = 0x000a0000,           /* remaining space      */
+               /* NOTE: this parttion size is re-calcated in           */
+               /* init_tqm834x_mtd() to cover actual remaining space.  */
+       },
+};
+
+/* Partition definition for the second flash bank which may be present on some
+ * TQM834x boards.
+ */
+static struct mtd_partition tqm834x_partitions_bank2[] = {
+       {
+               .name   = "jffs2",              /* jffs2 filesystem     */
+               .offset = 0x00000000,
+               .size   = 0x00400000,           /* whole device         */
+               /* NOTE: this parttion size is re-calcated in           */
+               /* init_tqm834x_mtd() to cover actual device size.      */
+       },
+};
+
+#endif /* CONFIG_MTD_PARTITIONS */
+
+static int __init init_tqm834x_mtd(void)
+{
+       int idx = 0, ret = 0;
+       unsigned long flash_addr, flash_size, mtd_size = 0;
+
+       /* pointer to TQM834x board info data */
+       bd_t *bd = (bd_t *)__res;
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+       int n;
+       char mtdid[4];
+       const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+       flash_addr = bd->bi_flashstart;
+       flash_size = bd->bi_flashsize;
+
+       /* request maximum flash size address space */
+       start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size);
+       if (!start_scan_addr) {
+               printk("%s: Failed to ioremap address: 0x%lx\n",
+                      __FUNCTION__, flash_addr);
+               return -EIO;
+       }
+
+       for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
+               if (mtd_size >= flash_size)
+                       break;
+
+               pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx);
+
+               map_banks[idx] =
+                       (struct map_info *)kmalloc(sizeof(struct map_info),
+                                                  GFP_KERNEL);
+               if (map_banks[idx] == NULL) {
+                       ret = -ENOMEM;
+                       goto error_mem;
+               }
+               memset((void *)map_banks[idx], 0, sizeof(struct map_info));
+               map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
+               if (map_banks[idx]->name == NULL) {
+                       ret = -ENOMEM;
+                       goto error_mem;
+               }
+               memset((void *)map_banks[idx]->name, 0, 16);
+
+               sprintf(map_banks[idx]->name, "TQM834x-%d", idx);
+               map_banks[idx]->size = flash_size;
+               map_banks[idx]->bankwidth = 4;
+
+               simple_map_init(map_banks[idx]);
+
+               map_banks[idx]->virt = (void __iomem *)
+                       (start_scan_addr + ((idx > 0) ?
+                       (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0));
+               map_banks[idx]->phys =
+                       flash_addr + ((idx > 0) ?
+                       (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0);
+
+               /* start to probe flash chips */
+               mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]);
+               if (mtd_banks[idx]) {
+                       mtd_banks[idx]->owner = THIS_MODULE;
+                       mtd_size += mtd_banks[idx]->size;
+                       num_banks++;
+                       pr_debug("%s: bank %ld, name: %s, size: %d bytes \n",
+                                __FUNCTION__, num_banks,
+                                mtd_banks[idx]->name, mtd_banks[idx]->size);
+               }
+       }
+
+       /* no supported flash chips found */
+       if (!num_banks) {
+               printk("TQM834x: No supported flash chips found!\n");
+               ret = -ENXIO;
+               goto error_mem;
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+       /*
+        * Select static partition definitions
+        */
+       n = ARRAY_SIZE(tqm834x_partitions_bank1);
+       part_banks[0].mtd_part  = tqm834x_partitions_bank1;
+       part_banks[0].type      = "static image bank1";
+       part_banks[0].nums      = n;
+
+       /* update last partition size to cover actual remaining space */
+       tqm834x_partitions_bank1[n - 1].size =
+               mtd_banks[0]->size -
+               tqm834x_partitions_bank1[n - 1].offset;
+
+       /* check if we have second bank? */
+       if (num_banks == 2) {
+               n = ARRAY_SIZE(tqm834x_partitions_bank2);
+               part_banks[1].mtd_part  = tqm834x_partitions_bank2;
+               part_banks[1].type      = "static image bank2";
+               part_banks[1].nums      = n;
+
+               /* update last partition size to cover actual remaining space */
+               tqm834x_partitions_bank2[n - 1].size =
+                       mtd_banks[1]->size -
+                       tqm834x_partitions_bank2[n - 1].offset;
+       }
+
+       for(idx = 0; idx < num_banks ; idx++) {
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+               sprintf(mtdid, "%d", idx);
+               n = parse_mtd_partitions(mtd_banks[idx],
+                                        part_probes,
+                                        &part_banks[idx].mtd_part,
+                                        0);
+               pr_debug("%s: %d command line partitions on bank %s\n",
+                        __FUNCTION__, n, mtdid);
+               if (n > 0) {
+                       part_banks[idx].type = "command line";
+                       part_banks[idx].nums = n;
+               }
+#endif /* CONFIG_MTD_CMDLINE_PARTS */
+               if (part_banks[idx].nums == 0) {
+                       printk(KERN_NOTICE
+                              "TQM834x flash bank %d: no partition info "
+                              "available, registering whole device\n", idx);
+                       add_mtd_device(mtd_banks[idx]);
+               } else {
+                       printk(KERN_NOTICE
+                              "TQM834x flash bank %d: Using %s partition "
+                              "definition\n", idx, part_banks[idx].type);
+                       add_mtd_partitions(mtd_banks[idx],
+                                          part_banks[idx].mtd_part,
+                                          part_banks[idx].nums);
+               }
+       }
+#else  /* ! CONFIG_MTD_PARTITIONS */
+       printk(KERN_NOTICE "TQM834x flash: registering %d flash banks "
+                       "at once\n", num_banks);
+
+       for(idx = 0 ; idx < num_banks ; idx++)
+               add_mtd_device(mtd_banks[idx]);
+
+#endif /* CONFIG_MTD_PARTITIONS */
+
+       return 0;
+error_mem:
+       for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
+               if (map_banks[idx] != NULL) {
+                       if (map_banks[idx]->name != NULL) {
+                               kfree(map_banks[idx]->name);
+                               map_banks[idx]->name = NULL;
+                       }
+                       kfree(map_banks[idx]);
+                       map_banks[idx] = NULL;
+               }
+       }
+
+       iounmap((void *)start_scan_addr);
+
+       return ret;
+}
+
+static void __exit cleanup_tqm834x_mtd(void)
+{
+       unsigned int idx = 0;
+       for(idx = 0 ; idx < num_banks ; idx++) {
+               /* destroy mtd_info previously allocated */
+               if (mtd_banks[idx]) {
+                       del_mtd_partitions(mtd_banks[idx]);
+                       map_destroy(mtd_banks[idx]);
+               }
+
+               /* release map_info not used anymore */
+               kfree(map_banks[idx]->name);
+               kfree(map_banks[idx]);
+       }
+
+       if (start_scan_addr) {
+               iounmap((void *)start_scan_addr);
+               start_scan_addr = 0;
+       }
+}
+
+module_init(init_tqm834x_mtd);
+module_exit(cleanup_tqm834x_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Wolfgang Denk <wd@denx.de>");
+MODULE_DESCRIPTION("MTD map driver for TQM834x boards");
index 0aca8179f27f676f022a6efb5eed81cd9a9412aa..a43517053e7cfe4819a51f0c1974ffc767ef8251 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Handle mapping of the flash memory access routines 
+ * Handle mapping of the flash memory access routines
  * on TQM8xxL based devices.
  *
- * $Id: tqm8xxl.c,v 1.13 2004/10/20 22:21:53 dwmw2 Exp $
+ * $Id: tqm8xxl.c,v 1.15 2005/11/07 11:14:28 gleixner Exp $
  *
  * based on rpxlite.c
  *
  * Copyright(C) 2001 Kirk Lee <kirk@hpc.ee.ntu.edu.tw>
  *
  * This code is GPLed
- * 
+ *
  */
 
 /*
@@ -19,7 +19,7 @@
  *         2MiB           512Kx16        2MiB             0
  *         4MiB           1Mx16          4MiB             0
  *         8MiB           1Mx16          4MiB             4MiB
- * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at 
+ * Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at
  * kernel configuration.
  */
 #include <linux/config.h>
@@ -58,9 +58,9 @@ static void __iomem *start_scan_addr;
  * Here are partition information for all known TQM8xxL series devices.
  * See include/linux/mtd/partitions.h for definition of the mtd_partition
  * structure.
- * 
+ *
  * The *_max_flash_size is the maximum possible mapped flash size which
- * is not necessarily the actual flash size.  It must correspond to the 
+ * is not necessarily the actual flash size.  It must correspond to the
  * value specified in the mapping definition defined by the
  * "struct map_desc *_io_desc" for the corresponding machine.
  */
@@ -132,9 +132,9 @@ int __init init_tqm_mtd(void)
        for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) {
                if(mtd_size >= flash_size)
                        break;
-               
+
                printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
-               
+
                map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL);
                if(map_banks[idx] == NULL) {
                        ret = -ENOMEM;
@@ -180,7 +180,7 @@ int __init init_tqm_mtd(void)
                        mtd_size += mtd_banks[idx]->size;
                        num_banks++;
 
-                       printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, 
+                       printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks,
                        mtd_banks[idx]->name, mtd_banks[idx]->size);
                }
        }
@@ -211,7 +211,7 @@ int __init init_tqm_mtd(void)
                } else {
                        printk(KERN_NOTICE "TQM flash%d: Using %s partition definition\n",
                                        idx, part_banks[idx].type);
-                       add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part, 
+                       add_mtd_partitions(mtd_banks[idx], part_banks[idx].mtd_part,
                                                                part_banks[idx].nums);
                }
        }
index 3ebd90f5650331e730ea7d9bdf8b71e470ed7ae3..4b372bcb17f1c0b6dbd5ec3312aa59edbb97f7dd 100644 (file)
  *
  * Note:
  * - In order for detection to work, jumper 3 must be set.
- * - Drive A and B use a proprietary FTL from General Software which isn't 
- *   supported as of yet so standard drives can't be mounted; you can create 
- *   your own (e.g. jffs) file system.
- * - If you have created your own jffs file system and the bios overwrites 
+ * - Drive A and B use the resident flash disk (RFD) flash translation layer.
+ * - If you have created your own jffs file system and the bios overwrites
  *   it during boot, try disabling Drive A: and B: in the boot order.
  *
- * $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: ts5500_flash.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
-
-#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#endif
+#include <linux/types.h>
+
 
 #define WINDOW_ADDR    0x09400000
 #define WINDOW_SIZE    0x00200000
@@ -50,7 +46,6 @@ static struct map_info ts5500_map = {
        .phys = WINDOW_ADDR
 };
 
-#ifdef CONFIG_MTD_PARTITIONS
 static struct mtd_partition ts5500_partitions[] = {
        {
                .name = "Drive A",
@@ -71,8 +66,6 @@ static struct mtd_partition ts5500_partitions[] = {
 
 #define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition))
 
-#endif
-
 static struct mtd_info *mymtd;
 
 static int __init init_ts5500_map(void)
@@ -81,48 +74,39 @@ static int __init init_ts5500_map(void)
 
        ts5500_map.virt = ioremap_nocache(ts5500_map.phys, ts5500_map.size);
 
-       if(!ts5500_map.virt) {
+       if (!ts5500_map.virt) {
                printk(KERN_ERR "Failed to ioremap_nocache\n");
                rc = -EIO;
-               goto err_out_ioremap;
+               goto err2;
        }
 
        simple_map_init(&ts5500_map);
 
        mymtd = do_map_probe("jedec_probe", &ts5500_map);
-       if(!mymtd)
+       if (!mymtd)
                mymtd = do_map_probe("map_rom", &ts5500_map);
 
-       if(!mymtd) {
+       if (!mymtd) {
                rc = -ENXIO;
-               goto err_out_map;
+               goto err1;
        }
 
        mymtd->owner = THIS_MODULE;
-#ifdef CONFIG_MTD_PARTITIONS
        add_mtd_partitions(mymtd, ts5500_partitions, NUM_PARTITIONS);
-#else  
-       add_mtd_device(mymtd);
-#endif
 
        return 0;
 
-err_out_map:
+err1:
        map_destroy(mymtd);
-err_out_ioremap:
        iounmap(ts5500_map.virt);
-
+err2:
        return rc;
 }
 
 static void __exit cleanup_ts5500_map(void)
 {
        if (mymtd) {
-#ifdef CONFIG_MTD_PARTITIONS
                del_mtd_partitions(mymtd);
-#else
-               del_mtd_device(mymtd);
-#endif
                map_destroy(mymtd);
        }
 
index 170d71239e5ed5d4b776244857b7f3e7ab081a5a..9e21e6c02f80df8af03aec9fdd9f0d8cd6cfd062 100644 (file)
@@ -2,7 +2,7 @@
  * tsunami_flash.c
  *
  * flash chip on alpha ds10...
- * $Id: tsunami_flash.c,v 1.9 2004/07/14 09:52:55 dwmw2 Exp $
+ * $Id: tsunami_flash.c,v 1.10 2005/11/07 11:14:29 gleixner Exp $
  */
 #include <asm/io.h>
 #include <asm/core_tsunami.h>
@@ -41,7 +41,7 @@ static void tsunami_flash_copy_from(
 }
 
 static void tsunami_flash_copy_to(
-       struct map_info *map, unsigned long offset, 
+       struct map_info *map, unsigned long offset,
        const void *addr, ssize_t len)
 {
        const unsigned char *src;
@@ -90,7 +90,7 @@ static int __init init_tsunami_flash(void)
        char **type;
 
        tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT);
-       
+
        tsunami_flash_mtd = 0;
        type = rom_probe_types;
        for(; !tsunami_flash_mtd && *type; type++) {
index cc372136e852750f87f42dd3d69c0d917d074908..79d92808b766fea1f006faedb5fb0d914d712238 100644 (file)
@@ -5,7 +5,7 @@
  *
  *     (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
  *
- *     $Id: uclinux.c,v 1.10 2005/01/05 18:05:13 dwmw2 Exp $
+ *     $Id: uclinux.c,v 1.12 2005/11/07 11:14:29 gleixner Exp $
  */
 
 /****************************************************************************/
@@ -82,7 +82,7 @@ int __init uclinux_mtd_init(void)
                iounmap(mapp->virt);
                return(-ENXIO);
        }
-               
+
        mtd->owner = THIS_MODULE;
        mtd->point = uclinux_point;
        mtd->priv = mapp;
index c8c74110ed1b561b7fde5b32fefb4fbb131417cb..e0063941c0df3090e71363c8325ef263d8d40ba8 100644 (file)
@@ -1,19 +1,19 @@
-// $Id: vmax301.c,v 1.30 2004/07/12 22:38:29 dwmw2 Exp $
+// $Id: vmax301.c,v 1.32 2005/11/07 11:14:29 gleixner Exp $
 /* ######################################################################
 
    Tempustech VMAX SBC301 MTD Driver.
-  
+
    The VMAx 301 is a SBC based on . It
    comes with three builtin AMD 29F016B flash chips and a socket for SRAM or
-   more flash. Each unit has it's own 8k mapping into a settable region 
+   more flash. Each unit has it's own 8k mapping into a settable region
    (0xD8000). There are two 8k mappings for each MTD, the first is always set
    to the lower 8k of the device the second is paged. Writing a 16 bit page
    value to anywhere in the first 8k will cause the second 8k to page around.
 
-   To boot the device a bios extension must be installed into the first 8k 
-   of flash that is smart enough to copy itself down, page in the rest of 
+   To boot the device a bios extension must be installed into the first 8k
+   of flash that is smart enough to copy itself down, page in the rest of
    itself and begin executing.
-   
+
    ##################################################################### */
 
 #include <linux/module.h>
@@ -35,7 +35,7 @@
 /* Actually we could use two spinlocks, but we'd have to have
    more private space in the struct map_info. We lose a little
    performance like this, but we'd probably lose more by having
-   the extra indirection from having one of the map->map_priv 
+   the extra indirection from having one of the map->map_priv
    fields pointing to yet another private struct.
 */
 static DEFINE_SPINLOCK(vmax301_spin);
@@ -98,7 +98,7 @@ static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *
                spin_lock(&vmax301_spin);
                vmax301_page(map, to);
                memcpy_toio(map->map_priv_2 + to, from, thislen);
-               spin_unlock(&vmax301_spin);             
+               spin_unlock(&vmax301_spin);
                to += thislen;
                from += thislen;
                len -= thislen;
@@ -137,7 +137,7 @@ static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
 static void __exit cleanup_vmax301(void)
 {
        int i;
-       
+
        for (i=0; i<2; i++) {
                if (vmax_mtd[i]) {
                        del_mtd_device(vmax_mtd[i]);
@@ -161,13 +161,13 @@ int __init init_vmax301(void)
                return -EIO;
        }
        /* Put the address in the map's private data area.
-          We store the actual MTD IO address rather than the 
+          We store the actual MTD IO address rather than the
           address of the first half, because it's used more
-          often. 
+          often.
        */
        vmax_map[0].map_priv_2 = iomapadr + WINDOW_START;
        vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START);
-       
+
        for (i=0; i<2; i++) {
                vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]);
                if (!vmax_mtd[i])
index d6137b1b567025c667a6f4f37361baca533f07bb..5c17bca3a37e0d52e981b65ec638e59d75524b06 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * $Id: walnut.c,v 1.2 2004/12/10 12:07:42 holindho Exp $
- * 
+ * $Id: walnut.c,v 1.3 2005/11/07 11:14:29 gleixner Exp $
+ *
  * Mapping for Walnut flash
  * (used ebony.c as a "framework")
- * 
+ *
  * Heikki Lindholm <holindho@infradead.org>
- * 
- * 
+ *
+ *
  * 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
@@ -48,7 +48,7 @@ static struct mtd_partition walnut_partitions[] = {
                .name =   "OpenBIOS",
                .offset = 0x0,
                .size =   WALNUT_FLASH_SIZE,
-               /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */         
+               /*.mask_flags = MTD_WRITEABLE, */ /* force read-only */
        }
 };
 
@@ -72,11 +72,11 @@ int __init init_walnut(void)
                printk("The on-board flash is disabled (U79 sw 5)!");
                return -EIO;
        }
-       if (WALNUT_FLASH_SRAM_SEL(fpga_brds1)) 
+       if (WALNUT_FLASH_SRAM_SEL(fpga_brds1))
                flash_base = WALNUT_FLASH_LOW;
        else
                flash_base = WALNUT_FLASH_HIGH;
-       
+
        walnut_map.phys = flash_base;
        walnut_map.virt =
                (void __iomem *)ioremap(flash_base, walnut_map.size);
index 82b887b05707127785d38a33e7d715394beae914..60c197ec455b87cf40b6ee20303fdb0fe3046610 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: wr_sbc82xx_flash.c,v 1.7 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: wr_sbc82xx_flash.c,v 1.8 2005/11/07 11:14:29 gleixner Exp $
  *
  * Map for flash chips on Wind River PowerQUICC II SBC82xx board.
  *
@@ -163,10 +163,10 @@ static void __exit cleanup_sbc82xx_flash(void)
                        del_mtd_partitions(sbcmtd[i]);
                else
                        del_mtd_device(sbcmtd[i]);
-                       
+
                kfree(sbcmtd_parts[i]);
                map_destroy(sbcmtd[i]);
-               
+
                iounmap((void *)sbc82xx_flash_map[i].virt);
                sbc82xx_flash_map[i].virt = 0;
        }
index f8d2185819e7e2e17348b0c3fd8b0c2b41208d44..339cb1218eaa0b9d7e7431f069ec89a354051873 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtd_blkdevs.c,v 1.24 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtd_blkdevs.c,v 1.27 2005/11/07 11:14:20 gleixner Exp $
  *
  * (C) 2003 David Woodhouse <dwmw2@infradead.org>
  *
@@ -21,7 +21,6 @@
 #include <linux/init.h>
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
-#include <linux/devfs_fs_kernel.h>
 
 static LIST_HEAD(blktrans_majors);
 
@@ -86,7 +85,7 @@ static int mtd_blktrans_thread(void *arg)
        daemonize("%sd", tr->name);
 
        /* daemonize() doesn't do this for us since some kernel threads
-          actually want to deal with signals. We can't just call 
+          actually want to deal with signals. We can't just call
           exit_sighand() since that'll cause an oops when we finally
           do exit. */
        spin_lock_irq(&current->sighand->siglock);
@@ -95,7 +94,7 @@ static int mtd_blktrans_thread(void *arg)
        spin_unlock_irq(&current->sighand->siglock);
 
        spin_lock_irq(rq->queue_lock);
-               
+
        while (!tr->blkcore_priv->exiting) {
                struct request *req;
                struct mtd_blktrans_dev *dev;
@@ -158,7 +157,7 @@ static int blktrans_open(struct inode *i, struct file *f)
        if (!try_module_get(tr->owner))
                goto out_tr;
 
-       /* FIXME: Locking. A hot pluggable device can go away 
+       /* FIXME: Locking. A hot pluggable device can go away
           (del_mtd_device can be called for it) without its module
           being unloaded. */
        dev->mtd->usecount++;
@@ -196,7 +195,7 @@ static int blktrans_release(struct inode *i, struct file *f)
 }
 
 
-static int blktrans_ioctl(struct inode *inode, struct file *file, 
+static int blktrans_ioctl(struct inode *inode, struct file *file,
                              unsigned int cmd, unsigned long arg)
 {
        struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data;
@@ -265,7 +264,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
                        /* Required number was free */
                        list_add_tail(&new->list, &d->list);
                        goto added;
-               } 
+               }
                last_devnum = d->devnum;
        }
        if (new->devnum == -1)
@@ -289,11 +288,19 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        gd->major = tr->major;
        gd->first_minor = (new->devnum) << tr->part_bits;
        gd->fops = &mtd_blktrans_ops;
-       
-       snprintf(gd->disk_name, sizeof(gd->disk_name),
-                "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
-       snprintf(gd->devfs_name, sizeof(gd->devfs_name),
-                "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
+
+       if (tr->part_bits)
+               if (new->devnum < 26)
+                       snprintf(gd->disk_name, sizeof(gd->disk_name),
+                                "%s%c", tr->name, 'a' + new->devnum);
+               else
+                       snprintf(gd->disk_name, sizeof(gd->disk_name),
+                                "%s%c%c", tr->name,
+                                'a' - 1 + new->devnum / 26,
+                                'a' + new->devnum % 26);
+       else
+               snprintf(gd->disk_name, sizeof(gd->disk_name),
+                        "%s%d", tr->name, new->devnum);
 
        /* 2.5 has capacity in units of 512 bytes while still
           having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
@@ -307,7 +314,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
                set_disk_ro(gd, 1);
 
        add_disk(gd);
-       
+
        return 0;
 }
 
@@ -322,7 +329,7 @@ int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
 
        del_gendisk(old->blkcore_priv);
        put_disk(old->blkcore_priv);
-               
+
        return 0;
 }
 
@@ -361,12 +368,12 @@ static struct mtd_notifier blktrans_notifier = {
        .add = blktrans_notify_add,
        .remove = blktrans_notify_remove,
 };
-      
+
 int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
 {
        int ret, i;
 
-       /* Register the notifier if/when the first device type is 
+       /* Register the notifier if/when the first device type is
           registered, to prevent the link/init ordering from fucking
           us over. */
        if (!blktrans_notifier.list.next)
@@ -409,9 +416,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
                kfree(tr->blkcore_priv);
                up(&mtd_table_mutex);
                return ret;
-       } 
-
-       devfs_mk_dir(tr->name);
+       }
 
        INIT_LIST_HEAD(&tr->devs);
        list_add(&tr->list, &blktrans_majors);
@@ -445,7 +450,6 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
                tr->remove_dev(dev);
        }
 
-       devfs_remove(tr->name);
        blk_cleanup_queue(tr->blkcore_priv->rq);
        unregister_blkdev(tr->major, tr->name);
 
index 400dd9c89883bb1462c85ae48646738abb8fb72b..e84756644fd1e1f5559a87406a6d71877c369bb8 100644 (file)
@@ -1,21 +1,22 @@
-/* 
+/*
  * Direct MTD block device access
  *
- * $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $
+ * $Id: mtdblock.c,v 1.68 2005/11/07 11:14:20 gleixner Exp $
  *
  * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
  * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
  */
 
 #include <linux/config.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/types.h>
 #include <linux/vmalloc.h>
-#include <linux/sched.h>       /* TASK_* */
+
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/blktrans.h>
 
@@ -31,7 +32,7 @@ static struct mtdblk_dev {
 
 /*
  * Cache stuff...
- * 
+ *
  * Since typical flash erasable sectors are much larger than what Linux's
  * buffer cache can handle, we must implement read-modify-write on flash
  * sectors for each block write requests.  To avoid over-erasing flash sectors
@@ -45,7 +46,7 @@ static void erase_callback(struct erase_info *done)
        wake_up(wait_q);
 }
 
-static int erase_write (struct mtd_info *mtd, unsigned long pos, 
+static int erase_write (struct mtd_info *mtd, unsigned long pos,
                        int len, const char *buf)
 {
        struct erase_info erase;
@@ -103,18 +104,18 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)
                return 0;
 
        DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" "
-                       "at 0x%lx, size 0x%x\n", mtd->name, 
+                       "at 0x%lx, size 0x%x\n", mtd->name,
                        mtdblk->cache_offset, mtdblk->cache_size);
-       
-       ret = erase_write (mtd, mtdblk->cache_offset, 
+
+       ret = erase_write (mtd, mtdblk->cache_offset,
                           mtdblk->cache_size, mtdblk->cache_data);
        if (ret)
                return ret;
 
        /*
         * Here we could argubly set the cache state to STATE_CLEAN.
-        * However this could lead to inconsistency since we will not 
-        * be notified if this content is altered on the flash by other 
+        * However this could lead to inconsistency since we will not
+        * be notified if this content is altered on the flash by other
         * means.  Let's declare it empty and leave buffering tasks to
         * the buffer cache instead.
         */
@@ -123,7 +124,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk)
 }
 
 
-static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, 
+static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
                            int len, const char *buf)
 {
        struct mtd_info *mtd = mtdblk->mtd;
@@ -133,7 +134,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
 
        DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
                mtd->name, pos, len);
-       
+
        if (!sect_size)
                return MTD_WRITE (mtd, pos, len, &retlen, buf);
 
@@ -141,11 +142,11 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
                unsigned long sect_start = (pos/sect_size)*sect_size;
                unsigned int offset = pos - sect_start;
                unsigned int size = sect_size - offset;
-               if( size > len ) 
+               if( size > len )
                        size = len;
 
                if (size == sect_size) {
-                       /* 
+                       /*
                         * We are covering a whole sector.  Thus there is no
                         * need to bother with the cache while it may still be
                         * useful for other partial writes.
@@ -159,7 +160,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
                        if (mtdblk->cache_state == STATE_DIRTY &&
                            mtdblk->cache_offset != sect_start) {
                                ret = write_cached_data(mtdblk);
-                               if (ret) 
+                               if (ret)
                                        return ret;
                        }
 
@@ -192,7 +193,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,
 }
 
 
-static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, 
+static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
                           int len, char *buf)
 {
        struct mtd_info *mtd = mtdblk->mtd;
@@ -200,9 +201,9 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
        size_t retlen;
        int ret;
 
-       DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", 
+       DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",
                        mtd->name, pos, len);
-       
+
        if (!sect_size)
                return MTD_READ (mtd, pos, len, &retlen, buf);
 
@@ -210,7 +211,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,
                unsigned long sect_start = (pos/sect_size)*sect_size;
                unsigned int offset = pos - sect_start;
                unsigned int size = sect_size - offset;
-               if (size > len) 
+               if (size > len)
                        size = len;
 
                /*
@@ -268,12 +269,12 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
        int dev = mbd->devnum;
 
        DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
-       
+
        if (mtdblks[dev]) {
                mtdblks[dev]->count++;
                return 0;
        }
-       
+
        /* OK, it's not open. Create cache info for it */
        mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
        if (!mtdblk)
@@ -292,7 +293,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
        }
 
        mtdblks[dev] = mtdblk;
-       
+
        DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
 
        return 0;
@@ -320,7 +321,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd)
        DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
 
        return 0;
-}  
+}
 
 static int mtdblock_flush(struct mtd_blktrans_dev *dev)
 {
index 16df1e4fb0e94d2efec9542e6114f0593c3ad3bf..6f044584bdc6ac3b38c4a20949bfcbabb5f292ae 100644 (file)
@@ -1,22 +1,23 @@
 /*
- * $Id: mtdchar.c,v 1.73 2005/07/04 17:36:41 gleixner Exp $
+ * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $
  *
  * Character-device access to raw MTD devices.
  *
  */
 
 #include <linux/config.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/compatmac.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/sched.h>       /* TASK_* */
-#include <asm/uaccess.h>
 
-#include <linux/device.h>
+#include <asm/uaccess.h>
 
 static struct class *mtd_class;
 
@@ -27,7 +28,7 @@ static void mtd_notify_add(struct mtd_info* mtd)
 
        class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
                            NULL, "mtd%d", mtd->index);
-       
+
        class_device_create(mtd_class, NULL,
                            MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
                            NULL, "mtd%dro", mtd->index);
@@ -70,26 +71,23 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
        switch (orig) {
        case 0:
                /* SEEK_SET */
-               file->f_pos = offset;
                break;
        case 1:
                /* SEEK_CUR */
-               file->f_pos += offset;
+               offset += file->f_pos;
                break;
        case 2:
                /* SEEK_END */
-               file->f_pos =mtd->size + offset;
+               offset += mtd->size;
                break;
        default:
                return -EINVAL;
        }
 
-       if (file->f_pos < 0)
-               file->f_pos = 0;
-       else if (file->f_pos >= mtd->size)
-               file->f_pos = mtd->size - 1;
+       if (offset >= 0 && offset < mtd->size)
+               return file->f_pos = offset;
 
-       return file->f_pos;
+       return -EINVAL;
 }
 
 
@@ -110,23 +108,23 @@ static int mtd_open(struct inode *inode, struct file *file)
                return -EACCES;
 
        mtd = get_mtd_device(NULL, devnum);
-       
+
        if (!mtd)
                return -ENODEV;
-       
+
        if (MTD_ABSENT == mtd->type) {
                put_mtd_device(mtd);
                return -ENODEV;
        }
 
        file->private_data = mtd;
-               
+
        /* You can't open it RW if it's not a writeable device */
        if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
                put_mtd_device(mtd);
                return -EACCES;
        }
-               
+
        return 0;
 } /* mtd_open */
 
@@ -139,10 +137,10 @@ static int mtd_close(struct inode *inode, struct file *file)
        DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
 
        mtd = TO_MTD(file);
-       
+
        if (mtd->sync)
                mtd->sync(mtd);
-       
+
        put_mtd_device(mtd);
 
        return 0;
@@ -161,7 +159,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
        int ret=0;
        int len;
        char *kbuf;
-       
+
        DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
 
        if (*ppos + count > mtd->size)
@@ -169,11 +167,11 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
 
        if (!count)
                return 0;
-       
+
        /* FIXME: Use kiovec in 2.5 to lock down the user's buffers
           and pass them directly to the MTD functions */
        while (count) {
-               if (count > MAX_KMALLOC_SIZE) 
+               if (count > MAX_KMALLOC_SIZE)
                        len = MAX_KMALLOC_SIZE;
                else
                        len = count;
@@ -181,7 +179,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
                kbuf=kmalloc(len,GFP_KERNEL);
                if (!kbuf)
                        return -ENOMEM;
-               
+
                switch (MTD_MODE(file)) {
                case MTD_MODE_OTP_FACT:
                        ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
@@ -194,7 +192,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
                }
                /* Nand returns -EBADMSG on ecc errors, but it returns
                 * the data. For our userspace tools it is important
-                * to dump areas with ecc errors ! 
+                * to dump areas with ecc errors !
                 * Userspace software which accesses NAND this way
                 * must be aware of the fact that it deals with NAND
                 */
@@ -216,7 +214,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
                        kfree(kbuf);
                        return ret;
                }
-               
+
                kfree(kbuf);
        }
 
@@ -233,10 +231,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
        int len;
 
        DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
-       
+
        if (*ppos == mtd->size)
                return -ENOSPC;
-       
+
        if (*ppos + count > mtd->size)
                count = mtd->size - *ppos;
 
@@ -244,7 +242,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
                return 0;
 
        while (count) {
-               if (count > MAX_KMALLOC_SIZE) 
+               if (count > MAX_KMALLOC_SIZE)
                        len = MAX_KMALLOC_SIZE;
                else
                        len = count;
@@ -259,7 +257,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
                        kfree(kbuf);
                        return -EFAULT;
                }
-               
+
                switch (MTD_MODE(file)) {
                case MTD_MODE_OTP_FACT:
                        ret = -EROFS;
@@ -284,7 +282,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
                        kfree(kbuf);
                        return ret;
                }
-               
+
                kfree(kbuf);
        }
 
@@ -308,7 +306,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
        void __user *argp = (void __user *)arg;
        int ret = 0;
        u_long size;
-       
+
        DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
 
        size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
@@ -320,7 +318,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                if (!access_ok(VERIFY_WRITE, argp, size))
                        return -EFAULT;
        }
-       
+
        switch (cmd) {
        case MEMGETREGIONCOUNT:
                if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
@@ -372,11 +370,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                        erase->mtd = mtd;
                        erase->callback = mtdchar_erase_callback;
                        erase->priv = (unsigned long)&waitq;
-                       
+
                        /*
                          FIXME: Allow INTERRUPTIBLE. Which means
                          not having the wait_queue head on the stack.
-                         
+
                          If the wq_head is on the stack, and we
                          leave because we got interrupted, then the
                          wq_head is no longer there when the
@@ -404,13 +402,13 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                struct mtd_oob_buf buf;
                void *databuf;
                ssize_t retlen;
-               
+
                if(!(file->f_mode & 2))
                        return -EPERM;
 
                if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
                        return -EFAULT;
-               
+
                if (buf.length > 0x4096)
                        return -EINVAL;
 
@@ -426,7 +424,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                databuf = kmalloc(buf.length, GFP_KERNEL);
                if (!databuf)
                        return -ENOMEM;
-               
+
                if (copy_from_user(databuf, buf.ptr, buf.length)) {
                        kfree(databuf);
                        return -EFAULT;
@@ -450,7 +448,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 
                if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
                        return -EFAULT;
-               
+
                if (buf.length > 0x4096)
                        return -EINVAL;
 
@@ -466,14 +464,14 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                databuf = kmalloc(buf.length, GFP_KERNEL);
                if (!databuf)
                        return -ENOMEM;
-               
+
                ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
                if (put_user(retlen, (uint32_t __user *)argp))
                        ret = -EFAULT;
                else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
                        ret = -EFAULT;
-               
+
                kfree(databuf);
                break;
        }
@@ -523,7 +521,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
        case MEMGETBADBLOCK:
        {
                loff_t offs;
-               
+
                if (copy_from_user(&offs, argp, sizeof(loff_t)))
                        return -EFAULT;
                if (!mtd->block_isbad)
index f3e65af33a9c86d6338847ddb2b4c16ed5229774..b1bf8c411de78e6c7685d7cd8928e642dd1afeb5 100644 (file)
@@ -7,14 +7,15 @@
  *
  * This code is GPL
  *
- * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $
+ * $Id: mtdconcat.c,v 1.11 2005/11/07 11:14:20 gleixner Exp $
  */
 
-#include <linux/module.h>
-#include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/sched.h>       /* TASK_* */
+#include <linux/sched.h>
+#include <linux/types.h>
+
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/concat.h>
 
@@ -43,7 +44,7 @@ struct mtd_concat {
  */
 #define CONCAT(x)  ((struct mtd_concat *)(x))
 
-/* 
+/*
  * MTD methods which look up the relevant subdevice, translate the
  * effective address and pass through to the subdevice.
  */
@@ -877,7 +878,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],       /* subdevices to c
        return &concat->mtd;
 }
 
-/* 
+/*
  * This function destroys an MTD object obtained from concat_mtd_devs()
  */
 
index dc86df18e94b72768ce0d7beaaf06e629c9217a0..dade02ab0687aeee729a3e1c80339b5e27fbdf87 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $
+ * $Id: mtdcore.c,v 1.47 2005/11/07 11:14:20 gleixner Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -25,7 +25,7 @@
 
 #include <linux/mtd/mtd.h>
 
-/* These are exported solely for the purpose of mtd_blkdevs.c. You 
+/* These are exported solely for the purpose of mtd_blkdevs.c. You
    should not use them for _anything_ else */
 DECLARE_MUTEX(mtd_table_mutex);
 struct mtd_info *mtd_table[MAX_MTD_DEVICES];
@@ -66,7 +66,7 @@ int add_mtd_device(struct mtd_info *mtd)
                                struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
                                not->add(mtd);
                        }
-                       
+
                        up(&mtd_table_mutex);
                        /* We _know_ we aren't being removed, because
                           our caller is still holding us here. So none
@@ -75,7 +75,7 @@ int add_mtd_device(struct mtd_info *mtd)
                        __module_get(THIS_MODULE);
                        return 0;
                }
-       
+
        up(&mtd_table_mutex);
        return 1;
 }
@@ -93,13 +93,13 @@ int add_mtd_device(struct mtd_info *mtd)
 int del_mtd_device (struct mtd_info *mtd)
 {
        int ret;
-       
+
        down(&mtd_table_mutex);
 
        if (mtd_table[mtd->index] != mtd) {
                ret = -ENODEV;
        } else if (mtd->usecount) {
-               printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", 
+               printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
                       mtd->index, mtd->name, mtd->usecount);
                ret = -EBUSY;
        } else {
@@ -140,7 +140,7 @@ void register_mtd_user (struct mtd_notifier *new)
        list_add(&new->list, &mtd_notifiers);
 
        __module_get(THIS_MODULE);
-       
+
        for (i=0; i< MAX_MTD_DEVICES; i++)
                if (mtd_table[i])
                        new->add(mtd_table[i]);
@@ -169,7 +169,7 @@ int unregister_mtd_user (struct mtd_notifier *old)
        for (i=0; i< MAX_MTD_DEVICES; i++)
                if (mtd_table[i])
                        old->remove(mtd_table[i]);
-                       
+
        list_del(&old->list);
        up(&mtd_table_mutex);
        return 0;
@@ -187,7 +187,7 @@ int unregister_mtd_user (struct mtd_notifier *old)
  *     both, return the num'th driver only if its address matches. Return NULL
  *     if not.
  */
-       
+
 struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
 {
        struct mtd_info *ret = NULL;
@@ -296,39 +296,6 @@ EXPORT_SYMBOL(unregister_mtd_user);
 EXPORT_SYMBOL(default_mtd_writev);
 EXPORT_SYMBOL(default_mtd_readv);
 
-/*====================================================================*/
-/* Power management code */
-
-#ifdef CONFIG_PM
-
-#include <linux/pm.h>
-
-static struct pm_dev *mtd_pm_dev = NULL;
-
-static int mtd_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
-       int ret = 0, i;
-
-       if (down_trylock(&mtd_table_mutex))
-               return -EAGAIN;
-       if (rqst == PM_SUSPEND) {
-               for (i = 0; ret == 0 && i < MAX_MTD_DEVICES; i++) {
-                       if (mtd_table[i] && mtd_table[i]->suspend)
-                               ret = mtd_table[i]->suspend(mtd_table[i]);
-               }
-       } else i = MAX_MTD_DEVICES-1;
-
-       if (rqst == PM_RESUME || ret) {
-               for ( ; i >= 0; i--) {
-                       if (mtd_table[i] && mtd_table[i]->resume)
-                               mtd_table[i]->resume(mtd_table[i]);
-               }
-       }
-       up(&mtd_table_mutex);
-       return ret;
-}
-#endif
-
 /*====================================================================*/
 /* Support for /proc/mtd */
 
@@ -388,22 +355,11 @@ static int __init init_mtd(void)
        if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
                proc_mtd->read_proc = mtd_read_proc;
 #endif
-
-#ifdef CONFIG_PM
-       mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback);
-#endif
        return 0;
 }
 
 static void __exit cleanup_mtd(void)
 {
-#ifdef CONFIG_PM
-       if (mtd_pm_dev) {
-               pm_unregister(mtd_pm_dev);
-               mtd_pm_dev = NULL;
-       }
-#endif
-
 #ifdef CONFIG_PROC_FS
         if (proc_mtd)
                remove_proc_entry( "mtd", NULL);
index b92e6bfffaf2afa78cf3aad8fe38d7248509200c..99395911d26f73577999a62b3808e4456529bb92 100644 (file)
@@ -5,11 +5,11 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
+ * $Id: mtdpart.c,v 1.55 2005/11/07 11:14:20 gleixner Exp $
  *
  *     02-21-2002      Thomas Gleixner <gleixner@autronix.de>
  *                     added support for read_oob, write_oob
- */    
+ */
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -41,13 +41,13 @@ struct mtd_part {
  */
 #define PART(x)  ((struct mtd_part *)(x))
 
-       
-/* 
+
+/*
  * MTD methods which simply translate the effective address and pass through
  * to the _real_ device.
  */
 
-static int part_read (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
@@ -55,15 +55,15 @@ static int part_read (struct mtd_info *mtd, loff_t from, size_t len,
                len = 0;
        else if (from + len > mtd->size)
                len = mtd->size - from;
-       if (part->master->read_ecc == NULL)     
-               return part->master->read (part->master, from + part->offset, 
+       if (part->master->read_ecc == NULL)
+               return part->master->read (part->master, from + part->offset,
                                        len, retlen, buf);
        else
-               return part->master->read_ecc (part->master, from + part->offset, 
+               return part->master->read_ecc (part->master, from + part->offset,
                                        len, retlen, buf, NULL, &mtd->oobinfo);
 }
 
-static int part_point (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char **buf)
 {
        struct mtd_part *part = PART(mtd);
@@ -71,7 +71,7 @@ static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
                len = 0;
        else if (from + len > mtd->size)
                len = mtd->size - from;
-       return part->master->point (part->master, from + part->offset, 
+       return part->master->point (part->master, from + part->offset,
                                    len, retlen, buf);
 }
 static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
@@ -82,7 +82,7 @@ static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_
 }
 
 
-static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
        struct mtd_part *part = PART(mtd);
@@ -92,11 +92,11 @@ static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                len = 0;
        else if (from + len > mtd->size)
                len = mtd->size - from;
-       return part->master->read_ecc (part->master, from + part->offset, 
+       return part->master->read_ecc (part->master, from + part->offset,
                                        len, retlen, buf, eccbuf, oobsel);
 }
 
-static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
@@ -104,15 +104,15 @@ static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
                len = 0;
        else if (from + len > mtd->size)
                len = mtd->size - from;
-       return part->master->read_oob (part->master, from + part->offset, 
+       return part->master->read_oob (part->master, from + part->offset,
                                        len, retlen, buf);
 }
 
-static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->read_user_prot_reg (part->master, from, 
+       return part->master->read_user_prot_reg (part->master, from,
                                        len, retlen, buf);
 }
 
@@ -123,11 +123,11 @@ static int part_get_user_prot_info (struct mtd_info *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, 
+static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->read_fact_prot_reg (part->master, from, 
+       return part->master->read_fact_prot_reg (part->master, from,
                                        len, retlen, buf);
 }
 
@@ -148,13 +148,13 @@ static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
                len = 0;
        else if (to + len > mtd->size)
                len = mtd->size - to;
-       if (part->master->write_ecc == NULL)    
-               return part->master->write (part->master, to + part->offset, 
+       if (part->master->write_ecc == NULL)
+               return part->master->write (part->master, to + part->offset,
                                        len, retlen, buf);
        else
-               return part->master->write_ecc (part->master, to + part->offset, 
+               return part->master->write_ecc (part->master, to + part->offset,
                                        len, retlen, buf, NULL, &mtd->oobinfo);
-                                                       
+
 }
 
 static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
@@ -170,7 +170,7 @@ static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                len = 0;
        else if (to + len > mtd->size)
                len = mtd->size - to;
-       return part->master->write_ecc (part->master, to + part->offset, 
+       return part->master->write_ecc (part->master, to + part->offset,
                                        len, retlen, buf, eccbuf, oobsel);
 }
 
@@ -184,19 +184,19 @@ static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
                len = 0;
        else if (to + len > mtd->size)
                len = mtd->size - to;
-       return part->master->write_oob (part->master, to + part->offset, 
+       return part->master->write_oob (part->master, to + part->offset,
                                        len, retlen, buf);
 }
 
-static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, 
+static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
                        size_t *retlen, u_char *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->write_user_prot_reg (part->master, from, 
+       return part->master->write_user_prot_reg (part->master, from,
                                        len, retlen, buf);
 }
 
-static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) 
+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);
@@ -208,7 +208,7 @@ static int part_writev (struct mtd_info *mtd,  const struct kvec *vecs,
        struct mtd_part *part = PART(mtd);
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
-       if (part->master->writev_ecc == NULL)   
+       if (part->master->writev_ecc == NULL)
                return part->master->writev (part->master, vecs, count,
                                        to + part->offset, retlen);
        else
@@ -221,12 +221,12 @@ static int part_readv (struct mtd_info *mtd,  struct kvec *vecs,
                         unsigned long count, loff_t from, size_t *retlen)
 {
        struct mtd_part *part = PART(mtd);
-       if (part->master->readv_ecc == NULL)    
+       if (part->master->readv_ecc == NULL)
                return part->master->readv (part->master, vecs, count,
                                        from + part->offset, retlen);
        else
                return part->master->readv_ecc (part->master, vecs, count,
-                                       from + part->offset, retlen, 
+                                       from + part->offset, retlen,
                                        NULL, &mtd->oobinfo);
 }
 
@@ -252,7 +252,7 @@ static int part_readv_ecc (struct mtd_info *mtd,  struct kvec *vecs,
        if (oobsel == NULL)
                oobsel = &mtd->oobinfo;
        return part->master->readv_ecc (part->master, vecs, count,
-                                       from + part->offset, retlen, 
+                                       from + part->offset, retlen,
                                        eccbuf, oobsel);
 }
 
@@ -286,7 +286,7 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
 static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
 {
        struct mtd_part *part = PART(mtd);
-       if ((len + ofs) > mtd->size) 
+       if ((len + ofs) > mtd->size)
                return -EINVAL;
        return part->master->lock(part->master, ofs + part->offset, len);
 }
@@ -294,7 +294,7 @@ static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
 static int part_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
 {
        struct mtd_part *part = PART(mtd);
-       if ((len + ofs) > mtd->size) 
+       if ((len + ofs) > mtd->size)
                return -EINVAL;
        return part->master->unlock(part->master, ofs + part->offset, len);
 }
@@ -337,8 +337,8 @@ static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
        return part->master->block_markbad(part->master, ofs);
 }
 
-/* 
- * This function unregisters and destroy all slave MTD objects which are 
+/*
+ * This function unregisters and destroy all slave MTD objects which are
  * attached to the given master MTD object.
  */
 
@@ -371,7 +371,7 @@ int del_mtd_partitions(struct mtd_info *master)
  * (Q: should we register the master MTD object as well?)
  */
 
-int add_mtd_partitions(struct mtd_info *master, 
+int add_mtd_partitions(struct mtd_info *master,
                       const struct mtd_partition *parts,
                       int nbparts)
 {
@@ -414,7 +414,7 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.point = part_point;
                        slave->mtd.unpoint = part_unpoint;
                }
-               
+
                if (master->read_ecc)
                        slave->mtd.read_ecc = part_read_ecc;
                if (master->write_ecc)
@@ -465,9 +465,10 @@ int add_mtd_partitions(struct mtd_info *master,
                if (slave->offset == MTDPART_OFS_APPEND)
                        slave->offset = cur_offset;
                if (slave->offset == MTDPART_OFS_NXTBLK) {
-                       u_int32_t emask = master->erasesize-1;
-                       slave->offset = (cur_offset + emask) & ~emask;
-                       if (slave->offset != cur_offset) {
+                       slave->offset = cur_offset;
+                       if ((cur_offset % master->erasesize) != 0) {
+                               /* Round up to next erasesize */
+                               slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize;
                                printk(KERN_NOTICE "Moving partition %d: "
                                       "0x%08x -> 0x%08x\n", i,
                                       cur_offset, slave->offset);
@@ -476,8 +477,8 @@ int add_mtd_partitions(struct mtd_info *master,
                if (slave->mtd.size == MTDPART_SIZ_FULL)
                        slave->mtd.size = master->size - slave->offset;
                cur_offset = slave->offset + slave->mtd.size;
-       
-               printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, 
+
+               printk (KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset,
                        slave->offset + slave->mtd.size, slave->mtd.name);
 
                /* let's do some sanity checks */
@@ -497,7 +498,7 @@ int add_mtd_partitions(struct mtd_info *master,
                        /* Deal with variable erase size stuff */
                        int i;
                        struct mtd_erase_region_info *regions = master->eraseregions;
-                       
+
                        /* Find the first erase regions which is part of this partition. */
                        for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)
                                ;
@@ -512,7 +513,7 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.erasesize = master->erasesize;
                }
 
-               if ((slave->mtd.flags & MTD_WRITEABLE) && 
+               if ((slave->mtd.flags & MTD_WRITEABLE) &&
                    (slave->offset % slave->mtd.erasesize)) {
                        /* Doesn't start on a boundary of major erase size */
                        /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */
@@ -520,14 +521,14 @@ int add_mtd_partitions(struct mtd_info *master,
                        printk ("mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
                                parts[i].name);
                }
-               if ((slave->mtd.flags & MTD_WRITEABLE) && 
+               if ((slave->mtd.flags & MTD_WRITEABLE) &&
                    (slave->mtd.size % slave->mtd.erasesize)) {
                        slave->mtd.flags &= ~MTD_WRITEABLE;
                        printk ("mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
                                parts[i].name);
                }
 
-               /* copy oobinfo from master */ 
+               /* copy oobinfo from master */
                memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
 
                if(parts[i].mtdp)
@@ -588,12 +589,12 @@ int deregister_mtd_parser(struct mtd_part_parser *p)
        return 0;
 }
 
-int parse_mtd_partitions(struct mtd_info *master, const char **types, 
+int parse_mtd_partitions(struct mtd_info *master, const char **types,
                         struct mtd_partition **pparts, unsigned long origin)
 {
        struct mtd_part_parser *parser;
        int ret = 0;
-               
+
        for ( ; ret <= 0 && *types; types++) {
                parser = get_partition_parser(*types);
 #ifdef CONFIG_KMOD
@@ -607,7 +608,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types,
                }
                ret = (*parser->parse_fn)(master, pparts, origin);
                if (ret > 0) {
-                       printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", 
+                       printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
                               ret, parser->name, master->name);
                }
                put_partition_parser(parser);
index 36d34e5e5a5ac21530593130d499aa5d0d0ec153..1fc4c134d9391f685eb1880ca90082d96cd30725 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/nand/Kconfig
-# $Id: Kconfig,v 1.31 2005/06/20 12:03:21 bjd Exp $
+# $Id: Kconfig,v 1.35 2005/11/07 11:14:30 gleixner Exp $
 
 menu "NAND Flash Device Drivers"
        depends on MTD!=n
@@ -25,33 +25,33 @@ config MTD_NAND_VERIFY_WRITE
 
 config MTD_NAND_AUTCPU12
        tristate "SmartMediaCard on autronix autcpu12 board"
-       depends on ARM && MTD_NAND && ARCH_AUTCPU12
+       depends on MTD_NAND && ARCH_AUTCPU12
        help
-         This enables the driver for the autronix autcpu12 board to 
+         This enables the driver for the autronix autcpu12 board to
          access the SmartMediaCard.
 
 config MTD_NAND_EDB7312
        tristate "Support for Cirrus Logic EBD7312 evaluation board"
-       depends on ARM && MTD_NAND && ARCH_EDB7312
+       depends on MTD_NAND && ARCH_EDB7312
        help
-         This enables the driver for the Cirrus Logic EBD7312 evaluation 
+         This enables the driver for the Cirrus Logic EBD7312 evaluation
          board to access the onboard NAND Flash.
 
 config MTD_NAND_H1900
        tristate "iPAQ H1900 flash"
-       depends on ARM && MTD_NAND && ARCH_PXA && MTD_PARTITIONS
+       depends on MTD_NAND && ARCH_PXA && MTD_PARTITIONS
        help
          This enables the driver for the iPAQ h1900 flash.
 
 config MTD_NAND_SPIA
        tristate "NAND Flash device on SPIA board"
-       depends on ARM && ARCH_P720T && MTD_NAND
+       depends on ARCH_P720T && MTD_NAND
        help
          If you had to ask, you don't have one. Say 'N'.
 
 config MTD_NAND_TOTO
        tristate "NAND Flash device on TOTO board"
-       depends on ARM && ARCH_OMAP && MTD_NAND
+       depends on ARCH_OMAP && MTD_NAND
        help
          Support for NAND flash on Texas Instruments Toto platform.
 
@@ -59,8 +59,8 @@ config MTD_NAND_IDS
        tristate
 
 config MTD_NAND_AU1550
-       tristate "Au1550 NAND support"
-       depends on SOC_AU1550 && MTD_NAND
+       tristate "Au1550/1200 NAND support"
+       depends on (SOC_AU1200 || SOC_AU1550) && MTD_NAND
        help
          This enables the driver for the NAND flash controller on the
          AMD/Alchemy 1550 SOC.
@@ -71,7 +71,7 @@ config MTD_NAND_RTC_FROM4
        select REED_SOLOMON
        select REED_SOLOMON_DEC8
        help
-         This enables the driver for the Renesas Technology AG-AND 
+         This enables the driver for the Renesas Technology AG-AND
          flash interface board (FROM_BOARD4)
 
 config MTD_NAND_PPCHAMELEONEVB
@@ -88,7 +88,7 @@ config MTD_NAND_S3C2410
          SoCs
 
          No board specfic support is done by this driver, each board
-         must advertise a platform_device for the driver to attach. 
+         must advertise a platform_device for the driver to attach.
 
 config MTD_NAND_S3C2410_DEBUG
        bool "S3C2410 NAND driver debug"
@@ -181,7 +181,7 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
          
  config MTD_NAND_SHARPSL
        bool "Support for NAND Flash on Sharp SL Series (C7xx + others)"
-       depends on MTD_NAND     && ARCH_PXA
+       depends on MTD_NAND && ARCH_PXA
  
  config MTD_NAND_NANDSIM
        bool "Support for NAND Flash Simulator"
index 4c7719ce3f4835abc09a55a45cbb0c5473caf569..3cafcdf28aedec5049949f21a25f19f53ed454e2 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2004 Embedded Edge, LLC
  *
- * $Id: au1550nd.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $
+ * $Id: au1550nd.c,v 1.13 2005/11/07 11:14:30 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
 
 /* fixme: this is ugly */
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
-#include <asm/mach-au1x00/au1000.h>
-#ifdef CONFIG_MIPS_PB1550
-#include <asm/mach-pb1x00/pb1550.h> 
-#endif
-#ifdef CONFIG_MIPS_DB1550
-#include <asm/mach-db1x00/db1x00.h> 
-#endif
+#include <asm/mach-au1x00/au1xxx.h>
 #else
 #include <asm/au1000.h>
 #ifdef CONFIG_MIPS_PB1550
-#include <asm/pb1550.h> 
+#include <asm/pb1550.h>
 #endif
 #ifdef CONFIG_MIPS_DB1550
-#include <asm/db1x00.h> 
+#include <asm/db1x00.h>
 #endif
 #endif
 
@@ -45,39 +39,22 @@ static struct mtd_info *au1550_mtd = NULL;
 static void __iomem *p_nand;
 static int nand_width = 1; /* default x8*/
 
-#define NAND_CS 1
-
 /*
  * Define partitions for flash device
  */
 const static struct mtd_partition partition_info[] = {
-#ifdef CONFIG_MIPS_PB1550
-#define NUM_PARTITIONS            2
-       { 
-               .name = "Pb1550 NAND FS 0",
+       {
+               .name   = "NAND FS 0",
                .offset = 0,
-               .size = 8*1024*1024 
+               .size   = 8*1024*1024
        },
-       { 
-               .name = "Pb1550 NAND FS 1",
+       {
+               .name   = "NAND FS 1",
                .offset =  MTDPART_OFS_APPEND,
-               .size =    MTDPART_SIZ_FULL
+               .size   =    MTDPART_SIZ_FULL
        }
-#endif
-#ifdef CONFIG_MIPS_DB1550
-#define NUM_PARTITIONS            2
-       { 
-               .name = "Db1550 NAND FS 0",
-               .offset = 0,
-               .size = 8*1024*1024 
-       },
-       { 
-               .name = "Db1550 NAND FS 1",
-               .offset =  MTDPART_OFS_APPEND,
-               .size =    MTDPART_SIZ_FULL
-       }
-#endif
 };
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
 
 
 /**
@@ -112,7 +89,7 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte)
  * au_read_byte16 -  read one byte endianess aware from the chip
  * @mtd:       MTD device structure
  *
- *  read function for 16bit buswith with 
+ *  read function for 16bit buswith with
  * endianess conversion
  */
 static u_char au_read_byte16(struct mtd_info *mtd)
@@ -142,7 +119,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte)
  * au_read_word -  read one word from the chip
  * @mtd:       MTD device structure
  *
- *  read function for 16bit buswith without 
+ *  read function for 16bit buswith without
  * endianess conversion
  */
 static u16 au_read_word(struct mtd_info *mtd)
@@ -158,7 +135,7 @@ static u16 au_read_word(struct mtd_info *mtd)
  * @mtd:       MTD device structure
  * @word:      data word to write
  *
- *  write function for 16bit buswith without 
+ *  write function for 16bit buswith without
  * endianess conversion
  */
 static void au_write_word(struct mtd_info *mtd, u16 word)
@@ -188,7 +165,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 }
 
 /**
- * au_read_buf -  read chip data into buffer 
+ * au_read_buf -  read chip data into buffer
  * @mtd:       MTD device structure
  * @buf:       buffer to store date
  * @len:       number of bytes to read
@@ -202,12 +179,12 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 
        for (i=0; i<len; i++) {
                buf[i] = readb(this->IO_ADDR_R);
-               au_sync();      
+               au_sync();
        }
 }
 
 /**
- * au_verify_buf -  Verify chip data against buffer 
+ * au_verify_buf -  Verify chip data against buffer
  * @mtd:       MTD device structure
  * @buf:       buffer containing the data to compare
  * @len:       number of bytes to compare
@@ -242,16 +219,16 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
        struct nand_chip *this = mtd->priv;
        u16 *p = (u16 *) buf;
        len >>= 1;
-       
+
        for (i=0; i<len; i++) {
                writew(p[i], this->IO_ADDR_W);
                au_sync();
        }
-               
+
 }
 
 /**
- * au_read_buf16 -  read chip data into buffer 
+ * au_read_buf16 -  read chip data into buffer
  * @mtd:       MTD device structure
  * @buf:       buffer to store date
  * @len:       number of bytes to read
@@ -272,7 +249,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
 }
 
 /**
- * au_verify_buf16 -  Verify chip data against buffer 
+ * au_verify_buf16 -  Verify chip data against buffer
  * @mtd:       MTD device structure
  * @buf:       buffer containing the data to compare
  * @len:       number of bytes to compare
@@ -305,26 +282,26 @@ static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
        case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;
 
        case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;
-       case NAND_CTL_CLRALE: 
-               this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; 
-               /* FIXME: Nobody knows why this is neccecary, 
+       case NAND_CTL_CLRALE:
+               this->IO_ADDR_W = p_nand + MEM_STNAND_DATA;
+               /* FIXME: Nobody knows why this is neccecary,
                 * but it works only that way */
-               udelay(1); 
+               udelay(1);
                break;
 
-       case NAND_CTL_SETNCE: 
+       case NAND_CTL_SETNCE:
                /* assert (force assert) chip enable */
                au_writel((1<<(4+NAND_CS)) , MEM_STNDCTL); break;
                break;
 
-       case NAND_CTL_CLRNCE: 
+       case NAND_CTL_CLRNCE:
                /* deassert chip enable */
                au_writel(0, MEM_STNDCTL); break;
                break;
        }
 
        this->IO_ADDR_R = this->IO_ADDR_W;
-       
+
        /* Drain the writebuffer */
        au_sync();
 }
@@ -339,14 +316,16 @@ int au1550_device_ready(struct mtd_info *mtd)
 /*
  * Main initialization routine
  */
-int __init au1550_init (void)
+int __init au1xxx_nand_init (void)
 {
        struct nand_chip *this;
        u16 boot_swapboot = 0; /* default value */
        int retval;
+       u32 mem_staddr;
+       u32 nand_phys;
 
        /* Allocate memory for MTD device structure and private data */
-       au1550_mtd = kmalloc (sizeof(struct mtd_info) + 
+       au1550_mtd = kmalloc (sizeof(struct mtd_info) +
                        sizeof (struct nand_chip), GFP_KERNEL);
        if (!au1550_mtd) {
                printk ("Unable to allocate NAND MTD dev structure.\n");
@@ -364,14 +343,17 @@ int __init au1550_init (void)
        au1550_mtd->priv = this;
 
 
-       /* MEM_STNDCTL: disable ints, disable nand boot */
-       au_writel(0, MEM_STNDCTL);
+       /* disable interrupts */
+       au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL);
+
+       /* disable NAND boot */
+       au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL);
 
 #ifdef CONFIG_MIPS_PB1550
        /* set gpio206 high */
        au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR);
 
-       boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | 
+       boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
                ((bcsr->status >> 6)  & 0x1);
        switch (boot_swapboot) {
                case 0:
@@ -397,25 +379,66 @@ int __init au1550_init (void)
        }
 #endif
 
-       /* Configure RCE1 - should be done by YAMON */
-       au_writel(0x5 | (nand_width << 22), 0xB4001010); /* MEM_STCFG1 */
-       au_writel(NAND_TIMING, 0xB4001014); /* MEM_STTIME1 */
-       au_sync();
+       /* Configure chip-select; normally done by boot code, e.g. YAMON */
+#ifdef NAND_STCFG
+       if (NAND_CS == 0) {
+               au_writel(NAND_STCFG,  MEM_STCFG0);
+               au_writel(NAND_STTIME, MEM_STTIME0);
+               au_writel(NAND_STADDR, MEM_STADDR0);
+       }
+       if (NAND_CS == 1) {
+               au_writel(NAND_STCFG,  MEM_STCFG1);
+               au_writel(NAND_STTIME, MEM_STTIME1);
+               au_writel(NAND_STADDR, MEM_STADDR1);
+       }
+       if (NAND_CS == 2) {
+               au_writel(NAND_STCFG,  MEM_STCFG2);
+               au_writel(NAND_STTIME, MEM_STTIME2);
+               au_writel(NAND_STADDR, MEM_STADDR2);
+       }
+       if (NAND_CS == 3) {
+               au_writel(NAND_STCFG,  MEM_STCFG3);
+               au_writel(NAND_STTIME, MEM_STTIME3);
+               au_writel(NAND_STADDR, MEM_STADDR3);
+       }
+#endif
 
-       /* setup and enable chip select, MEM_STADDR1 */
-       /* we really need to decode offsets only up till 0x20 */
-       au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | 
-                       (((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), 
-                       MEM_STADDR1);
-       au_sync();
+       /* Locate NAND chip-select in order to determine NAND phys address */
+       mem_staddr = 0x00000000;
+       if (((au_readl(MEM_STCFG0) & 0x7) == 0x5) && (NAND_CS == 0))
+               mem_staddr = au_readl(MEM_STADDR0);
+       else if (((au_readl(MEM_STCFG1) & 0x7) == 0x5) && (NAND_CS == 1))
+               mem_staddr = au_readl(MEM_STADDR1);
+       else if (((au_readl(MEM_STCFG2) & 0x7) == 0x5) && (NAND_CS == 2))
+               mem_staddr = au_readl(MEM_STADDR2);
+       else if (((au_readl(MEM_STCFG3) & 0x7) == 0x5) && (NAND_CS == 3))
+               mem_staddr = au_readl(MEM_STADDR3);
+
+       if (mem_staddr == 0x00000000) {
+               printk("Au1xxx NAND: ERROR WITH NAND CHIP-SELECT\n");
+               kfree(au1550_mtd);
+               return 1;
+       }
+       nand_phys = (mem_staddr << 4) & 0xFFFC0000;
+
+       p_nand = (void __iomem *)ioremap(nand_phys, 0x1000);
+
+       /* make controller and MTD agree */
+       if (NAND_CS == 0)
+               nand_width = au_readl(MEM_STCFG0) & (1<<22);
+       if (NAND_CS == 1)
+               nand_width = au_readl(MEM_STCFG1) & (1<<22);
+       if (NAND_CS == 2)
+               nand_width = au_readl(MEM_STCFG2) & (1<<22);
+       if (NAND_CS == 3)
+               nand_width = au_readl(MEM_STCFG3) & (1<<22);
 
-       p_nand = ioremap(NAND_PHYS_ADDR, 0x1000);
 
        /* Set address of hardware control function */
        this->hwcontrol = au1550_hwcontrol;
        this->dev_ready = au1550_device_ready;
        /* 30 us command delay time */
-       this->chip_delay = 30;          
+       this->chip_delay = 30;
        this->eccmode = NAND_ECC_SOFT;
 
        this->options = NAND_NO_AUTOINCR;
@@ -438,19 +461,19 @@ int __init au1550_init (void)
        }
 
        /* Register the partitions */
-       add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS);
+       add_mtd_partitions(au1550_mtd, partition_info, NB_OF(partition_info));
 
        return 0;
 
  outio:
        iounmap ((void *)p_nand);
-       
+
  outmem:
        kfree (au1550_mtd);
        return retval;
 }
 
-module_init(au1550_init);
+module_init(au1xxx_nand_init);
 
 /*
  * Clean up routine
index 4afa8ced05ade9a51128d6d6746f2765ccee6459..056dfc17a075acb69600320ec3975e2f17cbfd17 100644 (file)
@@ -5,8 +5,8 @@
  *
  *  Derived from drivers/mtd/spia.c
  *      Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- * 
- * $Id: autcpu12.c,v 1.22 2004/11/04 12:53:10 gleixner Exp $
+ *
+ * $Id: autcpu12.c,v 1.23 2005/11/07 11:14:30 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
@@ -14,7 +14,7 @@
  *
  *  Overview:
  *   This is a device driver for the NAND flash device found on the
- *   autronix autcpu12 board, which is a SmartMediaCard. It supports 
+ *   autronix autcpu12 board, which is a SmartMediaCard. It supports
  *   16MiB, 32MiB and 64MiB cards.
  *
  *
@@ -93,7 +93,7 @@ static struct mtd_partition partition_info128k[] = {
 #define NUM_PARTITIONS32K 2
 #define NUM_PARTITIONS64K 2
 #define NUM_PARTITIONS128K 2
-/* 
+/*
  *     hardware specific access to control-lines
 */
 static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
@@ -163,7 +163,7 @@ int __init autcpu12_init (void)
        this->hwcontrol = autcpu12_hwcontrol;
        this->dev_ready = autcpu12_device_ready;
        /* 20 us command delay time */
-       this->chip_delay = 20;          
+       this->chip_delay = 20;
        this->eccmode = NAND_ECC_SOFT;
 
        /* Enable the following for a flash based bad block table */
@@ -171,21 +171,21 @@ int __init autcpu12_init (void)
        this->options = NAND_USE_FLASH_BBT;
        */
        this->options = NAND_USE_FLASH_BBT;
-       
+
        /* Scan to find existance of the device */
        if (nand_scan (autcpu12_mtd, 1)) {
                err = -ENXIO;
                goto out_ior;
        }
-       
+
        /* Register the partitions */
        switch(autcpu12_mtd->size){
                case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
                case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break;
-               case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; 
-               case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; 
+               case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break;
+               case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break;
                default: {
-                       printk ("Unsupported SmartMedia device\n"); 
+                       printk ("Unsupported SmartMedia device\n");
                        err = -ENXIO;
                        goto out_ior;
                }
@@ -213,7 +213,7 @@ static void __exit autcpu12_cleanup (void)
 
        /* unmap physical adress */
        iounmap((void *)autcpu12_fio_base);
-       
+
        /* Free the MTD device structure */
        kfree (autcpu12_mtd);
 }
index fdb5d4ad3d526d0953629e26b5c433b07e5231ac..21d4e8f4b7af4c9ffa2c0f851cec1136f2d5b94e 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * drivers/mtd/nand/diskonchip.c
  *
  * (C) 2003 Red Hat, Inc.
@@ -8,15 +8,15 @@
  * Author: David Woodhouse <dwmw2@infradead.org>
  * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
  * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
- * 
+ *
  * Error correction code lifted from the old docecc code
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
  * Copyright (C) 2000 Netgem S.A.
  * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
- *  
+ *
  * Interface to generic NAND code for M-Systems DiskOnChip devices
  *
- * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $
+ * $Id: diskonchip.c,v 1.55 2005/11/07 11:14:30 gleixner Exp $
  */
 
 #include <linux/kernel.h>
 static unsigned long __initdata doc_locations[] = {
 #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
 #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
-       0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
+       0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
        0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
-       0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
-       0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 
+       0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
+       0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
        0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
 #else /*  CONFIG_MTD_DOCPROBE_HIGH */
-       0xc8000, 0xca000, 0xcc000, 0xce000, 
+       0xc8000, 0xca000, 0xcc000, 0xce000,
        0xd0000, 0xd2000, 0xd4000, 0xd6000,
-       0xd8000, 0xda000, 0xdc000, 0xde000, 
-       0xe0000, 0xe2000, 0xe4000, 0xe6000, 
+       0xd8000, 0xda000, 0xdc000, 0xde000,
+       0xe0000, 0xe2000, 0xe4000, 0xe6000,
        0xe8000, 0xea000, 0xec000, 0xee000,
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
 #elif defined(__PPC__)
@@ -138,7 +138,7 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe
 /* the Reed Solomon control structure */
 static struct rs_control *rs_decoder;
 
-/* 
+/*
  * The HW decoder in the DoC ASIC's provides us a error syndrome,
  * which we must convert to a standard syndrom usable by the generic
  * Reed-Solomon library code.
@@ -163,8 +163,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
        /* Initialize the syndrom buffer */
        for (i = 0; i < NROOTS; i++)
                s[i] = ds[0];
-       /* 
-        *  Evaluate 
+       /*
+        *  Evaluate
         *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
         *  where x = alpha^(FCR + i)
         */
@@ -188,7 +188,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
        if (nerr < 0)
                return nerr;
 
-       /* 
+       /*
         * Correct the errors. The bitpositions are a bit of magic,
         * but they are given by the design of the de/encoder circuit
         * in the DoC ASIC's.
@@ -205,7 +205,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
                           can be modified since pos is even */
                        index = (pos >> 3) ^ 1;
                        bitpos = pos & 7;
-                       if ((index >= 0 && index < SECTOR_SIZE) || 
+                       if ((index >= 0 && index < SECTOR_SIZE) ||
                            index == (SECTOR_SIZE + 1)) {
                                val = (uint8_t) (errval[i] >> (2 + bitpos));
                                parity ^= val;
@@ -216,7 +216,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
                        bitpos = (bitpos + 10) & 7;
                        if (bitpos == 0)
                                bitpos = 8;
-                       if ((index >= 0 && index < SECTOR_SIZE) || 
+                       if ((index >= 0 && index < SECTOR_SIZE) ||
                            index == (SECTOR_SIZE + 1)) {
                                val = (uint8_t)(errval[i] << (8 - bitpos));
                                parity ^= val;
@@ -233,7 +233,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
 {
        volatile char dummy;
        int i;
-       
+
        for (i = 0; i < cycles; i++) {
                if (DoC_is_Millennium(doc))
                        dummy = ReadDOC(doc->virtadr, NOP);
@@ -242,7 +242,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
                else
                        dummy = ReadDOC(doc->virtadr, DOCStatus);
        }
-       
+
 }
 
 #define CDSN_CTRL_FR_B_MASK    (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
@@ -327,7 +327,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd)
        return ret;
 }
 
-static void doc2000_writebuf(struct mtd_info *mtd, 
+static void doc2000_writebuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -343,7 +343,7 @@ static void doc2000_writebuf(struct mtd_info *mtd,
        if (debug) printk("\n");
 }
 
-static void doc2000_readbuf(struct mtd_info *mtd, 
+static void doc2000_readbuf(struct mtd_info *mtd,
                            u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -358,7 +358,7 @@ static void doc2000_readbuf(struct mtd_info *mtd,
        }
 }
 
-static void doc2000_readbuf_dword(struct mtd_info *mtd, 
+static void doc2000_readbuf_dword(struct mtd_info *mtd,
                            u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -379,7 +379,7 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd,
        }
 }
 
-static int doc2000_verifybuf(struct mtd_info *mtd, 
+static int doc2000_verifybuf(struct mtd_info *mtd,
                              const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -406,12 +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 
+        * command to complete
         */
        udelay(50);
-       
+
        ret = this->read_byte(mtd) << 8;
        ret |= this->read_byte(mtd);
 
@@ -438,7 +438,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
                        this->read_buf = &doc2000_readbuf_dword;
                }
        }
-               
+
        return ret;
 }
 
@@ -469,7 +469,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
        struct doc_priv *doc = this->priv;
 
        int status;
-       
+
        DoC_WaitReady(doc);
        this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
        DoC_WaitReady(doc);
@@ -503,7 +503,7 @@ static u_char doc2001_read_byte(struct mtd_info *mtd)
        return ReadDOC(docptr, LastDataRead);
 }
 
-static void doc2001_writebuf(struct mtd_info *mtd, 
+static void doc2001_writebuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -517,7 +517,7 @@ static void doc2001_writebuf(struct mtd_info *mtd,
        WriteDOC(0x00, docptr, WritePipeTerm);
 }
 
-static void doc2001_readbuf(struct mtd_info *mtd, 
+static void doc2001_readbuf(struct mtd_info *mtd,
                            u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -535,7 +535,7 @@ static void doc2001_readbuf(struct mtd_info *mtd,
        buf[i] = ReadDOC(docptr, LastDataRead);
 }
 
-static int doc2001_verifybuf(struct mtd_info *mtd, 
+static int doc2001_verifybuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -570,7 +570,7 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd)
        return ret;
 }
 
-static void doc2001plus_writebuf(struct mtd_info *mtd, 
+static void doc2001plus_writebuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -587,7 +587,7 @@ static void doc2001plus_writebuf(struct mtd_info *mtd,
        if (debug) printk("\n");
 }
 
-static void doc2001plus_readbuf(struct mtd_info *mtd, 
+static void doc2001plus_readbuf(struct mtd_info *mtd,
                            u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -617,7 +617,7 @@ static void doc2001plus_readbuf(struct mtd_info *mtd,
        if (debug) printk("\n");
 }
 
-static int doc2001plus_verifybuf(struct mtd_info *mtd, 
+static int doc2001plus_verifybuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
@@ -797,7 +797,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
                        WriteDOC(0, docptr, Mplus_FlashControl);
        }
 
-       /* 
+       /*
         * program and erase have their own busy handlers
         * status and sequential in needs no delay
        */
@@ -822,7 +822,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
 
        /* This applies to read commands */
        default:
-               /* 
+               /*
                 * If we don't have access to the busy pin, we apply the given
                 * command delay
                */
@@ -945,7 +945,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
        for (i = 0; i < 6; i++) {
                if (DoC_is_MillenniumPlus(doc))
                        ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
-               else 
+               else
                        ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
                if (ecc_code[i] != empty_write_ecc[i])
                        emptymatch = 0;
@@ -982,7 +982,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
         void __iomem *docptr = doc->virtadr;
        volatile u_char dummy;
        int emptymatch = 1;
-       
+
        /* flush the pipeline */
        if (DoC_is_2000(doc)) {
                dummy = ReadDOC(docptr, 2k_ECCStatus);
@@ -997,7 +997,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
                dummy = ReadDOC(docptr, ECCConf);
                dummy = ReadDOC(docptr, ECCConf);
        }
-       
+
        /* Error occured ? */
        if (dummy & 0x80) {
                for (i = 0; i < 6; i++) {
@@ -1035,7 +1035,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
                if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc);
                if (ret > 0)
                        printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
-       }       
+       }
        if (DoC_is_MillenniumPlus(doc))
                WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
        else
@@ -1046,7 +1046,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
        }
        return ret;
 }
-               
+
 //u_char mydatabuf[528];
 
 /* The strange out-of-order .oobfree list below is a (possibly unneeded)
@@ -1065,7 +1065,7 @@ static struct nand_oobinfo doc200x_oobinfo = {
         .eccpos = {0, 1, 2, 3, 4, 5},
         .oobfree = { {8, 8}, {6, 2} }
 };
+
 /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
    On sucessful return, buf will contain a copy of the media header for
    further processing.  id is the string to scan for, and will presumably be
@@ -1251,7 +1251,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
        mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
        mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
        mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
+
        printk(KERN_INFO "    bootRecordID          = %s\n"
                         "    NoOfBootImageBlocks   = %d\n"
                         "    NoOfBinaryPartitions  = %d\n"
@@ -1468,7 +1468,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
        ReadDOC(doc->virtadr, ChipID);
        if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
                /* It's not a Millennium; it's one of the newer
-                  DiskOnChip 2000 units with a similar ASIC. 
+                  DiskOnChip 2000 units with a similar ASIC.
                   Treat it like a Millennium, except that it
                   can have multiple chips. */
                doc2000_count_chips(mtd);
@@ -1530,20 +1530,20 @@ static inline int __init doc_probe(unsigned long physadr)
         * to the DOCControl register. So we store the current contents
         * of the DOCControl register's location, in case we later decide
         * that it's not a DiskOnChip, and want to put it back how we
-        * found it. 
+        * found it.
         */
        save_control = ReadDOC(virtadr, DOCControl);
 
        /* Reset the DiskOnChip ASIC */
-       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
                 virtadr, DOCControl);
-       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET,
                 virtadr, DOCControl);
 
        /* Enable the DiskOnChip ASIC */
-       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
                 virtadr, DOCControl);
-       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
+       WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL,
                 virtadr, DOCControl);
 
        ChipID = ReadDOC(virtadr, ChipID);
@@ -1738,7 +1738,7 @@ static int __init init_nanddoc(void)
        int i, ret = 0;
 
        /* We could create the decoder on demand, if memory is a concern.
-        * This way we have it handy, if an error happens 
+        * This way we have it handy, if an error happens
         *
         * Symbolsize is 10 (bits)
         * Primitve polynomial is x^10+x^3+1
index 5549681ccdce12b7597e34d125bbd8a524e168ef..9b1fd2f387faf59444378adc5b966ff948673477 100644 (file)
@@ -6,7 +6,7 @@
  *  Derived from drivers/mtd/nand/autcpu12.c
  *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
  *
- * $Id: edb7312.c,v 1.11 2004/11/04 12:53:10 gleixner Exp $
+ * $Id: edb7312.c,v 1.12 2005/11/07 11:14:30 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
@@ -71,27 +71,27 @@ static struct mtd_partition partition_info[] = {
 #endif
 
 
-/* 
+/*
  *     hardware specific access to control-lines
  */
-static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) 
+static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd)
 {
        switch(cmd) {
-               
-       case NAND_CTL_SETCLE: 
-               clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); 
+
+       case NAND_CTL_SETCLE:
+               clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr);
                break;
-       case NAND_CTL_CLRCLE: 
+       case NAND_CTL_CLRCLE:
                clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr);
                break;
-               
+
        case NAND_CTL_SETALE:
                clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr);
                break;
        case NAND_CTL_CLRALE:
                clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr);
                break;
-               
+
        case NAND_CTL_SETNCE:
                clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr);
                break;
@@ -122,16 +122,16 @@ static int __init ep7312_init (void)
        int mtd_parts_nb = 0;
        struct mtd_partition *mtd_parts = 0;
        void __iomem * ep7312_fio_base;
-       
+
        /* Allocate memory for MTD device structure and private data */
-       ep7312_mtd = kmalloc(sizeof(struct mtd_info) + 
+       ep7312_mtd = kmalloc(sizeof(struct mtd_info) +
                             sizeof(struct nand_chip),
                             GFP_KERNEL);
        if (!ep7312_mtd) {
                printk("Unable to allocate EDB7312 NAND MTD device structure.\n");
                return -ENOMEM;
        }
-       
+
        /* map physical adress */
        ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K);
        if(!ep7312_fio_base) {
@@ -139,23 +139,23 @@ static int __init ep7312_init (void)
                kfree(ep7312_mtd);
                return -EIO;
        }
-       
+
        /* Get pointer to private data */
        this = (struct nand_chip *) (&ep7312_mtd[1]);
-       
+
        /* Initialize structures */
        memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info));
        memset((char *) this, 0, sizeof(struct nand_chip));
-       
+
        /* Link the private data with the MTD structure */
        ep7312_mtd->priv = this;
-       
+
        /*
         * Set GPIO Port B control register so that the pins are configured
         * to be outputs for controlling the NAND flash.
         */
        clps_writeb(0xf0, ep7312_pxddr);
-       
+
        /* insert callbacks */
        this->IO_ADDR_R = ep7312_fio_base;
        this->IO_ADDR_W = ep7312_fio_base;
@@ -163,14 +163,14 @@ static int __init ep7312_init (void)
        this->dev_ready = ep7312_device_ready;
        /* 15 us command delay time */
        this->chip_delay = 15;
-       
+
        /* Scan to find existence of the device */
        if (nand_scan (ep7312_mtd, 1)) {
                iounmap((void *)ep7312_fio_base);
                kfree (ep7312_mtd);
                return -ENXIO;
        }
-       
+
 #ifdef CONFIG_MTD_PARTITIONS
        ep7312_mtd->name = "edb7312-nand";
        mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes,
@@ -185,11 +185,11 @@ static int __init ep7312_init (void)
                mtd_parts_nb = NUM_PARTITIONS;
                part_type = "static";
        }
-       
+
        /* Register the partitions */
        printk(KERN_NOTICE "Using %s partition definition\n", part_type);
        add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb);
-       
+
        /* Return happy */
        return 0;
 }
@@ -201,13 +201,13 @@ module_init(ep7312_init);
 static void __exit ep7312_cleanup (void)
 {
        struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
-       
+
        /* Release resources, unregister device */
        nand_release (ap7312_mtd);
-       
+
        /* Free internal data buffer */
        kfree (this->data_buf);
-       
+
        /* Free the MTD device structure */
        kfree (ep7312_mtd);
 }
index 3825a7a0900ced0707182f1e39c4547e85a7ea05..041e4b3358fbce2d953ef14d77e4c5e9e609e048 100644 (file)
@@ -7,7 +7,7 @@
  *       Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
  *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
  *
- * $Id: h1910.c,v 1.5 2004/11/04 12:53:10 gleixner Exp $
+ * $Id: h1910.c,v 1.6 2005/11/07 11:14:30 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
@@ -54,24 +54,24 @@ static struct mtd_partition partition_info[] = {
 #endif
 
 
-/* 
+/*
  *     hardware specific access to control-lines
  */
-static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) 
+static void h1910_hwcontrol(struct mtd_info *mtd, int cmd)
 {
        struct nand_chip* this = (struct nand_chip *) (mtd->priv);
-       
+
        switch(cmd) {
-               
-       case NAND_CTL_SETCLE: 
+
+       case NAND_CTL_SETCLE:
                this->IO_ADDR_R |= (1 << 2);
                this->IO_ADDR_W |= (1 << 2);
                break;
-       case NAND_CTL_CLRCLE: 
+       case NAND_CTL_CLRCLE:
                this->IO_ADDR_R &= ~(1 << 2);
                this->IO_ADDR_W &= ~(1 << 2);
                break;
-               
+
        case NAND_CTL_SETALE:
                this->IO_ADDR_R |= (1 << 3);
                this->IO_ADDR_W |= (1 << 3);
@@ -80,7 +80,7 @@ static void h1910_hwcontrol(struct mtd_info *mtd, int cmd)
                this->IO_ADDR_R &= ~(1 << 3);
                this->IO_ADDR_W &= ~(1 << 3);
                break;
-               
+
        case NAND_CTL_SETNCE:
                break;
        case NAND_CTL_CLRNCE:
@@ -108,18 +108,18 @@ static int __init h1910_init (void)
        int mtd_parts_nb = 0;
        struct mtd_partition *mtd_parts = 0;
        void __iomem *nandaddr;
-       
+
        if (!machine_is_h1900())
                return -ENODEV;
-               
+
        nandaddr = __ioremap(0x08000000, 0x1000, 0, 1);
        if (!nandaddr) {
                printk("Failed to ioremap nand flash.\n");
                return -ENOMEM;
        }
-       
+
        /* Allocate memory for MTD device structure and private data */
-       h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) + 
+       h1910_nand_mtd = kmalloc(sizeof(struct mtd_info) +
                             sizeof(struct nand_chip),
                             GFP_KERNEL);
        if (!h1910_nand_mtd) {
@@ -127,22 +127,22 @@ static int __init h1910_init (void)
                iounmap ((void *) nandaddr);
                return -ENOMEM;
        }
-       
+
        /* Get pointer to private data */
        this = (struct nand_chip *) (&h1910_nand_mtd[1]);
-       
+
        /* Initialize structures */
        memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info));
        memset((char *) this, 0, sizeof(struct nand_chip));
-       
+
        /* Link the private data with the MTD structure */
        h1910_nand_mtd->priv = this;
-       
+
        /*
         * Enable VPEN
         */
        GPSR(37) = GPIO_bit(37);
-       
+
        /* insert callbacks */
        this->IO_ADDR_R = nandaddr;
        this->IO_ADDR_W = nandaddr;
@@ -152,7 +152,7 @@ static int __init h1910_init (void)
        this->chip_delay = 50;
        this->eccmode = NAND_ECC_SOFT;
        this->options = NAND_NO_AUTOINCR;
-       
+
        /* Scan to find existence of the device */
        if (nand_scan (h1910_nand_mtd, 1)) {
                printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
@@ -160,9 +160,9 @@ static int __init h1910_init (void)
                iounmap ((void *) nandaddr);
                return -ENXIO;
        }
-       
+
 #ifdef CONFIG_MTD_CMDLINE_PARTS
-       mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, 
+       mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts,
                                                "h1910-nand");
        if (mtd_parts_nb > 0)
          part_type = "command line";
@@ -175,11 +175,11 @@ static int __init h1910_init (void)
                mtd_parts_nb = NUM_PARTITIONS;
                part_type = "static";
        }
-       
+
        /* Register the partitions */
        printk(KERN_NOTICE "Using %s partition definition\n", part_type);
        add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
-       
+
        /* Return happy */
        return 0;
 }
@@ -191,7 +191,7 @@ module_init(h1910_init);
 static void __exit h1910_cleanup (void)
 {
        struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1];
-       
+
        /* Release resources, unregister device */
        nand_release (h1910_nand_mtd);
 
index 8e78d7b96a5671af16033227e4582e694e502438..5d222460b42a87acd20c18f23183c67ad9f109e4 100644 (file)
@@ -5,14 +5,14 @@
  *   This is the generic MTD driver for NAND flash devices. It should be
  *   capable of working with almost all NAND chips currently available.
  *   Basic support for AG-AND chips is provided.
- *   
+ *
  *     Additional technical information is available on
  *     http://www.linux-mtd.infradead.org/tech/nand.html
- *     
+ *
  *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *               2002 Thomas Gleixner (tglx@linutronix.de)
  *
- *  02-08-2004  tglx: support for strange chips, which cannot auto increment 
+ *  02-08-2004  tglx: support for strange chips, which cannot auto increment
  *             pages on read / read_oob
  *
  *  03-17-2004  tglx: Check ready before auto increment check. Simon Bayes
@@ -21,7 +21,7 @@
  *             Make reads over block boundaries work too
  *
  *  04-14-2004 tglx: first working version for 2k page size chips
- *  
+ *
  *  05-19-2004  tglx: Basic support for Renesas AG-AND chips
  *
  *  09-24-2004  tglx: add support for hardware controllers (e.g. ECC) shared
  *
  *  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 
+ *             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 
+ *             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 
+ *  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 
+ *  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.
  *
+ * 08-20-2005  vwool: suspend/resume added
+ *
  * Credits:
- *     David Woodhouse for adding multichip support  
- *     
+ *     David Woodhouse for adding multichip support
+ *
  *     Aleph One Ltd. and Toby Churchill Ltd. for supporting the
  *     rework for 2K page size chips
  *
@@ -59,7 +61,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.147 2005/07/15 07:18:06 gleixner Exp $
+ * $Id: nand_base.c,v 1.150 2005/09/15 13:58:48 vwool 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
@@ -103,8 +105,8 @@ static struct nand_oobinfo nand_oob_64 = {
        .useecc = MTD_NANDECC_AUTOPLACE,
        .eccbytes = 24,
        .eccpos = {
-               40, 41, 42, 43, 44, 45, 46, 47, 
-               48, 49, 50, 51, 52, 53, 54, 55, 
+               40, 41, 42, 43, 44, 45, 46, 47,
+               48, 49, 50, 51, 52, 53, 54, 55,
                56, 57, 58, 59, 60, 61, 62, 63},
        .oobfree = { {2, 38} }
 };
@@ -147,19 +149,19 @@ static void nand_sync (struct mtd_info *mtd);
 static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,
                struct nand_oobinfo *oobsel, int mode);
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 
+static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
        u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);
 #else
 #define nand_verify_pages(...) (0)
 #endif
-               
-static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);
+
+static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state);
 
 /**
  * nand_release_device - [GENERIC] release chip
  * @mtd:       MTD device structure
- * 
- * Deselect, release chip lock and wake up anyone waiting on the device 
+ *
+ * Deselect, release chip lock and wake up anyone waiting on the device
  */
 static void nand_release_device (struct mtd_info *mtd)
 {
@@ -213,7 +215,7 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte)
  * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
  * @mtd:       MTD device structure
  *
- * Default read function for 16bit buswith with 
+ * Default read function for 16bit buswith with
  * endianess conversion
  */
 static u_char nand_read_byte16(struct mtd_info *mtd)
@@ -240,7 +242,7 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
  * nand_read_word - [DEFAULT] read one word from the chip
  * @mtd:       MTD device structure
  *
- * Default read function for 16bit buswith without 
+ * Default read function for 16bit buswith without
  * endianess conversion
  */
 static u16 nand_read_word(struct mtd_info *mtd)
@@ -254,7 +256,7 @@ static u16 nand_read_word(struct mtd_info *mtd)
  * @mtd:       MTD device structure
  * @word:      data word to write
  *
- * Default write function for 16bit buswith without 
+ * Default write function for 16bit buswith without
  * endianess conversion
  */
 static void nand_write_word(struct mtd_info *mtd, u16 word)
@@ -275,7 +277,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chip)
        struct nand_chip *this = mtd->priv;
        switch(chip) {
        case -1:
-               this->hwcontrol(mtd, NAND_CTL_CLRNCE);  
+               this->hwcontrol(mtd, NAND_CTL_CLRNCE);
                break;
        case 0:
                this->hwcontrol(mtd, NAND_CTL_SETNCE);
@@ -304,7 +306,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 }
 
 /**
- * nand_read_buf - [DEFAULT] read chip data into buffer 
+ * nand_read_buf - [DEFAULT] read chip data into buffer
  * @mtd:       MTD device structure
  * @buf:       buffer to store date
  * @len:       number of bytes to read
@@ -321,7 +323,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 }
 
 /**
- * nand_verify_buf - [DEFAULT] Verify chip data against buffer 
+ * nand_verify_buf - [DEFAULT] Verify chip data against buffer
  * @mtd:       MTD device structure
  * @buf:       buffer containing the data to compare
  * @len:       number of bytes to compare
@@ -354,14 +356,14 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
        struct nand_chip *this = mtd->priv;
        u16 *p = (u16 *) buf;
        len >>= 1;
-       
+
        for (i=0; i<len; i++)
                writew(p[i], this->IO_ADDR_W);
-               
+
 }
 
 /**
- * nand_read_buf16 - [DEFAULT] read chip data into buffer 
+ * nand_read_buf16 - [DEFAULT] read chip data into buffer
  * @mtd:       MTD device structure
  * @buf:       buffer to store date
  * @len:       number of bytes to read
@@ -380,7 +382,7 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
 }
 
 /**
- * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer 
+ * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer
  * @mtd:       MTD device structure
  * @buf:       buffer containing the data to compare
  * @len:       number of bytes to compare
@@ -407,7 +409,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
  * @ofs:       offset from device start
  * @getchip:   0, if the chip is already selected
  *
- * Check, if the block is bad. 
+ * Check, if the block is bad.
  */
 static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 {
@@ -424,14 +426,14 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 
                /* Select the NAND device */
                this->select_chip(mtd, chipnr);
-       } else 
-               page = (int) ofs;       
+       } else
+               page = (int) ofs;
 
        if (this->options & NAND_BUSWIDTH_16) {
                this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
                bad = cpu_to_le16(this->read_word(mtd));
                if (this->badblockpos & 0x1)
-                       bad >>= 1;
+                       bad >>= 8;
                if ((bad & 0xFF) != 0xff)
                        res = 1;
        } else {
@@ -439,12 +441,12 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
                if (this->read_byte(mtd) != 0xff)
                        res = 1;
        }
-               
+
        if (getchip) {
                /* Deselect and wake up anyone waiting on the device */
                nand_release_device(mtd);
-       }       
-       
+       }
+
        return res;
 }
 
@@ -462,7 +464,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        u_char buf[2] = {0, 0};
        size_t  retlen;
        int block;
-       
+
        /* Get block number */
        block = ((int) ofs) >> this->bbt_erase_shift;
        if (this->bbt)
@@ -471,25 +473,25 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
        /* Do we have a flash based bad block table ? */
        if (this->options & NAND_USE_FLASH_BBT)
                return nand_update_bbt (mtd, ofs);
-               
+
        /* We write two bytes, so we dont have to mess with 16 bit access */
        ofs += mtd->oobsize + (this->badblockpos & ~0x01);
        return nand_write_oob (mtd, ofs , 2, &retlen, buf);
 }
 
-/** 
+/**
  * nand_check_wp - [GENERIC] check if the chip is write protected
  * @mtd:       MTD device structure
- * Check, if the device is write protected 
+ * Check, if the device is write protected
  *
- * The function expects, that the device is already selected 
+ * The function expects, that the device is already selected
  */
 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) & NAND_STATUS_WP) ? 0 : 1; 
+       return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
 }
 
 /**
@@ -505,15 +507,15 @@ static int nand_check_wp (struct mtd_info *mtd)
 static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
 {
        struct nand_chip *this = mtd->priv;
-       
+
        if (!this->bbt)
                return this->block_bad(mtd, ofs, getchip);
-       
+
        /* Return info from the table */
        return nand_isbad_bbt (mtd, ofs, allowbbt);
 }
 
-/* 
+/*
  * Wait for the ready pin, after a command
  * The timeout is catched later.
  */
@@ -527,7 +529,7 @@ static void nand_wait_ready(struct mtd_info *mtd)
                if (this->dev_ready(mtd))
                        return;
                touch_softlockup_watchdog();
-       } while (time_before(jiffies, timeo));  
+       } while (time_before(jiffies, timeo));
 }
 
 /**
@@ -590,13 +592,13 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                /* Latch in address */
                this->hwcontrol(mtd, NAND_CTL_CLRALE);
        }
-       
-       /* 
-        * program and erase have their own busy handlers 
+
+       /*
+        * 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:
@@ -605,7 +607,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                return;
 
        case NAND_CMD_RESET:
-               if (this->dev_ready)    
+               if (this->dev_ready)
                        break;
                udelay(this->chip_delay);
                this->hwcontrol(mtd, NAND_CTL_SETCLE);
@@ -614,16 +616,16 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
                while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
                return;
 
-       /* This applies to read commands */     
+       /* This applies to read commands */
        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;
-               }       
+               }
        }
        /* Apply this short delay always to ensure that we do wait tWB in
         * any case on any machine. */
@@ -653,8 +655,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                column += mtd->oobblock;
                command = NAND_CMD_READ0;
        }
-       
-               
+
+
        /* Begin command latch cycle */
        this->hwcontrol(mtd, NAND_CTL_SETCLE);
        /* Write out the command to the device. */
@@ -672,7 +674,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                                column >>= 1;
                        this->write_byte(mtd, column & 0xff);
                        this->write_byte(mtd, column >> 8);
-               }       
+               }
                if (page_addr != -1) {
                        this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
                        this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
@@ -683,13 +685,13 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                /* Latch in address */
                this->hwcontrol(mtd, NAND_CTL_CLRALE);
        }
-       
-       /* 
-        * program and erase have their own busy handlers 
+
+       /*
+        * program and erase have their own busy handlers
         * status, sequential in, and deplete1 need no delay
         */
        switch (command) {
-                       
+
        case NAND_CMD_CACHEDPROG:
        case NAND_CMD_PAGEPROG:
        case NAND_CMD_ERASE1:
@@ -699,7 +701,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
        case NAND_CMD_DEPLETE1:
                return;
 
-       /* 
+       /*
         * read error status commands require only a short delay
         */
        case NAND_CMD_STATUS_ERROR:
@@ -711,7 +713,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                return;
 
        case NAND_CMD_RESET:
-               if (this->dev_ready)    
+               if (this->dev_ready)
                        break;
                udelay(this->chip_delay);
                this->hwcontrol(mtd, NAND_CTL_SETCLE);
@@ -728,17 +730,17 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
                /* End command latch cycle */
                this->hwcontrol(mtd, NAND_CTL_CLRCLE);
                /* Fall through into ready check */
-               
-       /* This applies to read commands */     
+
+       /* This applies to read commands */
        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;
-               }       
+               }
        }
 
        /* Apply this short delay always to ensure that we do wait tWB in
@@ -752,11 +754,11 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
  * nand_get_device - [GENERIC] Get chip for selected access
  * @this:      the nand chip descriptor
  * @mtd:       MTD device structure
- * @new_state: the state which is requested 
+ * @new_state: the state which is requested
  *
  * Get the device and lock it for exclusive access
  */
-static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
+static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
 {
        struct nand_chip *active;
        spinlock_t *lock;
@@ -779,7 +781,11 @@ retry:
        if (active == this && this->state == FL_READY) {
                this->state = new_state;
                spin_unlock(lock);
-               return;
+               return 0;
+       }
+       if (new_state == FL_PM_SUSPENDED) {
+               spin_unlock(lock);
+               return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
        }
        set_current_state(TASK_UNINTERRUPTIBLE);
        add_wait_queue(wq, &wait);
@@ -796,7 +802,7 @@ retry:
  * @state:     state to select the max. timeout value
  *
  * Wait for command done. This applies to erase and program only
- * Erase can take up to 400ms and program up to 20ms according to 
+ * Erase can take up to 400ms and program up to 20ms according to
  * general NAND and SmartMedia specs
  *
 */
@@ -805,7 +811,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
 
        unsigned long   timeo = jiffies;
        int     status;
-       
+
        if (state == FL_ERASING)
                 timeo += (HZ * 400) / 1000;
        else
@@ -817,17 +823,17 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
 
        if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
                this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1);
-       else    
+       else
                this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
 
-       while (time_before(jiffies, timeo)) {           
+       while (time_before(jiffies, timeo)) {
                /* Check, if we were interrupted */
                if (this->state != state)
                        return 0;
 
                if (this->dev_ready) {
                        if (this->dev_ready(mtd))
-                               break;  
+                               break;
                } else {
                        if (this->read_byte(mtd) & NAND_STATUS_READY)
                                break;
@@ -853,7 +859,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
  *
  * Cached programming is not supported yet.
  */
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, 
+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page,
        u_char *oob_buf,  struct nand_oobinfo *oobsel, int cached)
 {
        int     i, status;
@@ -862,10 +868,10 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
        int     *oob_config = oobsel->eccpos;
        int     datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
        int     eccbytes = 0;
-       
+
        /* FIXME: Enable cached programming */
        cached = 0;
-       
+
        /* Send command to begin auto page programming */
        this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
 
@@ -876,7 +882,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
                printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
                this->write_buf(mtd, this->data_poi, mtd->oobblock);
                break;
-               
+
        /* Software ecc 3/256, write all */
        case NAND_ECC_SOFT:
                for (; eccsteps; eccsteps--) {
@@ -905,11 +911,11 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
                }
                break;
        }
-                                                                               
+
        /* Write out OOB data */
        if (this->options & NAND_HWECC_SYNDROME)
                this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
-       else 
+       else
                this->write_buf(mtd, oob_buf, mtd->oobsize);
 
        /* Send command to actually program the data */
@@ -934,7 +940,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
                /* wait until cache is ready*/
                // status = this->waitfunc (mtd, this, FL_CACHEDRPG);
        }
-       return 0;       
+       return 0;
 }
 
 #ifdef CONFIG_MTD_NAND_VERIFY_WRITE
@@ -950,19 +956,19 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
  * @oobmode:   1 = full buffer verify, 0 = ecc only
  *
  * The NAND device assumes that it is always writing to a cleanly erased page.
- * Hence, it performs its internal write verification only on bits that 
+ * Hence, it performs its internal write verification only on bits that
  * transitioned from 1 to 0. The device does NOT verify the whole page on a
- * byte by byte basis. It is possible that the page was not completely erased 
- * or the page is becoming unusable due to wear. The read with ECC would catch 
- * the error later when the ECC page check fails, but we would rather catch 
+ * byte by byte basis. It is possible that the page was not completely erased
+ * or the page is becoming unusable due to wear. The read with ECC would catch
+ * the error later when the ECC page check fails, but we would rather catch
  * it early in the page write stage. Better to write no data than invalid data.
  */
-static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 
+static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages,
        u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
 {
        int     i, j, datidx = 0, oobofs = 0, res = -EIO;
        int     eccsteps = this->eccsteps;
-       int     hweccbytes; 
+       int     hweccbytes;
        u_char  oobdata[64];
 
        hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
@@ -1002,7 +1008,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
 
                        if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
                                int ecccnt = oobsel->eccbytes;
-               
+
                                for (i = 0; i < ecccnt; i++) {
                                        int idx = oobsel->eccpos[i];
                                        if (oobdata[idx] != oob_buf[oobofs + idx] ) {
@@ -1012,20 +1018,20 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
                                                goto out;
                                        }
                                }
-                       }       
+                       }
                }
                oobofs += mtd->oobsize - hweccbytes * eccsteps;
                page++;
                numpages--;
 
-               /* Apply delay or wait for ready/busy pin 
+               /* Apply delay or wait for ready/busy pin
                 * Do this before the AUTOINCR check, so no problems
                 * arise if a chip which does auto increment
                 * is marked as NOAUTOINCR by the board driver.
                 * Do this also before returning, so the chip is
                 * ready for the next command.
                */
-               if (!this->dev_ready) 
+               if (!this->dev_ready)
                        udelay (this->chip_delay);
                else
                        nand_wait_ready(mtd);
@@ -1033,17 +1039,17 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
                /* All done, return happy */
                if (!numpages)
                        return 0;
-               
-                       
-               /* Check, if the chip supports auto page increment */ 
+
+
+               /* Check, if the chip supports auto page increment */
                if (!NAND_CANAUTOINCR(this))
                        this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
        }
-       /* 
+       /*
         * Terminate the read command. We come here in case of an error
         * So we must issue a reset command.
         */
-out:    
+out:
        this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1);
        return res;
 }
@@ -1105,7 +1111,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
  * 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, 
+                            size_t * retlen, u_char * buf, u_char * oob_buf,
                             struct nand_oobinfo *oobsel, int flags)
 {
 
@@ -1139,7 +1145,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
                oobsel = this->autooob;
-               
+
        eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
        oob_config = oobsel->eccpos;
 
@@ -1157,28 +1163,28 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
        end = mtd->oobblock;
        ecc = this->eccsize;
        eccbytes = this->eccbytes;
-       
+
        if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
                compareecc = 0;
 
        oobreadlen = mtd->oobsize;
-       if (this->options & NAND_HWECC_SYNDROME) 
+       if (this->options & NAND_HWECC_SYNDROME)
                oobreadlen -= oobsel->eccbytes;
 
        /* Loop until all data read */
        while (read < len) {
-               
+
                int aligned = (!col && (len - read) >= end);
-               /* 
+               /*
                 * If the read is not page aligned, we have to read into data buffer
                 * due to ecc, else we read into return buffer direct
                 */
                if (aligned)
                        data_poi = &buf[read];
-               else 
+               else
                        data_poi = this->data_buf;
-               
-               /* Check, if we have this page in the buffer 
+
+               /* Check, if we have this page in the buffer
                 *
                 * FIXME: Make it work when we must provide oob data too,
                 * check the usage of data_buf oob field
@@ -1194,7 +1200,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                if (sndcmd) {
                        this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
                        sndcmd = 0;
-               }       
+               }
 
                /* get oob area, if we have no oob buffer from fs-driver */
                if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
@@ -1202,7 +1208,7 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                        oob_data = &this->data_buf[end];
 
                eccsteps = this->eccsteps;
-               
+
                switch (eccmode) {
                case NAND_ECC_NONE: {   /* No ECC, Read in a page */
                        static unsigned long lastwhinge = 0;
@@ -1213,12 +1219,12 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                        this->read_buf(mtd, data_poi, end);
                        break;
                }
-                       
+
                case NAND_ECC_SOFT:     /* Software ECC 3/256: Read in a page + oob data */
                        this->read_buf(mtd, data_poi, end);
-                       for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) 
+                       for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc)
                                this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
-                       break;  
+                       break;
 
                default:
                        for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {
@@ -1237,15 +1243,15 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                                         * does the error correction on the fly */
                                        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: " 
+                                               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
                                                        "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
                                                ecc_failed++;
                                        }
                                } else {
                                        this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
-                               }       
+                               }
                        }
-                       break;                                          
+                       break;
                }
 
                /* read oobdata */
@@ -1253,8 +1259,8 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
 
                /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
                if (!compareecc)
-                       goto readoob;   
-               
+                       goto readoob;
+
                /* Pick the ECC bytes out of the oob data */
                for (j = 0; j < oobsel->eccbytes; j++)
                        ecc_code[j] = oob_data[oob_config[j]];
@@ -1262,24 +1268,24 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                /* correct data, if neccecary */
                for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
                        ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
-                       
+
                        /* Get next chunk of ecc bytes */
                        j += eccbytes;
-                       
-                       /* Check, if we have a fs supplied oob-buffer, 
+
+                       /* Check, if we have a fs supplied oob-buffer,
                         * This is the legacy mode. Used by YAFFS1
                         * Should go away some day
                         */
-                       if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { 
+                       if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
                                int *p = (int *)(&oob_data[mtd->oobsize]);
                                p[i] = ecc_status;
                        }
-                       
-                       if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {     
+
+                       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++;
                        }
-               }               
+               }
 
        readoob:
                /* check, if we have a fs supplied oob-buffer */
@@ -1305,25 +1311,25 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                }
        readdata:
                /* Partial page read, transfer data into fs buffer */
-               if (!aligned) { 
+               if (!aligned) {
                        for (j = col; j < end && read < len; j++)
                                buf[read++] = data_poi[j];
-                       this->pagebuf = realpage;       
-               } else          
+                       this->pagebuf = realpage;
+               } else
                        read += mtd->oobblock;
 
-               /* Apply delay or wait for ready/busy pin 
+               /* Apply delay or wait for ready/busy pin
                 * Do this before the AUTOINCR check, so no problems
                 * arise if a chip which does auto increment
                 * is marked as NOAUTOINCR by the board driver.
                */
-               if (!this->dev_ready) 
+               if (!this->dev_ready)
                        udelay (this->chip_delay);
                else
                        nand_wait_ready(mtd);
-                       
+
                if (read == len)
-                       break;  
+                       break;
 
                /* For subsequent reads align to page boundary. */
                col = 0;
@@ -1337,11 +1343,11 @@ int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
                        this->select_chip(mtd, -1);
                        this->select_chip(mtd, chipnr);
                }
-               /* Check, if the chip supports auto page increment 
-                * or if we have hit a block boundary. 
-               */ 
+               /* Check, if the chip supports auto page increment
+                * or if we have hit a block boundary.
+               */
                if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
-                       sndcmd = 1;                             
+                       sndcmd = 1;
        }
 
        /* Deselect and wake up anyone waiting on the device */
@@ -1378,7 +1384,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
        /* Shift to get page */
        page = (int)(from >> this->page_shift);
        chipnr = (int)(from >> this->chip_shift);
-       
+
        /* Mask to get column */
        col = from & (mtd->oobsize - 1);
 
@@ -1400,7 +1406,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
 
        /* Send the read command */
        this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask);
-       /* 
+       /*
         * Read the data, if we read more than one page
         * oob data, let the device transfer the data !
         */
@@ -1422,20 +1428,20 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
                                this->select_chip(mtd, -1);
                                this->select_chip(mtd, chipnr);
                        }
-                               
-                       /* Apply delay or wait for ready/busy pin 
+
+                       /* Apply delay or wait for ready/busy pin
                         * Do this before the AUTOINCR check, so no problems
                         * arise if a chip which does auto increment
                         * is marked as NOAUTOINCR by the board driver.
                         */
-                       if (!this->dev_ready) 
+                       if (!this->dev_ready)
                                udelay (this->chip_delay);
                        else
                                nand_wait_ready(mtd);
 
-                       /* Check, if the chip supports auto page increment 
-                        * or if we have hit a block boundary. 
-                       */ 
+                       /* Check, if the chip supports auto page increment
+                        * or if we have hit a block boundary.
+                       */
                        if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
                                /* For subsequent page reads set offset to 0 */
                                this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
@@ -1481,27 +1487,27 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
        nand_get_device (this, mtd , FL_READING);
 
        this->select_chip (mtd, chip);
-       
+
        /* Add requested oob length */
        len += ooblen;
-       
+
        while (len) {
                if (sndcmd)
                        this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask);
-               sndcmd = 0;     
+               sndcmd = 0;
 
                this->read_buf (mtd, &buf[cnt], pagesize);
 
                len -= pagesize;
                cnt += pagesize;
                page++;
-               
-               if (!this->dev_ready) 
+
+               if (!this->dev_ready)
                        udelay (this->chip_delay);
                else
                        nand_wait_ready(mtd);
-                       
-               /* Check, if the chip supports auto page increment */ 
+
+               /* Check, if the chip supports auto page increment */
                if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
                        sndcmd = 1;
        }
@@ -1512,8 +1518,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
 }
 
 
-/** 
- * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer 
+/**
+ * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer
  * @mtd:       MTD device structure
  * @fsbuf:     buffer given by fs driver
  * @oobsel:    out of band selection structre
@@ -1542,20 +1548,20 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct
        int i, len, ofs;
 
        /* Zero copy fs supplied buffer */
-       if (fsbuf && !autoplace) 
+       if (fsbuf && !autoplace)
                return fsbuf;
 
        /* Check, if the buffer must be filled with ff again */
-       if (this->oobdirty) {   
-               memset (this->oob_buf, 0xff, 
+       if (this->oobdirty) {
+               memset (this->oob_buf, 0xff,
                        mtd->oobsize << (this->phys_erase_shift - this->page_shift));
                this->oobdirty = 0;
-       }       
-       
+       }
+
        /* If we have no autoplacement or no fs buffer use the internal one */
        if (!autoplace || !fsbuf)
                return this->oob_buf;
-       
+
        /* Walk through the pages and place the data */
        this->oobdirty = 1;
        ofs = 0;
@@ -1589,7 +1595,7 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret
 {
        return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));
 }
-                          
+
 /**
  * nand_write_ecc - [MTD Interface] NAND write with ECC
  * @mtd:       MTD device structure
@@ -1622,7 +1628,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                return -EINVAL;
        }
 
-       /* reject writes, which are not page aligned */ 
+       /* reject writes, which are not page aligned */
        if (NOTALIGNED (to) || NOTALIGNED(len)) {
                printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
                return -EINVAL;
@@ -1641,14 +1647,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                goto out;
 
        /* if oobsel is NULL, use chip defaults */
-       if (oobsel == NULL) 
-               oobsel = &mtd->oobinfo;         
-               
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
+
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
                oobsel = this->autooob;
                autoplace = 1;
-       }       
+       }
        if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                autoplace = 1;
 
@@ -1656,9 +1662,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
        totalpages = len >> this->page_shift;
        page = (int) (to >> this->page_shift);
        /* Invalidate the page cache, if we write to the cached page */
-       if (page <= this->pagebuf && this->pagebuf < (page + totalpages))  
+       if (page <= this->pagebuf && this->pagebuf < (page + totalpages))
                this->pagebuf = -1;
-       
+
        /* Set it relative to chip */
        page &= this->pagemask;
        startpage = page;
@@ -1680,14 +1686,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                if (ret) {
                        DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
                        goto out;
-               }       
+               }
                /* Next oob page */
                oob += mtd->oobsize;
                /* Update written bytes count */
                written += mtd->oobblock;
-               if (written == len) 
+               if (written == len)
                        goto cmp;
-               
+
                /* Increment page address */
                page++;
 
@@ -1698,13 +1704,13 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                if (!(page & (ppblock - 1))){
                        int ofs;
                        this->data_poi = bufstart;
-                       ret = nand_verify_pages (mtd, this, startpage, 
+                       ret = nand_verify_pages (mtd, this, startpage,
                                page - startpage,
                                oobbuf, oobsel, chipnr, (eccbuf != NULL));
                        if (ret) {
                                DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
                                goto out;
-                       }       
+                       }
                        *retlen = written;
 
                        ofs = autoplace ? mtd->oobavail : mtd->oobsize;
@@ -1714,8 +1720,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
                        numpages = min (totalpages, ppblock);
                        page &= this->pagemask;
                        startpage = page;
-                       oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, 
+                       oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel,
                                        autoplace, numpages);
+                       oob = 0;
                        /* Check, if we cross a chip boundary */
                        if (!page) {
                                chipnr++;
@@ -1731,7 +1738,7 @@ cmp:
                oobbuf, oobsel, chipnr, (eccbuf != NULL));
        if (!ret)
                *retlen = written;
-       else    
+       else
                DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
 
 out:
@@ -1791,7 +1798,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *
        /* Check, if it is write protected */
        if (nand_check_wp(mtd))
                goto out;
-       
+
        /* Invalidate the page cache, if we write to the cached page */
        if (page == this->pagebuf)
                this->pagebuf = -1;
@@ -1854,10 +1861,10 @@ out:
  *
  * NAND write with kvec. This just calls the ecc function
  */
-static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, 
+static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
                loff_t to, size_t * retlen)
 {
-       return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL));    
+       return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL));
 }
 
 /**
@@ -1872,7 +1879,7 @@ static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned
  *
  * NAND write with iovec with ecc
  */
-static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, 
+static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count,
                loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
 {
        int i, page, len, total_len, ret = -EIO, written = 0, chipnr;
@@ -1898,7 +1905,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                return -EINVAL;
        }
 
-       /* reject writes, which are not page aligned */ 
+       /* reject writes, which are not page aligned */
        if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
                printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
                return -EINVAL;
@@ -1917,21 +1924,21 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                goto out;
 
        /* if oobsel is NULL, use chip defaults */
-       if (oobsel == NULL) 
-               oobsel = &mtd->oobinfo;         
+       if (oobsel == NULL)
+               oobsel = &mtd->oobinfo;
 
        /* Autoplace of oob data ? Use the default placement scheme */
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
                oobsel = this->autooob;
                autoplace = 1;
-       }       
+       }
        if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                autoplace = 1;
 
        /* Setup start page */
        page = (int) (to >> this->page_shift);
        /* Invalidate the page cache, if we write to the cached page */
-       if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))  
+       if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))
                this->pagebuf = -1;
 
        startpage = page & this->pagemask;
@@ -1955,10 +1962,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                        oob = 0;
                        for (i = 1; i <= numpages; i++) {
                                /* Write one page. If this is the last page to write
-                                * then use the real pageprogram command, else select 
+                                * then use the real pageprogram command, else select
                                 * cached programming if supported by the chip.
                                 */
-                               ret = nand_write_page (mtd, this, page & this->pagemask, 
+                               ret = nand_write_page (mtd, this, page & this->pagemask,
                                        &oobbuf[oob], oobsel, i != numpages);
                                if (ret)
                                        goto out;
@@ -1974,12 +1981,12 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                                count--;
                        }
                } else {
-                       /* We must use the internal buffer, read data out of each 
+                       /* We must use the internal buffer, read data out of each
                         * tuple until we have a full page to write
                         */
                        int cnt = 0;
                        while (cnt < mtd->oobblock) {
-                               if (vecs->iov_base != NULL && vecs->iov_len) 
+                               if (vecs->iov_base != NULL && vecs->iov_len)
                                        this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
                                /* Check, if we have to switch to the next tuple */
                                if (len >= (int) vecs->iov_len) {
@@ -1988,10 +1995,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                                        count--;
                                }
                        }
-                       this->pagebuf = page;   
-                       this->data_poi = this->data_buf;        
+                       this->pagebuf = page;
+                       this->data_poi = this->data_buf;
                        bufstart = this->data_poi;
-                       numpages = 1;           
+                       numpages = 1;
                        oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages);
                        ret = nand_write_page (mtd, this, page & this->pagemask,
                                oobbuf, oobsel, 0);
@@ -2004,7 +2011,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
                ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
                if (ret)
                        goto out;
-                       
+
                written += mtd->oobblock * numpages;
                /* All done ? */
                if (!count)
@@ -2072,7 +2079,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)
@@ -2154,14 +2161,14 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
                        instr->state = MTD_ERASE_FAILED;
                        goto erase_exit;
                }
-               
-               /* Invalidate the page cache, if we erase the block which contains 
+
+               /* Invalidate the page cache, if we erase the block which contains
                   the current cached page */
                if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
                        this->pagebuf = -1;
 
                this->erase_cmd (mtd, page & this->pagemask);
-               
+
                status = this->waitfunc (mtd, this, FL_ERASING);
 
                /* See if operation failed and additional status checks are available */
@@ -2179,12 +2186,12 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
 
                /* 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) && 
+                       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);
                page += pages_per_block;
@@ -2195,7 +2202,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
                        this->select_chip(mtd, -1);
                        this->select_chip(mtd, chipnr);
 
-                       /* if BBT requires refresh and BBT-PERCHIP, 
+                       /* 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;
@@ -2220,7 +2227,7 @@ erase_exit:
                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", 
+                               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]);
                        }
@@ -2258,9 +2265,9 @@ static void nand_sync (struct mtd_info *mtd)
 static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs)
 {
        /* Check for invalid offset */
-       if (ofs > mtd->size) 
+       if (ofs > mtd->size)
                return -EINVAL;
-       
+
        return nand_block_checkbad (mtd, ofs, 1, 0);
 }
 
@@ -2284,6 +2291,34 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
        return this->block_markbad(mtd, ofs);
 }
 
+/**
+ * nand_suspend - [MTD Interface] Suspend the NAND flash
+ * @mtd:       MTD device structure
+ */
+static int nand_suspend(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+
+       return nand_get_device (this, mtd, FL_PM_SUSPENDED);
+}
+
+/**
+ * nand_resume - [MTD Interface] Resume the NAND flash
+ * @mtd:       MTD device structure
+ */
+static void nand_resume(struct mtd_info *mtd)
+{
+       struct nand_chip *this = mtd->priv;
+
+       if (this->state == FL_PM_SUSPENDED)
+               nand_release_device(mtd);
+       else
+               printk(KERN_ERR "resume() called for the chip which is not "
+                               "in suspended state\n");
+
+}
+
+
 /**
  * nand_scan - [NAND Interface] Scan for the NAND device
  * @mtd:       MTD device structure
@@ -2351,13 +2386,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
 
        /* Print and store flash device information */
        for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-                               
-               if (nand_dev_id != nand_flash_ids[i].id) 
+
+               if (nand_dev_id != nand_flash_ids[i].id)
                        continue;
 
                if (!mtd->name) mtd->name = nand_flash_ids[i].name;
                this->chipsize = nand_flash_ids[i].chipsize << 20;
-               
+
                /* New devices have all the information in additional id bytes */
                if (!nand_flash_ids[i].pagesize) {
                        int extid;
@@ -2369,14 +2404,14 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                        mtd->oobblock = 1024 << (extid & 0x3);
                        extid >>= 2;
                        /* Calc oobsize */
-                       mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512);
+                       mtd->oobsize = (8 << (extid & 0x01)) * (mtd->oobblock >> 9);
                        extid >>= 2;
                        /* Calc blocksize. Blocksize is multiples of 64KiB */
                        mtd->erasesize = (64 * 1024)  << (extid & 0x03);
                        extid >>= 2;
                        /* Get buswidth information */
                        busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
-               
+
                } else {
                        /* Old devices have this data hardcoded in the
                         * device id table */
@@ -2396,23 +2431,23 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                 * 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, 
+                               " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
                                nand_manuf_ids[maf_id].name , mtd->name);
-                       printk (KERN_WARNING 
-                               "NAND bus width %d instead %d bit\n", 
+                       printk (KERN_WARNING
+                               "NAND bus width %d instead %d bit\n",
                                        (this->options & NAND_BUSWIDTH_16) ? 16 : 8,
                                        busw ? 16 : 8);
                        this->select_chip(mtd, -1);
-                       return 1;       
+                       return 1;
                }
-               
-               /* Calculate the address shift from the page size */    
+
+               /* Calculate the address shift from the page size */
                this->page_shift = ffs(mtd->oobblock) - 1;
                this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
                this->chip_shift = ffs(this->chipsize) - 1;
 
                /* Set the bad block position */
-               this->badblockpos = mtd->oobblock > 512 ? 
+               this->badblockpos = mtd->oobblock > 512 ?
                        NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
 
                /* Get chip options, preserve non chip based options */
@@ -2422,10 +2457,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                this->options |= NAND_NO_AUTOINCR;
                /* Check if this is a not a samsung device. Do not clear the options
                 * for chips which are not having an extended id.
-                */     
+                */
                if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
                        this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
-               
+
                /* Check for AND chips with 4 page planes */
                if (this->options & NAND_4PAGE_ARRAY)
                        this->erase_cmd = multi_erase_cmd;
@@ -2435,9 +2470,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                /* Do not replace user supplied command function ! */
                if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
                        this->cmdfunc = nand_command_lp;
-                               
+
                printk (KERN_INFO "NAND device: Manufacturer ID:"
-                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
+                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
                        nand_manuf_ids[maf_id].name , nand_flash_ids[i].name);
                break;
        }
@@ -2461,7 +2496,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        }
        if (i > 1)
                printk(KERN_INFO "%d NAND chips detected\n", i);
-       
+
        /* Allocate buffers, if neccecary */
        if (!this->oob_buf) {
                size_t len;
@@ -2473,7 +2508,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                }
                this->options |= NAND_OOBBUF_ALLOC;
        }
-       
+
        if (!this->data_buf) {
                size_t len;
                len = mtd->oobblock + mtd->oobsize;
@@ -2500,7 +2535,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        if (!this->autooob) {
                /* Select the appropriate default oob placement scheme for
                 * placement agnostic filesystems */
-               switch (mtd->oobsize) { 
+               switch (mtd->oobsize) {
                case 8:
                        this->autooob = &nand_oob_8;
                        break;
@@ -2516,19 +2551,19 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                        BUG();
                }
        }
-       
+
        /* The number of bytes available for the filesystem to place fs dependend
         * oob data */
        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
         * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
-        * fallback to software ECC 
+        * fallback to software ECC
        */
-       this->eccsize = 256;    /* set default eccsize */       
+       this->eccsize = 256;    /* set default eccsize */
        this->eccbytes = 3;
 
        switch (this->eccmode) {
@@ -2543,56 +2578,56 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                        this->eccsize = 2048;
                break;
 
-       case NAND_ECC_HW3_512: 
-       case NAND_ECC_HW6_512: 
-       case NAND_ECC_HW8_512: 
+       case NAND_ECC_HW3_512:
+       case NAND_ECC_HW6_512:
+       case NAND_ECC_HW8_512:
                if (mtd->oobblock == 256) {
                        printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
                        this->eccmode = NAND_ECC_SOFT;
                        this->calculate_ecc = nand_calculate_ecc;
                        this->correct_data = nand_correct_data;
-               } else 
+               } else
                        this->eccsize = 512; /* set eccsize to 512 */
                break;
-                       
+
        case NAND_ECC_HW3_256:
                break;
-               
-       case NAND_ECC_NONE: 
+
+       case NAND_ECC_NONE:
                printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
                this->eccmode = NAND_ECC_NONE;
                break;
 
-       case NAND_ECC_SOFT:     
+       case NAND_ECC_SOFT:
                this->calculate_ecc = nand_calculate_ecc;
                this->correct_data = nand_correct_data;
                break;
 
        default:
                printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-               BUG();  
-       }       
+               BUG();
+       }
 
-       /* Check hardware ecc function availability and adjust number of ecc bytes per 
+       /* Check hardware ecc function availability and adjust number of ecc bytes per
         * calculation step
        */
        switch (this->eccmode) {
        case NAND_ECC_HW12_2048:
                this->eccbytes += 4;
-       case NAND_ECC_HW8_512: 
+       case NAND_ECC_HW8_512:
                this->eccbytes += 2;
-       case NAND_ECC_HW6_512: 
+       case NAND_ECC_HW6_512:
                this->eccbytes += 3;
-       case NAND_ECC_HW3_512: 
+       case NAND_ECC_HW3_512:
        case NAND_ECC_HW3_256:
                if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
                        break;
                printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
-               BUG();  
+               BUG();
        }
-               
+
        mtd->eccsize = this->eccsize;
-       
+
        /* Set the number of read / write steps for one page to ensure ECC generation */
        switch (this->eccmode) {
        case NAND_ECC_HW12_2048:
@@ -2604,15 +2639,15 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
                this->eccsteps = mtd->oobblock / 512;
                break;
        case NAND_ECC_HW3_256:
-       case NAND_ECC_SOFT:     
+       case NAND_ECC_SOFT:
                this->eccsteps = mtd->oobblock / 256;
                break;
-               
-       case NAND_ECC_NONE: 
+
+       case NAND_ECC_NONE:
                this->eccsteps = 1;
                break;
        }
-       
+
        /* Initialize state, waitqueue and spinlock */
        this->state = FL_READY;
        init_waitqueue_head (&this->wq);
@@ -2643,8 +2678,8 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
        mtd->sync = nand_sync;
        mtd->lock = NULL;
        mtd->unlock = NULL;
-       mtd->suspend = NULL;
-       mtd->resume = NULL;
+       mtd->suspend = nand_suspend;
+       mtd->resume = nand_resume;
        mtd->block_isbad = nand_block_isbad;
        mtd->block_markbad = nand_block_markbad;
 
@@ -2652,7 +2687,7 @@ 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;
@@ -2662,7 +2697,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
 }
 
 /**
- * nand_release - [NAND Interface] Free resources held by the NAND device 
+ * nand_release - [NAND Interface] Free resources held by the NAND device
  * @mtd:       MTD device structure
 */
 void nand_release (struct mtd_info *mtd)
index 7535ef53685e8aaa13c8409d88187fd1a354be96..ca286999fe08ab3b39e89f6f2963bc708b440569 100644 (file)
@@ -3,10 +3,10 @@
  *
  *  Overview:
  *   Bad block table support for the NAND driver
- *   
+ *
  *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
  *
- * $Id: nand_bbt.c,v 1.35 2005/07/15 13:53:47 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 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
  *
  * Description:
  *
- * When nand_scan_bbt is called, then it tries to find the bad block table 
- * depending on the options in the bbt descriptor(s). If a bbt is found 
- * then the contents are read and the memory based bbt is created. If a 
+ * When nand_scan_bbt is called, then it tries to find the bad block table
+ * depending on the options in the bbt descriptor(s). If a bbt is found
+ * then the contents are read and the memory based bbt is created. If a
  * mirrored bbt is selected then the mirror is searched too and the
- * versions are compared. If the mirror has a greater version number 
+ * versions are compared. If the mirror has a greater version number
  * than the mirror bbt is used to build the memory based bbt.
  * If the tables are not versioned, then we "or" the bad block information.
- * If one of the bbt's is out of date or does not exist it is (re)created. 
- * If no bbt exists at all then the device is scanned for factory marked 
- * good / bad blocks and the bad block tables are created. 
+ * If one of the bbt's is out of date or does not exist it is (re)created.
+ * If no bbt exists at all then the device is scanned for factory marked
+ * good / bad blocks and the bad block tables are created.
  *
- * For manufacturer created bbts like the one found on M-SYS DOC devices 
+ * For manufacturer created bbts like the one found on M-SYS DOC devices
  * the bbt is searched and read but never created
  *
- * The autogenerated bad block table is located in the last good blocks 
- * of the device. The table is mirrored, so it can be updated eventually. 
- * The table is marked in the oob area with an ident pattern and a version 
+ * The autogenerated bad block table is located in the last good blocks
+ * of the device. The table is mirrored, so it can be updated eventually.
+ * The table is marked in the oob area with an ident pattern and a version
  * number which indicates which of both tables is more up to date.
  *
  * The table uses 2 bits per block
  * 01b:                block is marked bad due to wear
  * 10b:                block is reserved (to protect the bbt area)
  * 11b:                block is factory marked bad
- * 
+ *
  * Multichip devices like DOC store the bad block info per floor.
  *
  * Following assumptions are made:
  * - bbts start at a page boundary, if autolocated on a block boundary
  * - the space neccecary for a bbt in FLASH does not exceed a block boundary
- * 
+ *
  */
 
 #include <linux/slab.h>
@@ -62,7 +62,7 @@
 #include <linux/delay.h>
 
 
-/** 
+/**
  * check_pattern - [GENERIC] check if a pattern is in the buffer
  * @buf:       the buffer to search
  * @len:       the length of buffer to search
@@ -86,9 +86,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
                        if (p[i] != 0xff)
                                return -1;
                }
-       }       
+       }
        p += end;
-       
+
        /* Compare the pattern */
        for (i = 0; i < td->len; i++) {
                if (p[i] != td->pattern[i])
@@ -106,13 +106,13 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
        return 0;
 }
 
-/** 
+/**
  * check_short_pattern - [GENERIC] check if a pattern is in the buffer
  * @buf:       the buffer to search
  * @td:                search pattern descriptor
  *
  * Check for a pattern at the given place. Used to search bad block
- * tables and good / bad block identifiers. Same as check_pattern, but 
+ * tables and good / bad block identifiers. Same as check_pattern, but
  * no optional empty check
  *
 */
@@ -142,7 +142,7 @@ static int check_short_pattern (uint8_t *buf, struct nand_bbt_descr *td)
  * Read the bad block table starting from page.
  *
  */
-static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, 
+static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
        int bits, int offs, int reserved_block_code)
 {
        int res, i, j, act = 0;
@@ -153,7 +153,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
 
        totlen = (num * bits) >> 3;
        from = ((loff_t)page) << this->page_shift;
-       
+
        while (totlen) {
                len = min (totlen, (size_t) (1 << this->bbt_erase_shift));
                res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
@@ -163,7 +163,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
                                return res;
                        }
                        printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");
-               }       
+               }
 
                /* Analyse data */
                for (i = 0; i < len; i++) {
@@ -183,12 +183,12 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
                                 * message to MTD_DEBUG_LEVEL0 */
                                printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
                                        ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
-                               /* Factory marked bad or worn out ? */  
+                               /* Factory marked bad or worn out ? */
                                if (tmp == 0)
                                        this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
                                else
                                        this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
-                       }       
+                       }
                }
                totlen -= len;
                from += len;
@@ -200,7 +200,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num,
  * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
  * @mtd:       MTD device structure
  * @buf:       temporary buffer
- * @td:                descriptor for the bad block table 
+ * @td:                descriptor for the bad block table
  * @chip:      read the table for a specific chip, -1 read all chips.
  *             Applies only if NAND_BBT_PERCHIP option is set
  *
@@ -235,7 +235,7 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
  * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
  * @mtd:       MTD device structure
  * @buf:       temporary buffer
- * @td:                descriptor for the bad block table 
+ * @td:                descriptor for the bad block table
  * @md:                descriptor for the bad block table mirror
  *
  * Read the bad block table(s) for all chips starting at a given page
@@ -247,16 +247,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de
 {
        struct nand_chip *this = mtd->priv;
 
-       /* Read the primary version, if available */    
+       /* Read the primary version, if available */
        if (td->options & NAND_BBT_VERSION) {
-               nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); 
+               nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
                td->version[0] = buf[mtd->oobblock + td->veroffs];
                printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]);
        }
 
-       /* Read the mirror version, if available */     
+       /* Read the mirror version, if available */
        if (md && (md->options & NAND_BBT_VERSION)) {
-               nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); 
+               nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize);
                md->version[0] = buf[mtd->oobblock + md->veroffs];
                printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
        }
@@ -290,7 +290,7 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
        else {
                if (bd->options & NAND_BBT_SCAN2NDPAGE)
                        len = 2;
-               else    
+               else
                        len = 1;
        }
 
@@ -322,10 +322,10 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                numblocks += startblock;
                from = startblock << (this->bbt_erase_shift - 1);
        }
-       
+
        for (i = startblock; i < numblocks;) {
                int ret;
-               
+
                if (bd->options & NAND_BBT_SCANEMPTY)
                        if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
                                return ret;
@@ -333,8 +333,8 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                for (j = 0; j < len; j++) {
                        if (!(bd->options & NAND_BBT_SCANEMPTY)) {
                                size_t retlen;
-                               
-                               /* Read the full oob until read_oob is fixed to 
+
+                               /* Read the full oob until read_oob is fixed to
                                 * handle single byte reads for 16 bit buswidth */
                                ret = mtd->read_oob(mtd, from + j * mtd->oobblock,
                                                        mtd->oobsize, &retlen, buf);
@@ -343,14 +343,14 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
 
                                if (check_short_pattern (buf, bd)) {
                                        this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-                                       printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 
+                                       printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
                                                i >> 1, (unsigned int) from);
                                        break;
                                }
                        } else {
                                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", 
+                                       printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
                                                i >> 1, (unsigned int) from);
                                        break;
                                }
@@ -369,15 +369,15 @@ static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
  * @td:                descriptor for the bad block table
  *
  * Read the bad block table by searching for a given ident pattern.
- * Search is preformed either from the beginning up or from the end of 
+ * Search is preformed either from the beginning up or from the end of
  * the device downwards. The search starts always at the start of a
  * block.
- * If the option NAND_BBT_PERCHIP is given, each chip is searched 
+ * If the option NAND_BBT_PERCHIP is given, each chip is searched
  * for a bbt, which contains the bad block information of this chip.
  * This is neccecary to provide support for certain DOC devices.
  *
- * The bbt ident pattern resides in the oob area of the first page 
- * in a block. 
+ * The bbt ident pattern resides in the oob area of the first page
+ * in a block.
  */
 static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
 {
@@ -392,10 +392,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                startblock = (mtd->size >> this->bbt_erase_shift) -1;
                dir = -1;
        } else {
-               startblock = 0; 
+               startblock = 0;
                dir = 1;
-       }       
-       
+       }
+
        /* Do we have a bbt per chip ? */
        if (td->options & NAND_BBT_PERCHIP) {
                chips = this->numchips;
@@ -405,19 +405,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                chips = 1;
                bbtblocks = mtd->size >> this->bbt_erase_shift;
        }
-       
+
        /* Number of bits for each erase block in the bbt */
        bits = td->options & NAND_BBT_NRBITS_MSK;
-       
+
        for (i = 0; i < chips; i++) {
                /* Reset version information */
-               td->version[i] = 0;     
+               td->version[i] = 0;
                td->pages[i] = -1;
                /* Scan the maximum number of blocks */
                for (block = 0; block < td->maxblocks; block++) {
                        int actblock = startblock + dir * block;
                        /* Read first page */
-                       nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); 
+                       nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize);
                        if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
                                td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
                                if (td->options & NAND_BBT_VERSION) {
@@ -435,46 +435,46 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                else
                        printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]);
        }
-       return 0;       
+       return 0;
 }
 
 /**
  * search_read_bbts - [GENERIC] scan the device for bad block table(s)
  * @mtd:       MTD device structure
  * @buf:       temporary buffer
- * @td:                descriptor for the bad block table 
+ * @td:                descriptor for the bad block table
  * @md:                descriptor for the bad block table mirror
  *
  * Search and read the bad block table(s)
 */
-static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, 
+static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf,
        struct nand_bbt_descr *td, struct nand_bbt_descr *md)
 {
        /* Search the primary table */
        search_bbt (mtd, buf, td);
-               
+
        /* Search the mirror table */
        if (md)
                search_bbt (mtd, buf, md);
-       
+
        /* Force result check */
-       return 1;       
+       return 1;
 }
-       
 
-/** 
+
+/**
  * write_bbt - [GENERIC] (Re)write the bad block table
  *
  * @mtd:       MTD device structure
  * @buf:       temporary buffer
- * @td:                descriptor for the bad block table 
+ * @td:                descriptor for the bad block table
  * @md:                descriptor for the bad block table mirror
  * @chipsel:   selector for a specific chip, -1 for all
  *
  * (Re)write the bad block table
  *
 */
-static int write_bbt (struct mtd_info *mtd, uint8_t *buf, 
+static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
        struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
 {
        struct nand_chip *this = mtd->priv;
@@ -493,7 +493,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
        /* Write bad block table per chip rather than per device ? */
        if (td->options & NAND_BBT_PERCHIP) {
                numblocks = (int) (this->chipsize >> this->bbt_erase_shift);
-               /* Full device write or specific chip ? */      
+               /* Full device write or specific chip ? */
                if (chipsel == -1) {
                        nrchips = this->numchips;
                } else {
@@ -503,19 +503,19 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
        } else {
                numblocks = (int) (mtd->size >> this->bbt_erase_shift);
                nrchips = 1;
-       }       
-       
+       }
+
        /* Loop through the chips */
        for (; chip < nrchips; chip++) {
-               
-               /* There was already a version of the table, reuse the page 
-                * This applies for absolute placement too, as we have the 
+
+               /* There was already a version of the table, reuse the page
+                * This applies for absolute placement too, as we have the
                 * page nr. in td->pages.
                 */
                if (td->pages[chip] != -1) {
                        page = td->pages[chip];
                        goto write;
-               }       
+               }
 
                /* Automatic placement of the bad block table */
                /* Search direction top -> down ? */
@@ -525,7 +525,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
                } else {
                        startblock = chip * numblocks;
                        dir = 1;
-               }       
+               }
 
                for (i = 0; i < td->maxblocks; i++) {
                        int block = startblock + dir * i;
@@ -542,7 +542,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf,
                }
                printk (KERN_ERR "No space left to write bad block table\n");
                return -ENOSPC;
-write: 
+write:
 
                /* Set up shift count and masks for the flash table */
                bits = td->options & NAND_BBT_NRBITS_MSK;
@@ -553,14 +553,14 @@ write:
                case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
                default: return -EINVAL;
                }
-               
+
                bbtoffs = chip * (numblocks >> 2);
-               
+
                to = ((loff_t) page) << this->page_shift;
 
                memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
                oobinfo.useecc = MTD_NANDECC_PLACEONLY;
-               
+
                /* Must we save the block contents ? */
                if (td->options & NAND_BBT_SAVECONTENT) {
                        /* Make it block aligned */
@@ -599,7 +599,7 @@ write:
                                buf[len + td->veroffs] = td->version[chip];
                        }
                }
-       
+
                /* walk through the memory table */
                for (i = 0; i < numblocks; ) {
                        uint8_t dat;
@@ -611,7 +611,7 @@ write:
                                dat >>= 2;
                        }
                }
-               
+
                memset (&einfo, 0, sizeof (einfo));
                einfo.mtd = mtd;
                einfo.addr = (unsigned long) to;
@@ -621,18 +621,18 @@ write:
                        printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
                        return res;
                }
-       
+
                res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
                if (res < 0) {
                        printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
                        return res;
                }
-               printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", 
+               printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n",
                        (unsigned int) to, td->version[chip]);
-       
+
                /* Mark it as used */
                td->pages[chip] = page;
-       }       
+       }
        return 0;
 }
 
@@ -641,7 +641,7 @@ write:
  * @mtd:       MTD device structure
  * @bd:                descriptor for the good/bad block search pattern
  *
- * The function creates a memory based bbt by scanning the device 
+ * The function creates a memory based bbt by scanning the device
  * for manufacturer / software marked good / bad blocks
 */
 static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
@@ -673,11 +673,11 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
        struct nand_bbt_descr *rd, *rd2;
 
        /* Do we have a bbt per chip ? */
-       if (td->options & NAND_BBT_PERCHIP) 
+       if (td->options & NAND_BBT_PERCHIP)
                chips = this->numchips;
-       else 
+       else
                chips = 1;
-       
+
        for (i = 0; i < chips; i++) {
                writeops = 0;
                rd = NULL;
@@ -692,7 +692,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
                        }
 
                        if (td->pages[i] == -1) {
-                               rd = md;                                
+                               rd = md;
                                td->version[i] = md->version[i];
                                writeops = 1;
                                goto writecheck;
@@ -710,7 +710,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
                                if (!(td->options & NAND_BBT_VERSION))
                                        rd2 = md;
                                goto writecheck;
-                       }       
+                       }
 
                        if (((int8_t) (td->version[i] - md->version[i])) > 0) {
                                rd = td;
@@ -735,15 +735,15 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des
 create:
                /* Create the bad block table by scanning the device ? */
                if (!(td->options & NAND_BBT_CREATE))
-                       continue;       
-               
+                       continue;
+
                /* Create the table in memory by scanning the chip(s) */
                create_bbt (mtd, buf, bd, chipsel);
-               
+
                td->version[i] = 1;
                if (md)
-                       md->version[i] = 1;     
-writecheck:    
+                       md->version[i] = 1;
+writecheck:
                /* read back first ? */
                if (rd)
                        read_abs_bbt (mtd, buf, rd, chipsel);
@@ -757,7 +757,7 @@ writecheck:
                        if (res < 0)
                                return res;
                }
-               
+
                /* Write the mirror bad block table to the device ? */
                if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
                        res = write_bbt (mtd, buf, md, td, chipsel);
@@ -765,11 +765,11 @@ writecheck:
                                return res;
                }
        }
-       return 0;       
+       return 0;
 }
 
 /**
- * mark_bbt_regions - [GENERIC] mark the bad block table regions 
+ * mark_bbt_regions - [GENERIC] mark the bad block table regions
  * @mtd:       MTD device structure
  * @td:                bad block table descriptor
  *
@@ -790,14 +790,14 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
        } else {
                chips = 1;
                nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
-       }       
-       
+       }
+
        for (i = 0; i < chips; i++) {
                if ((td->options & NAND_BBT_ABSPAGE) ||
                    !(td->options & NAND_BBT_WRITE)) {
                        if (td->pages[i] == -1) continue;
                        block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
-                       block <<= 1;            
+                       block <<= 1;
                        oldval = this->bbt[(block >> 3)];
                        newval = oldval | (0x2 << (block & 0x06));
                        this->bbt[(block >> 3)] = newval;
@@ -808,16 +808,16 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
                update = 0;
                if (td->options & NAND_BBT_LASTBLOCK)
                        block = ((i + 1) * nrblocks) - td->maxblocks;
-               else    
+               else
                        block = i * nrblocks;
-               block <<= 1;    
+               block <<= 1;
                for (j = 0; j < td->maxblocks; j++) {
                        oldval = this->bbt[(block >> 3)];
                        newval = oldval | (0x2 << (block & 0x06));
                        this->bbt[(block >> 3)] = newval;
                        if (oldval != newval) update = 1;
                        block += 2;
-               }       
+               }
                /* If we want reserved blocks to be recorded to flash, and some
                   new ones have been marked, then we need to update the stored
                   bbts.  This should only happen once. */
@@ -831,7 +831,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
  * @mtd:       MTD device structure
  * @bd:                descriptor for the good/bad block search pattern
  *
- * The function checks, if a bad block table(s) is/are already 
+ * The function checks, if a bad block table(s) is/are already
  * available. If not it scans the device for manufacturer
  * marked good / bad blocks and writes the bad block table(s) to
  * the selected place.
@@ -880,30 +880,30 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
                this->bbt = NULL;
                return -ENOMEM;
        }
-       
+
        /* Is the bbt at a given page ? */
        if (td->options & NAND_BBT_ABSPAGE) {
                res = read_abs_bbts (mtd, buf, td, md);
-       } else {        
+       } else {
                /* Search the bad block table using a pattern in oob */
                res = search_read_bbts (mtd, buf, td, md);
-       }       
+       }
 
-       if (res) 
+       if (res)
                res = check_create (mtd, buf, bd);
-       
+
        /* Prevent the bbt regions from erasing / writing */
        mark_bbt_region (mtd, td);
        if (md)
                mark_bbt_region (mtd, md);
-       
+
        kfree (buf);
        return res;
 }
 
 
 /**
- * nand_update_bbt - [NAND Interface] update bad block table(s) 
+ * nand_update_bbt - [NAND Interface] update bad block table(s)
  * @mtd:       MTD device structure
  * @offs:      the offset of the newly marked block
  *
@@ -930,7 +930,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
                printk (KERN_ERR "nand_update_bbt: Out of memory\n");
                return -ENOMEM;
        }
-       
+
        writeops = md != NULL ? 0x03 : 0x01;
 
        /* Do we have a bbt per chip ? */
@@ -944,7 +944,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
 
        td->version[chip]++;
        if (md)
-               md->version[chip]++;    
+               md->version[chip]++;
 
        /* Write the bad block table to the device ? */
        if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
@@ -957,12 +957,12 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
                res = write_bbt (mtd, buf, md, td, chipsel);
        }
 
-out:   
+out:
        kfree (buf);
        return res;
 }
 
-/* Define some generic bad / good block scan pattern which are used 
+/* Define some generic bad / good block scan pattern which are used
  * while scanning a device for factory marked good / bad blocks. */
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
 
@@ -1009,7 +1009,7 @@ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
 static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
 
 static struct nand_bbt_descr bbt_main_descr = {
-       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
                | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
        .offs = 8,
        .len = 4,
@@ -1019,7 +1019,7 @@ static struct nand_bbt_descr bbt_main_descr = {
 };
 
 static struct nand_bbt_descr bbt_mirror_descr = {
-       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
                | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
        .offs = 8,
        .len = 4,
@@ -1029,7 +1029,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 };
 
 /**
- * nand_default_bbt - [NAND Interface] Select a default bad block table for the device 
+ * nand_default_bbt - [NAND Interface] Select a default bad block table for the device
  * @mtd:       MTD device structure
  *
  * This function selects the default bad block table
@@ -1039,29 +1039,29 @@ static struct nand_bbt_descr bbt_mirror_descr = {
 int nand_default_bbt (struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       
-       /* Default for AG-AND. We must use a flash based 
+
+       /* Default for AG-AND. We must use a flash based
         * bad block table as the devices have factory marked
         * _good_ blocks. Erasing those blocks leads to loss
         * of the good / bad information, so we _must_ store
-        * this information in a good / bad table during 
+        * this information in a good / bad table during
         * startup
        */
        if (this->options & NAND_IS_AND) {
                /* Use the default pattern descriptors */
-               if (!this->bbt_td) {    
+               if (!this->bbt_td) {
                        this->bbt_td = &bbt_main_descr;
                        this->bbt_md = &bbt_mirror_descr;
-               }       
+               }
                this->options |= NAND_USE_FLASH_BBT;
                return nand_scan_bbt (mtd, &agand_flashbased);
        }
-       
-       
+
+
        /* Is a flash based bad block table requested ? */
        if (this->options & NAND_USE_FLASH_BBT) {
-               /* Use the default pattern descriptors */       
-               if (!this->bbt_td) {    
+               /* Use the default pattern descriptors */
+               if (!this->bbt_td) {
                        this->bbt_td = &bbt_main_descr;
                        this->bbt_md = &bbt_mirror_descr;
                }
@@ -1081,7 +1081,7 @@ int nand_default_bbt (struct mtd_info *mtd)
 }
 
 /**
- * nand_isbad_bbt - [NAND Interface] Check if a block is bad 
+ * nand_isbad_bbt - [NAND Interface] Check if a block is bad
  * @mtd:       MTD device structure
  * @offs:      offset in the device
  * @allowbbt:  allow access to bad block table region
@@ -1092,12 +1092,12 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
        struct nand_chip *this = mtd->priv;
        int block;
        uint8_t res;
-       
+
        /* Get block number * 2 */
        block = (int) (offs >> (this->bbt_erase_shift - 1));
        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", 
+       DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
                (unsigned int)offs, block >> 1, res);
 
        switch ((int)res) {
index 2e341b75437ae2e15fb7b3dc54bb8b578bf5a308..40ac909150a3db5701c572fe536b9e1e6a5c766b 100644 (file)
@@ -7,22 +7,22 @@
  * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
  *                         Toshiba America Electronics Components, Inc.
  *
- * $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $
+ * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $
  *
  * This file 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 or (at your option) any
  * later version.
- * 
+ *
  * This file 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 file; if not, write to the Free Software Foundation, Inc.,
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- * 
+ *
  * As a special exception, if other files instantiate templates or use
  * macros or inline functions from these files, or you compile these
  * files and link them with other works to produce a work based on these
@@ -30,7 +30,7 @@
  * covered by the GNU General Public License. However the source code for
  * these files must still be made available in accordance with section (3)
  * of the GNU General Public License.
- * 
+ *
  * This exception does not invalidate any other reasons why a work based on
  * this file might be covered by the GNU General Public License.
  */
@@ -67,7 +67,7 @@ static const u_char nand_ecc_precalc_table[] = {
  * nand_trans_result - [GENERIC] create non-inverted ECC
  * @reg2:      line parity reg 2
  * @reg3:      line parity reg 3
- * @ecc_code:  ecc 
+ * @ecc_code:  ecc
  *
  * Creates non-inverted ECC code from line parity
  */
@@ -75,11 +75,11 @@ static void nand_trans_result(u_char reg2, u_char reg3,
        u_char *ecc_code)
 {
        u_char a, b, i, tmp1, tmp2;
-       
+
        /* Initialize variables */
        a = b = 0x80;
        tmp1 = tmp2 = 0;
-       
+
        /* Calculate first ECC byte */
        for (i = 0; i < 4; i++) {
                if (reg3 & a)           /* LP15,13,11,9 --> ecc_code[0] */
@@ -90,7 +90,7 @@ static void nand_trans_result(u_char reg2, u_char reg3,
                b >>= 1;
                a >>= 1;
        }
-       
+
        /* Calculate second ECC byte */
        b = 0x80;
        for (i = 0; i < 4; i++) {
@@ -102,7 +102,7 @@ static void nand_trans_result(u_char reg2, u_char reg3,
                b >>= 1;
                a >>= 1;
        }
-       
+
        /* Store two of the ECC bytes */
        ecc_code[0] = tmp1;
        ecc_code[1] = tmp2;
@@ -118,28 +118,28 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code
 {
        u_char idx, reg1, reg2, reg3;
        int j;
-       
+
        /* Initialize variables */
        reg1 = reg2 = reg3 = 0;
        ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
-       
-       /* Build up column parity */ 
+
+       /* Build up column parity */
        for(j = 0; j < 256; j++) {
-               
+
                /* Get CP0 - CP5 from table */
                idx = nand_ecc_precalc_table[dat[j]];
                reg1 ^= (idx & 0x3f);
-               
+
                /* All bit XOR = 1 ? */
                if (idx & 0x40) {
                        reg3 ^= (u_char) j;
                        reg2 ^= ~((u_char) j);
                }
        }
-       
+
        /* Create non-inverted ECC code from line parity */
        nand_trans_result(reg2, reg3, ecc_code);
-       
+
        /* Calculate final ECC code */
        ecc_code[0] = ~ecc_code[0];
        ecc_code[1] = ~ecc_code[1];
@@ -159,12 +159,12 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code
 int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
 {
        u_char a, b, c, d1, d2, d3, add, bit, i;
-       
-       /* Do error detection */ 
+
+       /* Do error detection */
        d1 = calc_ecc[0] ^ read_ecc[0];
        d2 = calc_ecc[1] ^ read_ecc[1];
        d3 = calc_ecc[2] ^ read_ecc[2];
-       
+
        if ((d1 | d2 | d3) == 0) {
                /* No errors */
                return 0;
@@ -173,7 +173,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha
                a = (d1 ^ (d1 >> 1)) & 0x55;
                b = (d2 ^ (d2 >> 1)) & 0x55;
                c = (d3 ^ (d3 >> 1)) & 0x54;
-               
+
                /* Found and will correct single bit error in the data */
                if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
                        c = 0x80;
@@ -237,7 +237,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha
                        }
                }
        }
-       
+
        /* Should never happen */
        return -1;
 }
index efe246961b69fe1d1ee7b490a0108cdd24e95e1c..dbc7e55a4247a215cf1097c1ea289be0d51bd357 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
  *
- * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $
+ * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 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
 #include <linux/mtd/nand.h>
 /*
 *      Chip ID list
-*      
+*
 *      Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
 *      options
-* 
+*
 *      Pagesize; 0, 256, 512
 *      0       get this information from the extended chip ID
 +      256     256 Byte page size
-*      512     512 Byte page size      
+*      512     512 Byte page size
 */
 struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 1MiB 5V 8-bit",          0x6e, 256, 1, 0x1000, 0},
@@ -34,27 +34,27 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 4MiB 3,3V 8-bit",        0xe3, 512, 4, 0x2000, 0},
        {"NAND 4MiB 3,3V 8-bit",        0xe5, 512, 4, 0x2000, 0},
        {"NAND 8MiB 3,3V 8-bit",        0xd6, 512, 8, 0x2000, 0},
-       
+
        {"NAND 8MiB 1,8V 8-bit",        0x39, 512, 8, 0x2000, 0},
        {"NAND 8MiB 3,3V 8-bit",        0xe6, 512, 8, 0x2000, 0},
        {"NAND 8MiB 1,8V 16-bit",       0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
        {"NAND 8MiB 3,3V 16-bit",       0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
-       
+
        {"NAND 16MiB 1,8V 8-bit",       0x33, 512, 16, 0x4000, 0},
        {"NAND 16MiB 3,3V 8-bit",       0x73, 512, 16, 0x4000, 0},
        {"NAND 16MiB 1,8V 16-bit",      0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 16MiB 3,3V 16-bit",      0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
-       
+
        {"NAND 32MiB 1,8V 8-bit",       0x35, 512, 32, 0x4000, 0},
        {"NAND 32MiB 3,3V 8-bit",       0x75, 512, 32, 0x4000, 0},
        {"NAND 32MiB 1,8V 16-bit",      0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 32MiB 3,3V 16-bit",      0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
-       
+
        {"NAND 64MiB 1,8V 8-bit",       0x36, 512, 64, 0x4000, 0},
        {"NAND 64MiB 3,3V 8-bit",       0x76, 512, 64, 0x4000, 0},
        {"NAND 64MiB 1,8V 16-bit",      0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 64MiB 3,3V 16-bit",      0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
-       
+
        {"NAND 128MiB 1,8V 8-bit",      0x78, 512, 128, 0x4000, 0},
        {"NAND 128MiB 1,8V 8-bit",      0x39, 512, 128, 0x4000, 0},
        {"NAND 128MiB 3,3V 8-bit",      0x79, 512, 128, 0x4000, 0},
@@ -62,7 +62,7 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 128MiB 1,8V 16-bit",     0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 128MiB 3,3V 16-bit",     0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
        {"NAND 128MiB 3,3V 16-bit",     0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
-       
+
        {"NAND 256MiB 3,3V 8-bit",      0x71, 512, 256, 0x4000, 0},
 
        /* These are the new chips with large page size. The pagesize
@@ -73,7 +73,7 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 64MiB 3,3V 8-bit",       0xF2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
        {"NAND 64MiB 1,8V 16-bit",      0xB2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
        {"NAND 64MiB 3,3V 16-bit",      0xC2, 0,  64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-       
+
        /* 1 Gigabit */
        {"NAND 128MiB 1,8V 8-bit",      0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
        {"NAND 128MiB 3,3V 8-bit",      0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
@@ -85,13 +85,13 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 256MiB 3,3V 8-bit",      0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
        {"NAND 256MiB 1,8V 16-bit",     0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
        {"NAND 256MiB 3,3V 16-bit",     0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-       
+
        /* 4 Gigabit */
        {"NAND 512MiB 1,8V 8-bit",      0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
        {"NAND 512MiB 3,3V 8-bit",      0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
        {"NAND 512MiB 1,8V 16-bit",     0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
        {"NAND 512MiB 3,3V 16-bit",     0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
-       
+
        /* 8 Gigabit */
        {"NAND 1GiB 1,8V 8-bit",        0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
        {"NAND 1GiB 3,3V 8-bit",        0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
@@ -104,11 +104,11 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"NAND 2GiB 1,8V 16-bit",       0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
        {"NAND 2GiB 3,3V 16-bit",       0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
 
-       /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! 
+       /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout !
         * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes
         * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7
         * 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 
+        * 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 | BBT_AUTO_REFRESH},
 
index 754b6ed7ce140b5470f5c8533ac45b0aedf4030a..de4500395300065d99e3489e4d445947c64b1fed 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
  *
- * Copyright (C) 2004 Nokia Corporation 
+ * Copyright (C) 2004 Nokia Corporation
  *
  * Note: NS means "NAND Simulator".
  * Note: Input means input TO flash chip, output means output FROM chip.
@@ -126,7 +126,7 @@ MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
 
 /* The largest possible page size */
 #define NS_LARGEST_PAGE_SIZE   2048
-       
+
 /* The prefix for simulator output */
 #define NS_OUTPUT_PREFIX "[nandsim]"
 
@@ -145,7 +145,7 @@ MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
         do { if (do_delays) udelay(us); } while(0)
 #define NS_MDELAY(us) \
         do { if (do_delays) mdelay(us); } while(0)
-       
+
 /* Is the nandsim structure initialized ? */
 #define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0)
 
@@ -153,12 +153,12 @@ MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
 #define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0)))
 
 /* Operation failed completion status */
-#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) 
+#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns))
 
 /* Calculate the page offset in flash RAM image by (row, column) address */
 #define NS_RAW_OFFSET(ns) \
        (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column)
-       
+
 /* Calculate the OOB offset in flash RAM image by (row, column) address */
 #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
 
@@ -223,15 +223,15 @@ MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
 
 /* Remove action bits ftom state */
 #define NS_STATE(x) ((x) & ~ACTION_MASK)
-       
-/* 
+
+/*
  * Maximum previous states which need to be saved. Currently saving is
  * only needed for page programm operation with preceeded read command
  * (which is only valid for 512-byte pages).
  */
 #define NS_MAX_PREVSTATES 1
 
-/* 
+/*
  * The structure which describes all the internal simulator data.
  */
 struct nandsim {
@@ -242,7 +242,7 @@ struct nandsim {
        uint32_t options;       /* chip's characteristic bits */
        uint32_t state;         /* current chip state */
        uint32_t nxstate;       /* next expected state */
-       
+
        uint32_t *op;           /* current operation, NULL operations isn't known yet  */
        uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */
        uint16_t npstates;      /* number of previous states saved */
@@ -413,7 +413,7 @@ init_nandsim(struct mtd_info *mtd)
                        ns->geom.secaddrbytes = 3;
                }
        }
-       
+
        /* Detect how many ID bytes the NAND chip outputs */
         for (i = 0; nand_flash_ids[i].name != NULL; i++) {
                 if (second_id_byte != nand_flash_ids[i].id)
@@ -444,7 +444,7 @@ init_nandsim(struct mtd_info *mtd)
 #ifdef CONFIG_NS_ABS_POS
        ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob);
        if (!ns->mem.byte) {
-               NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", 
+               NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n",
                        (void *)CONFIG_NS_ABS_POS);
                return -ENOMEM;
        }
@@ -567,7 +567,7 @@ static int
 check_command(int cmd)
 {
        switch (cmd) {
-               
+
        case NAND_CMD_READ0:
        case NAND_CMD_READSTART:
        case NAND_CMD_PAGEPROG:
@@ -580,7 +580,7 @@ check_command(int cmd)
        case NAND_CMD_RESET:
        case NAND_CMD_READ1:
                return 0;
-               
+
        case NAND_CMD_STATUS_MULTI:
        default:
                return 1;
@@ -631,7 +631,7 @@ static inline void
 accept_addr_byte(struct nandsim *ns, u_char bt)
 {
        uint byte = (uint)bt;
-       
+
        if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes))
                ns->regs.column |= (byte << 8 * ns->regs.count);
        else {
@@ -642,11 +642,11 @@ accept_addr_byte(struct nandsim *ns, u_char bt)
 
        return;
 }
-               
+
 /*
  * Switch to STATE_READY state.
  */
-static inline void 
+static inline void
 switch_to_ready_state(struct nandsim *ns, u_char status)
 {
        NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
@@ -675,7 +675,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
  *      (for example program from the second half and read from the
  *      second half operations both begin with the READ1 command). In this
  *      case the ns->pstates[] array contains previous states.
- * 
+ *
  * Thus, the function tries to find operation containing the following
  * states (if the 'flag' parameter is 0):
  *    ns->pstates[0], ... ns->pstates[ns->npstates], ns->state
@@ -683,7 +683,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
  * If (one and only one) matching operation is found, it is accepted (
  * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is
  * zeroed).
- * 
+ *
  * If there are several maches, the current state is pushed to the
  * ns->pstates.
  *
@@ -692,7 +692,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
  * In such situation the function is called with 'flag' != 0, and the
  * operation is searched using the following pattern:
  *     ns->pstates[0], ... ns->pstates[ns->npstates], <address input>
- * 
+ *
  * It is supposed that this pattern must either match one operation on
  * none. There can't be ambiguity in that case.
  *
@@ -711,15 +711,15 @@ find_operation(struct nandsim *ns, uint32_t flag)
 {
        int opsfound = 0;
        int i, j, idx = 0;
-       
+
        for (i = 0; i < NS_OPER_NUM; i++) {
 
                int found = 1;
-       
+
                if (!(ns->options & ops[i].reqopts))
                        /* Ignore operations we can't perform */
                        continue;
-                       
+
                if (flag) {
                        if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK))
                                continue;
@@ -728,7 +728,7 @@ find_operation(struct nandsim *ns, uint32_t flag)
                                continue;
                }
 
-               for (j = 0; j < ns->npstates; j++) 
+               for (j = 0; j < ns->npstates; j++)
                        if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j])
                                && (ns->options & ops[idx].reqopts)) {
                                found = 0;
@@ -745,7 +745,7 @@ find_operation(struct nandsim *ns, uint32_t flag)
                /* Exact match */
                ns->op = &ops[idx].states[0];
                if (flag) {
-                       /* 
+                       /*
                         * In this case the find_operation function was
                         * called when address has just began input. But it isn't
                         * yet fully input and the current state must
@@ -763,7 +763,7 @@ find_operation(struct nandsim *ns, uint32_t flag)
                                idx, get_state_name(ns->state), get_state_name(ns->nxstate));
                return 0;
        }
-       
+
        if (opsfound == 0) {
                /* Nothing was found. Try to ignore previous commands (if any) and search again */
                if (ns->npstates != 0) {
@@ -777,13 +777,13 @@ find_operation(struct nandsim *ns, uint32_t flag)
                switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
                return -2;
        }
-       
+
        if (flag) {
                /* This shouldn't happen */
                NS_DBG("find_operation: BUG, operation must be known if address is input\n");
                return -2;
        }
-       
+
        NS_DBG("find_operation: there is still ambiguity\n");
 
        ns->pstates[ns->npstates++] = ns->state;
@@ -803,7 +803,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
        int busdiv = ns->busw == 8 ? 1 : 2;
 
        action &= ACTION_MASK;
-       
+
        /* Check that page address input is correct */
        if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) {
                NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row);
@@ -827,14 +827,14 @@ do_state_action(struct nandsim *ns, uint32_t action)
 
                NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
                        num, NS_RAW_OFFSET(ns) + ns->regs.off);
-               
+
                if (ns->regs.off == 0)
                        NS_LOG("read page %d\n", ns->regs.row);
                else if (ns->regs.off < ns->geom.pgsz)
                        NS_LOG("read page %d (second half)\n", ns->regs.row);
                else
                        NS_LOG("read OOB of page %d\n", ns->regs.row);
-               
+
                NS_UDELAY(access_delay);
                NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv);
 
@@ -844,30 +844,30 @@ do_state_action(struct nandsim *ns, uint32_t action)
                /*
                 * Erase sector.
                 */
-               
+
                if (ns->lines.wp) {
                        NS_ERR("do_state_action: device is write-protected, ignore sector erase\n");
                        return -1;
                }
-               
+
                if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec
                        || (ns->regs.row & ~(ns->geom.secsz - 1))) {
                        NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row);
                        return -1;
                }
-               
+
                ns->regs.row = (ns->regs.row <<
                                8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column;
                ns->regs.column = 0;
-               
+
                NS_DBG("do_state_action: erase sector at address %#x, off = %d\n",
                                ns->regs.row, NS_RAW_OFFSET(ns));
                NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
 
                memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob);
-               
+
                NS_MDELAY(erase_delay);
-               
+
                break;
 
        case ACTION_PRGPAGE:
@@ -893,12 +893,12 @@ do_state_action(struct nandsim *ns, uint32_t action)
                NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
                        num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
                NS_LOG("programm page %d\n", ns->regs.row);
-               
+
                NS_UDELAY(programm_delay);
                NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv);
-               
+
                break;
-       
+
        case ACTION_ZEROOFF:
                NS_DBG("do_state_action: set internal offset to 0\n");
                ns->regs.off = 0;
@@ -918,7 +918,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
                NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz);
                ns->regs.off = ns->geom.pgsz;
                break;
-               
+
        default:
                NS_DBG("do_state_action: BUG! unknown action\n");
        }
@@ -937,7 +937,7 @@ switch_state(struct nandsim *ns)
                 * The current operation have already been identified.
                 * Just follow the states chain.
                 */
-               
+
                ns->stateidx += 1;
                ns->state = ns->nxstate;
                ns->nxstate = ns->op[ns->stateidx + 1];
@@ -951,14 +951,14 @@ switch_state(struct nandsim *ns)
                        switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
                        return;
                }
-               
+
        } else {
                /*
                 * We don't yet know which operation we perform.
                 * Try to identify it.
                 */
 
-               /*  
+               /*
                 *  The only event causing the switch_state function to
                 *  be called with yet unknown operation is new command.
                 */
@@ -987,7 +987,7 @@ switch_state(struct nandsim *ns)
                 */
 
                u_char status = NS_STATUS_OK(ns);
-               
+
                /* In case of data states, see if all bytes were input/output */
                if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK))
                        && ns->regs.count != ns->regs.num) {
@@ -995,17 +995,17 @@ switch_state(struct nandsim *ns)
                                        ns->regs.num - ns->regs.count);
                        status = NS_STATUS_FAILED(ns);
                }
-                               
+
                NS_DBG("switch_state: operation complete, switch to STATE_READY state\n");
 
                switch_to_ready_state(ns, status);
 
                return;
        } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) {
-               /* 
+               /*
                 * If the next state is data input/output, switch to it now
                 */
-               
+
                ns->state      = ns->nxstate;
                ns->nxstate    = ns->op[++ns->stateidx + 1];
                ns->regs.num   = ns->regs.count = 0;
@@ -1023,16 +1023,16 @@ switch_state(struct nandsim *ns)
                        case STATE_DATAOUT:
                                ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
                                break;
-                               
+
                        case STATE_DATAOUT_ID:
                                ns->regs.num = ns->geom.idbytes;
                                break;
-                               
+
                        case STATE_DATAOUT_STATUS:
                        case STATE_DATAOUT_STATUS_M:
                                ns->regs.count = ns->regs.num = 0;
                                break;
-                               
+
                        default:
                                NS_ERR("switch_state: BUG! unknown data state\n");
                }
@@ -1044,16 +1044,16 @@ switch_state(struct nandsim *ns)
                 */
 
                ns->regs.count = 0;
-               
+
                switch (NS_STATE(ns->nxstate)) {
                        case STATE_ADDR_PAGE:
                                ns->regs.num = ns->geom.pgaddrbytes;
-               
+
                                break;
                        case STATE_ADDR_SEC:
                                ns->regs.num = ns->geom.secaddrbytes;
                                break;
-       
+
                        case STATE_ADDR_ZERO:
                                ns->regs.num = 1;
                                break;
@@ -1062,7 +1062,7 @@ switch_state(struct nandsim *ns)
                                NS_ERR("switch_state: BUG! unknown address state\n");
                }
        } else {
-               /* 
+               /*
                 * Just reset internal counters.
                 */
 
@@ -1184,7 +1184,7 @@ ns_nand_read_byte(struct mtd_info *mtd)
                default:
                        BUG();
        }
-       
+
        if (ns->regs.count == ns->regs.num) {
                NS_DBG("read_byte: all bytes were read\n");
 
@@ -1201,9 +1201,9 @@ ns_nand_read_byte(struct mtd_info *mtd)
                }
                else if (NS_STATE(ns->nxstate) == STATE_READY)
                        switch_state(ns);
-               
+
        }
-       
+
        return outb;
 }
 
@@ -1211,7 +1211,7 @@ static void
 ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 {
         struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
-       
+
        /* Sanity and correctness checks */
        if (!ns->lines.ce) {
                NS_ERR("write_byte: chip is disabled, ignore write\n");
@@ -1221,7 +1221,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
                NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n");
                return;
        }
-                       
+
        if (ns->lines.cle == 1) {
                /*
                 * The byte written is a command.
@@ -1233,7 +1233,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
                        return;
                }
 
-               /* 
+               /*
                 * Chip might still be in STATE_DATAOUT
                 * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or
                 * STATE_DATAOUT_STATUS_M state. If so, switch state.
@@ -1254,13 +1254,13 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
                                "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate));
                        switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
                }
-               
+
                /* Check that the command byte is correct */
                if (check_command(byte)) {
                        NS_ERR("write_byte: unknown command %#x\n", (uint)byte);
                        return;
                }
-               
+
                NS_DBG("command byte corresponding to %s state accepted\n",
                        get_state_name(get_state_by_command(byte)));
                ns->regs.command = byte;
@@ -1277,12 +1277,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
 
                        if (find_operation(ns, 1) < 0)
                                return;
-                       
+
                        if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
                                switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
                                return;
                        }
-                               
+
                        ns->regs.count = 0;
                        switch (NS_STATE(ns->nxstate)) {
                                case STATE_ADDR_PAGE:
@@ -1306,7 +1306,7 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
                        switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
                        return;
                }
-               
+
                /* Check if this is expected byte */
                if (ns->regs.count == ns->regs.num) {
                        NS_ERR("write_byte: no more address bytes expected\n");
@@ -1325,12 +1325,12 @@ ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
                        NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column);
                        switch_state(ns);
                }
-               
+
        } else {
                /*
                 * The byte written is an input data.
                 */
-               
+
                /* Check that chip is expecting data input */
                if (!(ns->state & STATE_DATAIN_MASK)) {
                        NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, "
@@ -1372,7 +1372,7 @@ ns_nand_read_word(struct mtd_info *mtd)
        struct nand_chip *chip = (struct nand_chip *)mtd->priv;
 
        NS_DBG("read_word\n");
-       
+
        return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
 }
 
@@ -1380,14 +1380,14 @@ static void
 ns_nand_write_word(struct mtd_info *mtd, uint16_t word)
 {
        struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-       
+
        NS_DBG("write_word\n");
-       
+
        chip->write_byte(mtd, word & 0xFF);
        chip->write_byte(mtd, word >> 8);
 }
 
-static void 
+static void
 ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
         struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
@@ -1409,13 +1409,13 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
 
        memcpy(ns->buf.byte + ns->regs.count, buf, len);
        ns->regs.count += len;
-       
+
        if (ns->regs.count == ns->regs.num) {
                NS_DBG("write_buf: %d bytes were written\n", ns->regs.count);
        }
 }
 
-static void 
+static void
 ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 {
         struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
@@ -1453,7 +1453,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
 
        memcpy(buf, ns->buf.byte + ns->regs.count, len);
        ns->regs.count += len;
-       
+
        if (ns->regs.count == ns->regs.num) {
                if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
                        ns->regs.count = 0;
@@ -1465,11 +1465,11 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
                else if (NS_STATE(ns->nxstate) == STATE_READY)
                        switch_state(ns);
        }
-       
+
        return;
 }
 
-static int 
+static int
 ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
 {
        ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len);
@@ -1496,7 +1496,7 @@ int __init ns_init_module(void)
                NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width);
                return -EINVAL;
        }
-       
+
        /* Allocate and initialize mtd_info, nand_chip and nandsim structures */
        nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
                                + sizeof(struct nandsim), GFP_KERNEL);
@@ -1509,7 +1509,7 @@ int __init ns_init_module(void)
        chip        = (struct nand_chip *)(nsmtd + 1);
         nsmtd->priv = (void *)chip;
        nand        = (struct nandsim *)(chip + 1);
-       chip->priv  = (void *)nand;     
+       chip->priv  = (void *)nand;
 
        /*
         * Register simulator's callbacks.
@@ -1526,9 +1526,9 @@ int __init ns_init_module(void)
        chip->eccmode    = NAND_ECC_SOFT;
        chip->options   |= NAND_SKIP_BBTSCAN;
 
-       /* 
+       /*
         * Perform minimum nandsim structure initialization to handle
-        * the initial ID read command correctly 
+        * the initial ID read command correctly
         */
        if (third_id_byte != 0xFF || fourth_id_byte != 0xFF)
                nand->geom.idbytes = 4;
@@ -1557,7 +1557,7 @@ int __init ns_init_module(void)
                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;
index e510a83d7bdbc24768185fd2668e93ddf16e6a5a..91a95f34a6eed2c6763ec849cadcb490e6a0e21d 100644 (file)
@@ -6,7 +6,7 @@
  *  Derived from drivers/mtd/nand/edb7312.c
  *
  *
- * $Id: ppchameleonevb.c,v 1.6 2004/11/05 16:07:16 kalev Exp $
+ * $Id: ppchameleonevb.c,v 1.7 2005/11/07 11:14:31 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
@@ -338,7 +338,7 @@ nand_evb_init:
        out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0);
        out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF);
        /* enable output driver */
-       out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | 
+       out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN |
                 NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
 #ifdef USE_READY_BUSY_PIN
        /* three-state select */
@@ -402,7 +402,7 @@ static void __exit ppchameleonevb_cleanup (void)
        /* Release resources, unregister device(s) */
        nand_release (ppchameleon_mtd);
        nand_release (ppchameleonevb_mtd);
-       
+
        /* Release iomaps */
        this = (struct nand_chip *) &ppchameleon_mtd[1];
        iounmap((void *) this->IO_ADDR_R;
index 031051cbde7637589a224f14f618485fcb688040..3a5841c9d950edd00f05b21767fa15bf23edec03 100644 (file)
@@ -2,11 +2,11 @@
  *  drivers/mtd/nand/rtc_from4.c
  *
  *  Copyright (C) 2004  Red Hat, Inc.
- * 
+ *
  *  Derived from drivers/mtd/nand/spia.c
  *       Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *
- * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $
+ * $Id: rtc_from4.c,v 1.10 2005/11/07 11:14:31 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
@@ -14,8 +14,8 @@
  *
  * Overview:
  *   This is a device driver for the AG-AND flash device found on the
- *   Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), 
- *   which utilizes the Renesas HN29V1G91T-30 part. 
+ *   Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4),
+ *   which utilizes the Renesas HN29V1G91T-30 part.
  *   This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device.
  */
 
@@ -105,9 +105,9 @@ const static struct mtd_partition partition_info[] = {
 };
 #define NUM_PARTITIONS 1
 
-/* 
+/*
  *     hardware specific flash bbt decriptors
- *     Note: this is to allow debugging by disabling 
+ *     Note: this is to allow debugging by disabling
  *             NAND_BBT_CREATE and/or NAND_BBT_WRITE
  *
  */
@@ -141,7 +141,7 @@ static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = {
 /* the Reed Solomon control structure */
 static struct rs_control *rs_decoder;
 
-/* 
+/*
  *      hardware specific Out Of Band information
  */
 static struct nand_oobinfo rtc_from4_nand_oobinfo = {
@@ -200,38 +200,38 @@ static uint8_t revbits[256] = {
 
 
 
-/* 
+/*
  * rtc_from4_hwcontrol - hardware specific access to control-lines
  * @mtd:       MTD device structure
  * @cmd:       hardware control command
  *
- * Address lines (A5 and A4) are used to control Command and Address Latch 
+ * Address lines (A5 and A4) are used to control Command and Address Latch
  * Enable on this board, so set the read/write address appropriately.
  *
- * Chip Enable is also controlled by the Chip Select (CS5) and 
+ * Chip Enable is also controlled by the Chip Select (CS5) and
  * Address lines (A24-A22), so no action is required here.
  *
  */
 static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd)
 {
        struct nand_chip* this = (struct nand_chip *) (mtd->priv);
-       
+
        switch(cmd) {
-               
-       case NAND_CTL_SETCLE: 
+
+       case NAND_CTL_SETCLE:
                this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_CLE);
                break;
-       case NAND_CTL_CLRCLE: 
+       case NAND_CTL_CLRCLE:
                this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_CLE);
                break;
-               
+
        case NAND_CTL_SETALE:
                this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W | RTC_FROM4_ALE);
                break;
        case NAND_CTL_CLRALE:
                this->IO_ADDR_W = (void __iomem *)((unsigned long)this->IO_ADDR_W & ~RTC_FROM4_ALE);
                break;
-               
+
        case NAND_CTL_SETNCE:
                break;
        case NAND_CTL_CLRNCE:
@@ -296,7 +296,7 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
  * @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 
+ * 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.
@@ -312,7 +312,7 @@ static void deplete(struct mtd_info *mtd, int chip)
         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);
@@ -330,7 +330,7 @@ static void deplete(struct mtd_info *mtd, int chip)
  * @mtd:       MTD device structure
  * @mode:      I/O mode; read or write
  *
- * enable hardware ECC for data read or write 
+ * enable hardware ECC for data read or write
  *
  */
 static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
@@ -340,7 +340,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
 
        switch (mode) {
            case NAND_ECC_READ :
-               status =  RTC_FROM4_RS_ECC_CTL_CLR 
+               status =  RTC_FROM4_RS_ECC_CTL_CLR
                        | RTC_FROM4_RS_ECC_CTL_FD_E;
 
                *rs_ecc_ctl = status;
@@ -353,8 +353,8 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
                break;
 
            case NAND_ECC_WRITE :
-               status =  RTC_FROM4_RS_ECC_CTL_CLR 
-                       | RTC_FROM4_RS_ECC_CTL_GEN 
+               status =  RTC_FROM4_RS_ECC_CTL_CLR
+                       | RTC_FROM4_RS_ECC_CTL_GEN
                        | RTC_FROM4_RS_ECC_CTL_FD_E;
 
                *rs_ecc_ctl = status;
@@ -411,7 +411,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
 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; 
+       unsigned short status;
        uint16_t par[6], syn[6];
        uint8_t ecc[8];
         volatile unsigned short *rs_ecc;
@@ -430,7 +430,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
         }
 
        /* convert into 6 10bit syndrome fields */
-       par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) | 
+       par[5] = rs_decoder->index_of[(((uint16_t)ecc[0] >> 0) & 0x0ff) |
                                      (((uint16_t)ecc[1] << 8) & 0x300)];
        par[4] = rs_decoder->index_of[(((uint16_t)ecc[1] >> 2) & 0x03f) |
                                      (((uint16_t)ecc[2] << 6) & 0x3c0)];
@@ -456,7 +456,7 @@ 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, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
        if (res > 0) {
-               DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " 
+               DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: "
                        "ECC corrected %d errors on read\n", res);
        }
        return res;
@@ -470,9 +470,9 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
  * @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 
+ *
+ * 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.
@@ -633,7 +633,7 @@ int __init rtc_from4_init (void)
 
 #ifdef RTC_FROM4_HWECC
        /* We could create the decoder on demand, if memory is a concern.
-        * This way we have it handy, if an error happens 
+        * This way we have it handy, if an error happens
         *
         * Symbolsize is 10 (bits)
         * Primitve polynomial is x^10+x^3+1
index 2df5e47d1f5ce2ec7c16a9ab6018d7e4be6c1eff..97e9b7892d29dfce8f5eab6f724b85f9740940ed 100644 (file)
@@ -17,8 +17,9 @@
  *     02-May-2005  BJD  Reduced hwcontrol decode
  *     20-Jun-2005  BJD  Updated s3c2440 support, fixed timing bug
  *     08-Jul-2005  BJD  Fix OOPS when no platform data supplied
+ *     20-Oct-2005  BJD  Fix timing calculation bug
  *
- * $Id: s3c2410.c,v 1.14 2005/07/06 20:05:06 bjd Exp $
+ * $Id: s3c2410.c,v 1.20 2005/11/07 11:14:31 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
@@ -136,13 +137,13 @@ static struct s3c2410_platform_nand *to_nand_plat(struct device *dev)
 
 /* timing calculations */
 
-#define NS_IN_KHZ 10000000
+#define NS_IN_KHZ 1000000
 
 static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
 {
        int result;
 
-       result = (wanted * NS_IN_KHZ) / clk;
+       result = (wanted * clk) / NS_IN_KHZ;
        result++;
 
        pr_debug("result %d from %ld, %d\n", result, clk, wanted);
@@ -159,20 +160,22 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
        return result;
 }
 
-#define to_ns(ticks,clk) (((clk) * (ticks)) / NS_IN_KHZ)
+#define to_ns(ticks,clk) (((ticks) * NS_IN_KHZ) / (unsigned int)(clk))
 
 /* controller setup */
 
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, 
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
                               struct device *dev)
 {
        struct s3c2410_platform_nand *plat = to_nand_plat(dev);
-       unsigned int tacls, twrph0, twrph1;
        unsigned long clkrate = clk_get_rate(info->clk);
+       int tacls, twrph0, twrph1;
        unsigned long cfg;
 
        /* calculate the timing information for the controller */
 
+       clkrate /= 1000;        /* turn clock into kHz for ease of use */
+
        if (plat != NULL) {
                tacls  = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
                twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
@@ -183,16 +186,16 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
                twrph0 = 8;
                twrph1 = 8;
        }
-       
+
        if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
                printk(KERN_ERR PFX "cannot get timings suitable for board\n");
                return -EINVAL;
        }
 
-       printk(KERN_INFO PFX "timing: Tacls %ldns, Twrph0 %ldns, Twrph1 %ldns\n",
-              to_ns(tacls, clkrate),
-              to_ns(twrph0, clkrate),
-              to_ns(twrph1, clkrate));
+       printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
+              tacls, to_ns(tacls, clkrate),
+              twrph0, to_ns(twrph0, clkrate),
+              twrph1, to_ns(twrph1, clkrate));
 
        if (!info->is_s3c2440) {
                cfg  = S3C2410_NFCONF_EN;
@@ -216,7 +219,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
 static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
 {
        struct s3c2410_nand_info *info;
-       struct s3c2410_nand_mtd *nmtd; 
+       struct s3c2410_nand_mtd *nmtd;
        struct nand_chip *this = mtd->priv;
        void __iomem *reg;
        unsigned long cur;
@@ -249,7 +252,7 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
        writel(cur, reg);
 }
 
-/* command and control functions 
+/* command and control functions
  *
  * Note, these all use tglx's method of changing the IO_ADDR_W field
  * to make the code simpler, and use the nand layer's code to issue the
@@ -321,7 +324,7 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
 static int s3c2410_nand_devready(struct mtd_info *mtd)
 {
        struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-       
+
        if (info->is_s3c2440)
                return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
        return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
@@ -342,7 +345,7 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
 
        if (read_ecc[0] == calc_ecc[0] &&
            read_ecc[1] == calc_ecc[1] &&
-           read_ecc[2] == calc_ecc[2]) 
+           read_ecc[2] == calc_ecc[2])
                return 0;
 
        /* we curently have no method for correcting the error */
@@ -433,14 +436,14 @@ static int s3c2410_nand_remove(struct device *dev)
 
        dev_set_drvdata(dev, NULL);
 
-       if (info == NULL) 
+       if (info == NULL)
                return 0;
 
        /* first thing we need to do is release all our mtds
         * and their partitions, then go through freeing the
-        * resources used 
+        * resources used
         */
-       
+
        if (info->mtds != NULL) {
                struct s3c2410_nand_mtd *ptr = info->mtds;
                int mtdno;
@@ -504,7 +507,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info,
 
 /* s3c2410_nand_init_chip
  *
- * init a single instance of an chip 
+ * init a single instance of an chip
 */
 
 static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
@@ -576,7 +579,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
 
        info = kmalloc(sizeof(*info), GFP_KERNEL);
        if (info == NULL) {
-               printk(KERN_ERR PFX "no memory for flash info\n");
+               dev_err(dev, "no memory for flash info\n");
                err = -ENOMEM;
                goto exit_error;
        }
@@ -591,7 +594,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
 
        info->clk = clk_get(dev, "nand");
        if (IS_ERR(info->clk)) {
-               printk(KERN_ERR PFX "failed to get clock");
+               dev_err(dev, "failed to get clock");
                err = -ENOENT;
                goto exit_error;
        }
@@ -608,7 +611,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
        info->area = request_mem_region(res->start, size, pdev->name);
 
        if (info->area == NULL) {
-               printk(KERN_ERR PFX "cannot reserve register region\n");
+               dev_err(dev, "cannot reserve register region\n");
                err = -ENOENT;
                goto exit_error;
        }
@@ -619,12 +622,12 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
        info->is_s3c2440 = is_s3c2440;
 
        if (info->regs == NULL) {
-               printk(KERN_ERR PFX "cannot reserve register region\n");
+               dev_err(dev, "cannot reserve register region\n");
                err = -EIO;
                goto exit_error;
-       }               
+       }
 
-       printk(KERN_INFO PFX "mapped registers at %p\n", info->regs);
+       dev_dbg(dev, "mapped registers at %p\n", info->regs);
 
        /* initialise the hardware */
 
@@ -642,7 +645,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
        size = nr_sets * sizeof(*info->mtds);
        info->mtds = kmalloc(size, GFP_KERNEL);
        if (info->mtds == NULL) {
-               printk(KERN_ERR PFX "failed to allocate mtd storage\n");
+               dev_err(dev, "failed to allocate mtd storage\n");
                err = -ENOMEM;
                goto exit_error;
        }
@@ -656,7 +659,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
        for (setno = 0; setno < nr_sets; setno++, nmtd++) {
                pr_debug("initialising set %d (%p, info %p)\n",
                         setno, nmtd, info);
-               
+
                s3c2410_nand_init_chip(info, nmtd, sets);
 
                nmtd->scan_res = nand_scan(&nmtd->mtd,
@@ -669,7 +672,7 @@ static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
                if (sets != NULL)
                        sets++;
        }
-       
+
        pr_debug("initialised ok\n");
        return 0;
 
@@ -695,6 +698,7 @@ static int s3c2440_nand_probe(struct device *dev)
 
 static struct device_driver s3c2410_nand_driver = {
        .name           = "s3c2410-nand",
+       .owner          = THIS_MODULE,
        .bus            = &platform_bus_type,
        .probe          = s3c2410_nand_probe,
        .remove         = s3c2410_nand_remove,
@@ -702,6 +706,7 @@ static struct device_driver s3c2410_nand_driver = {
 
 static struct device_driver s3c2440_nand_driver = {
        .name           = "s3c2440-nand",
+       .owner          = THIS_MODULE,
        .bus            = &platform_bus_type,
        .probe          = s3c2440_nand_probe,
        .remove         = s3c2410_nand_remove,
index 88b5b5b40b43aa07fed88f2b56edfb1b1b9cdab2..1924a4f137c79eed315673de214224d225e78e70 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2004 Richard Purdie
  *
- *  $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $
+ *  $Id: sharpsl.c,v 1.7 2005/11/07 11:14:31 gleixner Exp $
  *
  *  Based on Sharp's NAND driver sharp_sl.c
  *
@@ -76,14 +76,14 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = {
        },
 };
 
-/* 
+/*
  *     hardware specific access to control-lines
  */
 static void
 sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
 {
        switch (cmd) {
-       case NAND_CTL_SETCLE: 
+       case NAND_CTL_SETCLE:
                writeb(readb(FLASHCTL) | FLCLE, FLASHCTL);
                break;
        case NAND_CTL_CLRCLE:
@@ -97,10 +97,10 @@ sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
                writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL);
                break;
 
-       case NAND_CTL_SETNCE: 
+       case NAND_CTL_SETNCE:
                writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL);
                break;
-       case NAND_CTL_CLRNCE: 
+       case NAND_CTL_CLRNCE:
                writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL);
                break;
        }
@@ -115,6 +115,23 @@ static struct nand_bbt_descr sharpsl_bbt = {
        .pattern = scan_ff_pattern
 };
 
+static struct nand_bbt_descr sharpsl_akita_bbt = {
+       .options = 0,
+       .offs = 4,
+       .len = 1,
+       .pattern = scan_ff_pattern
+};
+
+static struct nand_oobinfo akita_oobinfo = {
+       .useecc = MTD_NANDECC_AUTOPLACE,
+       .eccbytes = 24,
+       .eccpos = {
+               0x5,  0x1,  0x2,  0x3,  0x6,  0x7,  0x15, 0x11,
+               0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23,
+               0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37},
+       .oobfree = { {0x08, 0x09} }
+};
+
 static int
 sharpsl_nand_dev_ready(struct mtd_info* mtd)
 {
@@ -160,7 +177,7 @@ sharpsl_nand_init(void)
                printk ("Unable to allocate SharpSL NAND MTD device structure.\n");
                return -ENOMEM;
        }
-       
+
        /* map physical adress */
        sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
        if(!sharpsl_io_base){
@@ -168,7 +185,7 @@ sharpsl_nand_init(void)
                kfree(sharpsl_mtd);
                return -EIO;
        }
-       
+
        /* Get pointer to private data */
        this = (struct nand_chip *) (&sharpsl_mtd[1]);
 
@@ -194,10 +211,14 @@ sharpsl_nand_init(void)
        this->chip_delay = 15;
        /* set eccmode using hardware ECC */
        this->eccmode = NAND_ECC_HW3_256;
+       this->badblock_pattern = &sharpsl_bbt;
+       if (machine_is_akita() || machine_is_borzoi()) {
+               this->badblock_pattern = &sharpsl_akita_bbt;
+               this->autooob = &akita_oobinfo;
+       }
        this->enable_hwecc = sharpsl_nand_enable_hwecc;
        this->calculate_ecc = sharpsl_nand_calculate_ecc;
        this->correct_data = nand_correct_data;
-       this->badblock_pattern = &sharpsl_bbt;
 
        /* Scan to find existence of the device */
        err=nand_scan(sharpsl_mtd,1);
@@ -211,7 +232,7 @@ sharpsl_nand_init(void)
        sharpsl_mtd->name = "sharpsl-nand";
        nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes,
                                                &sharpsl_partition_info, 0);
-                                                
+
        if (nr_partitions <= 0) {
                nr_partitions = DEFAULT_NUM_PARTITIONS;
                sharpsl_partition_info = sharpsl_nand_default_partition_info;
@@ -230,7 +251,7 @@ sharpsl_nand_init(void)
                }
        }
 
-       if (machine_is_husky() || machine_is_borzoi()) {
+       if (machine_is_husky() || machine_is_borzoi() || machine_is_akita()) {
                /* Need to use small eraseblock size for backward compatibility */
                sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS;
        }
index b777c412b75835e7ebbb08bef2e7e681d031ebcc..32541cbb0103284669c6fc91c62aa58501132e2f 100644 (file)
@@ -8,7 +8,7 @@
  *                     to controllines (due to change in nand.c)
  *                     page_cache added
  *
- * $Id: spia.c,v 1.24 2004/11/04 12:53:10 gleixner Exp $
+ * $Id: spia.c,v 1.25 2005/11/07 11:14:31 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
@@ -82,7 +82,7 @@ const static struct mtd_partition partition_info[] = {
 #define NUM_PARTITIONS 2
 
 
-/* 
+/*
  *     hardware specific access to control-lines
 */
 static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
@@ -137,7 +137,7 @@ int __init spia_init (void)
        /* Set address of hardware control function */
        this->hwcontrol = spia_hwcontrol;
        /* 15 us command delay time */
-       this->chip_delay = 15;          
+       this->chip_delay = 15;
 
        /* Scan to find existence of the device */
        if (nand_scan (spia_mtd, 1)) {
index 52c808fb5fa93165038f59a4c399136899134789..7609c43cb3ec759baf4b24d5728b34d9dbe64a03 100644 (file)
@@ -15,7 +15,7 @@
  *   This is a device driver for the NAND flash device found on the
  *   TI fido board. It supports 32MiB and 64MiB cards
  *
- * $Id: toto.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $
+ * $Id: toto.c,v 1.5 2005/11/07 11:14:31 gleixner Exp $
  */
 
 #include <linux/slab.h>
@@ -57,7 +57,7 @@ static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
 #endif
 #define T_NAND_CTL_SETNCE(iob)  gpiosetout(NAND_NCE, 0)
 #define T_NAND_CTL_CLRNCE(iob)  gpiosetout(NAND_NCE, NAND_NCE)
-                
+
 /*
  * Define partitions for flash devices
  */
@@ -91,7 +91,7 @@ static struct mtd_partition partition_info32M[] = {
 
 #define NUM_PARTITIONS32M 3
 #define NUM_PARTITIONS64M 4
-/* 
+/*
  *     hardware specific access to control-lines
 */
 
@@ -146,7 +146,7 @@ int __init toto_init (void)
        this->hwcontrol = toto_hwcontrol;
        this->dev_ready = NULL;
        /* 25 us command delay time */
-       this->chip_delay = 30;          
+       this->chip_delay = 30;
        this->eccmode = NAND_ECC_SOFT;
 
         /* Scan to find existance of the device */
@@ -157,10 +157,10 @@ int __init toto_init (void)
 
        /* Register the partitions */
        switch(toto_mtd->size){
-               case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; 
-               case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; 
+               case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break;
+               case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break;
                default: {
-                       printk (KERN_WARNING "Unsupported Nand device\n"); 
+                       printk (KERN_WARNING "Unsupported Nand device\n");
                        err = -ENXIO;
                        goto out_buf;
                }
@@ -170,9 +170,9 @@ int __init toto_init (void)
        archflashwp(0,0);        /* open up flash for writing */
 
        goto out;
-    
+
 out_buf:
-       kfree (this->data_buf);    
+       kfree (this->data_buf);
 out_mtd:
        kfree (toto_mtd);
 out:
@@ -194,7 +194,7 @@ static void __exit toto_cleanup (void)
 
        /* stop flash writes */
         archflashwp(0,1);
-       
+
        /* release gpios to system */
         gpiorelease(NAND_MASK);
 }
index 062ff3877536066e04a56bdd2bac8d0a3b0829ff..d7cd5fa16ba445e8d854760de615e7ec15821949 100644 (file)
@@ -1,7 +1,7 @@
 /* Linux driver for NAND Flash Translation Layer      */
 /* (c) 1999 Machine Vision Holdings, Inc.             */
 /* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftlcore.c,v 1.97 2004/11/16 18:28:59 dwmw2 Exp $ */
+/* $Id: nftlcore.c,v 1.98 2005/11/07 11:14:21 gleixner Exp $ */
 
 /*
   The contents of this file are distributed under the GNU General
@@ -101,14 +101,14 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 
        if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
                /*
-                 Oh no we don't have 
+                 Oh no we don't have
                   mbd.size == heads * cylinders * sectors
                */
                printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
                       "match size of 0x%lx.\n", nftl->mbd.size);
                printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
                        "(== 0x%lx sects)\n",
-                       nftl->cylinders, nftl->heads , nftl->sectors, 
+                       nftl->cylinders, nftl->heads , nftl->sectors,
                        (long)nftl->cylinders * (long)nftl->heads *
                        (long)nftl->sectors );
        }
@@ -174,7 +174,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
 
                if (!silly--) {
                        printk("Argh! No free blocks found! LastFreeEUN = %d, "
-                              "FirstEUN = %d\n", nftl->LastFreeEUN, 
+                              "FirstEUN = %d\n", nftl->LastFreeEUN,
                               le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
                        return 0xffff;
                }
@@ -206,7 +206,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                       "Virtual Unit Chain %d!\n", thisVUC);
                return BLOCK_NIL;
        }
-       
+
        /* Scan to find the Erase Unit which holds the actual data for each
           512-byte block within the Chain.
        */
@@ -223,7 +223,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                        if (block == 2) {
                                 foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
                                 if (foldmark == FOLD_MARK_IN_PROGRESS) {
-                                        DEBUG(MTD_DEBUG_LEVEL1, 
+                                        DEBUG(MTD_DEBUG_LEVEL1,
                                               "Write Inhibited on EUN %d\n", thisEUN);
                                        inplace = 0;
                                } else {
@@ -245,7 +245,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                                if (!BlockFreeFound[block])
                                        BlockMap[block] = thisEUN;
                                else
-                                       printk(KERN_WARNING 
+                                       printk(KERN_WARNING
                                               "SECTOR_USED found after SECTOR_FREE "
                                               "in Virtual Unit Chain %d for block %d\n",
                                               thisVUC, block);
@@ -254,7 +254,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                                if (!BlockFreeFound[block])
                                        BlockMap[block] = BLOCK_NIL;
                                else
-                                       printk(KERN_WARNING 
+                                       printk(KERN_WARNING
                                               "SECTOR_DELETED found after SECTOR_FREE "
                                               "in Virtual Unit Chain %d for block %d\n",
                                               thisVUC, block);
@@ -273,14 +273,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                               thisVUC);
                        return BLOCK_NIL;
                }
-               
+
                thisEUN = nftl->ReplUnitTable[thisEUN];
        }
 
        if (inplace) {
                /* We're being asked to be a fold-in-place. Check
                   that all blocks which actually have data associated
-                  with them (i.e. BlockMap[block] != BLOCK_NIL) are 
+                  with them (i.e. BlockMap[block] != BLOCK_NIL) are
                   either already present or SECTOR_FREE in the target
                   block. If not, we're going to have to fold out-of-place
                   anyway.
@@ -293,7 +293,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                                      "block %d was %x lastEUN, "
                                      "and is in EUN %d (%s) %d\n",
                                      thisVUC, block, BlockLastState[block],
-                                     BlockMap[block], 
+                                     BlockMap[block],
                                      BlockMap[block]== targetEUN ? "==" : "!=",
                                      targetEUN);
                                inplace = 0;
@@ -310,17 +310,17 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                        inplace = 0;
                }
        }
-       
+
        if (!inplace) {
                DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
                      "Trying out-of-place\n", thisVUC);
                /* We need to find a targetEUN to fold into. */
                targetEUN = NFTL_findfreeblock(nftl, 1);
                if (targetEUN == BLOCK_NIL) {
-                       /* Ouch. Now we're screwed. We need to do a 
+                       /* Ouch. Now we're screwed. We need to do a
                           fold-in-place of another chain to make room
                           for this one. We need a better way of selecting
-                          which chain to fold, because makefreeblock will 
+                          which chain to fold, because makefreeblock will
                           only ask us to fold the same one again.
                        */
                        printk(KERN_WARNING
@@ -334,7 +334,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                chain by selecting the longer one */
             oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
             oob.u.c.unused = 0xffffffff;
-            MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 
+            MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
                          8, &retlen, (char *)&oob.u);
         }
 
@@ -357,14 +357,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                    happen in case of media errors or deleted blocks) */
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
-                
+
                 ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
-                                 512, &retlen, movebuf); 
+                                 512, &retlen, movebuf);
                 if (ret < 0) {
                     ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
                                       + (block * 512), 512, &retlen,
-                                      movebuf); 
-                    if (ret != -EIO) 
+                                      movebuf);
+                    if (ret != -EIO)
                         printk("Error went away on retry.\n");
                 }
                memset(&oob, 0xff, sizeof(struct nftl_oob));
@@ -372,18 +372,18 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                 MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
                              512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
        }
-        
+
         /* add the header so that it is now a valid chain */
         oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
                 = cpu_to_le16(thisVUC);
         oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
-        
-        MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, 
+
+        MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8,
                      8, &retlen, (char *)&oob.u);
 
        /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
 
-       /* At this point, we have two different chains for this Virtual Unit, and no way to tell 
+       /* At this point, we have two different chains for this Virtual Unit, and no way to tell
           them apart. If we crash now, we get confused. However, both contain the same data, so we
           shouldn't actually lose data in this case. It's just that when we load up on a medium which
           has duplicate chains, we need to free one of the chains because it's not necessary any more.
@@ -391,7 +391,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
        thisEUN = nftl->EUNtable[thisVUC];
        DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
 
-       /* For each block in the old chain (except the targetEUN of course), 
+       /* For each block in the old chain (except the targetEUN of course),
           free it and make it available for future use */
        while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
                unsigned int EUNtmp;
@@ -409,7 +409,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                 }
                 thisEUN = EUNtmp;
        }
-       
+
        /* Make this the new start of chain for thisVUC */
        nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
        nftl->EUNtable[thisVUC] = targetEUN;
@@ -419,7 +419,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
 
 static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
 {
-       /* This is the part that needs some cleverness applied. 
+       /* This is the part that needs some cleverness applied.
           For now, I'm doing the minimum applicable to actually
           get the thing to work.
           Wear-levelling and other clever stuff needs to be implemented
@@ -466,7 +466,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
        return NFTL_foldchain (nftl, LongestChain, pendingblock);
 }
 
-/* NFTL_findwriteunit: Return the unit number into which we can write 
+/* NFTL_findwriteunit: Return the unit number into which we can write
                        for this block. Make it available if it isn't already
 */
 static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
@@ -484,7 +484,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                   a free space for the block in question.
                */
 
-               /* This condition catches the 0x[7f]fff cases, as well as 
+               /* This condition catches the 0x[7f]fff cases, as well as
                   being a sanity check for past-end-of-media access
                */
                lastEUN = BLOCK_NIL;
@@ -499,7 +499,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
 
                        MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
                                    8, &retlen, (char *)&bci);
-                       
+
                        DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
                              block , writeEUN, le16_to_cpu(bci.Status));
 
@@ -514,10 +514,10 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                                break;
                        default:
                                // Invalid block. Don't use it any more. Must implement.
-                               break;                  
+                               break;
                        }
-                       
-                       if (!silly--) { 
+
+                       if (!silly--) {
                                printk(KERN_WARNING
                                       "Infinite loop in Virtual Unit Chain 0x%x\n",
                                       thisVUC);
@@ -528,7 +528,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                        writeEUN = nftl->ReplUnitTable[writeEUN];
                }
 
-               /* OK. We didn't find one in the existing chain, or there 
+               /* OK. We didn't find one in the existing chain, or there
                   is no existing chain. */
 
                /* Try to find an already-free block */
@@ -542,12 +542,12 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
 
                        /* First remember the start of this chain */
                        //u16 startEUN = nftl->EUNtable[thisVUC];
-                       
+
                        //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
                        writeEUN = NFTL_makefreeblock(nftl, 0xffff);
 
                        if (writeEUN == BLOCK_NIL) {
-                               /* OK, we accept that the above comment is 
+                               /* OK, we accept that the above comment is
                                   lying - there may have been free blocks
                                   last time we called NFTL_findfreeblock(),
                                   but they are reserved for when we're
@@ -558,21 +558,21 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
                        }
                        if (writeEUN == BLOCK_NIL) {
                                /* Ouch. This should never happen - we should
-                                  always be able to make some room somehow. 
-                                  If we get here, we've allocated more storage 
+                                  always be able to make some room somehow.
+                                  If we get here, we've allocated more storage
                                   space than actual media, or our makefreeblock
                                   routine is missing something.
                                */
                                printk(KERN_WARNING "Cannot make free space.\n");
                                return BLOCK_NIL;
-                       }                       
+                       }
                        //printk("Restarting scan\n");
                        lastEUN = BLOCK_NIL;
                        continue;
                }
 
                /* We've found a free block. Insert it into the chain. */
-               
+
                if (lastEUN != BLOCK_NIL) {
                     thisVUC |= 0x8000; /* It's a replacement block */
                } else {
@@ -745,7 +745,7 @@ extern char nftlmountrev[];
 
 static int __init init_nftl(void)
 {
-       printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.97 $, nftlmount.c %s\n", nftlmountrev);
+       printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.98 $, nftlmount.c %s\n", nftlmountrev);
 
        return register_mtd_blktrans(&nftl_tr);
 }
index 84afd9029f53e58591533f41dcad4cc48d543bc0..3b104ebb219ad9cbe816575ecd25d9f23b7844b3 100644 (file)
@@ -1,10 +1,10 @@
-/* 
+/*
  * NFTL mount code with extensive checks
  *
- * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev Exp $
+ * $Id: nftlmount.c,v 1.41 2005/11/07 11:14:21 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
@@ -31,7 +31,7 @@
 
 #define SECTORSIZE 512
 
-char nftlmountrev[]="$Revision: 1.40 $";
+char nftlmountrev[]="$Revision: 1.41 $";
 
 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
  *     various device information of the NFTL partition and Bad Unit Table. Update
@@ -47,7 +47,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
        struct NFTLMediaHeader *mh = &nftl->MediaHdr;
        unsigned int i;
 
-        /* Assume logical EraseSize == physical erasesize for starting the scan. 
+        /* Assume logical EraseSize == physical erasesize for starting the scan.
           We'll sort it out later if we find a MediaHeader which says otherwise */
        /* Actually, we won't.  The new DiskOnChip driver has already scanned
           the MediaHeader and adjusted the virtual erasesize it presents in
@@ -83,9 +83,9 @@ static int find_boot_record(struct NFTLrecord *nftl)
                if (retlen < 6 || memcmp(buf, "ANAND", 6)) {
                        /* ANAND\0 not found. Continue */
 #if 0
-                       printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", 
+                       printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n",
                               block * nftl->EraseSize, nftl->mbd.mtd->index);
-#endif                 
+#endif
                        continue;
                }
 
@@ -103,7 +103,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
       */
                if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) {
                        printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n",
-                              block * nftl->EraseSize, nftl->mbd.mtd->index, 
+                              block * nftl->EraseSize, nftl->mbd.mtd->index,
                               le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1));
                        continue;
                }
@@ -175,7 +175,7 @@ device is already correct.
                nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
                if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
                        printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
-                       printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", 
+                       printk(KERN_NOTICE "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n",
                               nftl->nb_boot_blocks, nftl->nb_blocks);
                        return -1;
                }
@@ -187,7 +187,7 @@ device is already correct.
                               nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks);
                        return -1;
                }
-               
+
                nftl->mbd.size  = nftl->numvunits * (nftl->EraseSize / SECTORSIZE);
 
                /* If we're not using the last sectors in the device for some reason,
@@ -210,12 +210,12 @@ device is already correct.
                        printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n");
                        return -ENOMEM;
                }
-               
+
                /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */
                for (i = 0; i < nftl->nb_boot_blocks; i++)
                        nftl->ReplUnitTable[i] = BLOCK_RESERVED;
                /* mark all remaining blocks as potentially containing data */
-               for (; i < nftl->nb_blocks; i++) { 
+               for (; i < nftl->nb_blocks; i++) {
                        nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED;
                }
 
@@ -245,12 +245,12 @@ The new DiskOnChip driver already scanned the bad block table.  Just query it.
                        if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize))
                                nftl->ReplUnitTable[i] = BLOCK_RESERVED;
                }
-               
+
                nftl->MediaUnit = block;
                boot_record_count++;
-               
+
        } /* foreach (block) */
-               
+
        return boot_record_count?0:-1;
 }
 
@@ -265,7 +265,7 @@ static int memcmpb(void *a, int c, int n)
 }
 
 /* check_free_sector: check if a free sector is actually FREE, i.e. All 0xff in data and oob area */
-static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len, 
+static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int len,
                              int check_oob)
 {
        int i;
@@ -293,7 +293,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int
  *
  * Return: 0 when succeed, -1 on error.
  *
- *  ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
+ *  ToDo: 1. Is it neceressary to check_free_sector after erasing ??
  */
 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
 {
@@ -385,7 +385,7 @@ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_b
                                /* verify that the sector is really free. If not, mark
                                   as ignore */
                                if (memcmpb(&bci, 0xff, 8) != 0 ||
-                                   check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE, 
+                                   check_free_sectors(nftl, block * nftl->EraseSize + i * SECTORSIZE,
                                                       SECTORSIZE, 0) != 0) {
                                        printk("Incorrect free sector %d in block %d: "
                                               "marking it as ignored\n",
@@ -486,7 +486,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
        size_t retlen;
 
        /* check erase mark. */
-       if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
+       if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
                        &retlen, (char *)&h1) < 0)
                return -1;
 
@@ -501,7 +501,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block)
                h1.EraseMark = cpu_to_le16(ERASE_MARK);
                h1.EraseMark1 = cpu_to_le16(ERASE_MARK);
                h1.WearInfo = cpu_to_le32(0);
-               if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, 
+               if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
                                 &retlen, (char *)&h1) < 0)
                        return -1;
        } else {
@@ -582,9 +582,9 @@ int NFTL_mount(struct NFTLrecord *s)
 
                        for (;;) {
                                /* read the block header. If error, we format the chain */
-                               if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, 
+                               if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8,
                                                &retlen, (char *)&h0) < 0 ||
-                                   MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, 
+                                   MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8,
                                                &retlen, (char *)&h1) < 0) {
                                        s->ReplUnitTable[block] = BLOCK_NIL;
                                        do_format_chain = 1;
@@ -639,7 +639,7 @@ int NFTL_mount(struct NFTLrecord *s)
                                        first_logical_block = logical_block;
                                } else {
                                        if (logical_block != first_logical_block) {
-                                               printk("Block %d: incorrect logical block: %d expected: %d\n", 
+                                               printk("Block %d: incorrect logical block: %d expected: %d\n",
                                                       block, logical_block, first_logical_block);
                                                /* the chain is incorrect : we must format it,
                                                   but we need to read it completly */
@@ -668,7 +668,7 @@ int NFTL_mount(struct NFTLrecord *s)
                                        s->ReplUnitTable[block] = BLOCK_NIL;
                                        break;
                                } else if (rep_block >= s->nb_blocks) {
-                                       printk("Block %d: referencing invalid block %d\n", 
+                                       printk("Block %d: referencing invalid block %d\n",
                                               block, rep_block);
                                        do_format_chain = 1;
                                        s->ReplUnitTable[block] = BLOCK_NIL;
@@ -688,7 +688,7 @@ int NFTL_mount(struct NFTLrecord *s)
                                                s->ReplUnitTable[block] = rep_block;
                                                s->EUNtable[first_logical_block] = BLOCK_NIL;
                                        } else {
-                                               printk("Block %d: referencing block %d already in another chain\n", 
+                                               printk("Block %d: referencing block %d already in another chain\n",
                                                       block, rep_block);
                                                /* XXX: should handle correctly fold in progress chains */
                                                do_format_chain = 1;
@@ -710,7 +710,7 @@ int NFTL_mount(struct NFTLrecord *s)
                        } else {
                                unsigned int first_block1, chain_to_format, chain_length1;
                                int fold_mark;
-                               
+
                                /* valid chain : get foldmark */
                                fold_mark = get_fold_mark(s, first_block);
                                if (fold_mark == 0) {
@@ -729,9 +729,9 @@ int NFTL_mount(struct NFTLrecord *s)
                                        if (first_block1 != BLOCK_NIL) {
                                                /* XXX: what to do if same length ? */
                                                chain_length1 = calc_chain_length(s, first_block1);
-                                               printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n", 
+                                               printk("Two chains at blocks %d (len=%d) and %d (len=%d)\n",
                                                       first_block1, chain_length1, first_block, chain_length);
-                                               
+
                                                if (chain_length >= chain_length1) {
                                                        chain_to_format = first_block1;
                                                        s->EUNtable[first_logical_block] = first_block;
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
new file mode 100644 (file)
index 0000000..126ff6b
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# linux/drivers/mtd/onenand/Kconfig
+#
+
+menu "OneNAND Flash Device Drivers"
+       depends on MTD != n
+
+config MTD_ONENAND
+       tristate "OneNAND Device Support"
+       depends on MTD
+       help
+         This enables support for accessing all type of OneNAND flash
+         devices. For further information see
+         <http://www.samsung.com/Products/Semiconductor/Flash/OneNAND_TM/index.htm>.
+
+config MTD_ONENAND_VERIFY_WRITE
+       bool "Verify OneNAND page writes"
+       depends on MTD_ONENAND
+       help
+         This adds an extra check when data is written to the flash. The
+         OneNAND flash device internally checks only bits transitioning
+         from 1 to 0. There is a rare possibility that even though the
+         device thinks the write was successful, a bit could have been
+         flipped accidentaly due to device wear or something else.
+
+config MTD_ONENAND_GENERIC
+       tristate "OneNAND Flash device via platform device driver"
+       depends on MTD_ONENAND && ARM
+       help
+         Support for OneNAND flash via platform device driver.
+
+config MTD_ONENAND_SYNC_READ
+       bool "OneNAND Sync. Burst Read Support"
+       depends on ARCH_OMAP
+       help
+         This enables support for Sync. Burst Read.
+
+endmenu
diff --git a/drivers/mtd/onenand/Makefile b/drivers/mtd/onenand/Makefile
new file mode 100644 (file)
index 0000000..269cfe4
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the OneNAND MTD
+#
+
+# Core functionality.
+obj-$(CONFIG_MTD_ONENAND)              += onenand.o
+
+# Board specific.
+obj-$(CONFIG_MTD_ONENAND_GENERIC)      += generic.o
+
+onenand-objs = onenand_base.o onenand_bbt.o
diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c
new file mode 100644 (file)
index 0000000..48cce43
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *  linux/drivers/mtd/onenand/generic.c
+ *
+ *  Copyright (c) 2005 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Overview:
+ *   This is a device driver for the OneNAND flash for generic boards.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/mach/flash.h>
+
+#define DRIVER_NAME    "onenand"
+
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL,  };
+#endif
+
+struct onenand_info {
+       struct mtd_info         mtd;
+       struct mtd_partition    *parts;
+       struct onenand_chip     onenand;
+};
+
+static int __devinit generic_onenand_probe(struct device *dev)
+{
+       struct onenand_info *info;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct onenand_platform_data *pdata = pdev->dev.platform_data;
+       struct resource *res = pdev->resource;
+       unsigned long size = res->end - res->start + 1;
+       int err;
+
+       info = kmalloc(sizeof(struct onenand_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       memset(info, 0, sizeof(struct onenand_info));
+
+       if (!request_mem_region(res->start, size, dev->driver->name)) {
+               err = -EBUSY;
+               goto out_free_info;
+       }
+
+       info->onenand.base = ioremap(res->start, size);
+       if (!info->onenand.base) {
+               err = -ENOMEM;
+               goto out_release_mem_region;
+       }
+
+       info->onenand.mmcontrol = pdata->mmcontrol;
+
+       info->mtd.name = pdev->dev.bus_id;
+       info->mtd.priv = &info->onenand;
+       info->mtd.owner = THIS_MODULE;
+
+       if (onenand_scan(&info->mtd, 1)) {
+               err = -ENXIO;
+               goto out_iounmap;
+       }
+
+#ifdef CONFIG_MTD_PARTITIONS
+       err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
+       if (err > 0)
+               add_mtd_partitions(&info->mtd, info->parts, err);
+       else if (err < 0 && pdata->parts)
+               add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts);
+       else
+#endif
+               err = add_mtd_device(&info->mtd);
+
+       dev_set_drvdata(&pdev->dev, info);
+
+       return 0;
+
+out_iounmap:
+       iounmap(info->onenand.base);
+out_release_mem_region:
+       release_mem_region(res->start, size);
+out_free_info:
+       kfree(info);
+
+       return err;
+}
+
+static int __devexit generic_onenand_remove(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct onenand_info *info = dev_get_drvdata(&pdev->dev);
+       struct resource *res = pdev->resource;
+       unsigned long size = res->end - res->start + 1;
+
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       if (info) {
+               if (info->parts)
+                       del_mtd_partitions(&info->mtd);
+               else
+                       del_mtd_device(&info->mtd);
+
+               onenand_release(&info->mtd);
+               release_mem_region(res->start, size);
+               iounmap(info->onenand.base);
+               kfree(info);
+       }
+
+       return 0;
+}
+
+static struct device_driver generic_onenand_driver = {
+       .name           = DRIVER_NAME,
+       .bus            = &platform_bus_type,
+       .probe          = generic_onenand_probe,
+       .remove         = __devexit_p(generic_onenand_remove),
+};
+
+MODULE_ALIAS(DRIVER_NAME);
+
+static int __init generic_onenand_init(void)
+{
+       return driver_register(&generic_onenand_driver);
+}
+
+static void __exit generic_onenand_exit(void)
+{
+       driver_unregister(&generic_onenand_driver);
+}
+
+module_init(generic_onenand_init);
+module_exit(generic_onenand_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards");
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
new file mode 100644 (file)
index 0000000..cc38fa0
--- /dev/null
@@ -0,0 +1,1588 @@
+/*
+ *  linux/drivers/mtd/onenand/onenand_base.c
+ *
+ *  Copyright (C) 2005 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+/**
+ * onenand_oob_64 - oob info for large (2KB) page
+ */
+static struct nand_oobinfo onenand_oob_64 = {
+       .useecc         = MTD_NANDECC_AUTOPLACE,
+       .eccbytes       = 20,
+       .eccpos         = {
+               8, 9, 10, 11, 12,
+               24, 25, 26, 27, 28,
+               40, 41, 42, 43, 44,
+               56, 57, 58, 59, 60,
+               },
+       .oobfree        = {
+               {2, 3}, {14, 2}, {18, 3}, {30, 2},
+               {24, 3}, {46, 2}, {40, 3}, {62, 2} }
+};
+
+/**
+ * onenand_oob_32 - oob info for middle (1KB) page
+ */
+static struct nand_oobinfo onenand_oob_32 = {
+       .useecc         = MTD_NANDECC_AUTOPLACE,
+       .eccbytes       = 10,
+       .eccpos         = {
+               8, 9, 10, 11, 12,
+               24, 25, 26, 27, 28,
+               },
+       .oobfree        = { {2, 3}, {14, 2}, {18, 3}, {30, 2} }
+};
+
+static const unsigned char ffchars[] = {
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */
+};
+
+/**
+ * onenand_readw - [OneNAND Interface] Read OneNAND register
+ * @param addr         address to read
+ *
+ * Read OneNAND register
+ */
+static unsigned short onenand_readw(void __iomem *addr)
+{
+       return readw(addr);
+}
+
+/**
+ * onenand_writew - [OneNAND Interface] Write OneNAND register with value
+ * @param value                value to write
+ * @param addr         address to write
+ *
+ * Write OneNAND register with value
+ */
+static void onenand_writew(unsigned short value, void __iomem *addr)
+{
+       writew(value, addr);
+}
+
+/**
+ * onenand_block_address - [DEFAULT] Get block address
+ * @param this         onenand chip data structure
+ * @param block                the block
+ * @return             translated block address if DDP, otherwise same
+ *
+ * Setup Start Address 1 Register (F100h)
+ */
+static int onenand_block_address(struct onenand_chip *this, int block)
+{
+       if (this->device_id & ONENAND_DEVICE_IS_DDP) {
+               /* Device Flash Core select, NAND Flash Block Address */
+               int dfs = 0;
+
+               if (block & this->density_mask)
+                       dfs = 1;
+
+               return (dfs << ONENAND_DDP_SHIFT) |
+                       (block & (this->density_mask - 1));
+       }
+
+       return block;
+}
+
+/**
+ * onenand_bufferram_address - [DEFAULT] Get bufferram address
+ * @param this         onenand chip data structure
+ * @param block                the block
+ * @return             set DBS value if DDP, otherwise 0
+ *
+ * Setup Start Address 2 Register (F101h) for DDP
+ */
+static int onenand_bufferram_address(struct onenand_chip *this, int block)
+{
+       if (this->device_id & ONENAND_DEVICE_IS_DDP) {
+               /* Device BufferRAM Select */
+               int dbs = 0;
+
+               if (block & this->density_mask)
+                       dbs = 1;
+
+               return (dbs << ONENAND_DDP_SHIFT);
+       }
+
+       return 0;
+}
+
+/**
+ * onenand_page_address - [DEFAULT] Get page address
+ * @param page         the page address
+ * @param sector       the sector address
+ * @return             combined page and sector address
+ *
+ * Setup Start Address 8 Register (F107h)
+ */
+static int onenand_page_address(int page, int sector)
+{
+       /* Flash Page Address, Flash Sector Address */
+       int fpa, fsa;
+
+       fpa = page & ONENAND_FPA_MASK;
+       fsa = sector & ONENAND_FSA_MASK;
+
+       return ((fpa << ONENAND_FPA_SHIFT) | fsa);
+}
+
+/**
+ * onenand_buffer_address - [DEFAULT] Get buffer address
+ * @param dataram1     DataRAM index
+ * @param sectors      the sector address
+ * @param count                the number of sectors
+ * @return             the start buffer value
+ *
+ * Setup Start Buffer Register (F200h)
+ */
+static int onenand_buffer_address(int dataram1, int sectors, int count)
+{
+       int bsa, bsc;
+
+       /* BufferRAM Sector Address */
+       bsa = sectors & ONENAND_BSA_MASK;
+
+       if (dataram1)
+               bsa |= ONENAND_BSA_DATARAM1;    /* DataRAM1 */
+       else
+               bsa |= ONENAND_BSA_DATARAM0;    /* DataRAM0 */
+
+       /* BufferRAM Sector Count */
+       bsc = count & ONENAND_BSC_MASK;
+
+       return ((bsa << ONENAND_BSA_SHIFT) | bsc);
+}
+
+/**
+ * onenand_command - [DEFAULT] Send command to OneNAND device
+ * @param mtd          MTD device structure
+ * @param cmd          the command to be sent
+ * @param addr         offset to read from or write to
+ * @param len          number of bytes to read or write
+ *
+ * Send command to OneNAND device. This function is used for middle/large page
+ * devices (1KB/2KB Bytes per page)
+ */
+static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t len)
+{
+       struct onenand_chip *this = mtd->priv;
+       int value, readcmd = 0;
+       int block, page;
+       /* Now we use page size operation */
+       int sectors = 4, count = 4;
+
+       /* Address translation */
+       switch (cmd) {
+       case ONENAND_CMD_UNLOCK:
+       case ONENAND_CMD_LOCK:
+       case ONENAND_CMD_LOCK_TIGHT:
+               block = -1;
+               page = -1;
+               break;
+
+       case ONENAND_CMD_ERASE:
+       case ONENAND_CMD_BUFFERRAM:
+               block = (int) (addr >> this->erase_shift);
+               page = -1;
+               break;
+
+       default:
+               block = (int) (addr >> this->erase_shift);
+               page = (int) (addr >> this->page_shift);
+               page &= this->page_mask;
+               break;
+       }
+
+       /* NOTE: The setting order of the registers is very important! */
+       if (cmd == ONENAND_CMD_BUFFERRAM) {
+               /* Select DataRAM for DDP */
+               value = onenand_bufferram_address(this, block);
+               this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
+
+               /* Switch to the next data buffer */
+               ONENAND_SET_NEXT_BUFFERRAM(this);
+
+               return 0;
+       }
+
+       if (block != -1) {
+               /* Write 'DFS, FBA' of Flash */
+               value = onenand_block_address(this, block);
+               this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
+       }
+
+       if (page != -1) {
+               int dataram;
+
+               switch (cmd) {
+               case ONENAND_CMD_READ:
+               case ONENAND_CMD_READOOB:
+                       dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
+                       readcmd = 1;
+                       break;
+
+               default:
+                       dataram = ONENAND_CURRENT_BUFFERRAM(this);
+                       break;
+               }
+
+               /* Write 'FPA, FSA' of Flash */
+               value = onenand_page_address(page, sectors);
+               this->write_word(value, this->base + ONENAND_REG_START_ADDRESS8);
+
+               /* Write 'BSA, BSC' of DataRAM */
+               value = onenand_buffer_address(dataram, sectors, count);
+               this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
+
+               if (readcmd) {
+                       /* Select DataRAM for DDP */
+                       value = onenand_bufferram_address(this, block);
+                       this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
+               }
+       }
+
+       /* Interrupt clear */
+       this->write_word(ONENAND_INT_CLEAR, this->base + ONENAND_REG_INTERRUPT);
+
+       /* Write command */
+       this->write_word(cmd, this->base + ONENAND_REG_COMMAND);
+
+       return 0;
+}
+
+/**
+ * onenand_wait - [DEFAULT] wait until the command is done
+ * @param mtd          MTD device structure
+ * @param state                state to select the max. timeout value
+ *
+ * Wait for command done. This applies to all OneNAND command
+ * Read can take up to 30us, erase up to 2ms and program up to 350us
+ * according to general OneNAND specs
+ */
+static int onenand_wait(struct mtd_info *mtd, int state)
+{
+       struct onenand_chip * this = mtd->priv;
+       unsigned long timeout;
+       unsigned int flags = ONENAND_INT_MASTER;
+       unsigned int interrupt = 0;
+       unsigned int ctrl, ecc;
+
+       /* The 20 msec is enough */
+       timeout = jiffies + msecs_to_jiffies(20);
+       while (time_before(jiffies, timeout)) {
+               interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+
+               if (interrupt & flags)
+                       break;
+
+               if (state != FL_READING)
+                       cond_resched();
+       }
+       /* To get correct interrupt status in timeout case */
+       interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
+
+       ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+
+       if (ctrl & ONENAND_CTRL_ERROR) {
+               /* It maybe occur at initial bad block */
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: controller error = 0x%04x\n", ctrl);
+               /* Clear other interrupt bits for preventing ECC error */
+               interrupt &= ONENAND_INT_MASTER;
+       }
+
+       if (ctrl & ONENAND_CTRL_LOCK) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: it's locked error = 0x%04x\n", ctrl);
+               return -EACCES;
+       }
+
+       if (interrupt & ONENAND_INT_READ) {
+               ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+               if (ecc & ONENAND_ECC_2BIT_ALL) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_wait: ECC error = 0x%04x\n", ecc);
+                       return -EBADMSG;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * onenand_bufferram_offset - [DEFAULT] BufferRAM offset
+ * @param mtd          MTD data structure
+ * @param area         BufferRAM area
+ * @return             offset given area
+ *
+ * Return BufferRAM offset given area
+ */
+static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)
+{
+       struct onenand_chip *this = mtd->priv;
+
+       if (ONENAND_CURRENT_BUFFERRAM(this)) {
+               if (area == ONENAND_DATARAM)
+                       return mtd->oobblock;
+               if (area == ONENAND_SPARERAM)
+                       return mtd->oobsize;
+       }
+
+       return 0;
+}
+
+/**
+ * onenand_read_bufferram - [OneNAND Interface] Read the bufferram area
+ * @param mtd          MTD data structure
+ * @param area         BufferRAM area
+ * @param buffer       the databuffer to put/get data
+ * @param offset       offset to read from or write to
+ * @param count                number of bytes to read/write
+ *
+ * Read the BufferRAM area
+ */
+static int onenand_read_bufferram(struct mtd_info *mtd, int area,
+               unsigned char *buffer, int offset, size_t count)
+{
+       struct onenand_chip *this = mtd->priv;
+       void __iomem *bufferram;
+
+       bufferram = this->base + area;
+
+       bufferram += onenand_bufferram_offset(mtd, area);
+
+       memcpy(buffer, bufferram + offset, count);
+
+       return 0;
+}
+
+/**
+ * onenand_sync_read_bufferram - [OneNAND Interface] Read the bufferram area with Sync. Burst mode
+ * @param mtd          MTD data structure
+ * @param area         BufferRAM area
+ * @param buffer       the databuffer to put/get data
+ * @param offset       offset to read from or write to
+ * @param count                number of bytes to read/write
+ *
+ * Read the BufferRAM area with Sync. Burst Mode
+ */
+static int onenand_sync_read_bufferram(struct mtd_info *mtd, int area,
+               unsigned char *buffer, int offset, size_t count)
+{
+       struct onenand_chip *this = mtd->priv;
+       void __iomem *bufferram;
+
+       bufferram = this->base + area;
+
+       bufferram += onenand_bufferram_offset(mtd, area);
+
+       this->mmcontrol(mtd, ONENAND_SYS_CFG1_SYNC_READ);
+
+       memcpy(buffer, bufferram + offset, count);
+
+       this->mmcontrol(mtd, 0);
+
+       return 0;
+}
+
+/**
+ * onenand_write_bufferram - [OneNAND Interface] Write the bufferram area
+ * @param mtd          MTD data structure
+ * @param area         BufferRAM area
+ * @param buffer       the databuffer to put/get data
+ * @param offset       offset to read from or write to
+ * @param count                number of bytes to read/write
+ *
+ * Write the BufferRAM area
+ */
+static int onenand_write_bufferram(struct mtd_info *mtd, int area,
+               const unsigned char *buffer, int offset, size_t count)
+{
+       struct onenand_chip *this = mtd->priv;
+       void __iomem *bufferram;
+
+       bufferram = this->base + area;
+
+       bufferram += onenand_bufferram_offset(mtd, area);
+
+       memcpy(bufferram + offset, buffer, count);
+
+       return 0;
+}
+
+/**
+ * onenand_check_bufferram - [GENERIC] Check BufferRAM information
+ * @param mtd          MTD data structure
+ * @param addr         address to check
+ * @return             1 if there are valid data, otherwise 0
+ *
+ * Check bufferram if there is data we required
+ */
+static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
+{
+       struct onenand_chip *this = mtd->priv;
+       int block, page;
+       int i;
+
+       block = (int) (addr >> this->erase_shift);
+       page = (int) (addr >> this->page_shift);
+       page &= this->page_mask;
+
+       i = ONENAND_CURRENT_BUFFERRAM(this);
+
+       /* Is there valid data? */
+       if (this->bufferram[i].block == block &&
+           this->bufferram[i].page == page &&
+           this->bufferram[i].valid)
+               return 1;
+
+       return 0;
+}
+
+/**
+ * onenand_update_bufferram - [GENERIC] Update BufferRAM information
+ * @param mtd          MTD data structure
+ * @param addr         address to update
+ * @param valid                valid flag
+ *
+ * Update BufferRAM information
+ */
+static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
+               int valid)
+{
+       struct onenand_chip *this = mtd->priv;
+       int block, page;
+       int i;
+
+       block = (int) (addr >> this->erase_shift);
+       page = (int) (addr >> this->page_shift);
+       page &= this->page_mask;
+
+       /* Invalidate BufferRAM */
+       for (i = 0; i < MAX_BUFFERRAM; i++) {
+               if (this->bufferram[i].block == block &&
+                   this->bufferram[i].page == page)
+                       this->bufferram[i].valid = 0;
+       }
+
+       /* Update BufferRAM */
+       i = ONENAND_CURRENT_BUFFERRAM(this);
+       this->bufferram[i].block = block;
+       this->bufferram[i].page = page;
+       this->bufferram[i].valid = valid;
+
+       return 0;
+}
+
+/**
+ * onenand_get_device - [GENERIC] Get chip for selected access
+ * @param mtd          MTD device structure
+ * @param new_state    the state which is requested
+ *
+ * Get the device and lock it for exclusive access
+ */
+static int onenand_get_device(struct mtd_info *mtd, int new_state)
+{
+       struct onenand_chip *this = mtd->priv;
+       DECLARE_WAITQUEUE(wait, current);
+
+       /*
+        * Grab the lock and see if the device is available
+        */
+       while (1) {
+               spin_lock(&this->chip_lock);
+               if (this->state == FL_READY) {
+                       this->state = new_state;
+                       spin_unlock(&this->chip_lock);
+                       break;
+               }
+               if (new_state == FL_PM_SUSPENDED) {
+                       spin_unlock(&this->chip_lock);
+                       return (this->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
+               }
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               add_wait_queue(&this->wq, &wait);
+               spin_unlock(&this->chip_lock);
+               schedule();
+               remove_wait_queue(&this->wq, &wait);
+       }
+
+       return 0;
+}
+
+/**
+ * onenand_release_device - [GENERIC] release chip
+ * @param mtd          MTD device structure
+ *
+ * Deselect, release chip lock and wake up anyone waiting on the device
+ */
+static void onenand_release_device(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+
+       /* Release the chip */
+       spin_lock(&this->chip_lock);
+       this->state = FL_READY;
+       wake_up(&this->wq);
+       spin_unlock(&this->chip_lock);
+}
+
+/**
+ * onenand_read_ecc - [MTD Interface] Read data with ECC
+ * @param mtd          MTD device structure
+ * @param from         offset to read from
+ * @param len          number of bytes to read
+ * @param retlen       pointer to variable to store the number of read bytes
+ * @param buf          the databuffer to put data
+ * @param oob_buf      filesystem supplied oob data buffer
+ * @param oobsel       oob selection structure
+ *
+ * OneNAND read with ECC
+ */
+static int onenand_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)
+{
+       struct onenand_chip *this = mtd->priv;
+       int read = 0, column;
+       int thislen;
+       int ret = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+
+       /* Do not allow reads past end of device */
+       if ((from + len) > mtd->size) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n");
+               *retlen = 0;
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_READING);
+
+       /* TODO handling oob */
+
+       while (read < len) {
+               thislen = min_t(int, mtd->oobblock, len - read);
+
+               column = from & (mtd->oobblock - 1);
+               if (column + thislen > mtd->oobblock)
+                       thislen = mtd->oobblock - column;
+
+               if (!onenand_check_bufferram(mtd, from)) {
+                       this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock);
+
+                       ret = this->wait(mtd, FL_READING);
+                       /* First copy data and check return value for ECC handling */
+                       onenand_update_bufferram(mtd, from, 1);
+               }
+
+               this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
+
+               read += thislen;
+
+               if (read == len)
+                       break;
+
+               if (ret) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret);
+                       goto out;
+               }
+
+               from += thislen;
+               buf += thislen;
+       }
+
+out:
+       /* Deselect and wake up anyone waiting on the device */
+       onenand_release_device(mtd);
+
+       /*
+        * Return success, if no ECC failures, else -EBADMSG
+        * fs driver will take care of that, because
+        * retlen == desired len and result == -EBADMSG
+        */
+       *retlen = read;
+       return ret;
+}
+
+/**
+ * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc
+ * @param mtd          MTD device structure
+ * @param from         offset to read from
+ * @param len          number of bytes to read
+ * @param retlen       pointer to variable to store the number of read bytes
+ * @param buf          the databuffer to put data
+ *
+ * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL
+*/
+static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,
+       size_t *retlen, u_char *buf)
+{
+       return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+}
+
+/**
+ * onenand_read_oob - [MTD Interface] OneNAND read out-of-band
+ * @param mtd          MTD device structure
+ * @param from         offset to read from
+ * @param len          number of bytes to read
+ * @param retlen       pointer to variable to store the number of read bytes
+ * @param buf          the databuffer to put data
+ *
+ * OneNAND read out-of-band data from the spare area
+ */
+static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
+       size_t *retlen, u_char *buf)
+{
+       struct onenand_chip *this = mtd->priv;
+       int read = 0, thislen, column;
+       int ret = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
+
+       /* Initialize return length value */
+       *retlen = 0;
+
+       /* Do not allow reads past end of device */
+       if (unlikely((from + len) > mtd->size)) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n");
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_READING);
+
+       column = from & (mtd->oobsize - 1);
+
+       while (read < len) {
+               thislen = mtd->oobsize - column;
+               thislen = min_t(int, thislen, len);
+
+               this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+
+               onenand_update_bufferram(mtd, from, 0);
+
+               ret = this->wait(mtd, FL_READING);
+               /* First copy data and check return value for ECC handling */
+
+               this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
+
+               read += thislen;
+
+               if (read == len)
+                       break;
+
+               if (ret) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret);
+                       goto out;
+               }
+
+               buf += thislen;
+
+               /* Read more? */
+               if (read < len) {
+                       /* Page size */
+                       from += mtd->oobblock;
+                       column = 0;
+               }
+       }
+
+out:
+       /* Deselect and wake up anyone waiting on the device */
+       onenand_release_device(mtd);
+
+       *retlen = read;
+       return ret;
+}
+
+#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
+/**
+ * onenand_verify_page - [GENERIC] verify the chip contents after a write
+ * @param mtd          MTD device structure
+ * @param buf          the databuffer to verify
+ *
+ * Check DataRAM area directly
+ */
+static int onenand_verify_page(struct mtd_info *mtd, u_char *buf, loff_t addr)
+{
+       struct onenand_chip *this = mtd->priv;
+       void __iomem *dataram0, *dataram1;
+       int ret = 0;
+
+       this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock);
+
+       ret = this->wait(mtd, FL_READING);
+       if (ret)
+               return ret;
+
+       onenand_update_bufferram(mtd, addr, 1);
+
+       /* Check, if the two dataram areas are same */
+       dataram0 = this->base + ONENAND_DATARAM;
+       dataram1 = dataram0 + mtd->oobblock;
+
+       if (memcmp(dataram0, dataram1, mtd->oobblock))
+               return -EBADMSG;
+
+       return 0;
+}
+#else
+#define onenand_verify_page(...)       (0)
+#endif
+
+#define NOTALIGNED(x)  ((x & (mtd->oobblock - 1)) != 0)
+
+/**
+ * onenand_write_ecc - [MTD Interface] OneNAND write with ECC
+ * @param mtd          MTD device structure
+ * @param to           offset to write to
+ * @param len          number of bytes to write
+ * @param retlen       pointer to variable to store the number of written bytes
+ * @param buf          the data to write
+ * @param eccbuf       filesystem supplied oob data buffer
+ * @param oobsel       oob selection structure
+ *
+ * OneNAND write with ECC
+ */
+static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
+       size_t *retlen, const u_char *buf,
+       u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+       struct onenand_chip *this = mtd->priv;
+       int written = 0;
+       int ret = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+
+       /* Initialize retlen, in case of early exit */
+       *retlen = 0;
+
+       /* Do not allow writes past end of device */
+       if (unlikely((to + len) > mtd->size)) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n");
+               return -EINVAL;
+       }
+
+       /* Reject writes, which are not page aligned */
+        if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {
+                DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n");
+                return -EINVAL;
+        }
+
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_WRITING);
+
+       /* Loop until all data write */
+       while (written < len) {
+               int thislen = min_t(int, mtd->oobblock, len - written);
+
+               this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock);
+
+               this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen);
+               this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+
+               this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock);
+
+               onenand_update_bufferram(mtd, to, 1);
+
+               ret = this->wait(mtd, FL_WRITING);
+               if (ret) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret);
+                       goto out;
+               }
+
+               written += thislen;
+
+               /* Only check verify write turn on */
+               ret = onenand_verify_page(mtd, (u_char *) buf, to);
+               if (ret) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret);
+                       goto out;
+               }
+
+               if (written == len)
+                       break;
+
+               to += thislen;
+               buf += thislen;
+       }
+
+out:
+       /* Deselect and wake up anyone waiting on the device */
+       onenand_release_device(mtd);
+
+       *retlen = written;
+
+       return ret;
+}
+
+/**
+ * onenand_write - [MTD Interface] compability function for onenand_write_ecc
+ * @param mtd          MTD device structure
+ * @param to           offset to write to
+ * @param len          number of bytes to write
+ * @param retlen       pointer to variable to store the number of written bytes
+ * @param buf          the data to write
+ *
+ * This function simply calls onenand_write_ecc
+ * with oob buffer and oobsel = NULL
+ */
+static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,
+       size_t *retlen, const u_char *buf)
+{
+       return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);
+}
+
+/**
+ * onenand_write_oob - [MTD Interface] OneNAND write out-of-band
+ * @param mtd          MTD device structure
+ * @param to           offset to write to
+ * @param len          number of bytes to write
+ * @param retlen       pointer to variable to store the number of written bytes
+ * @param buf          the data to write
+ *
+ * OneNAND write out-of-band
+ */
+static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
+       size_t *retlen, const u_char *buf)
+{
+       struct onenand_chip *this = mtd->priv;
+       int column, status;
+       int written = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
+
+       /* Initialize retlen, in case of early exit */
+       *retlen = 0;
+
+       /* Do not allow writes past end of device */
+       if (unlikely((to + len) > mtd->size)) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n");
+               return -EINVAL;
+       }
+
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_WRITING);
+
+       /* Loop until all data write */
+       while (written < len) {
+               int thislen = min_t(int, mtd->oobsize, len - written);
+
+               column = to & (mtd->oobsize - 1);
+
+               this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);
+
+               this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+               this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);
+
+               this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
+
+               onenand_update_bufferram(mtd, to, 0);
+
+               status = this->wait(mtd, FL_WRITING);
+               if (status)
+                       goto out;
+
+               written += thislen;
+
+               if (written == len)
+                       break;
+
+               to += thislen;
+               buf += thislen;
+       }
+
+out:
+       /* Deselect and wake up anyone waiting on the device */
+       onenand_release_device(mtd);
+
+       *retlen = written;
+
+       return 0;
+}
+
+/**
+ * onenand_writev_ecc - [MTD Interface] write with iovec with ecc
+ * @param mtd          MTD device structure
+ * @param vecs         the iovectors to write
+ * @param count                number of vectors
+ * @param to           offset to write to
+ * @param retlen       pointer to variable to store the number of written bytes
+ * @param eccbuf       filesystem supplied oob data buffer
+ * @param oobsel       oob selection structure
+ *
+ * OneNAND write with iovec with ecc
+ */
+static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
+       unsigned long count, loff_t to, size_t *retlen,
+       u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+       struct onenand_chip *this = mtd->priv;
+       unsigned char buffer[MAX_ONENAND_PAGESIZE], *pbuf;
+       size_t total_len, len;
+       int i, written = 0;
+       int ret = 0;
+
+       /* Preset written len for early exit */
+       *retlen = 0;
+
+       /* Calculate total length of data */
+       total_len = 0;
+       for (i = 0; i < count; i++)
+               total_len += vecs[i].iov_len;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
+
+       /* Do not allow write past end of the device */
+       if (unlikely((to + total_len) > mtd->size)) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n");
+               return -EINVAL;
+       }
+
+       /* Reject writes, which are not page aligned */
+        if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) {
+                DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n");
+                return -EINVAL;
+        }
+
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_WRITING);
+
+       /* TODO handling oob */
+
+       /* Loop until all keve's data has been written */
+       len = 0;
+       while (count) {
+               pbuf = buffer;
+               /*
+                * If the given tuple is >= pagesize then
+                * write it out from the iov
+                */
+               if ((vecs->iov_len - len) >= mtd->oobblock) {
+                       pbuf = vecs->iov_base + len;
+
+                       len += mtd->oobblock;
+
+                       /* Check, if we have to switch to the next tuple */
+                       if (len >= (int) vecs->iov_len) {
+                               vecs++;
+                               len = 0;
+                               count--;
+                       }
+               } else {
+                       int cnt = 0, thislen;
+                       while (cnt < mtd->oobblock) {
+                               thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len);
+                               memcpy(buffer + cnt, vecs->iov_base + len, thislen);
+                               cnt += thislen;
+                               len += thislen;
+
+                               /* Check, if we have to switch to the next tuple */
+                               if (len >= (int) vecs->iov_len) {
+                                       vecs++;
+                                       len = 0;
+                                       count--;
+                               }
+                       }
+               }
+
+               this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock);
+
+               this->write_bufferram(mtd, ONENAND_DATARAM, pbuf, 0, mtd->oobblock);
+               this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);
+
+               this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock);
+
+               onenand_update_bufferram(mtd, to, 1);
+
+               ret = this->wait(mtd, FL_WRITING);
+               if (ret) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: write failed %d\n", ret);
+                       goto out;
+               }
+
+
+               /* Only check verify write turn on */
+               ret = onenand_verify_page(mtd, (u_char *) pbuf, to);
+               if (ret) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: verify failed %d\n", ret);
+                       goto out;
+               }
+
+               written += mtd->oobblock;
+
+               to += mtd->oobblock;
+       }
+
+out:
+       /* Deselect and wakt up anyone waiting on the device */
+       onenand_release_device(mtd);
+
+       *retlen = written;
+
+       return 0;
+}
+
+/**
+ * onenand_writev - [MTD Interface] compabilty function for onenand_writev_ecc
+ * @param mtd          MTD device structure
+ * @param vecs         the iovectors to write
+ * @param count                number of vectors
+ * @param to           offset to write to
+ * @param retlen       pointer to variable to store the number of written bytes
+ *
+ * OneNAND write with kvec. This just calls the ecc function
+ */
+static int onenand_writev(struct mtd_info *mtd, const struct kvec *vecs,
+       unsigned long count, loff_t to, size_t *retlen)
+{
+       return onenand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL);
+}
+
+/**
+ * onenand_block_checkbad - [GENERIC] Check if a block is marked bad
+ * @param mtd          MTD device structure
+ * @param ofs          offset from device start
+ * @param getchip      0, if the chip is already selected
+ * @param allowbbt     1, if its allowed to access the bbt area
+ *
+ * Check, if the block is bad. Either by reading the bad block table or
+ * calling of the scan function.
+ */
+static int onenand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct bbm_info *bbm = this->bbm;
+
+       /* Return info from the table */
+       return bbm->isbad_bbt(mtd, ofs, allowbbt);
+}
+
+/**
+ * onenand_erase - [MTD Interface] erase block(s)
+ * @param mtd          MTD device structure
+ * @param instr                erase instruction
+ *
+ * Erase one ore more blocks
+ */
+static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct onenand_chip *this = mtd->priv;
+       unsigned int block_size;
+       loff_t addr;
+       int len;
+       int ret = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
+
+       block_size = (1 << this->erase_shift);
+
+       /* Start address must align on block boundary */
+       if (unlikely(instr->addr & (block_size - 1))) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");
+               return -EINVAL;
+       }
+
+       /* Length must align on block boundary */
+       if (unlikely(instr->len & (block_size - 1))) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Length not block aligned\n");
+               return -EINVAL;
+       }
+
+       /* Do not allow erase past end of device */
+       if (unlikely((instr->len + instr->addr) > mtd->size)) {
+               DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n");
+               return -EINVAL;
+       }
+
+       instr->fail_addr = 0xffffffff;
+
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_ERASING);
+
+       /* Loop throught the pages */
+       len = instr->len;
+       addr = instr->addr;
+
+       instr->state = MTD_ERASING;
+
+       while (len) {
+
+               /* Check if we have a bad block, we do not erase bad blocks */
+               if (onenand_block_checkbad(mtd, addr, 0, 0)) {
+                       printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr);
+                       instr->state = MTD_ERASE_FAILED;
+                       goto erase_exit;
+               }
+
+               this->command(mtd, ONENAND_CMD_ERASE, addr, block_size);
+
+               ret = this->wait(mtd, FL_ERASING);
+               /* Check, if it is write protected */
+               if (ret) {
+                       if (ret == -EPERM)
+                               DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Device is write protected!!!\n");
+                       else
+                               DEBUG(MTD_DEBUG_LEVEL0, "onenand_erase: Failed erase, block %d\n", (unsigned) (addr >> this->erase_shift));
+                       instr->state = MTD_ERASE_FAILED;
+                       instr->fail_addr = addr;
+                       goto erase_exit;
+               }
+
+               len -= block_size;
+               addr += block_size;
+       }
+
+       instr->state = MTD_ERASE_DONE;
+
+erase_exit:
+
+       ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
+       /* Do call back function */
+       if (!ret)
+               mtd_erase_callback(instr);
+
+       /* Deselect and wake up anyone waiting on the device */
+       onenand_release_device(mtd);
+
+       return ret;
+}
+
+/**
+ * onenand_sync - [MTD Interface] sync
+ * @param mtd          MTD device structure
+ *
+ * Sync is actually a wait for chip ready function
+ */
+static void onenand_sync(struct mtd_info *mtd)
+{
+       DEBUG(MTD_DEBUG_LEVEL3, "onenand_sync: called\n");
+
+       /* Grab the lock and see if the device is available */
+       onenand_get_device(mtd, FL_SYNCING);
+
+       /* Release it and go back */
+       onenand_release_device(mtd);
+}
+
+
+/**
+ * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
+ * @param mtd          MTD device structure
+ * @param ofs          offset relative to mtd start
+ *
+ * Check whether the block is bad
+ */
+static int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+       /* Check for invalid offset */
+       if (ofs > mtd->size)
+               return -EINVAL;
+
+       return onenand_block_checkbad(mtd, ofs, 1, 0);
+}
+
+/**
+ * onenand_default_block_markbad - [DEFAULT] mark a block bad
+ * @param mtd          MTD device structure
+ * @param ofs          offset from device start
+ *
+ * This is the default implementation, which can be overridden by
+ * a hardware specific driver.
+ */
+static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct bbm_info *bbm = this->bbm;
+       u_char buf[2] = {0, 0};
+       size_t retlen;
+       int block;
+
+       /* Get block number */
+       block = ((int) ofs) >> bbm->bbt_erase_shift;
+        if (bbm->bbt)
+                bbm->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+
+        /* We write two bytes, so we dont have to mess with 16 bit access */
+        ofs += mtd->oobsize + (bbm->badblockpos & ~0x01);
+        return mtd->write_oob(mtd, ofs , 2, &retlen, buf);
+}
+
+/**
+ * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
+ * @param mtd          MTD device structure
+ * @param ofs          offset relative to mtd start
+ *
+ * Mark the block as bad
+ */
+static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct onenand_chip *this = mtd->priv;
+       int ret;
+
+       ret = onenand_block_isbad(mtd, ofs);
+       if (ret) {
+               /* If it was bad already, return success and do nothing */
+               if (ret > 0)
+                       return 0;
+               return ret;
+       }
+
+       return this->block_markbad(mtd, ofs);
+}
+
+/**
+ * onenand_unlock - [MTD Interface] Unlock block(s)
+ * @param mtd          MTD device structure
+ * @param ofs          offset relative to mtd start
+ * @param len          number of bytes to unlock
+ *
+ * Unlock one or more blocks
+ */
+static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+       struct onenand_chip *this = mtd->priv;
+       int start, end, block, value, status;
+
+       start = ofs >> this->erase_shift;
+       end = len >> this->erase_shift;
+
+       /* Continuous lock scheme */
+       if (this->options & ONENAND_CONT_LOCK) {
+               /* Set start block address */
+               this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
+               /* Set end block address */
+               this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
+               /* Write unlock command */
+               this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
+
+               /* There's no return value */
+               this->wait(mtd, FL_UNLOCKING);
+
+               /* Sanity check */
+               while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
+                   & ONENAND_CTRL_ONGO)
+                       continue;
+
+               /* Check lock status */
+               status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
+               if (!(status & ONENAND_WP_US))
+                       printk(KERN_ERR "wp status = 0x%x\n", status);
+
+               return 0;
+       }
+
+       /* Block lock scheme */
+       for (block = start; block < end; block++) {
+               /* Set start block address */
+               this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
+               /* Write unlock command */
+               this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
+
+               /* There's no return value */
+               this->wait(mtd, FL_UNLOCKING);
+
+               /* Sanity check */
+               while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
+                   & ONENAND_CTRL_ONGO)
+                       continue;
+
+               /* Set block address for read block status */
+               value = onenand_block_address(this, block);
+               this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
+
+               /* Check lock status */
+               status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
+               if (!(status & ONENAND_WP_US))
+                       printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
+       }
+
+       return 0;
+}
+
+/**
+ * onenand_print_device_info - Print device ID
+ * @param device        device ID
+ *
+ * Print device ID
+ */
+static void onenand_print_device_info(int device)
+{
+        int vcc, demuxed, ddp, density;
+
+        vcc = device & ONENAND_DEVICE_VCC_MASK;
+        demuxed = device & ONENAND_DEVICE_IS_DEMUX;
+        ddp = device & ONENAND_DEVICE_IS_DDP;
+        density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
+        printk(KERN_INFO "%sOneNAND%s %dMB %sV 16-bit (0x%02x)\n",
+                demuxed ? "" : "Muxed ",
+                ddp ? "(DDP)" : "",
+                (16 << density),
+                vcc ? "2.65/3.3" : "1.8",
+                device);
+}
+
+static const struct onenand_manufacturers onenand_manuf_ids[] = {
+        {ONENAND_MFR_SAMSUNG, "Samsung"},
+        {ONENAND_MFR_UNKNOWN, "Unknown"}
+};
+
+/**
+ * onenand_check_maf - Check manufacturer ID
+ * @param manuf         manufacturer ID
+ *
+ * Check manufacturer ID
+ */
+static int onenand_check_maf(int manuf)
+{
+        int i;
+
+        for (i = 0; onenand_manuf_ids[i].id; i++) {
+                if (manuf == onenand_manuf_ids[i].id)
+                        break;
+        }
+
+        printk(KERN_DEBUG "OneNAND Manufacturer: %s (0x%0x)\n",
+                onenand_manuf_ids[i].name, manuf);
+
+        return (i != ONENAND_MFR_UNKNOWN);
+}
+
+/**
+ * onenand_probe - [OneNAND Interface] Probe the OneNAND device
+ * @param mtd          MTD device structure
+ *
+ * OneNAND detection method:
+ *   Compare the the values from command with ones from register
+ */
+static int onenand_probe(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+       int bram_maf_id, bram_dev_id, maf_id, dev_id;
+       int version_id;
+       int density;
+
+       /* Send the command for reading device ID from BootRAM */
+       this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
+
+       /* Read manufacturer and device IDs from BootRAM */
+       bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
+       bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
+
+       /* Check manufacturer ID */
+       if (onenand_check_maf(bram_maf_id))
+               return -ENXIO;
+
+       /* Reset OneNAND to read default register values */
+       this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
+
+       /* Read manufacturer and device IDs from Register */
+       maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
+       dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
+
+       /* Check OneNAND device */
+       if (maf_id != bram_maf_id || dev_id != bram_dev_id)
+               return -ENXIO;
+
+       /* Flash device information */
+       onenand_print_device_info(dev_id);
+       this->device_id = dev_id;
+
+       density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+       this->chipsize = (16 << density) << 20;
+       /* Set density mask. it is used for DDP */
+       this->density_mask = (1 << (density + 6));
+
+       /* OneNAND page size & block size */
+       /* The data buffer size is equal to page size */
+       mtd->oobblock = this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
+       mtd->oobsize = mtd->oobblock >> 5;
+       /* Pagers per block is always 64 in OneNAND */
+       mtd->erasesize = mtd->oobblock << 6;
+
+       this->erase_shift = ffs(mtd->erasesize) - 1;
+       this->page_shift = ffs(mtd->oobblock) - 1;
+       this->ppb_shift = (this->erase_shift - this->page_shift);
+       this->page_mask = (mtd->erasesize / mtd->oobblock) - 1;
+
+       /* REVIST: Multichip handling */
+
+       mtd->size = this->chipsize;
+
+       /* Version ID */
+       version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
+       printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id);
+
+       /* Lock scheme */
+       if (density <= ONENAND_DEVICE_DENSITY_512Mb &&
+           !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) {
+               printk(KERN_INFO "Lock scheme is Continues Lock\n");
+               this->options |= ONENAND_CONT_LOCK;
+       }
+
+       return 0;
+}
+
+/**
+ * onenand_suspend - [MTD Interface] Suspend the OneNAND flash
+ * @param mtd          MTD device structure
+ */
+static int onenand_suspend(struct mtd_info *mtd)
+{
+       return onenand_get_device(mtd, FL_PM_SUSPENDED);
+}
+
+/**
+ * onenand_resume - [MTD Interface] Resume the OneNAND flash
+ * @param mtd          MTD device structure
+ */
+static void onenand_resume(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+
+       if (this->state == FL_PM_SUSPENDED)
+               onenand_release_device(mtd);
+       else
+               printk(KERN_ERR "resume() called for the chip which is not"
+                               "in suspended state\n");
+}
+
+
+/**
+ * onenand_scan - [OneNAND Interface] Scan for the OneNAND device
+ * @param mtd          MTD device structure
+ * @param maxchips     Number of chips to scan for
+ *
+ * This fills out all the not initialized function pointers
+ * with the defaults.
+ * The flash ID is read and the mtd/chip structures are
+ * filled with the appropriate values.
+ */
+int onenand_scan(struct mtd_info *mtd, int maxchips)
+{
+       struct onenand_chip *this = mtd->priv;
+
+       if (!this->read_word)
+               this->read_word = onenand_readw;
+       if (!this->write_word)
+               this->write_word = onenand_writew;
+
+       if (!this->command)
+               this->command = onenand_command;
+       if (!this->wait)
+               this->wait = onenand_wait;
+
+       if (!this->read_bufferram)
+               this->read_bufferram = onenand_read_bufferram;
+       if (!this->write_bufferram)
+               this->write_bufferram = onenand_write_bufferram;
+
+       if (!this->block_markbad)
+               this->block_markbad = onenand_default_block_markbad;
+       if (!this->scan_bbt)
+               this->scan_bbt = onenand_default_bbt;
+
+       if (onenand_probe(mtd))
+               return -ENXIO;
+
+       /* Set Sync. Burst Read after probing */
+       if (this->mmcontrol) {
+               printk(KERN_INFO "OneNAND Sync. Burst Read support\n");
+               this->read_bufferram = onenand_sync_read_bufferram;
+       }
+
+       this->state = FL_READY;
+       init_waitqueue_head(&this->wq);
+       spin_lock_init(&this->chip_lock);
+
+       switch (mtd->oobsize) {
+       case 64:
+               this->autooob = &onenand_oob_64;
+               break;
+
+       case 32:
+               this->autooob = &onenand_oob_32;
+               break;
+
+       default:
+               printk(KERN_WARNING "No OOB scheme defined for oobsize %d\n",
+                       mtd->oobsize);
+               /* To prevent kernel oops */
+               this->autooob = &onenand_oob_32;
+               break;
+       }
+
+       memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
+
+       /* Fill in remaining MTD driver data */
+       mtd->type = MTD_NANDFLASH;
+       mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
+       mtd->ecctype = MTD_ECC_SW;
+       mtd->erase = onenand_erase;
+       mtd->point = NULL;
+       mtd->unpoint = NULL;
+       mtd->read = onenand_read;
+       mtd->write = onenand_write;
+       mtd->read_ecc = onenand_read_ecc;
+       mtd->write_ecc = onenand_write_ecc;
+       mtd->read_oob = onenand_read_oob;
+       mtd->write_oob = onenand_write_oob;
+       mtd->readv = NULL;
+       mtd->readv_ecc = NULL;
+       mtd->writev = onenand_writev;
+       mtd->writev_ecc = onenand_writev_ecc;
+       mtd->sync = onenand_sync;
+       mtd->lock = NULL;
+       mtd->unlock = onenand_unlock;
+       mtd->suspend = onenand_suspend;
+       mtd->resume = onenand_resume;
+       mtd->block_isbad = onenand_block_isbad;
+       mtd->block_markbad = onenand_block_markbad;
+       mtd->owner = THIS_MODULE;
+
+       /* Unlock whole block */
+       mtd->unlock(mtd, 0x0, this->chipsize);
+
+       return this->scan_bbt(mtd);
+}
+
+/**
+ * onenand_release - [OneNAND Interface] Free resources held by the OneNAND device
+ * @param mtd          MTD device structure
+ */
+void onenand_release(struct mtd_info *mtd)
+{
+#ifdef CONFIG_MTD_PARTITIONS
+       /* Deregister partitions */
+       del_mtd_partitions (mtd);
+#endif
+       /* Deregister the device */
+       del_mtd_device (mtd);
+}
+
+EXPORT_SYMBOL_GPL(onenand_scan);
+EXPORT_SYMBOL_GPL(onenand_release);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
+MODULE_DESCRIPTION("Generic OneNAND flash driver code");
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
new file mode 100644 (file)
index 0000000..f40190f
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ *  linux/drivers/mtd/onenand/onenand_bbt.c
+ *
+ *  Bad Block Table support for the OneNAND driver
+ *
+ *  Copyright(c) 2005 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ *  Derived from nand_bbt.c
+ *
+ *  TODO:
+ *    Split BBT core and chip specific BBT.
+ */
+
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/onenand.h>
+#include <linux/mtd/compatmac.h>
+
+/**
+ * check_short_pattern - [GENERIC] check if a pattern is in the buffer
+ * @param buf          the buffer to search
+ * @param len          the length of buffer to search
+ * @param paglen       the pagelength
+ * @param td           search pattern descriptor
+ *
+ * Check for a pattern at the given place. Used to search bad block
+ * tables and good / bad block identifiers. Same as check_pattern, but
+ * no optional empty check and the pattern is expected to start
+ * at offset 0.
+ *
+ */
+static int check_short_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
+{
+       int i;
+       uint8_t *p = buf;
+
+       /* Compare the pattern */
+       for (i = 0; i < td->len; i++) {
+               if (p[i] != td->pattern[i])
+                       return -1;
+       }
+        return 0;
+}
+
+/**
+ * create_bbt - [GENERIC] Create a bad block table by scanning the device
+ * @param mtd          MTD device structure
+ * @param buf          temporary buffer
+ * @param bd           descriptor for the good/bad block search pattern
+ * @param chip         create the table for a specific chip, -1 read all chips.
+ *              Applies only if NAND_BBT_PERCHIP option is set
+ *
+ * Create a bad block table by scanning the device
+ * for the given good/bad block identify pattern
+ */
+static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct bbm_info *bbm = this->bbm;
+       int i, j, numblocks, len, scanlen;
+       int startblock;
+       loff_t from;
+       size_t readlen, ooblen;
+
+       printk(KERN_INFO "Scanning device for bad blocks\n");
+
+       len = 1;
+
+       /* We need only read few bytes from the OOB area */
+       scanlen = ooblen = 0;
+       readlen = bd->len;
+
+       /* chip == -1 case only */
+       /* Note that numblocks is 2 * (real numblocks) here;
+        * see i += 2 below as it makses shifting and masking less painful
+        */
+       numblocks = mtd->size >> (bbm->bbt_erase_shift - 1);
+       startblock = 0;
+       from = 0;
+
+       for (i = startblock; i < numblocks; ) {
+               int ret;
+
+               for (j = 0; j < len; j++) {
+                       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_short_pattern(&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
+                               bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
+                               printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
+                                       i >> 1, (unsigned int) from);
+                               break;
+                       }
+               }
+               i += 2;
+               from += (1 << bbm->bbt_erase_shift);
+       }
+
+       return 0;
+}
+
+
+/**
+ * onenand_memory_bbt - [GENERIC] create a memory based bad block table
+ * @param mtd          MTD device structure
+ * @param bd           descriptor for the good/bad block search pattern
+ *
+ * The function creates a memory based bbt by scanning the device
+ * for manufacturer / software marked good / bad blocks
+ */
+static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
+{
+       unsigned char data_buf[MAX_ONENAND_PAGESIZE];
+
+        bd->options &= ~NAND_BBT_SCANEMPTY;
+        return create_bbt(mtd, data_buf, bd, -1);
+}
+
+/**
+ * onenand_isbad_bbt - [OneNAND Interface] Check if a block is bad
+ * @param mtd          MTD device structure
+ * @param offs         offset in the device
+ * @param allowbbt     allow access to bad block table region
+ */
+static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct bbm_info *bbm = this->bbm;
+       int block;
+       uint8_t res;
+
+       /* Get block number * 2 */
+       block = (int) (offs >> (bbm->bbt_erase_shift - 1));
+       res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n",
+               (unsigned int) offs, block >> 1, res);
+
+       switch ((int) res) {
+       case 0x00:      return 0;
+       case 0x01:      return 1;
+       case 0x02:      return allowbbt ? 0 : 1;
+       }
+
+       return 1;
+}
+
+/**
+ * onenand_scan_bbt - [OneNAND Interface] scan, find, read and maybe create bad block table(s)
+ * @param mtd          MTD device structure
+ * @param bd           descriptor for the good/bad block search pattern
+ *
+ * The function checks, if a bad block table(s) is/are already
+ * available. If not it scans the device for manufacturer
+ * marked good / bad blocks and writes the bad block table(s) to
+ * the selected place.
+ *
+ * The bad block table memory is allocated here. It must be freed
+ * by calling the onenand_free_bbt function.
+ *
+ */
+int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct bbm_info *bbm = this->bbm;
+       int len, ret = 0;
+
+       len = mtd->size >> (this->erase_shift + 2);
+       /* Allocate memory (2bit per block) */
+       bbm->bbt = kmalloc(len, GFP_KERNEL);
+       if (!bbm->bbt) {
+               printk(KERN_ERR "onenand_scan_bbt: Out of memory\n");
+               return -ENOMEM;
+       }
+       /* Clear the memory bad block table */
+       memset(bbm->bbt, 0x00, len);
+
+       /* Set the bad block position */
+       bbm->badblockpos = ONENAND_BADBLOCK_POS;
+
+       /* Set erase shift */
+       bbm->bbt_erase_shift = this->erase_shift;
+
+       if (!bbm->isbad_bbt)
+               bbm->isbad_bbt = onenand_isbad_bbt;
+
+       /* Scan the device to build a memory based bad block table */
+       if ((ret = onenand_memory_bbt(mtd, bd))) {
+               printk(KERN_ERR "onenand_scan_bbt: Can't scan flash and build the RAM-based BBT\n");
+               kfree(bbm->bbt);
+               bbm->bbt = NULL;
+       }
+
+       return ret;
+}
+
+/*
+ * Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks.
+ */
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+
+static struct nand_bbt_descr largepage_memorybased = {
+       .options = 0,
+       .offs = 0,
+       .len = 2,
+       .pattern = scan_ff_pattern,
+};
+
+/**
+ * onenand_default_bbt - [OneNAND Interface] Select a default bad block table for the device
+ * @param mtd          MTD device structure
+ *
+ * This function selects the default bad block table
+ * support for the device and calls the onenand_scan_bbt function
+ */
+int onenand_default_bbt(struct mtd_info *mtd)
+{
+       struct onenand_chip *this = mtd->priv;
+       struct bbm_info *bbm;
+
+       this->bbm = kmalloc(sizeof(struct bbm_info), GFP_KERNEL);
+       if (!this->bbm)
+               return -ENOMEM;
+
+       bbm = this->bbm;
+
+       memset(bbm, 0, sizeof(struct bbm_info));
+
+       /* 1KB page has same configuration as 2KB page */
+       if (!bbm->badblock_pattern)
+               bbm->badblock_pattern = &largepage_memorybased;
+
+       return onenand_scan_bbt(mtd, bbm->badblock_pattern);
+}
+
+EXPORT_SYMBOL(onenand_scan_bbt);
+EXPORT_SYMBOL(onenand_default_bbt);
index 13f9e992bef8bb0bc5b5801a1dd9207bdeb2b85e..7b7ca5ab5ae41c27502c1f28800250263a2015f8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $
+ * $Id: redboot.c,v 1.18 2005/11/07 11:14:21 gleixner Exp $
  *
  * Parse RedBoot-style Flash Image System (FIS) tables and
  * produce a Linux partition array to match.
@@ -39,7 +39,7 @@ static inline int redboot_checksum(struct fis_image_desc *img)
        return 1;
 }
 
-static int parse_redboot_partitions(struct mtd_info *master, 
+static int parse_redboot_partitions(struct mtd_info *master,
                              struct mtd_partition **pparts,
                              unsigned long fis_origin)
 {
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
new file mode 100644 (file)
index 0000000..041ee59
--- /dev/null
@@ -0,0 +1,855 @@
+/*
+ * rfd_ftl.c -- resident flash disk (flash translation layer)
+ *
+ * Copyright (C) 2005  Sean Young <sean@mess.org>
+ *
+ * $Id: rfd_ftl.c,v 1.5 2005/11/07 11:14:21 gleixner Exp $
+ *
+ * This type of flash translation layer (FTL) is used by the Embedded BIOS
+ * by General Software. It is known as the Resident Flash Disk (RFD), see:
+ *
+ *     http://www.gensw.com/pages/prod/bios/rfd.htm
+ *
+ * based on ftl.c
+ */
+
+#include <linux/hdreg.h>
+#include <linux/init.h>
+#include <linux/mtd/blktrans.h>
+#include <linux/mtd/mtd.h>
+#include <linux/vmalloc.h>
+
+#include <asm/types.h>
+
+#define const_cpu_to_le16      __constant_cpu_to_le16
+
+static int block_size = 0;
+module_param(block_size, int, 0);
+MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size");
+
+#define PREFIX "rfd_ftl: "
+
+/* Major device # for FTL device */
+
+/* A request for this major has been sent to device@lanana.org */
+#ifndef RFD_FTL_MAJOR
+#define RFD_FTL_MAJOR          95
+#endif
+
+/* Maximum number of partitions in an FTL region */
+#define PART_BITS              4
+
+/* An erase unit should start with this value */
+#define RFD_MAGIC              0x9193
+
+/* the second value is 0xffff or 0xffc8; function unknown */
+
+/* the third value is always 0xffff, ignored */
+
+/* next is an array of mapping for each corresponding sector */
+#define HEADER_MAP_OFFSET      3
+#define SECTOR_DELETED         0x0000
+#define SECTOR_ZERO            0xfffe
+#define SECTOR_FREE            0xffff
+
+#define SECTOR_SIZE            512
+
+#define SECTORS_PER_TRACK      63
+
+struct block {
+       enum {
+               BLOCK_OK,
+               BLOCK_ERASING,
+               BLOCK_ERASED,
+               BLOCK_FAILED
+       } state;
+       int free_sectors;
+       int used_sectors;
+       int erases;
+       u_long offset;
+};
+
+struct partition {
+       struct mtd_blktrans_dev mbd;
+
+       u_int block_size;               /* size of erase unit */
+       u_int total_blocks;             /* number of erase units */
+       u_int header_sectors_per_block; /* header sectors in erase unit */
+       u_int data_sectors_per_block;   /* data sectors in erase unit */
+       u_int sector_count;             /* sectors in translated disk */
+       u_int header_size;              /* bytes in header sector */
+       int reserved_block;             /* block next up for reclaim */
+       int current_block;              /* block to write to */
+       u16 *header_cache;              /* cached header */
+
+       int is_reclaiming;
+       int cylinders;
+       int errors;
+       u_long *sector_map;
+       struct block *blocks;
+};
+
+static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf);
+
+static int build_block_map(struct partition *part, int block_no)
+{
+       struct block *block = &part->blocks[block_no];
+       int i;
+
+       block->offset = part->block_size * block_no;
+
+       if (le16_to_cpu(part->header_cache[0]) != RFD_MAGIC) {
+               block->state = BLOCK_ERASED; /* assumption */
+               block->free_sectors = part->data_sectors_per_block;
+               part->reserved_block = block_no;
+               return 1;
+       }
+
+       block->state = BLOCK_OK;
+
+       for (i=0; i<part->data_sectors_per_block; i++) {
+               u16 entry;
+
+               entry = le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i]);
+
+               if (entry == SECTOR_DELETED)
+                       continue;
+
+               if (entry == SECTOR_FREE) {
+                       block->free_sectors++;
+                       continue;
+               }
+
+               if (entry == SECTOR_ZERO)
+                       entry = 0;
+
+               if (entry >= part->sector_count) {
+                       printk(KERN_NOTICE PREFIX
+                               "'%s': unit #%d: entry %d corrupt, "
+                               "sector %d out of range\n",
+                               part->mbd.mtd->name, block_no, i, entry);
+                       continue;
+               }
+
+               if (part->sector_map[entry] != -1) {
+                       printk(KERN_NOTICE PREFIX
+                               "'%s': more than one entry for sector %d\n",
+                               part->mbd.mtd->name, entry);
+                       part->errors = 1;
+                       continue;
+               }
+
+               part->sector_map[entry] = block->offset +
+                       (i + part->header_sectors_per_block) * SECTOR_SIZE;
+
+               block->used_sectors++;
+       }
+
+       if (block->free_sectors == part->data_sectors_per_block)
+               part->reserved_block = block_no;
+
+       return 0;
+}
+
+static int scan_header(struct partition *part)
+{
+       int sectors_per_block;
+       int i, rc = -ENOMEM;
+       int blocks_found;
+       size_t retlen;
+
+       sectors_per_block = part->block_size / SECTOR_SIZE;
+       part->total_blocks = part->mbd.mtd->size / part->block_size;
+
+       if (part->total_blocks < 2)
+               return -ENOENT;
+
+       /* each erase block has three bytes header, followed by the map */
+       part->header_sectors_per_block =
+                       ((HEADER_MAP_OFFSET + sectors_per_block) *
+                       sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE;
+
+       part->data_sectors_per_block = sectors_per_block -
+                       part->header_sectors_per_block;
+
+       part->header_size = (HEADER_MAP_OFFSET +
+                       part->data_sectors_per_block) * sizeof(u16);
+
+       part->cylinders = (part->data_sectors_per_block *
+                       (part->total_blocks - 1) - 1) / SECTORS_PER_TRACK;
+
+       part->sector_count = part->cylinders * SECTORS_PER_TRACK;
+
+       part->current_block = -1;
+       part->reserved_block = -1;
+       part->is_reclaiming = 0;
+
+       part->header_cache = kmalloc(part->header_size, GFP_KERNEL);
+       if (!part->header_cache)
+               goto err;
+
+       part->blocks = kcalloc(part->total_blocks, sizeof(struct block),
+                       GFP_KERNEL);
+       if (!part->blocks)
+               goto err;
+
+       part->sector_map = vmalloc(part->sector_count * sizeof(u_long));
+       if (!part->sector_map) {
+               printk(KERN_ERR PREFIX "'%s': unable to allocate memory for "
+                       "sector map", part->mbd.mtd->name);
+               goto err;
+       }
+
+       for (i=0; i<part->sector_count; i++)
+               part->sector_map[i] = -1;
+
+       for (i=0, blocks_found=0; i<part->total_blocks; i++) {
+               rc = part->mbd.mtd->read(part->mbd.mtd,
+                               i * part->block_size, part->header_size,
+                               &retlen, (u_char*)part->header_cache);
+
+               if (!rc && retlen != part->header_size)
+                       rc = -EIO;
+
+               if (rc)
+                       goto err;
+
+               if (!build_block_map(part, i))
+                       blocks_found++;
+       }
+
+       if (blocks_found == 0) {
+               printk(KERN_NOTICE PREFIX "no RFD magic found in '%s'\n",
+                               part->mbd.mtd->name);
+               rc = -ENOENT;
+               goto err;
+       }
+
+       if (part->reserved_block == -1) {
+               printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n",
+                               part->mbd.mtd->name);
+
+               part->errors = 1;
+       }
+
+       return 0;
+
+err:
+       vfree(part->sector_map);
+       kfree(part->header_cache);
+       kfree(part->blocks);
+
+       return rc;
+}
+
+static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *buf)
+{
+       struct partition *part = (struct partition*)dev;
+       u_long addr;
+       size_t retlen;
+       int rc;
+
+       if (sector >= part->sector_count)
+               return -EIO;
+
+       addr = part->sector_map[sector];
+       if (addr != -1) {
+               rc = part->mbd.mtd->read(part->mbd.mtd, addr, SECTOR_SIZE,
+                                               &retlen, (u_char*)buf);
+               if (!rc && retlen != SECTOR_SIZE)
+                       rc = -EIO;
+
+               if (rc) {
+                       printk(KERN_WARNING PREFIX "error reading '%s' at "
+                               "0x%lx\n", part->mbd.mtd->name, addr);
+                       return rc;
+               }
+       } else
+               memset(buf, 0, SECTOR_SIZE);
+
+       return 0;
+}
+
+static void erase_callback(struct erase_info *erase)
+{
+       struct partition *part;
+       u16 magic;
+       int i, rc;
+       size_t retlen;
+
+       part = (struct partition*)erase->priv;
+
+       i = erase->addr / part->block_size;
+       if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) {
+               printk(KERN_ERR PREFIX "erase callback for unknown offset %x "
+                               "on '%s'\n", erase->addr, part->mbd.mtd->name);
+               return;
+       }
+
+       if (erase->state != MTD_ERASE_DONE) {
+               printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', "
+                               "state %d\n", erase->addr,
+                               part->mbd.mtd->name, erase->state);
+
+               part->blocks[i].state = BLOCK_FAILED;
+               part->blocks[i].free_sectors = 0;
+               part->blocks[i].used_sectors = 0;
+
+               kfree(erase);
+
+               return;
+       }
+
+       magic = const_cpu_to_le16(RFD_MAGIC);
+
+       part->blocks[i].state = BLOCK_ERASED;
+       part->blocks[i].free_sectors = part->data_sectors_per_block;
+       part->blocks[i].used_sectors = 0;
+       part->blocks[i].erases++;
+
+       rc = part->mbd.mtd->write(part->mbd.mtd,
+               part->blocks[i].offset, sizeof(magic), &retlen,
+               (u_char*)&magic);
+
+       if (!rc && retlen != sizeof(magic))
+               rc = -EIO;
+
+       if (rc) {
+               printk(KERN_NOTICE PREFIX "'%s': unable to write RFD "
+                               "header at 0x%lx\n",
+                               part->mbd.mtd->name,
+                               part->blocks[i].offset);
+               part->blocks[i].state = BLOCK_FAILED;
+       }
+       else
+               part->blocks[i].state = BLOCK_OK;
+
+       kfree(erase);
+}
+
+static int erase_block(struct partition *part, int block)
+{
+       struct erase_info *erase;
+       int rc = -ENOMEM;
+
+       erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
+       if (!erase)
+               goto err;
+
+       erase->mtd = part->mbd.mtd;
+       erase->callback = erase_callback;
+       erase->addr = part->blocks[block].offset;
+       erase->len = part->block_size;
+       erase->priv = (u_long)part;
+
+       part->blocks[block].state = BLOCK_ERASING;
+       part->blocks[block].free_sectors = 0;
+
+       rc = part->mbd.mtd->erase(part->mbd.mtd, erase);
+
+       if (rc) {
+               printk(KERN_WARNING PREFIX "erase of region %x,%x on '%s' "
+                               "failed\n", erase->addr, erase->len,
+                               part->mbd.mtd->name);
+               kfree(erase);
+       }
+
+err:
+       return rc;
+}
+
+static int move_block_contents(struct partition *part, int block_no, u_long *old_sector)
+{
+       void *sector_data;
+       u16 *map;
+       size_t retlen;
+       int i, rc = -ENOMEM;
+
+       part->is_reclaiming = 1;
+
+       sector_data = kmalloc(SECTOR_SIZE, GFP_KERNEL);
+       if (!sector_data)
+               goto err3;
+
+       map = kmalloc(part->header_size, GFP_KERNEL);
+       if (!map)
+               goto err2;
+
+       rc = part->mbd.mtd->read(part->mbd.mtd,
+               part->blocks[block_no].offset, part->header_size,
+               &retlen, (u_char*)map);
+
+       if (!rc && retlen != part->header_size)
+               rc = -EIO;
+
+       if (rc) {
+               printk(KERN_NOTICE PREFIX "error reading '%s' at "
+                       "0x%lx\n", part->mbd.mtd->name,
+                       part->blocks[block_no].offset);
+
+               goto err;
+       }
+
+       for (i=0; i<part->data_sectors_per_block; i++) {
+               u16 entry = le16_to_cpu(map[HEADER_MAP_OFFSET + i]);
+               u_long addr;
+
+
+               if (entry == SECTOR_FREE || entry == SECTOR_DELETED)
+                       continue;
+
+               if (entry == SECTOR_ZERO)
+                       entry = 0;
+
+               /* already warned about and ignored in build_block_map() */
+               if (entry >= part->sector_count)
+                       continue;
+
+               addr = part->blocks[block_no].offset +
+                       (i + part->header_sectors_per_block) * SECTOR_SIZE;
+
+               if (*old_sector == addr) {
+                       *old_sector = -1;
+                       if (!part->blocks[block_no].used_sectors--) {
+                               rc = erase_block(part, block_no);
+                               break;
+                       }
+                       continue;
+               }
+               rc = part->mbd.mtd->read(part->mbd.mtd, addr,
+                       SECTOR_SIZE, &retlen, sector_data);
+
+               if (!rc && retlen != SECTOR_SIZE)
+                       rc = -EIO;
+
+               if (rc) {
+                       printk(KERN_NOTICE PREFIX "'%s': Unable to "
+                               "read sector for relocation\n",
+                               part->mbd.mtd->name);
+
+                       goto err;
+               }
+
+               rc = rfd_ftl_writesect((struct mtd_blktrans_dev*)part,
+                               entry, sector_data);
+
+               if (rc)
+                       goto err;
+       }
+
+err:
+       kfree(map);
+err2:
+       kfree(sector_data);
+err3:
+       part->is_reclaiming = 0;
+
+       return rc;
+}
+
+static int reclaim_block(struct partition *part, u_long *old_sector)
+{
+       int block, best_block, score, old_sector_block;
+       int rc;
+
+       /* we have a race if sync doesn't exist */
+       if (part->mbd.mtd->sync)
+               part->mbd.mtd->sync(part->mbd.mtd);
+
+       score = 0x7fffffff; /* MAX_INT */
+       best_block = -1;
+       if (*old_sector != -1)
+               old_sector_block = *old_sector / part->block_size;
+       else
+               old_sector_block = -1;
+
+       for (block=0; block<part->total_blocks; block++) {
+               int this_score;
+
+               if (block == part->reserved_block)
+                       continue;
+
+               /*
+                * Postpone reclaiming if there is a free sector as
+                * more removed sectors is more efficient (have to move
+                * less).
+                */
+               if (part->blocks[block].free_sectors)
+                       return 0;
+
+               this_score = part->blocks[block].used_sectors;
+
+               if (block == old_sector_block)
+                       this_score--;
+               else {
+                       /* no point in moving a full block */
+                       if (part->blocks[block].used_sectors ==
+                                       part->data_sectors_per_block)
+                               continue;
+               }
+
+               this_score += part->blocks[block].erases;
+
+               if (this_score < score) {
+                       best_block = block;
+                       score = this_score;
+               }
+       }
+
+       if (best_block == -1)
+               return -ENOSPC;
+
+       part->current_block = -1;
+       part->reserved_block = best_block;
+
+       pr_debug("reclaim_block: reclaiming block #%d with %d used "
+                "%d free sectors\n", best_block,
+                part->blocks[best_block].used_sectors,
+                part->blocks[best_block].free_sectors);
+
+       if (part->blocks[best_block].used_sectors)
+               rc = move_block_contents(part, best_block, old_sector);
+       else
+               rc = erase_block(part, best_block);
+
+       return rc;
+}
+
+/*
+ * IMPROVE: It would be best to choose the block with the most deleted sectors,
+ * because if we fill that one up first it'll have the most chance of having
+ * the least live sectors at reclaim.
+ */
+static int find_free_block(const struct partition *part)
+{
+       int block, stop;
+
+       block = part->current_block == -1 ?
+                       jiffies % part->total_blocks : part->current_block;
+       stop = block;
+
+       do {
+               if (part->blocks[block].free_sectors &&
+                               block != part->reserved_block)
+                       return block;
+
+               if (++block >= part->total_blocks)
+                       block = 0;
+
+       } while (block != stop);
+
+       return -1;
+}
+
+static int find_writeable_block(struct partition *part, u_long *old_sector)
+{
+       int rc, block;
+       size_t retlen;
+
+       block = find_free_block(part);
+
+       if (block == -1) {
+               if (!part->is_reclaiming) {
+                       rc = reclaim_block(part, old_sector);
+                       if (rc)
+                               goto err;
+
+                       block = find_free_block(part);
+               }
+
+               if (block == -1) {
+                       rc = -ENOSPC;
+                       goto err;
+               }
+       }
+
+       rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset,
+               part->header_size, &retlen, (u_char*)part->header_cache);
+
+       if (!rc && retlen != part->header_size)
+               rc = -EIO;
+
+       if (rc) {
+               printk(KERN_NOTICE PREFIX "'%s': unable to read header at "
+                               "0x%lx\n", part->mbd.mtd->name,
+                               part->blocks[block].offset);
+               goto err;
+       }
+
+       part->current_block = block;
+
+err:
+       return rc;
+}
+
+static int mark_sector_deleted(struct partition *part, u_long old_addr)
+{
+       int block, offset, rc;
+       u_long addr;
+       size_t retlen;
+       u16 del = const_cpu_to_le16(SECTOR_DELETED);
+
+       block = old_addr / part->block_size;
+       offset = (old_addr % part->block_size) / SECTOR_SIZE -
+               part->header_sectors_per_block;
+
+       addr = part->blocks[block].offset +
+                       (HEADER_MAP_OFFSET + offset) * sizeof(u16);
+       rc = part->mbd.mtd->write(part->mbd.mtd, addr,
+               sizeof(del), &retlen, (u_char*)&del);
+
+       if (!rc && retlen != sizeof(del))
+               rc = -EIO;
+
+       if (rc) {
+               printk(KERN_WARNING PREFIX "error writing '%s' at "
+                       "0x%lx\n", part->mbd.mtd->name, addr);
+               if (rc)
+                       goto err;
+       }
+       if (block == part->current_block)
+               part->header_cache[offset + HEADER_MAP_OFFSET] = del;
+
+       part->blocks[block].used_sectors--;
+
+       if (!part->blocks[block].used_sectors &&
+           !part->blocks[block].free_sectors)
+               rc = erase_block(part, block);
+
+err:
+       return rc;
+}
+
+static int find_free_sector(const struct partition *part, const struct block *block)
+{
+       int i, stop;
+
+       i = stop = part->data_sectors_per_block - block->free_sectors;
+
+       do {
+               if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i])
+                               == SECTOR_FREE)
+                       return i;
+
+               if (++i == part->data_sectors_per_block)
+                       i = 0;
+       }
+       while(i != stop);
+
+       return -1;
+}
+
+static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ulong *old_addr)
+{
+       struct partition *part = (struct partition*)dev;
+       struct block *block;
+       u_long addr;
+       int i;
+       int rc;
+       size_t retlen;
+       u16 entry;
+
+       if (part->current_block == -1 ||
+               !part->blocks[part->current_block].free_sectors) {
+
+               rc = find_writeable_block(part, old_addr);
+               if (rc)
+                       goto err;
+       }
+
+       block = &part->blocks[part->current_block];
+
+       i = find_free_sector(part, block);
+
+       if (i < 0) {
+               rc = -ENOSPC;
+               goto err;
+       }
+
+       addr = (i + part->header_sectors_per_block) * SECTOR_SIZE +
+               block->offset;
+       rc = part->mbd.mtd->write(part->mbd.mtd,
+               addr, SECTOR_SIZE, &retlen, (u_char*)buf);
+
+       if (!rc && retlen != SECTOR_SIZE)
+               rc = -EIO;
+
+       if (rc) {
+               printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n",
+                               part->mbd.mtd->name, addr);
+               if (rc)
+                       goto err;
+       }
+
+       part->sector_map[sector] = addr;
+
+       entry = cpu_to_le16(sector == 0 ? SECTOR_ZERO : sector);
+
+       part->header_cache[i + HEADER_MAP_OFFSET] = entry;
+
+       addr = block->offset + (HEADER_MAP_OFFSET + i) * sizeof(u16);
+       rc = part->mbd.mtd->write(part->mbd.mtd, addr,
+                       sizeof(entry), &retlen, (u_char*)&entry);
+
+       if (!rc && retlen != sizeof(entry))
+               rc = -EIO;
+
+       if (rc) {
+               printk(KERN_WARNING PREFIX "error writing '%s' at 0x%lx\n",
+                               part->mbd.mtd->name, addr);
+               if (rc)
+                       goto err;
+       }
+       block->used_sectors++;
+       block->free_sectors--;
+
+err:
+       return rc;
+}
+
+static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf)
+{
+       struct partition *part = (struct partition*)dev;
+       u_long old_addr;
+       int i;
+       int rc = 0;
+
+       pr_debug("rfd_ftl_writesect(sector=0x%lx)\n", sector);
+
+       if (part->reserved_block == -1) {
+               rc = -EACCES;
+               goto err;
+       }
+
+       if (sector >= part->sector_count) {
+               rc = -EIO;
+               goto err;
+       }
+
+       old_addr = part->sector_map[sector];
+
+       for (i=0; i<SECTOR_SIZE; i++) {
+               if (!buf[i])
+                       continue;
+
+               rc = do_writesect(dev, sector, buf, &old_addr);
+               if (rc)
+                       goto err;
+               break;
+       }
+
+       if (i == SECTOR_SIZE)
+               part->sector_map[sector] = -1;
+
+       if (old_addr != -1)
+               rc = mark_sector_deleted(part, old_addr);
+
+err:
+       return rc;
+}
+
+static int rfd_ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
+{
+       struct partition *part = (struct partition*)dev;
+
+       geo->heads = 1;
+       geo->sectors = SECTORS_PER_TRACK;
+       geo->cylinders = part->cylinders;
+
+       return 0;
+}
+
+static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
+{
+       struct partition *part;
+
+       if (mtd->type != MTD_NORFLASH)
+               return;
+
+       part = kcalloc(1, sizeof(struct partition), GFP_KERNEL);
+       if (!part)
+               return;
+
+       part->mbd.mtd = mtd;
+
+       if (block_size)
+               part->block_size = block_size;
+       else {
+               if (!mtd->erasesize) {
+                       printk(KERN_NOTICE PREFIX "please provide block_size");
+                       return;
+               }
+               else
+                       part->block_size = mtd->erasesize;
+       }
+
+       if (scan_header(part) == 0) {
+               part->mbd.size = part->sector_count;
+               part->mbd.blksize = SECTOR_SIZE;
+               part->mbd.tr = tr;
+               part->mbd.devnum = -1;
+               if (!(mtd->flags & MTD_WRITEABLE))
+                       part->mbd.readonly = 1;
+               else if (part->errors) {
+                       printk(KERN_NOTICE PREFIX "'%s': errors found, "
+                                       "setting read-only", mtd->name);
+                       part->mbd.readonly = 1;
+               }
+
+               printk(KERN_INFO PREFIX "name: '%s' type: %d flags %x\n",
+                               mtd->name, mtd->type, mtd->flags);
+
+               if (!add_mtd_blktrans_dev((void*)part))
+                       return;
+       }
+
+       kfree(part);
+}
+
+static void rfd_ftl_remove_dev(struct mtd_blktrans_dev *dev)
+{
+       struct partition *part = (struct partition*)dev;
+       int i;
+
+       for (i=0; i<part->total_blocks; i++) {
+               pr_debug("rfd_ftl_remove_dev:'%s': erase unit #%02d: %d erases\n",
+                       part->mbd.mtd->name, i, part->blocks[i].erases);
+       }
+
+       del_mtd_blktrans_dev(dev);
+       vfree(part->sector_map);
+       kfree(part->header_cache);
+       kfree(part->blocks);
+       kfree(part);
+}
+
+struct mtd_blktrans_ops rfd_ftl_tr = {
+       .name           = "rfd",
+       .major          = RFD_FTL_MAJOR,
+       .part_bits      = PART_BITS,
+       .readsect       = rfd_ftl_readsect,
+       .writesect      = rfd_ftl_writesect,
+       .getgeo         = rfd_ftl_getgeo,
+       .add_mtd        = rfd_ftl_add_mtd,
+       .remove_dev     = rfd_ftl_remove_dev,
+       .owner          = THIS_MODULE,
+};
+
+static int __init init_rfd_ftl(void)
+{
+       return register_mtd_blktrans(&rfd_ftl_tr);
+}
+
+static void __exit cleanup_rfd_ftl(void)
+{
+       deregister_mtd_blktrans(&rfd_ftl_tr);
+}
+
+module_init(init_rfd_ftl);
+module_exit(cleanup_rfd_ftl);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_DESCRIPTION("Support code for RFD Flash Translation Layer, "
+               "used by General Software's Embedded BIOS");
+
index 7cf36ca157ffed120b4e9a3ec771725964ea245d..7d6ae369ce4404600489c238908087774bb424d1 100644 (file)
@@ -1051,6 +1051,19 @@ config JFFS2_FS_WRITEBUFFER
            - NOR flash with transparent ECC
            - DataFlash
 
+config JFFS2_SUMMARY
+       bool "JFFS2 summary support (EXPERIMENTAL)"
+       depends on JFFS2_FS && EXPERIMENTAL
+       default n
+       help
+         This feature makes it possible to use summary information
+         for faster filesystem mount.
+
+         The summary information can be inserted into a filesystem image
+         by the utility 'sumtool'.
+
+         If unsure, say 'N'.
+
 config JFFS2_COMPRESSION_OPTIONS
        bool "Advanced compression options for JFFS2"
        depends on JFFS2_FS
@@ -1072,10 +1085,10 @@ config JFFS2_ZLIB
        default y
         help
           Zlib is designed to be a free, general-purpose, legally unencumbered,
-          lossless data-compression library for use on virtually any computer 
+          lossless data-compression library for use on virtually any computer
           hardware and operating system. See <http://www.gzip.org/zlib/> for
           further information.
-          
+
           Say 'Y' if unsure.
 
 config JFFS2_RTIME
@@ -1097,7 +1110,7 @@ choice
         default JFFS2_CMODE_PRIORITY
         depends on JFFS2_FS
         help
-          You can set here the default compression mode of JFFS2 from 
+          You can set here the default compression mode of JFFS2 from
           the available compression modes. Don't touch if unsure.
 
 config JFFS2_CMODE_NONE
@@ -1108,13 +1121,13 @@ config JFFS2_CMODE_NONE
 config JFFS2_CMODE_PRIORITY
         bool "priority"
         help
-          Tries the compressors in a predefinied order and chooses the first 
+          Tries the compressors in a predefinied order and chooses the first
           successful one.
 
 config JFFS2_CMODE_SIZE
         bool "size (EXPERIMENTAL)"
         help
-          Tries all compressors and chooses the one which has the smallest 
+          Tries all compressors and chooses the one which has the smallest
           result.
 
 endchoice
index f1afe681ecd6a950f685476905b24b0e164a881e..77dc5561a04e7def0490e1fa3af3634945726bf0 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux Journalling Flash File System v2 (JFFS2)
 #
-# $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $
+# $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $
 #
 
 obj-$(CONFIG_JFFS2_FS) += jffs2.o
@@ -9,9 +9,10 @@ obj-$(CONFIG_JFFS2_FS) += jffs2.o
 jffs2-y        := compr.o dir.o file.o ioctl.o nodelist.o malloc.o
 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-y        += super.o debug.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
+jffs2-$(CONFIG_JFFS2_SUMMARY)   += summary.o
index 2bff82fd221f7095aa691305382a21b2f346a79e..d0e23b26fa505a0c47a8a2e09cfef039016fc8fc 100644 (file)
@@ -1,5 +1,11 @@
-$Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $
+$Id: TODO,v 1.18 2005/09/22 11:24:56 dedekind Exp $
 
+ - support asynchronous operation -- add a per-fs 'reserved_space' count,
+   let each outstanding write reserve the _maximum_ amount of physical
+   space it could take. Let GC flush the outstanding writes because the
+   reservations will necessarily be pessimistic. With this we could even
+   do shared writable mmap, if we can have a fs hook for do_wp_page() to
+   make the reservation.
  - disable compression in commit_write()?
  - fine-tune the allocation / GC thresholds
  - chattr support - turning on/off and tuning compression per-inode
@@ -11,26 +17,15 @@ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $
  - test, test, test
 
  - NAND flash support:
-       - flush_wbuf using GC to fill it, don't just pad.
-       - Deal with write errors. Data don't get lost - we just have to write 
-         the affected node(s) out again somewhere else.
-       - make fsync flush only if actually required
-       - make sys_sync() work.
-       - reboot notifier
-       - timed flush of old wbuf
-       - fix magical second arg of jffs2_flush_wbuf(). Split into two or more functions instead.
-
+       - almost done :)
+       - use bad block check instead of the hardwired byte check
 
  - Optimisations:
-   - Stop GC from decompressing and immediately recompressing nodes which could
-     just be copied intact. (We now keep track of REF_PRISTINE flag. Easy now.)
-   - Furthermore, in the case where it could be copied intact we don't even need
-     to call iget() for it -- if we use (raw_node_raw->flash_offset & 2) as a flag
-     to show a node can be copied intact and it's _not_ in icache, we could just do
-     it, fix up the next_in_ino list and move on. We would need a way to find out
-     _whether_ it's in icache though -- if it's in icache we also need to do the 
-     fragment lists, etc. P'raps a flag or pointer in the jffs2_inode_cache could
-     help. (We have half of this now.)
+   - Split writes so they go to two separate blocks rather than just c->nextblock.
+       By writing _new_ nodes to one block, and garbage-collected REF_PRISTINE
+       nodes to a different one, we can separate clean nodes from those which
+       are likely to become dirty, and end up with blocks which are each far
+       closer to 100% or 0% clean, hence speeding up later GC progress dramatically.
    - Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in 
      the full dirent, we only need to go to the flash in lookup() when we think we've
      got a match, and in readdir(). 
@@ -38,3 +33,8 @@ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $
    - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into
        jffs2_mark_node_obsolete(). Can all callers work it out?
    - Remove size from jffs2_raw_node_frag. 
+
+dedekind:
+1. __jffs2_flush_wbuf() has a strange 'pad' parameter. Eliminate.
+2. get_sb()->build_fs()->scan() path... Why get_sb() removes scan()'s crap in
+   case of failure? scan() does not clean everything. Fix.
index 8210ac16a36827df97a8ae43e04a4efe979892a7..7b77a9541125b7b62aa01d0cf3961f45cb1ca47c 100644 (file)
@@ -51,7 +51,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
                D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid));
                wait_for_completion(&c->gc_thread_start);
        }
+
        return ret;
 }
 
@@ -101,7 +101,7 @@ static int jffs2_garbage_collect_thread(void *_c)
 
                cond_resched();
 
-               /* Put_super will send a SIGKILL and then wait on the sem. 
+               /* Put_super will send a SIGKILL and then wait on the sem.
                 */
                while (signal_pending(current)) {
                        siginfo_t info;
index 97dc39796e2cc1f59aa4ad2edea8d275e93a4be3..fff108bb118b14db6a4ca927b62320a4cf4f2b19 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: build.c,v 1.71 2005/07/12 16:37:08 dedekind Exp $
+ * $Id: build.c,v 1.85 2005/11/07 11:14:38 gleixner Exp $
  *
  */
 
@@ -18,7 +18,8 @@
 #include <linux/mtd/mtd.h>
 #include "nodelist.h"
 
-static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **);
+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *,
+               struct jffs2_inode_cache *, struct jffs2_full_dirent **);
 
 static inline struct jffs2_inode_cache *
 first_inode_chain(int *i, struct jffs2_sb_info *c)
@@ -46,11 +47,12 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
             ic = next_inode(&i, ic, (c)))
 
 
-static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
+                                       struct jffs2_inode_cache *ic)
 {
        struct jffs2_full_dirent *fd;
 
-       D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino));
+       dbg_fsbuild("building directory inode #%u\n", ic->ino);
 
        /* For each child, increase nlink */
        for(fd = ic->scan_dents; fd; fd = fd->next) {
@@ -58,26 +60,23 @@ static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2
                if (!fd->ino)
                        continue;
 
-               /* XXX: Can get high latency here with huge directories */
+               /* we can get high latency here with huge directories */
 
                child_ic = jffs2_get_ino_cache(c, fd->ino);
                if (!child_ic) {
-                       printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
+                       dbg_fsbuild("child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
                                  fd->name, fd->ino, ic->ino);
                        jffs2_mark_node_obsolete(c, fd->raw);
                        continue;
                }
 
                if (child_ic->nlink++ && fd->type == DT_DIR) {
-                       printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
-                       if (fd->ino == 1 && ic->ino == 1) {
-                               printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
-                               printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
-                       }
-                       /* What do we do about it? */
+                       JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
+                               fd->name, fd->ino, ic->ino);
+                       /* TODO: What do we do about it? */
                }
-               D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
-               /* Can't free them. We might need them in pass 2 */
+               dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
+               /* Can't free scan_dents so far. We might need them in pass 2 */
        }
 }
 
@@ -94,6 +93,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        struct jffs2_full_dirent *fd;
        struct jffs2_full_dirent *dead_fds = NULL;
 
+       dbg_fsbuild("build FS data structures\n");
+
        /* First, scan the medium and build all the inode caches with
           lists of physical nodes */
 
@@ -103,60 +104,54 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        if (ret)
                goto exit;
 
-       D1(printk(KERN_DEBUG "Scanned flash completely\n"));
-       D2(jffs2_dump_block_lists(c));
+       dbg_fsbuild("scanned flash completely\n");
+       jffs2_dbg_dump_block_lists_nolock(c);
 
+       dbg_fsbuild("pass 1 starting\n");
        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));
-
-               D1(BUG_ON(ic->ino > c->highest_ino));
-
                if (ic->scan_dents) {
                        jffs2_build_inode_pass1(c, ic);
                        cond_resched();
                }
        }
 
-       D1(printk(KERN_DEBUG "Pass 1 complete\n"));
+       dbg_fsbuild("pass 1 complete\n");
 
        /* Next, scan for inodes with nlink == 0 and remove them. If
           they were directories, then decrement the nlink of their
           children too, and repeat the scan. As that's going to be
           a fairly uncommon occurrence, it's not so evil to do it this
           way. Recursion bad. */
-       D1(printk(KERN_DEBUG "Pass 2 starting\n"));
+       dbg_fsbuild("pass 2 starting\n");
 
        for_each_inode(i, c, ic) {
-               D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
                if (ic->nlink)
                        continue;
-                       
+
                jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
                cond_resched();
-       } 
+       }
 
-       D1(printk(KERN_DEBUG "Pass 2a starting\n"));
+       dbg_fsbuild("pass 2a starting\n");
 
        while (dead_fds) {
                fd = dead_fds;
                dead_fds = fd->next;
 
                ic = jffs2_get_ino_cache(c, fd->ino);
-               D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic));
 
                if (ic)
                        jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
                jffs2_free_full_dirent(fd);
        }
 
-       D1(printk(KERN_DEBUG "Pass 2 complete\n"));
-       
+       dbg_fsbuild("pass 2a complete\n");
+       dbg_fsbuild("freeing temporary data structures\n");
+
        /* Finally, we can scan again and free the dirent structs */
        for_each_inode(i, c, ic) {
-               D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
-
                while(ic->scan_dents) {
                        fd = ic->scan_dents;
                        ic->scan_dents = fd->next;
@@ -166,9 +161,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
                cond_resched();
        }
        c->flags &= ~JFFS2_SB_FLAG_BUILDING;
-       
-       D1(printk(KERN_DEBUG "Pass 3 complete\n"));
-       D2(jffs2_dump_block_lists(c));
+
+       dbg_fsbuild("FS build complete\n");
 
        /* Rotate the lists by some number to ensure wear levelling */
        jffs2_rotate_lists(c);
@@ -189,24 +183,26 @@ exit:
        return ret;
 }
 
-static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds)
+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
+                                       struct jffs2_inode_cache *ic,
+                                       struct jffs2_full_dirent **dead_fds)
 {
        struct jffs2_raw_node_ref *raw;
        struct jffs2_full_dirent *fd;
 
-       D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
-       
+       dbg_fsbuild("removing ino #%u with nlink == zero.\n", ic->ino);
+
        raw = ic->nodes;
        while (raw != (void *)ic) {
                struct jffs2_raw_node_ref *next = raw->next_in_ino;
-               D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw)));
+               dbg_fsbuild("obsoleting node at 0x%08x\n", ref_offset(raw));
                jffs2_mark_node_obsolete(c, raw);
                raw = next;
        }
 
        if (ic->scan_dents) {
                int whinged = 0;
-               D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino));
+               dbg_fsbuild("inode #%u was a directory which may have children...\n", ic->ino);
 
                while(ic->scan_dents) {
                        struct jffs2_inode_cache *child_ic;
@@ -216,45 +212,43 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jf
 
                        if (!fd->ino) {
                                /* It's a deletion dirent. Ignore it */
-                               D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name));
+                               dbg_fsbuild("child \"%s\" is a deletion dirent, skipping...\n", fd->name);
                                jffs2_free_full_dirent(fd);
                                continue;
                        }
-                       if (!whinged) {
+                       if (!whinged)
                                whinged = 1;
-                               printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
-                       }
 
-                       D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
-                                 fd->name, fd->ino));
-                       
+                       dbg_fsbuild("removing child \"%s\", ino #%u\n", fd->name, fd->ino);
+
                        child_ic = jffs2_get_ino_cache(c, fd->ino);
                        if (!child_ic) {
-                               printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
+                               dbg_fsbuild("cannot remove child \"%s\", ino #%u, because it doesn't exist\n",
+                                               fd->name, fd->ino);
                                jffs2_free_full_dirent(fd);
                                continue;
                        }
 
-                       /* Reduce nlink of the child. If it's now zero, stick it on the 
+                       /* Reduce nlink of the child. If it's now zero, stick it on the
                           dead_fds list to be cleaned up later. Else just free the fd */
 
                        child_ic->nlink--;
-                       
+
                        if (!child_ic->nlink) {
-                               D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n",
-                                         fd->ino, fd->name));
+                               dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n",
+                                         fd->ino, fd->name);
                                fd->next = *dead_fds;
                                *dead_fds = fd;
                        } else {
-                               D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
-                                         fd->ino, fd->name, child_ic->nlink));
+                               dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
+                                         fd->ino, fd->name, child_ic->nlink);
                                jffs2_free_full_dirent(fd);
                        }
                }
        }
 
        /*
-          We don't delete the inocache from the hash list and free it yet. 
+          We don't delete the inocache from the hash list and free it yet.
           The erase code will do that, when all the nodes are completely gone.
        */
 }
@@ -268,7 +262,7 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
           because there's not enough free space... */
        c->resv_blocks_deletion = 2;
 
-       /* Be conservative about how much space we need before we allow writes. 
+       /* Be conservative about how much space we need before we allow writes.
           On top of that which is required for deletia, require an extra 2%
           of the medium to be available, for overhead caused by nodes being
           split across blocks, etc. */
@@ -283,7 +277,7 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
 
        c->resv_blocks_gctrigger = c->resv_blocks_write + 1;
 
-       /* When do we allow garbage collection to merge nodes to make 
+       /* When do we allow garbage collection to merge nodes to make
           long-term progress at the expense of short-term space exhaustion? */
        c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1;
 
@@ -295,45 +289,45 @@ static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
           trying to GC to make more space. It'll be a fruitless task */
        c->nospc_dirty_size = c->sector_size + (c->flash_size / 100);
 
-       D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
-                 c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks));
-       D1(printk(KERN_DEBUG "Blocks required to allow deletion:    %d (%d KiB)\n",
-                 c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024));
-       D1(printk(KERN_DEBUG "Blocks required to allow writes:      %d (%d KiB)\n",
-                 c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024));
-       D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n",
-                 c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024));
-       D1(printk(KERN_DEBUG "Blocks required to allow GC merges:   %d (%d KiB)\n",
-                 c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024));
-       D1(printk(KERN_DEBUG "Blocks required to GC bad blocks:     %d (%d KiB)\n",
-                 c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024));
-       D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n",
-                 c->nospc_dirty_size));
-} 
+       dbg_fsbuild("JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n",
+                 c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks);
+       dbg_fsbuild("Blocks required to allow deletion:    %d (%d KiB)\n",
+                 c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024);
+       dbg_fsbuild("Blocks required to allow writes:      %d (%d KiB)\n",
+                 c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024);
+       dbg_fsbuild("Blocks required to quiesce GC thread: %d (%d KiB)\n",
+                 c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024);
+       dbg_fsbuild("Blocks required to allow GC merges:   %d (%d KiB)\n",
+                 c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024);
+       dbg_fsbuild("Blocks required to GC bad blocks:     %d (%d KiB)\n",
+                 c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024);
+       dbg_fsbuild("Amount of dirty space required to GC: %d bytes\n",
+                 c->nospc_dirty_size);
+}
 
 int jffs2_do_mount_fs(struct jffs2_sb_info *c)
 {
+       int ret;
        int i;
+       int size;
 
        c->free_size = c->flash_size;
        c->nr_blocks = c->flash_size / c->sector_size;
-       if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
-               c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks);
+       size = sizeof(struct jffs2_eraseblock) * c->nr_blocks;
+#ifndef __ECOS
+       if (jffs2_blocks_use_vmalloc(c))
+               c->blocks = vmalloc(size);
        else
-               c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
+#endif
+               c->blocks = kmalloc(size, GFP_KERNEL);
        if (!c->blocks)
                return -ENOMEM;
+
+       memset(c->blocks, 0, size);
        for (i=0; i<c->nr_blocks; i++) {
                INIT_LIST_HEAD(&c->blocks[i].list);
                c->blocks[i].offset = i * c->sector_size;
                c->blocks[i].free_size = c->sector_size;
-               c->blocks[i].dirty_size = 0;
-               c->blocks[i].wasted_size = 0;
-               c->blocks[i].unchecked_size = 0;
-               c->blocks[i].used_size = 0;
-               c->blocks[i].first_node = NULL;
-               c->blocks[i].last_node = NULL;
-               c->blocks[i].bad_count = 0;
        }
 
        INIT_LIST_HEAD(&c->clean_list);
@@ -348,16 +342,23 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
        INIT_LIST_HEAD(&c->bad_list);
        INIT_LIST_HEAD(&c->bad_used_list);
        c->highest_ino = 1;
+       c->summary = NULL;
+
+       ret = jffs2_sum_init(c);
+       if (ret)
+               return ret;
 
        if (jffs2_build_filesystem(c)) {
-               D1(printk(KERN_DEBUG "build_fs failed\n"));
+               dbg_fsbuild("build_fs failed\n");
                jffs2_free_ino_caches(c);
                jffs2_free_raw_node_refs(c);
-               if (c->mtd->flags & MTD_NO_VIRTBLOCKS) {
+#ifndef __ECOS
+               if (jffs2_blocks_use_vmalloc(c))
                        vfree(c->blocks);
-               } else {
+               else
+#endif
                        kfree(c->blocks);
-               }
+
                return -EIO;
        }
 
index af922a9618ac0af62795addcc1e7cdfd990e134f..e7944e665b9fc9245135c0c455b959f47cc721a3 100644 (file)
@@ -9,7 +9,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.42 2004/08/07 21:56:08 dwmw2 Exp $
+ * $Id: compr.c,v 1.46 2005/11/07 11:14:38 gleixner Exp $
  *
  */
 
@@ -36,16 +36,16 @@ static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_co
  *     data.
  *
  * Returns: Lower byte to be stored with data indicating compression type used.
- * Zero is used to show that the data could not be compressed - the 
+ * Zero is used to show that the data could not be compressed - the
  * compressed version was actually larger than the original.
  * Upper byte will be used later. (soon)
  *
  * If the cdata buffer isn't large enough to hold all the uncompressed data,
- * jffs2_compress should compress as much as will fit, and should set 
+ * jffs2_compress should compress as much as will fit, and should set
  * *datalen accordingly to show the amount of data which were compressed.
  */
 uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                            unsigned char *data_in, unsigned char **cpage_out, 
+                            unsigned char *data_in, unsigned char **cpage_out,
                             uint32_t *datalen, uint32_t *cdatalen)
 {
        int ret = JFFS2_COMPR_NONE;
@@ -164,7 +164,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 }
 
 int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                    uint16_t comprtype, unsigned char *cdata_in, 
+                    uint16_t comprtype, unsigned char *cdata_in,
                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
 {
         struct jffs2_compressor *this;
@@ -298,7 +298,7 @@ char *jffs2_stats(void)
 
         act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n");
         act_buf += sprintf(act_buf,"%10s   ","none");
-        act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks, 
+        act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks,
                            none_stat_compr_size, none_stat_decompr_blocks);
         spin_lock(&jffs2_compressor_list_lock);
         list_for_each_entry(this, &jffs2_compressor_list, list) {
@@ -307,8 +307,8 @@ char *jffs2_stats(void)
                         act_buf += sprintf(act_buf,"- ");
                 else
                         act_buf += sprintf(act_buf,"+ ");
-                act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks, 
-                                   this->stat_compr_new_size, this->stat_compr_orig_size, 
+                act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks,
+                                   this->stat_compr_new_size, this->stat_compr_orig_size,
                                    this->stat_decompr_blocks);
                 act_buf += sprintf(act_buf,"\n");
         }
@@ -317,7 +317,7 @@ char *jffs2_stats(void)
         return buf;
 }
 
-char *jffs2_get_compression_mode_name(void) 
+char *jffs2_get_compression_mode_name(void)
 {
         switch (jffs2_compression_mode) {
         case JFFS2_COMPR_MODE_NONE:
@@ -330,7 +330,7 @@ char *jffs2_get_compression_mode_name(void)
         return "unkown";
 }
 
-int jffs2_set_compression_mode_name(const char *name) 
+int jffs2_set_compression_mode_name(const char *name)
 {
         if (!strcmp("none",name)) {
                 jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
@@ -355,7 +355,7 @@ static int jffs2_compressor_Xable(const char *name, int disabled)
                 if (!strcmp(this->name, name)) {
                         this->disabled = disabled;
                         spin_unlock(&jffs2_compressor_list_lock);
-                        return 0;                        
+                        return 0;
                 }
         }
         spin_unlock(&jffs2_compressor_list_lock);
@@ -385,7 +385,7 @@ int jffs2_set_compressor_priority(const char *name, int priority)
                 }
         }
         spin_unlock(&jffs2_compressor_list_lock);
-        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);        
+        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
         return 1;
 reinsert:
         /* list is sorted in the order of priority, so if
@@ -412,7 +412,7 @@ void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
                 kfree(comprbuf);
 }
 
-int jffs2_compressors_init(void) 
+int jffs2_compressors_init(void)
 {
 /* Registering compressors */
 #ifdef CONFIG_JFFS2_ZLIB
@@ -425,12 +425,6 @@ int jffs2_compressors_init(void)
         jffs2_rubinmips_init();
         jffs2_dynrubin_init();
 #endif
-#ifdef CONFIG_JFFS2_LZARI
-        jffs2_lzari_init();
-#endif
-#ifdef CONFIG_JFFS2_LZO
-        jffs2_lzo_init();
-#endif
 /* Setting default compression mode */
 #ifdef CONFIG_JFFS2_CMODE_NONE
         jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
@@ -446,15 +440,9 @@ int jffs2_compressors_init(void)
         return 0;
 }
 
-int jffs2_compressors_exit(void) 
+int jffs2_compressors_exit(void)
 {
 /* Unregistering compressors */
-#ifdef CONFIG_JFFS2_LZO
-        jffs2_lzo_exit();
-#endif
-#ifdef CONFIG_JFFS2_LZARI
-        jffs2_lzari_exit();
-#endif
 #ifdef CONFIG_JFFS2_RUBIN
         jffs2_dynrubin_exit();
         jffs2_rubinmips_exit();
index 89ceeed201eb8e5a00c745ed35d2196b3137fcd0..a77e830d85c5fb0cd230dba36670422554bcb398 100644 (file)
@@ -4,10 +4,10 @@
  * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
  *                    University of Szeged, Hungary
  *
- * For licensing information, see the file 'LICENCE' in the 
+ * For licensing information, see the file 'LICENCE' in the
  * jffs2 directory.
  *
- * $Id: compr.h,v 1.6 2004/07/16 15:17:57 dwmw2 Exp $
+ * $Id: compr.h,v 1.9 2005/11/07 11:14:38 gleixner Exp $
  *
  */
 
@@ -103,13 +103,5 @@ void jffs2_rtime_exit(void);
 int jffs2_zlib_init(void);
 void jffs2_zlib_exit(void);
 #endif
-#ifdef CONFIG_JFFS2_LZARI
-int jffs2_lzari_init(void);
-void jffs2_lzari_exit(void);
-#endif
-#ifdef CONFIG_JFFS2_LZO
-int jffs2_lzo_init(void);
-void jffs2_lzo_exit(void);
-#endif
 
 #endif /* __JFFS2_COMPR_H__ */
index 39312941866682e2627e2fd62d71b47650ae23f5..2eb1b7428d1628104cda0403ef1c1dbebcca3ee8 100644 (file)
@@ -24,8 +24,8 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/string.h> 
-#include <linux/jffs2.h> 
+#include <linux/string.h>
+#include <linux/jffs2.h>
 #include "compr.h"
 
 /* _compress returns the compressed size, -1 if bigger */
@@ -38,19 +38,19 @@ static int jffs2_rtime_compress(unsigned char *data_in,
        int outpos = 0;
        int pos=0;
 
-       memset(positions,0,sizeof(positions)); 
-       
+       memset(positions,0,sizeof(positions));
+
        while (pos < (*sourcelen) && outpos <= (*dstlen)-2) {
                int backpos, runlen=0;
                unsigned char value;
-               
+
                value = data_in[pos];
 
                cpage_out[outpos++] = data_in[pos++];
-               
+
                backpos = positions[value];
                positions[value]=pos;
-               
+
                while ((backpos < pos) && (pos < (*sourcelen)) &&
                       (data_in[pos]==data_in[backpos++]) && (runlen<255)) {
                        pos++;
@@ -63,12 +63,12 @@ static int jffs2_rtime_compress(unsigned char *data_in,
                /* We failed */
                return -1;
        }
-       
+
        /* Tell the caller how much we managed to compress, and how much space it took */
        *sourcelen = pos;
        *dstlen = outpos;
        return 0;
-}                 
+}
 
 
 static int jffs2_rtime_decompress(unsigned char *data_in,
@@ -79,19 +79,19 @@ static int jffs2_rtime_decompress(unsigned char *data_in,
        short positions[256];
        int outpos = 0;
        int pos=0;
-       
-       memset(positions,0,sizeof(positions)); 
-       
+
+       memset(positions,0,sizeof(positions));
+
        while (outpos<destlen) {
                unsigned char value;
                int backoffs;
                int repeat;
-               
+
                value = data_in[pos++];
                cpage_out[outpos++] = value; /* first the verbatim copied byte */
                repeat = data_in[pos++];
                backoffs = positions[value];
-               
+
                positions[value]=outpos;
                if (repeat) {
                        if (backoffs + repeat >= outpos) {
@@ -101,12 +101,12 @@ static int jffs2_rtime_decompress(unsigned char *data_in,
                                }
                        } else {
                                memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
-                               outpos+=repeat;         
+                               outpos+=repeat;
                        }
                }
        }
         return 0;
-}                 
+}
 
 static struct jffs2_compressor jffs2_rtime_comp = {
     .priority = JFFS2_RTIME_PRIORITY,
index 09422388fb96716681b151871144eed992b72be7..e792e675d624eecb5fcabfd4dc33cebf7c527bfa 100644 (file)
@@ -11,7 +11,6 @@
  *
  */
 
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/jffs2.h>
@@ -20,7 +19,7 @@
 #include "compr.h"
 
 static void init_rubin(struct rubin_state *rs, int div, int *bits)
-{      
+{
        int c;
 
        rs->q = 0;
@@ -40,7 +39,7 @@ static int encode(struct rubin_state *rs, long A, long B, int symbol)
 
        while ((rs->q >= UPPER_BIT_RUBIN) || ((rs->p + rs->q) <= UPPER_BIT_RUBIN)) {
                rs->bit_number++;
-               
+
                ret = pushbit(&rs->pp, (rs->q & UPPER_BIT_RUBIN) ? 1 : 0, 0);
                if (ret)
                        return ret;
@@ -68,7 +67,7 @@ static int encode(struct rubin_state *rs, long A, long B, int symbol)
 
 
 static void end_rubin(struct rubin_state *rs)
-{                              
+{
 
        int i;
 
@@ -82,7 +81,7 @@ static void end_rubin(struct rubin_state *rs)
 
 static void init_decode(struct rubin_state *rs, int div, int *bits)
 {
-       init_rubin(rs, div, bits);              
+       init_rubin(rs, div, bits);
 
        /* behalve lower */
        rs->rec_q = 0;
@@ -188,7 +187,7 @@ static int in_byte(struct rubin_state *rs)
 
 
 
-static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, 
+static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
                      unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen)
        {
        int outpos = 0;
@@ -198,31 +197,31 @@ static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
        init_pushpull(&rs.pp, cpage_out, *dstlen * 8, 0, 32);
 
        init_rubin(&rs, bit_divider, bits);
-       
+
        while (pos < (*sourcelen) && !out_byte(&rs, data_in[pos]))
                pos++;
-       
+
        end_rubin(&rs);
 
        if (outpos > pos) {
                /* We failed */
                return -1;
        }
-       
-       /* Tell the caller how much we managed to compress, 
+
+       /* Tell the caller how much we managed to compress,
         * and how much space it took */
-       
+
        outpos = (pushedbits(&rs.pp)+7)/8;
-       
+
        if (outpos >= pos)
                return -1; /* We didn't actually compress */
        *sourcelen = pos;
        *dstlen = outpos;
        return 0;
-}                 
+}
 #if 0
 /* _compress returns the compressed size, -1 if bigger */
-int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, 
+int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
                   uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
        return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
@@ -277,7 +276,7 @@ static int jffs2_dynrubin_compress(unsigned char *data_in,
        }
 
        ret = rubin_do_compress(256, bits, data_in, cpage_out+8, &mysrclen, &mydstlen);
-       if (ret) 
+       if (ret)
                return ret;
 
        /* Add back the 8 bytes we took for the probabilities */
@@ -293,19 +292,19 @@ static int jffs2_dynrubin_compress(unsigned char *data_in,
        return 0;
 }
 
-static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, 
+static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
                         unsigned char *page_out, uint32_t srclen, uint32_t destlen)
 {
        int outpos = 0;
        struct rubin_state rs;
-       
+
        init_pushpull(&rs.pp, cdata_in, srclen, 0, 0);
        init_decode(&rs, bit_divider, bits);
-       
+
        while (outpos < destlen) {
                page_out[outpos++] = in_byte(&rs);
        }
-}                 
+}
 
 
 static int jffs2_rubinmips_decompress(unsigned char *data_in,
index cf51e34f657458edb817015f1a093f86c8bb0e22..bf1a934516210608229241e14e1ace0329d9c0fa 100644 (file)
@@ -1,7 +1,7 @@
 /* Rubin encoder/decoder header       */
 /* work started at   : aug   3, 1994  */
 /* last modification : aug  15, 1994  */
-/* $Id: compr_rubin.h,v 1.6 2002/01/25 01:49:26 dwmw2 Exp $ */
+/* $Id: compr_rubin.h,v 1.7 2005/11/07 11:14:38 gleixner Exp $ */
 
 #include "pushpull.h"
 
@@ -11,8 +11,8 @@
 
 
 struct rubin_state {
-       unsigned long p;                
-       unsigned long q;        
+       unsigned long p;
+       unsigned long q;
        unsigned long rec_q;
        long bit_number;
        struct pushpull pp;
index 83f7e0788fd0a551ad715b2ad2ea380fa07d7a33..4db8be8e90cc09dea0f71d09d55048d612bbb17a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $
+ * $Id: compr_zlib.c,v 1.32 2005/11/07 11:14:38 gleixner Exp $
  *
  */
 
 #include "nodelist.h"
 #include "compr.h"
 
-       /* Plan: call deflate() with avail_in == *sourcelen, 
-               avail_out = *dstlen - 12 and flush == Z_FINISH. 
+       /* Plan: call deflate() with avail_in == *sourcelen,
+               avail_out = *dstlen - 12 and flush == Z_FINISH.
                If it doesn't manage to finish, call it again with
                avail_in == 0 and avail_out set to the remaining 12
-               bytes for it to clean up. 
+               bytes for it to clean up.
           Q: Is 12 bytes sufficient?
        */
 #define STREAM_END_SPACE 12
@@ -89,7 +89,7 @@ static int jffs2_zlib_compress(unsigned char *data_in,
 
        def_strm.next_in = data_in;
        def_strm.total_in = 0;
-       
+
        def_strm.next_out = cpage_out;
        def_strm.total_out = 0;
 
@@ -99,7 +99,7 @@ static int jffs2_zlib_compress(unsigned char *data_in,
                D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n",
                          def_strm.avail_in, def_strm.avail_out));
                ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH);
-               D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", 
+               D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n",
                          def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out));
                if (ret != Z_OK) {
                        D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret));
@@ -150,7 +150,7 @@ static int jffs2_zlib_decompress(unsigned char *data_in,
        inf_strm.next_in = data_in;
        inf_strm.avail_in = srclen;
        inf_strm.total_in = 0;
-       
+
        inf_strm.next_out = cpage_out;
        inf_strm.avail_out = destlen;
        inf_strm.total_out = 0;
index cf51f091d0e7325f741b2c2dcc7b874c726e0021..f0fb8be7740cc760243cc45b04799ccfba3867c7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: comprtest.c,v 1.5 2002/01/03 15:20:44 dwmw2 Exp $ */
+/* $Id: comprtest.c,v 1.6 2005/11/07 11:14:38 gleixner Exp $ */
 
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -265,9 +265,9 @@ static unsigned char testdata[TESTDATA_LEN] = {
 static unsigned char comprbuf[TESTDATA_LEN];
 static unsigned char decomprbuf[TESTDATA_LEN];
 
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, 
+int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, 
+unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
                             uint32_t *datalen, uint32_t *cdatalen);
 
 int init_module(void ) {
@@ -276,10 +276,10 @@ int init_module(void ) {
        int ret;
 
        printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-              testdata[0],testdata[1],testdata[2],testdata[3], 
-              testdata[4],testdata[5],testdata[6],testdata[7], 
-              testdata[8],testdata[9],testdata[10],testdata[11], 
-              testdata[12],testdata[13],testdata[14],testdata[15]); 
+              testdata[0],testdata[1],testdata[2],testdata[3],
+              testdata[4],testdata[5],testdata[6],testdata[7],
+              testdata[8],testdata[9],testdata[10],testdata[11],
+              testdata[12],testdata[13],testdata[14],testdata[15]);
        d = TESTDATA_LEN;
        c = TESTDATA_LEN;
        comprtype = jffs2_compress(testdata, comprbuf, &d, &c);
@@ -287,18 +287,18 @@ int init_module(void ) {
        printk("jffs2_compress used compression type %d. Compressed size %d, uncompressed size %d\n",
               comprtype, c, d);
        printk("Compressed data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-              comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3], 
-              comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7], 
-              comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11], 
-              comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]); 
+              comprbuf[0],comprbuf[1],comprbuf[2],comprbuf[3],
+              comprbuf[4],comprbuf[5],comprbuf[6],comprbuf[7],
+              comprbuf[8],comprbuf[9],comprbuf[10],comprbuf[11],
+              comprbuf[12],comprbuf[13],comprbuf[14],comprbuf[15]);
 
        ret = jffs2_decompress(comprtype, comprbuf, decomprbuf, c, d);
        printk("jffs2_decompress returned %d\n", ret);
        printk("Decompressed data:  %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
-              decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3], 
-              decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7], 
-              decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11], 
-              decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]); 
+              decomprbuf[0],decomprbuf[1],decomprbuf[2],decomprbuf[3],
+              decomprbuf[4],decomprbuf[5],decomprbuf[6],decomprbuf[7],
+              decomprbuf[8],decomprbuf[9],decomprbuf[10],decomprbuf[11],
+              decomprbuf[12],decomprbuf[13],decomprbuf[14],decomprbuf[15]);
        if (memcmp(decomprbuf, testdata, d))
                printk("Compression and decompression corrupted data\n");
        else
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c
new file mode 100644 (file)
index 0000000..1fe17de
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: debug.c,v 1.12 2005/11/07 11:14:39 gleixner Exp $
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pagemap.h>
+#include <linux/crc32.h>
+#include <linux/jffs2.h>
+#include <linux/mtd/mtd.h>
+#include "nodelist.h"
+#include "debug.h"
+
+#ifdef JFFS2_DBG_SANITY_CHECKS
+
+void
+__jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
+                                    struct jffs2_eraseblock *jeb)
+{
+       if (unlikely(jeb && jeb->used_size + jeb->dirty_size +
+                       jeb->free_size + jeb->wasted_size +
+                       jeb->unchecked_size != c->sector_size)) {
+               JFFS2_ERROR("eeep, space accounting for block at 0x%08x is screwed.\n", jeb->offset);
+               JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
+                       jeb->free_size, jeb->dirty_size, jeb->used_size,
+                       jeb->wasted_size, jeb->unchecked_size, c->sector_size);
+               BUG();
+       }
+
+       if (unlikely(c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size
+                               + c->wasted_size + c->unchecked_size != c->flash_size)) {
+               JFFS2_ERROR("eeep, space accounting superblock info is screwed.\n");
+               JFFS2_ERROR("free %#08x + dirty %#08x + used %#08x + erasing %#08x + bad %#08x + wasted %#08x + unchecked %#08x != total %#08x.\n",
+                       c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size,
+                       c->wasted_size, c->unchecked_size, c->flash_size);
+               BUG();
+       }
+}
+
+void
+__jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
+                             struct jffs2_eraseblock *jeb)
+{
+       spin_lock(&c->erase_completion_lock);
+       jffs2_dbg_acct_sanity_check_nolock(c, jeb);
+       spin_unlock(&c->erase_completion_lock);
+}
+
+#endif /* JFFS2_DBG_SANITY_CHECKS */
+
+#ifdef JFFS2_DBG_PARANOIA_CHECKS
+/*
+ * Check the fragtree.
+ */
+void
+__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f)
+{
+       down(&f->sem);
+       __jffs2_dbg_fragtree_paranoia_check_nolock(f);
+       up(&f->sem);
+}
+
+void
+__jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f)
+{
+       struct jffs2_node_frag *frag;
+       int bitched = 0;
+
+       for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
+               struct jffs2_full_dnode *fn = frag->node;
+
+               if (!fn || !fn->raw)
+                       continue;
+
+               if (ref_flags(fn->raw) == REF_PRISTINE) {
+                       if (fn->frags > 1) {
+                               JFFS2_ERROR("REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2.\n",
+                                       ref_offset(fn->raw), fn->frags);
+                               bitched = 1;
+                       }
+
+                       /* A hole node which isn't multi-page should be garbage-collected
+                          and merged anyway, so we just check for the frag size here,
+                          rather than mucking around with actually reading the node
+                          and checking the compression type, which is the real way
+                          to tell a hole node. */
+                       if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag)
+                                       && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
+                               JFFS2_ERROR("REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2.\n",
+                                       ref_offset(fn->raw));
+                               bitched = 1;
+                       }
+
+                       if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag)
+                                       && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
+                               JFFS2_ERROR("REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2.\n",
+                                      ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
+                               bitched = 1;
+                       }
+               }
+       }
+
+       if (bitched) {
+               JFFS2_ERROR("fragtree is corrupted.\n");
+               __jffs2_dbg_dump_fragtree_nolock(f);
+               BUG();
+       }
+}
+
+/*
+ * Check if the flash contains all 0xFF before we start writing.
+ */
+void
+__jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
+                                   uint32_t ofs, int len)
+{
+       size_t retlen;
+       int ret, i;
+       unsigned char *buf;
+
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return;
+
+       ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
+       if (ret || (retlen != len)) {
+               JFFS2_WARNING("read %d bytes failed or short. ret %d, retlen %zd.\n",
+                               len, ret, retlen);
+               kfree(buf);
+               return;
+       }
+
+       ret = 0;
+       for (i = 0; i < len; i++)
+               if (buf[i] != 0xff)
+                       ret = 1;
+
+       if (ret) {
+               JFFS2_ERROR("argh, about to write node to %#08x on flash, but there are data already there. The first corrupted byte is at %#08x offset.\n",
+                       ofs, ofs + i);
+               __jffs2_dbg_dump_buffer(buf, len, ofs);
+               kfree(buf);
+               BUG();
+       }
+
+       kfree(buf);
+}
+
+/*
+ * Check the space accounting and node_ref list correctness for the JFFS2 erasable block 'jeb'.
+ */
+void
+__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
+                               struct jffs2_eraseblock *jeb)
+{
+       spin_lock(&c->erase_completion_lock);
+       __jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
+       spin_unlock(&c->erase_completion_lock);
+}
+
+void
+__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
+                                      struct jffs2_eraseblock *jeb)
+{
+       uint32_t my_used_size = 0;
+       uint32_t my_unchecked_size = 0;
+       uint32_t my_dirty_size = 0;
+       struct jffs2_raw_node_ref *ref2 = jeb->first_node;
+
+       while (ref2) {
+               uint32_t totlen = ref_totlen(c, jeb, ref2);
+
+               if (ref2->flash_offset < jeb->offset ||
+                               ref2->flash_offset > jeb->offset + c->sector_size) {
+                       JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
+                               ref_offset(ref2), jeb->offset);
+                       goto error;
+
+               }
+               if (ref_flags(ref2) == REF_UNCHECKED)
+                       my_unchecked_size += totlen;
+               else if (!ref_obsolete(ref2))
+                       my_used_size += totlen;
+               else
+                       my_dirty_size += totlen;
+
+               if ((!ref2->next_phys) != (ref2 == jeb->last_node)) {
+                       JFFS2_ERROR("node_ref for node at %#08x (mem %p) has next_phys at %#08x (mem %p), last_node is at %#08x (mem %p).\n",
+                               ref_offset(ref2), ref2, ref_offset(ref2->next_phys), ref2->next_phys,
+                               ref_offset(jeb->last_node), jeb->last_node);
+                       goto error;
+               }
+               ref2 = ref2->next_phys;
+       }
+
+       if (my_used_size != jeb->used_size) {
+               JFFS2_ERROR("Calculated used size %#08x != stored used size %#08x.\n",
+                       my_used_size, jeb->used_size);
+               goto error;
+       }
+
+       if (my_unchecked_size != jeb->unchecked_size) {
+               JFFS2_ERROR("Calculated unchecked size %#08x != stored unchecked size %#08x.\n",
+                       my_unchecked_size, jeb->unchecked_size);
+               goto error;
+       }
+
+#if 0
+       /* This should work when we implement ref->__totlen elemination */
+       if (my_dirty_size != jeb->dirty_size + jeb->wasted_size) {
+               JFFS2_ERROR("Calculated dirty+wasted size %#08x != stored dirty + wasted size %#08x\n",
+                       my_dirty_size, jeb->dirty_size + jeb->wasted_size);
+               goto error;
+       }
+
+       if (jeb->free_size == 0
+               && my_used_size + my_unchecked_size + my_dirty_size != c->sector_size) {
+               JFFS2_ERROR("The sum of all nodes in block (%#x) != size of block (%#x)\n",
+                       my_used_size + my_unchecked_size + my_dirty_size,
+                       c->sector_size);
+               goto error;
+       }
+#endif
+
+       return;
+
+error:
+       __jffs2_dbg_dump_node_refs_nolock(c, jeb);
+       __jffs2_dbg_dump_jeb_nolock(jeb);
+       __jffs2_dbg_dump_block_lists_nolock(c);
+       BUG();
+
+}
+#endif /* JFFS2_DBG_PARANOIA_CHECKS */
+
+#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
+/*
+ * Dump the node_refs of the 'jeb' JFFS2 eraseblock.
+ */
+void
+__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
+                          struct jffs2_eraseblock *jeb)
+{
+       spin_lock(&c->erase_completion_lock);
+       __jffs2_dbg_dump_node_refs_nolock(c, jeb);
+       spin_unlock(&c->erase_completion_lock);
+}
+
+void
+__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
+                                 struct jffs2_eraseblock *jeb)
+{
+       struct jffs2_raw_node_ref *ref;
+       int i = 0;
+
+       printk(JFFS2_DBG_MSG_PREFIX " Dump node_refs of the eraseblock %#08x\n", jeb->offset);
+       if (!jeb->first_node) {
+               printk(JFFS2_DBG_MSG_PREFIX " no nodes in the eraseblock %#08x\n", jeb->offset);
+               return;
+       }
+
+       printk(JFFS2_DBG);
+       for (ref = jeb->first_node; ; ref = ref->next_phys) {
+               printk("%#08x(%#x)", ref_offset(ref), ref->__totlen);
+               if (ref->next_phys)
+                       printk("->");
+               else
+                       break;
+               if (++i == 4) {
+                       i = 0;
+                       printk("\n" JFFS2_DBG);
+               }
+       }
+       printk("\n");
+}
+
+/*
+ * Dump an eraseblock's space accounting.
+ */
+void
+__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+{
+       spin_lock(&c->erase_completion_lock);
+       __jffs2_dbg_dump_jeb_nolock(jeb);
+       spin_unlock(&c->erase_completion_lock);
+}
+
+void
+__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb)
+{
+       if (!jeb)
+               return;
+
+       printk(JFFS2_DBG_MSG_PREFIX " dump space accounting for the eraseblock at %#08x:\n",
+                       jeb->offset);
+
+       printk(JFFS2_DBG "used_size: %#08x\n",          jeb->used_size);
+       printk(JFFS2_DBG "dirty_size: %#08x\n",         jeb->dirty_size);
+       printk(JFFS2_DBG "wasted_size: %#08x\n",        jeb->wasted_size);
+       printk(JFFS2_DBG "unchecked_size: %#08x\n",     jeb->unchecked_size);
+       printk(JFFS2_DBG "free_size: %#08x\n",          jeb->free_size);
+}
+
+void
+__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c)
+{
+       spin_lock(&c->erase_completion_lock);
+       __jffs2_dbg_dump_block_lists_nolock(c);
+       spin_unlock(&c->erase_completion_lock);
+}
+
+void
+__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c)
+{
+       printk(JFFS2_DBG_MSG_PREFIX " dump JFFS2 blocks lists:\n");
+
+       printk(JFFS2_DBG "flash_size: %#08x\n",         c->flash_size);
+       printk(JFFS2_DBG "used_size: %#08x\n",          c->used_size);
+       printk(JFFS2_DBG "dirty_size: %#08x\n",         c->dirty_size);
+       printk(JFFS2_DBG "wasted_size: %#08x\n",        c->wasted_size);
+       printk(JFFS2_DBG "unchecked_size: %#08x\n",     c->unchecked_size);
+       printk(JFFS2_DBG "free_size: %#08x\n",          c->free_size);
+       printk(JFFS2_DBG "erasing_size: %#08x\n",       c->erasing_size);
+       printk(JFFS2_DBG "bad_size: %#08x\n",           c->bad_size);
+       printk(JFFS2_DBG "sector_size: %#08x\n",        c->sector_size);
+       printk(JFFS2_DBG "jffs2_reserved_blocks size: %#08x\n",
+                               c->sector_size * c->resv_blocks_write);
+
+       if (c->nextblock)
+               printk(JFFS2_DBG "nextblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                       c->nextblock->offset, c->nextblock->used_size,
+                       c->nextblock->dirty_size, c->nextblock->wasted_size,
+                       c->nextblock->unchecked_size, c->nextblock->free_size);
+       else
+               printk(JFFS2_DBG "nextblock: NULL\n");
+
+       if (c->gcblock)
+               printk(JFFS2_DBG "gcblock: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                       c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size,
+                       c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
+       else
+               printk(JFFS2_DBG "gcblock: NULL\n");
+
+       if (list_empty(&c->clean_list)) {
+               printk(JFFS2_DBG "clean_list: empty\n");
+       } else {
+               struct list_head *this;
+               int numblocks = 0;
+               uint32_t dirty = 0;
+
+               list_for_each(this, &c->clean_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+                       numblocks ++;
+                       dirty += jeb->wasted_size;
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "clean_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+
+               printk (JFFS2_DBG "Contains %d blocks with total wasted size %u, average wasted size: %u\n",
+                       numblocks, dirty, dirty / numblocks);
+       }
+
+       if (list_empty(&c->very_dirty_list)) {
+               printk(JFFS2_DBG "very_dirty_list: empty\n");
+       } else {
+               struct list_head *this;
+               int numblocks = 0;
+               uint32_t dirty = 0;
+
+               list_for_each(this, &c->very_dirty_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       numblocks ++;
+                       dirty += jeb->dirty_size;
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "very_dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+
+               printk (JFFS2_DBG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
+                       numblocks, dirty, dirty / numblocks);
+       }
+
+       if (list_empty(&c->dirty_list)) {
+               printk(JFFS2_DBG "dirty_list: empty\n");
+       } else {
+               struct list_head *this;
+               int numblocks = 0;
+               uint32_t dirty = 0;
+
+               list_for_each(this, &c->dirty_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       numblocks ++;
+                       dirty += jeb->dirty_size;
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "dirty_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+
+               printk (JFFS2_DBG "contains %d blocks with total dirty size %u, average dirty size: %u\n",
+                       numblocks, dirty, dirty / numblocks);
+       }
+
+       if (list_empty(&c->erasable_list)) {
+               printk(JFFS2_DBG "erasable_list: empty\n");
+       } else {
+               struct list_head *this;
+
+               list_for_each(this, &c->erasable_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "erasable_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+       }
+
+       if (list_empty(&c->erasing_list)) {
+               printk(JFFS2_DBG "erasing_list: empty\n");
+       } else {
+               struct list_head *this;
+
+               list_for_each(this, &c->erasing_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "erasing_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+       }
+
+       if (list_empty(&c->erase_pending_list)) {
+               printk(JFFS2_DBG "erase_pending_list: empty\n");
+       } else {
+               struct list_head *this;
+
+               list_for_each(this, &c->erase_pending_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "erase_pending_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+       }
+
+       if (list_empty(&c->erasable_pending_wbuf_list)) {
+               printk(JFFS2_DBG "erasable_pending_wbuf_list: empty\n");
+       } else {
+               struct list_head *this;
+
+               list_for_each(this, &c->erasable_pending_wbuf_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "erasable_pending_wbuf_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+       }
+
+       if (list_empty(&c->free_list)) {
+               printk(JFFS2_DBG "free_list: empty\n");
+       } else {
+               struct list_head *this;
+
+               list_for_each(this, &c->free_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "free_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+       }
+
+       if (list_empty(&c->bad_list)) {
+               printk(JFFS2_DBG "bad_list: empty\n");
+       } else {
+               struct list_head *this;
+
+               list_for_each(this, &c->bad_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "bad_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+       }
+
+       if (list_empty(&c->bad_used_list)) {
+               printk(JFFS2_DBG "bad_used_list: empty\n");
+       } else {
+               struct list_head *this;
+
+               list_for_each(this, &c->bad_used_list) {
+                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
+
+                       if (!(jeb->used_size == 0 && jeb->dirty_size == 0 && jeb->wasted_size == 0)) {
+                               printk(JFFS2_DBG "bad_used_list: %#08x (used %#08x, dirty %#08x, wasted %#08x, unchecked %#08x, free %#08x)\n",
+                                       jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size,
+                                       jeb->unchecked_size, jeb->free_size);
+                       }
+               }
+       }
+}
+
+void
+__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f)
+{
+       down(&f->sem);
+       jffs2_dbg_dump_fragtree_nolock(f);
+       up(&f->sem);
+}
+
+void
+__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f)
+{
+       struct jffs2_node_frag *this = frag_first(&f->fragtree);
+       uint32_t lastofs = 0;
+       int buggy = 0;
+
+       printk(JFFS2_DBG_MSG_PREFIX " dump fragtree of ino #%u\n", f->inocache->ino);
+       while(this) {
+               if (this->node)
+                       printk(JFFS2_DBG "frag %#04x-%#04x: %#08x(%d) on flash (*%p), left (%p), right (%p), parent (%p)\n",
+                               this->ofs, this->ofs+this->size, ref_offset(this->node->raw),
+                               ref_flags(this->node->raw), this, frag_left(this), frag_right(this),
+                               frag_parent(this));
+               else
+                       printk(JFFS2_DBG "frag %#04x-%#04x: hole (*%p). left (%p), right (%p), parent (%p)\n",
+                               this->ofs, this->ofs+this->size, this, frag_left(this),
+                               frag_right(this), frag_parent(this));
+               if (this->ofs != lastofs)
+                       buggy = 1;
+               lastofs = this->ofs + this->size;
+               this = frag_next(this);
+       }
+
+       if (f->metadata)
+               printk(JFFS2_DBG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
+
+       if (buggy) {
+               JFFS2_ERROR("frag tree got a hole in it.\n");
+               BUG();
+       }
+}
+
+#define JFFS2_BUFDUMP_BYTES_PER_LINE   32
+void
+__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs)
+{
+       int skip;
+       int i;
+
+       printk(JFFS2_DBG_MSG_PREFIX " dump from offset %#08x to offset %#08x (%x bytes).\n",
+               offs, offs + len, len);
+       i = skip = offs % JFFS2_BUFDUMP_BYTES_PER_LINE;
+       offs = offs & ~(JFFS2_BUFDUMP_BYTES_PER_LINE - 1);
+
+       if (skip != 0)
+               printk(JFFS2_DBG "%#08x: ", offs);
+
+       while (skip--)
+               printk("   ");
+
+       while (i < len) {
+               if ((i % JFFS2_BUFDUMP_BYTES_PER_LINE) == 0 && i != len -1) {
+                       if (i != 0)
+                               printk("\n");
+                       offs += JFFS2_BUFDUMP_BYTES_PER_LINE;
+                       printk(JFFS2_DBG "%0#8x: ", offs);
+               }
+
+               printk("%02x ", buf[i]);
+
+               i += 1;
+       }
+
+       printk("\n");
+}
+
+/*
+ * Dump a JFFS2 node.
+ */
+void
+__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs)
+{
+       union jffs2_node_union node;
+       int len = sizeof(union jffs2_node_union);
+       size_t retlen;
+       uint32_t crc;
+       int ret;
+
+       printk(JFFS2_DBG_MSG_PREFIX " dump node at offset %#08x.\n", ofs);
+
+       ret = jffs2_flash_read(c, ofs, len, &retlen, (unsigned char *)&node);
+       if (ret || (retlen != len)) {
+               JFFS2_ERROR("read %d bytes failed or short. ret %d, retlen %zd.\n",
+                       len, ret, retlen);
+               return;
+       }
+
+       printk(JFFS2_DBG "magic:\t%#04x\n", je16_to_cpu(node.u.magic));
+       printk(JFFS2_DBG "nodetype:\t%#04x\n", je16_to_cpu(node.u.nodetype));
+       printk(JFFS2_DBG "totlen:\t%#08x\n", je32_to_cpu(node.u.totlen));
+       printk(JFFS2_DBG "hdr_crc:\t%#08x\n", je32_to_cpu(node.u.hdr_crc));
+
+       crc = crc32(0, &node.u, sizeof(node.u) - 4);
+       if (crc != je32_to_cpu(node.u.hdr_crc)) {
+               JFFS2_ERROR("wrong common header CRC.\n");
+               return;
+       }
+
+       if (je16_to_cpu(node.u.magic) != JFFS2_MAGIC_BITMASK &&
+               je16_to_cpu(node.u.magic) != JFFS2_OLD_MAGIC_BITMASK)
+       {
+               JFFS2_ERROR("wrong node magic: %#04x instead of %#04x.\n",
+                       je16_to_cpu(node.u.magic), JFFS2_MAGIC_BITMASK);
+               return;
+       }
+
+       switch(je16_to_cpu(node.u.nodetype)) {
+
+       case JFFS2_NODETYPE_INODE:
+
+               printk(JFFS2_DBG "the node is inode node\n");
+               printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.i.ino));
+               printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.i.version));
+               printk(JFFS2_DBG "mode:\t%#08x\n", node.i.mode.m);
+               printk(JFFS2_DBG "uid:\t%#04x\n", je16_to_cpu(node.i.uid));
+               printk(JFFS2_DBG "gid:\t%#04x\n", je16_to_cpu(node.i.gid));
+               printk(JFFS2_DBG "isize:\t%#08x\n", je32_to_cpu(node.i.isize));
+               printk(JFFS2_DBG "atime:\t%#08x\n", je32_to_cpu(node.i.atime));
+               printk(JFFS2_DBG "mtime:\t%#08x\n", je32_to_cpu(node.i.mtime));
+               printk(JFFS2_DBG "ctime:\t%#08x\n", je32_to_cpu(node.i.ctime));
+               printk(JFFS2_DBG "offset:\t%#08x\n", je32_to_cpu(node.i.offset));
+               printk(JFFS2_DBG "csize:\t%#08x\n", je32_to_cpu(node.i.csize));
+               printk(JFFS2_DBG "dsize:\t%#08x\n", je32_to_cpu(node.i.dsize));
+               printk(JFFS2_DBG "compr:\t%#02x\n", node.i.compr);
+               printk(JFFS2_DBG "usercompr:\t%#02x\n", node.i.usercompr);
+               printk(JFFS2_DBG "flags:\t%#04x\n", je16_to_cpu(node.i.flags));
+               printk(JFFS2_DBG "data_crc:\t%#08x\n", je32_to_cpu(node.i.data_crc));
+               printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.i.node_crc));
+
+               crc = crc32(0, &node.i, sizeof(node.i) - 8);
+               if (crc != je32_to_cpu(node.i.node_crc)) {
+                       JFFS2_ERROR("wrong node header CRC.\n");
+                       return;
+               }
+               break;
+
+       case JFFS2_NODETYPE_DIRENT:
+
+               printk(JFFS2_DBG "the node is dirent node\n");
+               printk(JFFS2_DBG "pino:\t%#08x\n", je32_to_cpu(node.d.pino));
+               printk(JFFS2_DBG "version:\t%#08x\n", je32_to_cpu(node.d.version));
+               printk(JFFS2_DBG "ino:\t%#08x\n", je32_to_cpu(node.d.ino));
+               printk(JFFS2_DBG "mctime:\t%#08x\n", je32_to_cpu(node.d.mctime));
+               printk(JFFS2_DBG "nsize:\t%#02x\n", node.d.nsize);
+               printk(JFFS2_DBG "type:\t%#02x\n", node.d.type);
+               printk(JFFS2_DBG "node_crc:\t%#08x\n", je32_to_cpu(node.d.node_crc));
+               printk(JFFS2_DBG "name_crc:\t%#08x\n", je32_to_cpu(node.d.name_crc));
+
+               node.d.name[node.d.nsize] = '\0';
+               printk(JFFS2_DBG "name:\t\"%s\"\n", node.d.name);
+
+               crc = crc32(0, &node.d, sizeof(node.d) - 8);
+               if (crc != je32_to_cpu(node.d.node_crc)) {
+                       JFFS2_ERROR("wrong node header CRC.\n");
+                       return;
+               }
+               break;
+
+       default:
+               printk(JFFS2_DBG "node type is unknown\n");
+               break;
+       }
+}
+#endif /* JFFS2_DBG_DUMPS || JFFS2_DBG_PARANOIA_CHECKS */
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
new file mode 100644 (file)
index 0000000..f193d43
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@infradead.org>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: debug.h,v 1.21 2005/11/07 11:14:39 gleixner Exp $
+ *
+ */
+#ifndef _JFFS2_DEBUG_H_
+#define _JFFS2_DEBUG_H_
+
+#include <linux/config.h>
+
+#ifndef CONFIG_JFFS2_FS_DEBUG
+#define CONFIG_JFFS2_FS_DEBUG 0
+#endif
+
+#if CONFIG_JFFS2_FS_DEBUG > 0
+/* Enable "paranoia" checks and dumps */
+#define JFFS2_DBG_PARANOIA_CHECKS
+#define JFFS2_DBG_DUMPS
+
+/*
+ * By defining/undefining the below macros one may select debugging messages
+ * fro specific JFFS2 subsystems.
+ */
+#define JFFS2_DBG_READINODE_MESSAGES
+#define JFFS2_DBG_FRAGTREE_MESSAGES
+#define JFFS2_DBG_DENTLIST_MESSAGES
+#define JFFS2_DBG_NODEREF_MESSAGES
+#define JFFS2_DBG_INOCACHE_MESSAGES
+#define JFFS2_DBG_SUMMARY_MESSAGES
+#define JFFS2_DBG_FSBUILD_MESSAGES
+#endif
+
+#if CONFIG_JFFS2_FS_DEBUG > 1
+#define JFFS2_DBG_FRAGTREE2_MESSAGES
+#define JFFS2_DBG_MEMALLOC_MESSAGES
+#endif
+
+/* Sanity checks are supposed to be light-weight and enabled by default */
+#define JFFS2_DBG_SANITY_CHECKS
+
+/*
+ * Dx() are mainly used for debugging messages, they must go away and be
+ * superseded by nicer dbg_xxx() macros...
+ */
+#if CONFIG_JFFS2_FS_DEBUG > 0
+#define D1(x) x
+#else
+#define D1(x)
+#endif
+
+#if CONFIG_JFFS2_FS_DEBUG > 1
+#define D2(x) x
+#else
+#define D2(x)
+#endif
+
+/* The prefixes of JFFS2 messages */
+#define JFFS2_DBG_PREFIX       "[JFFS2 DBG]"
+#define JFFS2_ERR_PREFIX       "JFFS2 error:"
+#define JFFS2_WARN_PREFIX      "JFFS2 warning:"
+#define JFFS2_NOTICE_PREFIX    "JFFS2 notice:"
+
+#define JFFS2_ERR      KERN_ERR
+#define JFFS2_WARN     KERN_WARNING
+#define JFFS2_NOT      KERN_NOTICE
+#define JFFS2_DBG      KERN_DEBUG
+
+#define JFFS2_DBG_MSG_PREFIX   JFFS2_DBG JFFS2_DBG_PREFIX
+#define JFFS2_ERR_MSG_PREFIX   JFFS2_ERR JFFS2_ERR_PREFIX
+#define JFFS2_WARN_MSG_PREFIX  JFFS2_WARN JFFS2_WARN_PREFIX
+#define JFFS2_NOTICE_MSG_PREFIX        JFFS2_NOT JFFS2_NOTICE_PREFIX
+
+/* JFFS2 message macros */
+#define JFFS2_ERROR(fmt, ...)                                          \
+       do {                                                            \
+               printk(JFFS2_ERR_MSG_PREFIX                             \
+                       " (%d) %s: " fmt, current->pid,                 \
+                       __FUNCTION__, ##__VA_ARGS__);                   \
+       } while(0)
+
+#define JFFS2_WARNING(fmt, ...)                                                \
+       do {                                                            \
+               printk(JFFS2_WARN_MSG_PREFIX                            \
+                       " (%d) %s: " fmt, current->pid,                 \
+                       __FUNCTION__, ##__VA_ARGS__);                   \
+       } while(0)
+
+#define JFFS2_NOTICE(fmt, ...)                                         \
+       do {                                                            \
+               printk(JFFS2_NOTICE_MSG_PREFIX                          \
+                       " (%d) %s: " fmt, current->pid,                 \
+                       __FUNCTION__, ##__VA_ARGS__);                   \
+       } while(0)
+
+#define JFFS2_DEBUG(fmt, ...)                                          \
+       do {                                                            \
+               printk(JFFS2_DBG_MSG_PREFIX                             \
+                       " (%d) %s: " fmt, current->pid,                 \
+                       __FUNCTION__, ##__VA_ARGS__);                   \
+       } while(0)
+
+/*
+ * We split our debugging messages on several parts, depending on the JFFS2
+ * subsystem the message belongs to.
+ */
+/* Read inode debugging messages */
+#ifdef JFFS2_DBG_READINODE_MESSAGES
+#define dbg_readinode(fmt, ...)        JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_readinode(fmt, ...)
+#endif
+
+/* Fragtree build debugging messages */
+#ifdef JFFS2_DBG_FRAGTREE_MESSAGES
+#define dbg_fragtree(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_fragtree(fmt, ...)
+#endif
+#ifdef JFFS2_DBG_FRAGTREE2_MESSAGES
+#define dbg_fragtree2(fmt, ...)        JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_fragtree2(fmt, ...)
+#endif
+
+/* Directory entry list manilulation debugging messages */
+#ifdef JFFS2_DBG_DENTLIST_MESSAGES
+#define dbg_dentlist(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_dentlist(fmt, ...)
+#endif
+
+/* Print the messages about manipulating node_refs */
+#ifdef JFFS2_DBG_NODEREF_MESSAGES
+#define dbg_noderef(fmt, ...)  JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_noderef(fmt, ...)
+#endif
+
+/* Manipulations with the list of inodes (JFFS2 inocache) */
+#ifdef JFFS2_DBG_INOCACHE_MESSAGES
+#define dbg_inocache(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_inocache(fmt, ...)
+#endif
+
+/* Summary debugging messages */
+#ifdef JFFS2_DBG_SUMMARY_MESSAGES
+#define dbg_summary(fmt, ...)  JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_summary(fmt, ...)
+#endif
+
+/* File system build messages */
+#ifdef JFFS2_DBG_FSBUILD_MESSAGES
+#define dbg_fsbuild(fmt, ...)  JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_fsbuild(fmt, ...)
+#endif
+
+/* Watch the object allocations */
+#ifdef JFFS2_DBG_MEMALLOC_MESSAGES
+#define dbg_memalloc(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define dbg_memalloc(fmt, ...)
+#endif
+
+
+/* "Sanity" checks */
+void
+__jffs2_dbg_acct_sanity_check_nolock(struct jffs2_sb_info *c,
+                                    struct jffs2_eraseblock *jeb);
+void
+__jffs2_dbg_acct_sanity_check(struct jffs2_sb_info *c,
+                             struct jffs2_eraseblock *jeb);
+
+/* "Paranoia" checks */
+void
+__jffs2_dbg_fragtree_paranoia_check(struct jffs2_inode_info *f);
+void
+__jffs2_dbg_fragtree_paranoia_check_nolock(struct jffs2_inode_info *f);
+void
+__jffs2_dbg_acct_paranoia_check(struct jffs2_sb_info *c,
+                               struct jffs2_eraseblock *jeb);
+void
+__jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
+                                      struct jffs2_eraseblock *jeb);
+void
+__jffs2_dbg_prewrite_paranoia_check(struct jffs2_sb_info *c,
+                                   uint32_t ofs, int len);
+
+/* "Dump" functions */
+void
+__jffs2_dbg_dump_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+void
+__jffs2_dbg_dump_jeb_nolock(struct jffs2_eraseblock *jeb);
+void
+__jffs2_dbg_dump_block_lists(struct jffs2_sb_info *c);
+void
+__jffs2_dbg_dump_block_lists_nolock(struct jffs2_sb_info *c);
+void
+__jffs2_dbg_dump_node_refs(struct jffs2_sb_info *c,
+                          struct jffs2_eraseblock *jeb);
+void
+__jffs2_dbg_dump_node_refs_nolock(struct jffs2_sb_info *c,
+                                 struct jffs2_eraseblock *jeb);
+void
+__jffs2_dbg_dump_fragtree(struct jffs2_inode_info *f);
+void
+__jffs2_dbg_dump_fragtree_nolock(struct jffs2_inode_info *f);
+void
+__jffs2_dbg_dump_buffer(unsigned char *buf, int len, uint32_t offs);
+void
+__jffs2_dbg_dump_node(struct jffs2_sb_info *c, uint32_t ofs);
+
+#ifdef JFFS2_DBG_PARANOIA_CHECKS
+#define jffs2_dbg_fragtree_paranoia_check(f)                   \
+       __jffs2_dbg_fragtree_paranoia_check(f)
+#define jffs2_dbg_fragtree_paranoia_check_nolock(f)            \
+       __jffs2_dbg_fragtree_paranoia_check_nolock(f)
+#define jffs2_dbg_acct_paranoia_check(c, jeb)                  \
+       __jffs2_dbg_acct_paranoia_check(c,jeb)
+#define jffs2_dbg_acct_paranoia_check_nolock(c, jeb)           \
+       __jffs2_dbg_acct_paranoia_check_nolock(c,jeb)
+#define jffs2_dbg_prewrite_paranoia_check(c, ofs, len)         \
+       __jffs2_dbg_prewrite_paranoia_check(c, ofs, len)
+#else
+#define jffs2_dbg_fragtree_paranoia_check(f)
+#define jffs2_dbg_fragtree_paranoia_check_nolock(f)
+#define jffs2_dbg_acct_paranoia_check(c, jeb)
+#define jffs2_dbg_acct_paranoia_check_nolock(c, jeb)
+#define jffs2_dbg_prewrite_paranoia_check(c, ofs, len)
+#endif /* !JFFS2_PARANOIA_CHECKS */
+
+#ifdef JFFS2_DBG_DUMPS
+#define jffs2_dbg_dump_jeb(c, jeb)                             \
+       __jffs2_dbg_dump_jeb(c, jeb);
+#define jffs2_dbg_dump_jeb_nolock(jeb)                         \
+       __jffs2_dbg_dump_jeb_nolock(jeb);
+#define jffs2_dbg_dump_block_lists(c)                          \
+       __jffs2_dbg_dump_block_lists(c)
+#define jffs2_dbg_dump_block_lists_nolock(c)                   \
+       __jffs2_dbg_dump_block_lists_nolock(c)
+#define jffs2_dbg_dump_fragtree(f)                             \
+       __jffs2_dbg_dump_fragtree(f);
+#define jffs2_dbg_dump_fragtree_nolock(f)                      \
+       __jffs2_dbg_dump_fragtree_nolock(f);
+#define jffs2_dbg_dump_buffer(buf, len, offs)                  \
+       __jffs2_dbg_dump_buffer(*buf, len, offs);
+#define jffs2_dbg_dump_node(c, ofs)                            \
+       __jffs2_dbg_dump_node(c, ofs);
+#else
+#define jffs2_dbg_dump_jeb(c, jeb)
+#define jffs2_dbg_dump_jeb_nolock(jeb)
+#define jffs2_dbg_dump_block_lists(c)
+#define jffs2_dbg_dump_block_lists_nolock(c)
+#define jffs2_dbg_dump_fragtree(f)
+#define jffs2_dbg_dump_fragtree_nolock(f)
+#define jffs2_dbg_dump_buffer(buf, len, offs)
+#define jffs2_dbg_dump_node(c, ofs)
+#endif /* !JFFS2_DBG_DUMPS */
+
+#ifdef JFFS2_DBG_SANITY_CHECKS
+#define jffs2_dbg_acct_sanity_check(c, jeb)                    \
+       __jffs2_dbg_acct_sanity_check(c, jeb)
+#define jffs2_dbg_acct_sanity_check_nolock(c, jeb)             \
+       __jffs2_dbg_acct_sanity_check_nolock(c, jeb)
+#else
+#define jffs2_dbg_acct_sanity_check(c, jeb)
+#define jffs2_dbg_acct_sanity_check_nolock(c, jeb)
+#endif /* !JFFS2_DBG_SANITY_CHECKS */
+
+#endif /* _JFFS2_DEBUG_H_ */
index 3ca0d25eef1d529f82da3ec83d1644c331d629f6..a7bf9cb2567fc20b763354d5abd4a8e197c63373 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.86 2005/07/06 12:13:09 dwmw2 Exp $
+ * $Id: dir.c,v 1.90 2005/11/07 11:14:39 gleixner Exp $
  *
  */
 
@@ -64,7 +64,7 @@ struct inode_operations jffs2_dir_inode_operations =
 
 
 /* We keep the dirent list sorted in increasing order of name hash,
-   and we use the same hash function as the dentries. Makes this 
+   and we use the same hash function as the dentries. Makes this
    nice and simple
 */
 static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
@@ -85,7 +85,7 @@ static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target,
 
        /* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
        for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= target->d_name.hash; fd_list = fd_list->next) {
-               if (fd_list->nhash == target->d_name.hash && 
+               if (fd_list->nhash == target->d_name.hash &&
                    (!fd || fd_list->version > fd->version) &&
                    strlen(fd_list->name) == target->d_name.len &&
                    !strncmp(fd_list->name, target->d_name.name, target->d_name.len)) {
@@ -147,7 +147,7 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
                curofs++;
                /* First loop: curofs = 2; offset = 2 */
                if (curofs < offset) {
-                       D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n", 
+                       D2(printk(KERN_DEBUG "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
                                  fd->name, fd->ino, fd->type, curofs, offset));
                        continue;
                }
@@ -182,7 +182,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
        ri = jffs2_alloc_raw_inode();
        if (!ri)
                return -ENOMEM;
-       
+
        c = JFFS2_SB_INFO(dir_i->i_sb);
 
        D1(printk(KERN_DEBUG "jffs2_create()\n"));
@@ -203,7 +203,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
        f = JFFS2_INODE_INFO(inode);
        dir_f = JFFS2_INODE_INFO(dir_i);
 
-       ret = jffs2_do_create(c, dir_f, f, ri, 
+       ret = jffs2_do_create(c, dir_f, f, ri,
                              dentry->d_name.name, dentry->d_name.len);
 
        if (ret) {
@@ -232,11 +232,14 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
        struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
        struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode);
        int ret;
+       uint32_t now = get_seconds();
 
-       ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, 
-                              dentry->d_name.len, dead_f);
+       ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
+                             dentry->d_name.len, dead_f, now);
        if (dead_f->inocache)
                dentry->d_inode->i_nlink = dead_f->inocache->nlink;
+       if (!ret)
+               dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
        return ret;
 }
 /***********************************************************************/
@@ -249,6 +252,7 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
        struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
        int ret;
        uint8_t type;
+       uint32_t now;
 
        /* Don't let people make hard links to bad inodes. */
        if (!f->inocache)
@@ -261,13 +265,15 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
        type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
        if (!type) type = DT_REG;
 
-       ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len);
+       now = get_seconds();
+       ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len, now);
 
        if (!ret) {
                down(&f->sem);
                old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
                up(&f->sem);
                d_instantiate(dentry, old_dentry->d_inode);
+               dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
                atomic_inc(&old_dentry->d_inode->i_count);
        }
        return ret;
@@ -297,14 +303,15 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
 
        if (!ri)
                return -ENOMEM;
-       
+
        c = JFFS2_SB_INFO(dir_i->i_sb);
-       
-       /* Try to reserve enough space for both node and dirent. 
-        * Just the node will do for now, though 
+
+       /* Try to reserve enough space for both node and dirent.
+        * Just the node will do for now, though
         */
        namelen = dentry->d_name.len;
-       ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen,
+                               ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 
        if (ret) {
                jffs2_free_raw_inode(ri);
@@ -331,7 +338,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        ri->compr = JFFS2_COMPR_NONE;
        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, targetlen, phys_ofs, ALLOC_NORMAL);
 
        jffs2_free_raw_inode(ri);
@@ -344,9 +351,9 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                return PTR_ERR(fn);
        }
 
-       /* We use f->dents field to store the target path. */
-       f->dents = kmalloc(targetlen + 1, GFP_KERNEL);
-       if (!f->dents) {
+       /* We use f->target field to store the target path. */
+       f->target = kmalloc(targetlen + 1, GFP_KERNEL);
+       if (!f->target) {
                printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
                up(&f->sem);
                jffs2_complete_reservation(c);
@@ -354,17 +361,18 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
                return -ENOMEM;
        }
 
-       memcpy(f->dents, target, targetlen + 1);
-       D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents));
+       memcpy(f->target, target, targetlen + 1);
+       D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target));
 
-       /* No data here. Only a metadata node, which will be 
+       /* No data here. Only a metadata node, which will be
           obsoleted by the first data write
        */
        f->metadata = fn;
        up(&f->sem);
 
        jffs2_complete_reservation(c);
-       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+                               ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
        if (ret) {
                /* Eep. */
                jffs2_clear_inode(inode);
@@ -399,7 +407,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
        fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
 
        if (IS_ERR(fd)) {
-               /* dirent failed to write. Delete the inode normally 
+               /* dirent failed to write. Delete the inode normally
                   as if it were the final unlink() */
                jffs2_complete_reservation(c);
                jffs2_free_raw_dirent(rd);
@@ -442,14 +450,15 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
        ri = jffs2_alloc_raw_inode();
        if (!ri)
                return -ENOMEM;
-       
+
        c = JFFS2_SB_INFO(dir_i->i_sb);
 
-       /* Try to reserve enough space for both node and dirent. 
-        * Just the node will do for now, though 
+       /* Try to reserve enough space for both node and dirent.
+        * Just the node will do for now, though
         */
        namelen = dentry->d_name.len;
-       ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL,
+                               JFFS2_SUMMARY_INODE_SIZE);
 
        if (ret) {
                jffs2_free_raw_inode(ri);
@@ -473,7 +482,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
 
        ri->data_crc = cpu_to_je32(0);
        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-       
+
        fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
 
        jffs2_free_raw_inode(ri);
@@ -485,20 +494,21 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
                jffs2_clear_inode(inode);
                return PTR_ERR(fn);
        }
-       /* No data here. Only a metadata node, which will be 
+       /* No data here. Only a metadata node, which will be
           obsoleted by the first data write
        */
        f->metadata = fn;
        up(&f->sem);
 
        jffs2_complete_reservation(c);
-       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+                               ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
        if (ret) {
                /* Eep. */
                jffs2_clear_inode(inode);
                return ret;
        }
-       
+
        rd = jffs2_alloc_raw_dirent();
        if (!rd) {
                /* Argh. Now we treat it like a normal delete */
@@ -525,9 +535,9 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
        rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
 
        fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
-       
+
        if (IS_ERR(fd)) {
-               /* dirent failed to write. Delete the inode normally 
+               /* dirent failed to write. Delete the inode normally
                   as if it were the final unlink() */
                jffs2_complete_reservation(c);
                jffs2_free_raw_dirent(rd);
@@ -589,19 +599,20 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
        ri = jffs2_alloc_raw_inode();
        if (!ri)
                return -ENOMEM;
-       
+
        c = JFFS2_SB_INFO(dir_i->i_sb);
-       
+
        if (S_ISBLK(mode) || S_ISCHR(mode)) {
                dev = cpu_to_je16(old_encode_dev(rdev));
                devlen = sizeof(dev);
        }
-       
-       /* Try to reserve enough space for both node and dirent. 
-        * Just the node will do for now, though 
+
+       /* Try to reserve enough space for both node and dirent.
+        * Just the node will do for now, though
         */
        namelen = dentry->d_name.len;
-       ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen,
+                               ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
 
        if (ret) {
                jffs2_free_raw_inode(ri);
@@ -627,7 +638,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
        ri->compr = JFFS2_COMPR_NONE;
        ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
        ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
-       
+
        fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL);
 
        jffs2_free_raw_inode(ri);
@@ -639,14 +650,15 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
                jffs2_clear_inode(inode);
                return PTR_ERR(fn);
        }
-       /* No data here. Only a metadata node, which will be 
+       /* No data here. Only a metadata node, which will be
           obsoleted by the first data write
        */
        f->metadata = fn;
        up(&f->sem);
 
        jffs2_complete_reservation(c);
-       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+                               ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
        if (ret) {
                /* Eep. */
                jffs2_clear_inode(inode);
@@ -682,9 +694,9 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
        rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
 
        fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL);
-       
+
        if (IS_ERR(fd)) {
-               /* dirent failed to write. Delete the inode normally 
+               /* dirent failed to write. Delete the inode normally
                   as if it were the final unlink() */
                jffs2_complete_reservation(c);
                jffs2_free_raw_dirent(rd);
@@ -716,8 +728,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
        struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
        struct jffs2_inode_info *victim_f = NULL;
        uint8_t type;
+       uint32_t now;
 
-       /* The VFS will check for us and prevent trying to rename a 
+       /* The VFS will check for us and prevent trying to rename a
         * file over a directory and vice versa, but if it's a directory,
         * the VFS can't check whether the victim is empty. The filesystem
         * needs to do that for itself.
@@ -739,19 +752,20 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
        }
 
        /* XXX: We probably ought to alloc enough space for
-          both nodes at the same time. Writing the new link, 
+          both nodes at the same time. Writing the new link,
           then getting -ENOSPC, is quite bad :)
        */
 
        /* Make a hard link */
-       
+
        /* XXX: This is ugly */
        type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12;
        if (!type) type = DT_REG;
 
-       ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), 
+       now = get_seconds();
+       ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
                            old_dentry->d_inode->i_ino, type,
-                           new_dentry->d_name.name, new_dentry->d_name.len);
+                           new_dentry->d_name.name, new_dentry->d_name.len, now);
 
        if (ret)
                return ret;
@@ -768,14 +782,14 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                }
        }
 
-       /* If it was a directory we moved, and there was no victim, 
+       /* If it was a directory we moved, and there was no victim,
           increase i_nlink on its new parent */
        if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f)
                new_dir_i->i_nlink++;
 
        /* Unlink the original */
-       ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), 
-                     old_dentry->d_name.name, old_dentry->d_name.len, NULL);
+       ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
+                             old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
 
        /* We don't touch inode->i_nlink */
 
@@ -792,12 +806,15 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
                /* Might as well let the VFS know */
                d_instantiate(new_dentry, old_dentry->d_inode);
                atomic_inc(&old_dentry->d_inode->i_count);
+               new_dir_i->i_mtime = new_dir_i->i_ctime = ITIME(now);
                return ret;
        }
 
        if (S_ISDIR(old_dentry->d_inode->i_mode))
                old_dir_i->i_nlink--;
 
+       new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
+
        return 0;
 }
 
index 787d84ac2bcdaf580b9f9134124a09702aacdfd8..dad68fdffe9e3e3ac8662fcc1a98dd19126b0152 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.80 2005/07/14 19:46:24 joern Exp $
+ * $Id: erase.c,v 1.85 2005/09/20 14:53:15 dedekind Exp $
  *
  */
 
@@ -24,7 +24,7 @@ struct erase_priv_struct {
        struct jffs2_eraseblock *jeb;
        struct jffs2_sb_info *c;
 };
-      
+
 #ifndef __ECOS
 static void jffs2_erase_callback(struct erase_info *);
 #endif
@@ -48,7 +48,8 @@ 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));
+       D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#08x (range %#08x-%#08x)\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");
@@ -70,7 +71,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
        instr->callback = jffs2_erase_callback;
        instr->priv = (unsigned long)(&instr[1]);
        instr->fail_addr = 0xffffffff;
-       
+
        ((struct erase_priv_struct *)instr->priv)->jeb = jeb;
        ((struct erase_priv_struct *)instr->priv)->c = c;
 
@@ -95,7 +96,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
                return;
        }
 
-       if (ret == -EROFS) 
+       if (ret == -EROFS)
                printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset);
        else
                printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
@@ -196,7 +197,7 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock
        c->nr_erasing_blocks--;
        spin_unlock(&c->erase_completion_lock);
        wake_up(&c->erase_wait);
-}       
+}
 
 #ifndef __ECOS
 static void jffs2_erase_callback(struct erase_info *instr)
@@ -208,7 +209,7 @@ static void jffs2_erase_callback(struct erase_info *instr)
                jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
        } else {
                jffs2_erase_succeeded(priv->c, priv->jeb);
-       }       
+       }
        kfree(instr);
 }
 #endif /* !__ECOS */
@@ -226,13 +227,13 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
        /* Walk the inode's list once, removing any nodes from this eraseblock */
        while (1) {
                if (!(*prev)->next_in_ino) {
-                       /* We're looking at the jffs2_inode_cache, which is 
+                       /* We're looking at the jffs2_inode_cache, which is
                           at the end of the linked list. Stash it and continue
                           from the beginning of the list */
                        ic = (struct jffs2_inode_cache *)(*prev);
                        prev = &ic->nodes;
                        continue;
-               } 
+               }
 
                if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) {
                        /* It's in the block we're erasing */
@@ -266,7 +267,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
                printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
 
                this = ic->nodes;
-          
+
                while(this) {
                        printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this));
                        if (++i == 5) {
@@ -289,7 +290,7 @@ static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_erase
        while(jeb->first_node) {
                ref = jeb->first_node;
                jeb->first_node = ref->next_phys;
-               
+
                /* Remove from the inode-list */
                if (ref->next_in_ino)
                        jffs2_remove_node_refs_from_ino_list(c, ref, jeb);
@@ -306,7 +307,7 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl
        uint32_t ofs;
        size_t retlen;
        int ret = -EIO;
-       
+
        ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!ebuf) {
                printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset);
@@ -360,7 +361,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
        case -EIO:      goto filebad;
        }
 
-       /* Write the erase complete marker */   
+       /* Write the erase complete marker */
        D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
        bad_offset = jeb->offset;
 
@@ -398,7 +399,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                vecs[0].iov_base = (unsigned char *) &marker;
                vecs[0].iov_len = sizeof(marker);
                ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen);
-               
+
                if (ret || retlen != sizeof(marker)) {
                        if (ret)
                                printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
@@ -415,9 +416,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                marker_ref->next_phys = NULL;
                marker_ref->flash_offset = jeb->offset | REF_NORMAL;
                marker_ref->__totlen = c->cleanmarker_size;
-                       
+
                jeb->first_node = jeb->last_node = marker_ref;
-                       
+
                jeb->free_size = c->sector_size - c->cleanmarker_size;
                jeb->used_size = c->cleanmarker_size;
                jeb->dirty_size = 0;
@@ -429,8 +430,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
        c->free_size += jeb->free_size;
        c->used_size += jeb->used_size;
 
-       ACCT_SANITY_CHECK(c,jeb);
-       D1(ACCT_PARANOIA_CHECK(jeb));
+       jffs2_dbg_acct_sanity_check_nolock(c,jeb);
+       jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
 
        list_add_tail(&jeb->list, &c->free_list);
        c->nr_erasing_blocks--;
index 8279bf0133ff573549c0570b707a447042fa4cf9..935f273dc57b834bcb7491d8a099522653f19ce7 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $
+ * $Id: file.c,v 1.104 2005/10/18 23:29:35 tpoynor Exp $
  *
  */
 
@@ -34,8 +34,8 @@ int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
 
        /* Trigger GC to flush any pending writes for this inode */
        jffs2_flush_wbuf_gc(c, inode->i_ino);
-                       
-       return 0;       
+
+       return 0;
 }
 
 struct file_operations jffs2_file_operations =
@@ -107,7 +107,7 @@ static int jffs2_readpage (struct file *filp, struct page *pg)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host);
        int ret;
-       
+
        down(&f->sem);
        ret = jffs2_do_readpage_unlock(pg->mapping->host, pg);
        up(&f->sem);
@@ -130,11 +130,12 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg,
                struct jffs2_raw_inode ri;
                struct jffs2_full_dnode *fn;
                uint32_t phys_ofs, alloc_len;
-               
+
                D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
                          (unsigned int)inode->i_size, pageofs));
 
-               ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
+               ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len,
+                                       ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
                if (ret)
                        return ret;
 
@@ -159,7 +160,7 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg,
                ri.compr = JFFS2_COMPR_ZERO;
                ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
                ri.data_crc = cpu_to_je32(0);
-               
+
                fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
 
                if (IS_ERR(fn)) {
@@ -186,7 +187,7 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg,
                inode->i_size = pageofs;
                up(&f->sem);
        }
-       
+
        /* Read in the page if it wasn't already present, unless it's a whole page */
        if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) {
                down(&f->sem);
@@ -217,7 +218,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg,
        if (!start && end == PAGE_CACHE_SIZE) {
                /* We need to avoid deadlock with page_cache_read() in
                   jffs2_garbage_collect_pass(). So we have to mark the
-                  page up to date, to prevent page_cache_read() from 
+                  page up to date, to prevent page_cache_read() from
                   trying to re-lock it. */
                SetPageUptodate(pg);
        }
@@ -251,7 +252,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg,
                /* There was an error writing. */
                SetPageError(pg);
        }
-       
+
        /* Adjust writtenlen for the padding we did, so we don't confuse our caller */
        if (writtenlen < (start&3))
                writtenlen = 0;
@@ -262,7 +263,7 @@ static int jffs2_commit_write (struct file *filp, struct page *pg,
                if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) {
                        inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen;
                        inode->i_blocks = (inode->i_size + 511) >> 9;
-                       
+
                        inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime));
                }
        }
@@ -271,13 +272,13 @@ static int jffs2_commit_write (struct file *filp, struct page *pg,
 
        if (start+writtenlen < end) {
                /* generic_file_write has written more to the page cache than we've
-                  actually written to the medium. Mark the page !Uptodate so that 
+                  actually written to the medium. Mark the page !Uptodate so that
                   it gets reread */
                D1(printk(KERN_DEBUG "jffs2_commit_write(): Not all bytes written. Marking page !uptodate\n"));
                SetPageError(pg);
                ClearPageUptodate(pg);
        }
 
-       D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret));
-       return writtenlen?writtenlen:ret;
+       D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",start+writtenlen==end?0:ret));
+       return start+writtenlen==end?0:ret;
 }
index 5687c3f42002bf83e63b1caa95cbb354aa214bd5..543420665c5be2f641eacc6fa52062b15b4bcd0f 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs.c,v 1.56 2005/07/06 12:13:09 dwmw2 Exp $
+ * $Id: fs.c,v 1.66 2005/09/27 13:17:29 dedekind Exp $
  *
  */
 
@@ -40,7 +40,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        int ret;
        D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino));
        ret = inode_change_ok(inode, iattr);
-       if (ret) 
+       if (ret)
                return ret;
 
        /* Special cases - we don't want more than one data node
@@ -73,8 +73,9 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
                        kfree(mdata);
                return -ENOMEM;
        }
-               
-       ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+
+       ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen,
+                               ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
        if (ret) {
                jffs2_free_raw_inode(ri);
                if (S_ISLNK(inode->i_mode & S_IFMT))
@@ -83,7 +84,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        }
        down(&f->sem);
        ivalid = iattr->ia_valid;
-       
+
        ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
        ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
        ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
@@ -99,7 +100,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
                if (iattr->ia_mode & S_ISGID &&
                    !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
                        ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID);
-               else 
+               else
                        ri->mode = cpu_to_jemode(iattr->ia_mode);
        else
                ri->mode = cpu_to_jemode(inode->i_mode);
@@ -128,7 +129,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL);
        if (S_ISLNK(inode->i_mode))
                kfree(mdata);
-       
+
        if (IS_ERR(new_metadata)) {
                jffs2_complete_reservation(c);
                jffs2_free_raw_inode(ri);
@@ -147,7 +148,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        old_metadata = f->metadata;
 
        if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
-               jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
+               jffs2_truncate_fragtree (c, &f->fragtree, iattr->ia_size);
 
        if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
                jffs2_add_full_dnode_to_inode(c, f, new_metadata);
@@ -166,7 +167,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        jffs2_complete_reservation(c);
 
        /* We have to do the vmtruncate() without f->sem held, since
-          some pages may be locked and waiting for it in readpage(). 
+          some pages may be locked and waiting for it in readpage().
           We are protected from a simultaneous write() extending i_size
           back past iattr->ia_size, because do_truncate() holds the
           generic inode semaphore. */
@@ -194,31 +195,27 @@ int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
        buf->f_namelen = JFFS2_MAX_NAME_LEN;
 
        spin_lock(&c->erase_completion_lock);
-
        avail = c->dirty_size + c->free_size;
        if (avail > c->sector_size * c->resv_blocks_write)
                avail -= c->sector_size * c->resv_blocks_write;
        else
                avail = 0;
+       spin_unlock(&c->erase_completion_lock);
 
        buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
 
-       D2(jffs2_dump_block_lists(c));
-
-       spin_unlock(&c->erase_completion_lock);
-
        return 0;
 }
 
 
 void jffs2_clear_inode (struct inode *inode)
 {
-       /* We can forget about this inode for now - drop all 
+       /* We can forget about this inode for now - drop all
         *  the nodelists associated with it, etc.
         */
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
-       
+
        D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode));
 
        jffs2_do_clear_inode(c, f);
@@ -237,7 +234,7 @@ void jffs2_read_inode (struct inode *inode)
        c = JFFS2_SB_INFO(inode->i_sb);
 
        jffs2_init_inode_info(f);
-       
+
        ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
 
        if (ret) {
@@ -257,14 +254,14 @@ void jffs2_read_inode (struct inode *inode)
 
        inode->i_blksize = PAGE_SIZE;
        inode->i_blocks = (inode->i_size + 511) >> 9;
-       
+
        switch (inode->i_mode & S_IFMT) {
                jint16_t rdev;
 
        case S_IFLNK:
                inode->i_op = &jffs2_symlink_inode_operations;
                break;
-               
+
        case S_IFDIR:
        {
                struct jffs2_full_dirent *fd;
@@ -301,7 +298,7 @@ void jffs2_read_inode (struct inode *inode)
                        jffs2_do_clear_inode(c, f);
                        make_bad_inode(inode);
                        return;
-               }                       
+               }
 
        case S_IFSOCK:
        case S_IFIFO:
@@ -357,11 +354,11 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
                down(&c->alloc_sem);
                jffs2_flush_wbuf_pad(c);
                up(&c->alloc_sem);
-       }       
+       }
 
        if (!(*flags & MS_RDONLY))
                jffs2_start_garbage_collect_thread(c);
-       
+
        *flags |= MS_NOATIME;
 
        return 0;
@@ -395,9 +392,9 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
        D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
 
        c = JFFS2_SB_INFO(sb);
-       
+
        inode = new_inode(sb);
-       
+
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
@@ -461,40 +458,24 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
 #endif
 
        c->flash_size = c->mtd->size;
-
-       /* 
-        * Check, if we have to concatenate physical blocks to larger virtual blocks
-        * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation)
-        */
-       c->sector_size = c->mtd->erasesize; 
+       c->sector_size = c->mtd->erasesize;
        blocks = c->flash_size / c->sector_size;
-       if (!(c->mtd->flags & MTD_NO_VIRTBLOCKS)) {
-               while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
-                       blocks >>= 1;
-                       c->sector_size <<= 1;
-               }       
-       }
 
        /*
         * Size alignment check
         */
        if ((c->sector_size * blocks) != c->flash_size) {
-               c->flash_size = c->sector_size * blocks;                
+               c->flash_size = c->sector_size * blocks;
                printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n",
                        c->flash_size / 1024);
        }
 
-       if (c->sector_size != c->mtd->erasesize)
-               printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", 
-                       c->mtd->erasesize / 1024, c->sector_size / 1024);
-
        if (c->flash_size < 5*c->sector_size) {
                printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size);
                return -EINVAL;
        }
 
        c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
-       /* Joern -- stick alignment for weird 8-byte-page flash here */
 
        /* NAND (or other bizarre) flash... do setup accordingly */
        ret = jffs2_flash_setup(c);
@@ -517,7 +498,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
        root_i = iget(sb, 1);
        if (is_bad_inode(root_i)) {
                D1(printk(KERN_WARNING "get root inode failed\n"));
-               goto out_nodes;
+               goto out_root_i;
        }
 
        D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n"));
@@ -535,10 +516,9 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
 
  out_root_i:
        iput(root_i);
- out_nodes:
        jffs2_free_ino_caches(c);
        jffs2_free_raw_node_refs(c);
-       if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
+       if (jffs2_blocks_use_vmalloc(c))
                vfree(c->blocks);
        else
                kfree(c->blocks);
@@ -563,16 +543,16 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
        struct jffs2_inode_cache *ic;
        if (!nlink) {
                /* The inode has zero nlink but its nodes weren't yet marked
-                  obsolete. This has to be because we're still waiting for 
+                  obsolete. This has to be because we're still waiting for
                   the final (close() and) iput() to happen.
 
-                  There's a possibility that the final iput() could have 
+                  There's a possibility that the final iput() could have
                   happened while we were contemplating. In order to ensure
                   that we don't cause a new read_inode() (which would fail)
                   for the inode in question, we use ilookup() in this case
                   instead of iget().
 
-                  The nlink can't _become_ zero at this point because we're 
+                  The nlink can't _become_ zero at this point because we're
                   holding the alloc_sem, and jffs2_do_unlink() would also
                   need that while decrementing nlink on any inode.
                */
@@ -619,19 +599,19 @@ struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
        return JFFS2_INODE_INFO(inode);
 }
 
-unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
-                                  struct jffs2_inode_info *f, 
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
+                                  struct jffs2_inode_info *f,
                                   unsigned long offset,
                                   unsigned long *priv)
 {
        struct inode *inode = OFNI_EDONI_2SFFJ(f);
        struct page *pg;
 
-       pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, 
+       pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT,
                             (void *)jffs2_do_readpage_unlock, inode);
        if (IS_ERR(pg))
                return (void *)pg;
-       
+
        *priv = (unsigned long)pg;
        return kmap(pg);
 }
@@ -648,7 +628,7 @@ void jffs2_gc_release_page(struct jffs2_sb_info *c,
 
 static int jffs2_flash_setup(struct jffs2_sb_info *c) {
        int ret = 0;
-       
+
        if (jffs2_cleanmarker_oob(c)) {
                /* NAND flash... do setup accordingly */
                ret = jffs2_nand_flash_setup(c);
@@ -662,14 +642,21 @@ 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;
        }
-       
+
+       /* and Intel "Sibley" flash */
+       if (jffs2_nor_wbuf_flash(c)) {
+               ret = jffs2_nor_wbuf_flash_setup(c);
+               if (ret)
+                       return ret;
+       }
+
        return ret;
 }
 
@@ -683,9 +670,14 @@ 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);
        }
+
+       /* and Intel "Sibley" flash */
+       if (jffs2_nor_wbuf_flash(c)) {
+               jffs2_nor_wbuf_flash_cleanup(c);
+       }
 }
index 7086cd6345038cbc9015dacb4b23dcaf7f4f081f..f9ffece453a38e65542db843701749f943a71283 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $
+ * $Id: gc.c,v 1.155 2005/11/07 11:14:39 gleixner Exp $
  *
  */
 
 #include "nodelist.h"
 #include "compr.h"
 
-static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 
+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
                                          struct jffs2_inode_cache *ic,
                                          struct jffs2_raw_node_ref *raw);
-static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                        struct jffs2_inode_info *f, struct jffs2_full_dnode *fd);
-static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                        struct jffs2_inode_info *f, struct jffs2_full_dirent *fd);
-static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                        struct jffs2_inode_info *f, struct jffs2_full_dirent *fd);
 static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                      struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
@@ -55,7 +55,7 @@ again:
                D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
                nextlist = &c->bad_used_list;
        } else if (n < 50 && !list_empty(&c->erasable_list)) {
-               /* Note that most of them will have gone directly to be erased. 
+               /* Note that most of them will have gone directly to be erased.
                   So don't favour the erasable_list _too_ much. */
                D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n"));
                nextlist = &c->erasable_list;
@@ -101,7 +101,7 @@ again:
                printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset);
                BUG();
        }
-       
+
        /* Have we accidentally picked a clean block with wasted space ? */
        if (ret->wasted_size) {
                D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size));
@@ -111,7 +111,6 @@ again:
                ret->wasted_size = 0;
        }
 
-       D2(jffs2_dump_block_lists(c));
        return ret;
 }
 
@@ -137,12 +136,12 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 
                /* We can't start doing GC yet. We haven't finished checking
                   the node CRCs etc. Do it now. */
-               
+
                /* checked_ino is protected by the alloc_sem */
                if (c->checked_ino > c->highest_ino) {
                        printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
                               c->unchecked_size);
-                       D2(jffs2_dump_block_lists(c));
+                       jffs2_dbg_dump_block_lists_nolock(c);
                        spin_unlock(&c->erase_completion_lock);
                        BUG();
                }
@@ -179,7 +178,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 
                case INO_STATE_READING:
                        /* We need to wait for it to finish, lest we move on
-                          and trigger the BUG() above while we haven't yet 
+                          and trigger the BUG() above while we haven't yet
                           finished checking all its nodes */
                        D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino));
                        up(&c->alloc_sem);
@@ -229,13 +228,13 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
        }
 
        raw = jeb->gc_node;
-                       
+
        while(ref_obsolete(raw)) {
                D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
                raw = raw->next_phys;
                if (unlikely(!raw)) {
                        printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
-                       printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", 
+                       printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n",
                               jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
                        jeb->gc_node = raw;
                        spin_unlock(&c->erase_completion_lock);
@@ -260,7 +259,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
        ic = jffs2_raw_ref_to_ic(raw);
 
        /* We need to hold the inocache. Either the erase_completion_lock or
-          the inocache_lock are sufficient; we trade down since the inocache_lock 
+          the inocache_lock are sufficient; we trade down since the inocache_lock
           causes less contention. */
        spin_lock(&c->inocache_lock);
 
@@ -279,14 +278,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 
        switch(ic->state) {
        case INO_STATE_CHECKEDABSENT:
-               /* It's been checked, but it's not currently in-core. 
+               /* It's been checked, but it's not currently in-core.
                   We can just copy any pristine nodes, but have
                   to prevent anyone else from doing read_inode() while
                   we're at it, so we set the state accordingly */
                if (ref_flags(raw) == REF_PRISTINE)
                        ic->state = INO_STATE_GC;
                else {
-                       D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", 
+                       D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n",
                                  ic->ino));
                }
                break;
@@ -299,8 +298,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
        case INO_STATE_CHECKING:
        case INO_STATE_GC:
                /* Should never happen. We should have finished checking
-                  by the time we actually start doing any GC, and since 
-                  we're holding the alloc_sem, no other garbage collection 
+                  by the time we actually start doing any GC, and since
+                  we're holding the alloc_sem, no other garbage collection
                   can happen.
                */
                printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
@@ -320,21 +319,21 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
                          ic->ino, ic->state));
                sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-               /* And because we dropped the alloc_sem we must start again from the 
+               /* And because we dropped the alloc_sem we must start again from the
                   beginning. Ponder chance of livelock here -- we're returning success
                   without actually making any progress.
 
-                  Q: What are the chances that the inode is back in INO_STATE_READING 
+                  Q: What are the chances that the inode is back in INO_STATE_READING
                   again by the time we next enter this function? And that this happens
                   enough times to cause a real delay?
 
-                  A: Small enough that I don't care :) 
+                  A: Small enough that I don't care :)
                */
                return 0;
        }
 
        /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the
-          node intact, and we don't have to muck about with the fragtree etc. 
+          node intact, and we don't have to muck about with the fragtree etc.
           because we know it's not in-core. If it _was_ in-core, we go through
           all the iget() crap anyway */
 
@@ -454,7 +453,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_era
                        if (!ret) {
                                /* Urgh. Return it sensibly. */
                                frag->node->raw = f->inocache->nodes;
-                       }       
+                       }
                        if (ret != -EBADFD)
                                goto upnout;
                }
@@ -468,7 +467,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_era
                }
                goto upnout;
        }
-       
+
        /* Wasn't a dnode. Try dirent */
        for (fd = f->dents; fd; fd=fd->next) {
                if (fd->raw == raw)
@@ -485,7 +484,8 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_era
                if (ref_obsolete(raw)) {
                        printk(KERN_WARNING "But it's obsolete so we don't mind too much\n");
                } else {
-                       ret = -EIO;
+                       jffs2_dbg_dump_node(c, ref_offset(raw));
+                       BUG();
                }
        }
  upnout:
@@ -494,7 +494,7 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_era
        return ret;
 }
 
-static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 
+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
                                          struct jffs2_inode_cache *ic,
                                          struct jffs2_raw_node_ref *raw)
 {
@@ -513,8 +513,11 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
        /* Ask for a small amount of space (or the totlen if smaller) because we
           don't want to force wastage of the end of a block if splitting would
           work. */
-       ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, 
-                                             rawlen), &phys_ofs, &alloclen);
+       ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) +
+                               JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen);
+                               /* this is not the exact summary size of it,
+                                       it is only an upper estimation */
+
        if (ret)
                return ret;
 
@@ -577,7 +580,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
                }
                break;
        default:
-               printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", 
+               printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n",
                       ref_offset(raw), je16_to_cpu(node->u.nodetype));
                goto bail;
        }
@@ -618,17 +621,19 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
                        retried = 1;
 
                        D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n"));
-                       
-                       ACCT_SANITY_CHECK(c,jeb);
-                       D1(ACCT_PARANOIA_CHECK(jeb));
 
-                       ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy);
+                       jffs2_dbg_acct_sanity_check(c,jeb);
+                       jffs2_dbg_acct_paranoia_check(c, jeb);
+
+                       ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy, rawlen);
+                                               /* this is not the exact summary size of it,
+                                                       it is only an upper estimation */
 
                        if (!ret) {
                                D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
 
-                               ACCT_SANITY_CHECK(c,jeb);
-                               D1(ACCT_PARANOIA_CHECK(jeb));
+                               jffs2_dbg_acct_sanity_check(c,jeb);
+                               jffs2_dbg_acct_paranoia_check(c, jeb);
 
                                goto retry;
                        }
@@ -664,7 +669,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
        goto out_node;
 }
 
-static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                        struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
 {
        struct jffs2_full_dnode *new_fn;
@@ -679,7 +684,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
            S_ISCHR(JFFS2_F_I_MODE(f)) ) {
                /* For these, we don't actually need to read the old node */
                /* FIXME: for minor or major > 255. */
-               dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | 
+               dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) |
                        JFFS2_F_I_RDEV_MIN(f)));
                mdata = (char *)&dev;
                mdatalen = sizeof(dev);
@@ -700,14 +705,15 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
                D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bites of symlink target\n", mdatalen));
 
        }
-       
-       ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen);
+
+       ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen,
+                               JFFS2_SUMMARY_INODE_SIZE);
        if (ret) {
                printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
                       sizeof(ri)+ mdatalen, ret);
                goto out;
        }
-       
+
        last_frag = frag_last(&f->fragtree);
        if (last_frag)
                /* Fetch the inode length from the fragtree rather then
@@ -715,7 +721,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
                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);
@@ -754,7 +760,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
        return ret;
 }
 
-static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                        struct jffs2_inode_info *f, struct jffs2_full_dirent *fd)
 {
        struct jffs2_full_dirent *new_fd;
@@ -771,12 +777,18 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er
        rd.pino = cpu_to_je32(f->inocache->ino);
        rd.version = cpu_to_je32(++f->highest_version);
        rd.ino = cpu_to_je32(fd->ino);
-       rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f)));
+       /* If the times on this inode were set by explicit utime() they can be different,
+          so refrain from splatting them. */
+       if (JFFS2_F_I_MTIME(f) == JFFS2_F_I_CTIME(f))
+               rd.mctime = cpu_to_je32(JFFS2_F_I_MTIME(f));
+       else
+               rd.mctime = cpu_to_je32(0);
        rd.type = fd->type;
        rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
        rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));
-       
-       ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);
+
+       ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen,
+                               JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize));
        if (ret) {
                printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
                       sizeof(rd)+rd.nsize, ret);
@@ -792,7 +804,7 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er
        return 0;
 }
 
-static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
+static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                        struct jffs2_inode_info *f, struct jffs2_full_dirent *fd)
 {
        struct jffs2_full_dirent **fdp = &f->dents;
@@ -831,7 +843,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
                        if (ref_totlen(c, NULL, raw) != rawlen)
                                continue;
 
-                       /* Doesn't matter if there's one in the same erase block. We're going to 
+                       /* Doesn't matter if there's one in the same erase block. We're going to
                           delete it too at the same time. */
                        if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset))
                                continue;
@@ -883,6 +895,9 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
                kfree(rd);
        }
 
+       /* FIXME: If we're deleting a dirent which contains the current mtime and ctime,
+          we should update the metadata node with those times accordingly */
+
        /* No need for it any more. Just mark it obsolete and remove it from the list */
        while (*fdp) {
                if ((*fdp) == fd) {
@@ -912,13 +927,13 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
 
        D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",
                  f->inocache->ino, start, end));
-       
+
        memset(&ri, 0, sizeof(ri));
 
        if(fn->frags > 1) {
                size_t readlen;
                uint32_t crc;
-               /* It's partially obsoleted by a later write. So we have to 
+               /* It's partially obsoleted by a later write. So we have to
                   write it out again with the _same_ version as before */
                ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri);
                if (readlen != sizeof(ri) || ret) {
@@ -940,16 +955,16 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
                crc = crc32(0, &ri, sizeof(ri)-8);
                if (crc != je32_to_cpu(ri.node_crc)) {
                        printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n",
-                              ref_offset(fn->raw), 
+                              ref_offset(fn->raw),
                               je32_to_cpu(ri.node_crc), crc);
                        /* FIXME: We could possibly deal with this by writing new holes for each frag */
-                       printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", 
+                       printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
                               start, end, f->inocache->ino);
                        goto fill;
                }
                if (ri.compr != JFFS2_COMPR_ZERO) {
                        printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw));
-                       printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", 
+                       printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
                               start, end, f->inocache->ino);
                        goto fill;
                }
@@ -967,7 +982,7 @@ 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
@@ -986,7 +1001,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
        ri.data_crc = cpu_to_je32(0);
        ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
 
-       ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);
+       ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen,
+                               JFFS2_SUMMARY_INODE_SIZE);
        if (ret) {
                printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
                       sizeof(ri), ret);
@@ -1008,10 +1024,10 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
                return 0;
        }
 
-       /* 
+       /*
         * We should only get here in the case where the node we are
         * replacing had more than one frag, so we kept the same version
-        * number as before. (Except in case of error -- see 'goto fill;' 
+        * number as before. (Except in case of error -- see 'goto fill;'
         * above.)
         */
        D1(if(unlikely(fn->frags <= 1)) {
@@ -1023,7 +1039,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
        /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */
        mark_ref_normal(new_fn->raw);
 
-       for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); 
+       for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs);
             frag; frag = frag_next(frag)) {
                if (frag->ofs > fn->size + fn->ofs)
                        break;
@@ -1041,10 +1057,10 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
                printk(KERN_WARNING "jffs2_garbage_collect_hole: New node has no frags!\n");
                BUG();
        }
-               
+
        jffs2_mark_node_obsolete(c, fn->raw);
        jffs2_free_full_dnode(fn);
-       
+
        return 0;
 }
 
@@ -1054,12 +1070,12 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
 {
        struct jffs2_full_dnode *new_fn;
        struct jffs2_raw_inode ri;
-       uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;      
+       uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;
        int ret = 0;
        unsigned char *comprbuf = NULL, *writebuf;
        unsigned long pg;
        unsigned char *pg_ptr;
+
        memset(&ri, 0, sizeof(ri));
 
        D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",
@@ -1071,8 +1087,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
        if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) {
                /* Attempt to do some merging. But only expand to cover logically
                   adjacent frags if the block containing them is already considered
-                  to be dirty. Otherwise we end up with GC just going round in 
-                  circles dirtying the nodes it already wrote out, especially 
+                  to be dirty. Otherwise we end up with GC just going round in
+                  circles dirtying the nodes it already wrote out, especially
                   on NAND where we have small eraseblocks and hence a much higher
                   chance of nodes having to be split to cross boundaries. */
 
@@ -1106,7 +1122,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                                break;
                        } else {
 
-                               /* OK, it's a frag which extends to the beginning of the page. Does it live 
+                               /* OK, it's a frag which extends to the beginning of the page. Does it live
                                   in a block which is still considered clean? If so, don't obsolete it.
                                   If not, cover it anyway. */
 
@@ -1156,7 +1172,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                                break;
                        } else {
 
-                               /* OK, it's a frag which extends to the beginning of the page. Does it live 
+                               /* OK, it's a frag which extends to the beginning of the page. Does it live
                                   in a block which is still considered clean? If so, don't obsolete it.
                                   If not, cover it anyway. */
 
@@ -1183,14 +1199,14 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                                break;
                        }
                }
-               D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", 
+               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));
 
                D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size));
                BUG_ON(end < orig_end);
                BUG_ON(start > orig_start);
        }
-       
+
        /* First, use readpage() to read the appropriate page into the page cache */
        /* Q: What happens if we actually try to GC the _same_ page for which commit_write()
         *    triggered garbage collection in the first place?
@@ -1211,7 +1227,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                uint32_t cdatalen;
                uint16_t comprtype = JFFS2_COMPR_NONE;
 
-               ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
+               ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
+                                       &alloclen, JFFS2_SUMMARY_INODE_SIZE);
 
                if (ret) {
                        printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",
@@ -1246,7 +1263,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                ri.usercompr = (comprtype >> 8) & 0xff;
                ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
                ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
-       
+
                new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC);
 
                jffs2_free_comprbuf(comprbuf, writebuf);
@@ -1268,4 +1285,3 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
        jffs2_gc_release_page(c, pg_ptr, &pg);
        return ret;
 }
-
index 84f184f0836f2aab1b9514336f5d3bb75aea6fd5..22a93a08210c060f47dd2b71674b391b4ea27897 100644 (file)
@@ -1,3 +1,3 @@
 /* This file provides the bit-probabilities for the input file */
-#define BIT_DIVIDER 629 
+#define BIT_DIVIDER 629
 static int bits[9] = { 179,167,183,165,159,198,178,119,}; /* ia32 .so files */
index 9a443268d88576da92819a2a013464b33d45395b..fa3dac19a109eeb2cb1a1c481dda948979e6946a 100644 (file)
@@ -1,2 +1,2 @@
-#define BIT_DIVIDER_MIPS 1043 
+#define BIT_DIVIDER_MIPS 1043
 static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */
index 238c7992064cfbeb001f834096d425b60c3a40c9..69099835de1c3e8ed140a86eaee30d42fa682973 100644 (file)
@@ -7,17 +7,17 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: ioctl.c,v 1.9 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: ioctl.c,v 1.10 2005/11/07 11:14:40 gleixner Exp $
  *
  */
 
 #include <linux/fs.h>
 
-int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 
+int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
                unsigned long arg)
 {
        /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which
           will include compression support etc. */
        return -ENOTTY;
 }
-       
+
index 5abb431c2a00fcf1ccfa24d84474f20e9045a5a8..036cbd11c00449d6755481b8a51e53bbf0f7fb4f 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: malloc.c,v 1.28 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: malloc.c,v 1.31 2005/11/07 11:14:40 gleixner Exp $
  *
  */
 
 #include <linux/jffs2.h>
 #include "nodelist.h"
 
-#if 0
-#define JFFS2_SLAB_POISON SLAB_POISON
-#else
-#define JFFS2_SLAB_POISON 0
-#endif
-
-// replace this by #define D3 (x) x for cache debugging
-#define D3(x)
-
 /* These are initialised to NULL in the kernel startup code.
    If you're porting to other operating systems, beware */
 static kmem_cache_t *full_dnode_slab;
@@ -38,45 +29,45 @@ static kmem_cache_t *inode_cache_slab;
 
 int __init jffs2_create_slab_caches(void)
 {
-       full_dnode_slab = kmem_cache_create("jffs2_full_dnode", 
+       full_dnode_slab = kmem_cache_create("jffs2_full_dnode",
                                            sizeof(struct jffs2_full_dnode),
-                                           0, JFFS2_SLAB_POISON, NULL, NULL);
+                                           0, 0, NULL, NULL);
        if (!full_dnode_slab)
                goto err;
 
        raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent",
                                            sizeof(struct jffs2_raw_dirent),
-                                           0, JFFS2_SLAB_POISON, NULL, NULL);
+                                           0, 0, NULL, NULL);
        if (!raw_dirent_slab)
                goto err;
 
        raw_inode_slab = kmem_cache_create("jffs2_raw_inode",
                                           sizeof(struct jffs2_raw_inode),
-                                          0, JFFS2_SLAB_POISON, NULL, NULL);
+                                          0, 0, NULL, NULL);
        if (!raw_inode_slab)
                goto err;
 
        tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode",
                                                sizeof(struct jffs2_tmp_dnode_info),
-                                               0, JFFS2_SLAB_POISON, NULL, NULL);
+                                               0, 0, NULL, NULL);
        if (!tmp_dnode_info_slab)
                goto err;
 
        raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref",
                                              sizeof(struct jffs2_raw_node_ref),
-                                             0, JFFS2_SLAB_POISON, NULL, NULL);
+                                             0, 0, NULL, NULL);
        if (!raw_node_ref_slab)
                goto err;
 
        node_frag_slab = kmem_cache_create("jffs2_node_frag",
                                           sizeof(struct jffs2_node_frag),
-                                          0, JFFS2_SLAB_POISON, NULL, NULL);
+                                          0, 0, NULL, NULL);
        if (!node_frag_slab)
                goto err;
 
        inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
                                             sizeof(struct jffs2_inode_cache),
-                                            0, JFFS2_SLAB_POISON, NULL, NULL);
+                                            0, 0, NULL, NULL);
        if (inode_cache_slab)
                return 0;
  err:
@@ -104,102 +95,113 @@ void jffs2_destroy_slab_caches(void)
 
 struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
 {
-       return kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL);
+       struct jffs2_full_dirent *ret;
+       ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL);
+       dbg_memalloc("%p\n", ret);
+       return ret;
 }
 
 void jffs2_free_full_dirent(struct jffs2_full_dirent *x)
 {
+       dbg_memalloc("%p\n", x);
        kfree(x);
 }
 
 struct jffs2_full_dnode *jffs2_alloc_full_dnode(void)
 {
-       struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL);
-       D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret));
+       struct jffs2_full_dnode *ret;
+       ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL);
+       dbg_memalloc("%p\n", ret);
        return ret;
 }
 
 void jffs2_free_full_dnode(struct jffs2_full_dnode *x)
 {
-       D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x));
+       dbg_memalloc("%p\n", x);
        kmem_cache_free(full_dnode_slab, x);
 }
 
 struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void)
 {
-       struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL);
-       D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret));
+       struct jffs2_raw_dirent *ret;
+       ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL);
+       dbg_memalloc("%p\n", ret);
        return ret;
 }
 
 void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x)
 {
-       D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x));
+       dbg_memalloc("%p\n", x);
        kmem_cache_free(raw_dirent_slab, x);
 }
 
 struct jffs2_raw_inode *jffs2_alloc_raw_inode(void)
 {
-       struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL);
-       D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret));
+       struct jffs2_raw_inode *ret;
+       ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL);
+       dbg_memalloc("%p\n", ret);
        return ret;
 }
 
 void jffs2_free_raw_inode(struct jffs2_raw_inode *x)
 {
-       D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x));
+       dbg_memalloc("%p\n", x);
        kmem_cache_free(raw_inode_slab, x);
 }
 
 struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void)
 {
-       struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL);
-       D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret));
+       struct jffs2_tmp_dnode_info *ret;
+       ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL);
+       dbg_memalloc("%p\n",
+               ret);
        return ret;
 }
 
 void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x)
 {
-       D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x));
+       dbg_memalloc("%p\n", x);
        kmem_cache_free(tmp_dnode_info_slab, x);
 }
 
 struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
 {
-       struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
-       D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret));
+       struct jffs2_raw_node_ref *ret;
+       ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
+       dbg_memalloc("%p\n", ret);
        return ret;
 }
 
 void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
 {
-       D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x));
+       dbg_memalloc("%p\n", x);
        kmem_cache_free(raw_node_ref_slab, x);
 }
 
 struct jffs2_node_frag *jffs2_alloc_node_frag(void)
 {
-       struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL);
-       D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret));
+       struct jffs2_node_frag *ret;
+       ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL);
+       dbg_memalloc("%p\n", ret);
        return ret;
 }
 
 void jffs2_free_node_frag(struct jffs2_node_frag *x)
 {
-       D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x));
+       dbg_memalloc("%p\n", x);
        kmem_cache_free(node_frag_slab, x);
 }
 
 struct jffs2_inode_cache *jffs2_alloc_inode_cache(void)
 {
-       struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL);
-       D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret));
+       struct jffs2_inode_cache *ret;
+       ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL);
+       dbg_memalloc("%p\n", ret);
        return ret;
 }
 
 void jffs2_free_inode_cache(struct jffs2_inode_cache *x)
 {
-       D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x));
+       dbg_memalloc("%p\n", x);
        kmem_cache_free(inode_cache_slab, x);
 }
-
index 4991c348f6ec36ee82f2525e2ae4c86aeed82bfb..c79eebb8ab32caeeb0f3527ed54af5e37c8eff89 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.c,v 1.98 2005/07/10 15:15:32 dedekind Exp $
+ * $Id: nodelist.c,v 1.115 2005/11/07 11:14:40 gleixner Exp $
  *
  */
 
 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
 {
        struct jffs2_full_dirent **prev = list;
-       D1(printk(KERN_DEBUG "jffs2_add_fd_to_list( %p, %p (->%p))\n", new, list, *list));
+
+       dbg_dentlist("add dirent \"%s\", ino #%u\n", new->name, new->ino);
 
        while ((*prev) && (*prev)->nhash <= new->nhash) {
                if ((*prev)->nhash == new->nhash && !strcmp((*prev)->name, new->name)) {
                        /* Duplicate. Free one */
                        if (new->version < (*prev)->version) {
-                               D1(printk(KERN_DEBUG "Eep! Marking new dirent node obsolete\n"));
-                               D1(printk(KERN_DEBUG "New dirent is \"%s\"->ino #%u. Old is \"%s\"->ino #%u\n", new->name, new->ino, (*prev)->name, (*prev)->ino));
+                               dbg_dentlist("Eep! Marking new dirent node is obsolete, old is \"%s\", ino #%u\n",
+                                       (*prev)->name, (*prev)->ino);
                                jffs2_mark_node_obsolete(c, new->raw);
                                jffs2_free_full_dirent(new);
                        } else {
-                               D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) obsolete\n", (*prev)->ino));
+                               dbg_dentlist("marking old dirent \"%s\", ino #%u bsolete\n",
+                                       (*prev)->name, (*prev)->ino);
                                new->next = (*prev)->next;
                                jffs2_mark_node_obsolete(c, ((*prev)->raw));
                                jffs2_free_full_dirent(*prev);
                                *prev = new;
                        }
-                       goto out;
+                       return;
                }
                prev = &((*prev)->next);
        }
        new->next = *prev;
        *prev = new;
+}
+
+void jffs2_truncate_fragtree(struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
+{
+       struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
+
+       dbg_fragtree("truncating fragtree to 0x%08x bytes\n", size);
+
+       /* We know frag->ofs <= size. That's what lookup does for us */
+       if (frag && frag->ofs != size) {
+               if (frag->ofs+frag->size > size) {
+                       frag->size = size - frag->ofs;
+               }
+               frag = frag_next(frag);
+       }
+       while (frag && frag->ofs >= size) {
+               struct jffs2_node_frag *next = frag_next(frag);
+
+               frag_erase(frag, list);
+               jffs2_obsolete_node_frag(c, frag);
+               frag = next;
+       }
 
- out:
-       D2(while(*list) {
-               printk(KERN_DEBUG "Dirent \"%s\" (hash 0x%08x, ino #%u\n", (*list)->name, (*list)->nhash, (*list)->ino);
-               list = &(*list)->next;
-       });
+       if (size == 0)
+               return;
+
+       /*
+        * If the last fragment starts at the RAM page boundary, it is
+        * REF_PRISTINE irrespective of its size.
+        */
+       frag = frag_last(list);
+       if (frag->node && (frag->ofs & (PAGE_CACHE_SIZE - 1)) == 0) {
+               dbg_fragtree2("marking the last fragment 0x%08x-0x%08x REF_PRISTINE.\n",
+                       frag->ofs, frag->ofs + frag->size);
+               frag->node->raw->flash_offset = ref_offset(frag->node->raw) | REF_PRISTINE;
+       }
 }
 
-/* 
- * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in 
- * order of increasing version.
- */
-static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list)
+void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
 {
-       struct rb_node **p = &list->rb_node;
-       struct rb_node * parent = NULL;
-       struct jffs2_tmp_dnode_info *this;
-
-       while (*p) {
-               parent = *p;
-               this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
-
-               /* There may actually be a collision here, but it doesn't
-                  actually matter. As long as the two nodes with the same
-                  version are together, it's all fine. */
-               if (tn->version < this->version)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-        }
+       if (this->node) {
+               this->node->frags--;
+               if (!this->node->frags) {
+                       /* The node has no valid frags left. It's totally obsoleted */
+                       dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) obsolete\n",
+                               ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size);
+                       jffs2_mark_node_obsolete(c, this->node->raw);
+                       jffs2_free_full_dnode(this->node);
+               } else {
+                       dbg_fragtree2("marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n",
+                               ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, this->node->frags);
+                       mark_ref_normal(this->node->raw);
+               }
 
-       rb_link_node(&tn->rb, parent, p);
-       rb_insert_color(&tn->rb, list);
+       }
+       jffs2_free_node_frag(this);
 }
 
-static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
+static void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
 {
-       struct rb_node *this;
-       struct jffs2_tmp_dnode_info *tn;
+       struct rb_node *parent = &base->rb;
+       struct rb_node **link = &parent;
 
-       this = list->rb_node;
+       dbg_fragtree2("insert frag (0x%04x-0x%04x)\n", newfrag->ofs, newfrag->ofs + newfrag->size);
 
-       /* Now at bottom of tree */
-       while (this) {
-               if (this->rb_left)
-                       this = this->rb_left;
-               else if (this->rb_right)
-                       this = this->rb_right;
+       while (*link) {
+               parent = *link;
+               base = rb_entry(parent, struct jffs2_node_frag, rb);
+
+               if (newfrag->ofs > base->ofs)
+                       link = &base->rb.rb_right;
+               else if (newfrag->ofs < base->ofs)
+                       link = &base->rb.rb_left;
                else {
-                       tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb);
-                       jffs2_free_full_dnode(tn->fn);
-                       jffs2_free_tmp_dnode_info(tn);
-
-                       this = this->rb_parent;
-                       if (!this)
-                               break;
-
-                       if (this->rb_left == &tn->rb)
-                               this->rb_left = NULL;
-                       else if (this->rb_right == &tn->rb)
-                               this->rb_right = NULL;
-                       else BUG();
+                       JFFS2_ERROR("duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
+                       BUG();
                }
        }
-       list->rb_node = NULL;
+
+       rb_link_node(&newfrag->rb, &base->rb, link);
 }
 
-static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
+/*
+ * Allocate and initializes a new fragment.
+ */
+static inline struct jffs2_node_frag * new_fragment(struct jffs2_full_dnode *fn, uint32_t ofs, uint32_t size)
 {
-       struct jffs2_full_dirent *next;
-
-       while (fd) {
-               next = fd->next;
-               jffs2_free_full_dirent(fd);
-               fd = next;
+       struct jffs2_node_frag *newfrag;
+
+       newfrag = jffs2_alloc_node_frag();
+       if (likely(newfrag)) {
+               newfrag->ofs = ofs;
+               newfrag->size = size;
+               newfrag->node = fn;
+       } else {
+               JFFS2_ERROR("cannot allocate a jffs2_node_frag object\n");
        }
+
+       return newfrag;
 }
 
-/* Returns first valid node after 'ref'. May return 'ref' */
-static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref)
+/*
+ * Called when there is no overlapping fragment exist. Inserts a hole before the new
+ * fragment and inserts the new fragment to the fragtree.
+ */
+static int no_overlapping_node(struct jffs2_sb_info *c, struct rb_root *root,
+                              struct jffs2_node_frag *newfrag,
+                              struct jffs2_node_frag *this, uint32_t lastend)
 {
-       while (ref && ref->next_in_ino) {
-               if (!ref_obsolete(ref))
-                       return ref;
-               D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
-               ref = ref->next_in_ino;
+       if (lastend < newfrag->node->ofs) {
+               /* put a hole in before the new fragment */
+               struct jffs2_node_frag *holefrag;
+
+               holefrag= new_fragment(NULL, lastend, newfrag->node->ofs - lastend);
+               if (unlikely(!holefrag)) {
+                       jffs2_free_node_frag(newfrag);
+                       return -ENOMEM;
+               }
+
+               if (this) {
+                       /* By definition, the 'this' node has no right-hand child,
+                          because there are no frags with offset greater than it.
+                          So that's where we want to put the hole */
+                       dbg_fragtree2("add hole frag %#04x-%#04x on the right of the new frag.\n",
+                               holefrag->ofs, holefrag->ofs + holefrag->size);
+                       rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
+               } else {
+                       dbg_fragtree2("Add hole frag %#04x-%#04x to the root of the tree.\n",
+                               holefrag->ofs, holefrag->ofs + holefrag->size);
+                       rb_link_node(&holefrag->rb, NULL, &root->rb_node);
+               }
+               rb_insert_color(&holefrag->rb, root);
+               this = holefrag;
+       }
+
+       if (this) {
+               /* By definition, the 'this' node has no right-hand child,
+                  because there are no frags with offset greater than it.
+                  So that's where we want to put new fragment */
+               dbg_fragtree2("add the new node at the right\n");
+               rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
+       } else {
+               dbg_fragtree2("insert the new node at the root of the tree\n");
+               rb_link_node(&newfrag->rb, NULL, &root->rb_node);
        }
-       return NULL;
+       rb_insert_color(&newfrag->rb, root);
+
+       return 0;
 }
 
-/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
-   with this ino, returning the former in order of version */
+/* Doesn't set inode->i_size */
+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *root, struct jffs2_node_frag *newfrag)
+{
+       struct jffs2_node_frag *this;
+       uint32_t lastend;
+
+       /* Skip all the nodes which are completed before this one starts */
+       this = jffs2_lookup_node_frag(root, newfrag->node->ofs);
+
+       if (this) {
+               dbg_fragtree2("lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
+                         this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this);
+               lastend = this->ofs + this->size;
+       } else {
+               dbg_fragtree2("lookup gave no frag\n");
+               lastend = 0;
+       }
+
+       /* See if we ran off the end of the fragtree */
+       if (lastend <= newfrag->ofs) {
+               /* We did */
+
+               /* Check if 'this' node was on the same page as the new node.
+                  If so, both 'this' and the new node get marked REF_NORMAL so
+                  the GC can take a look.
+               */
+               if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
+                       if (this->node)
+                               mark_ref_normal(this->node->raw);
+                       mark_ref_normal(newfrag->node->raw);
+               }
+
+               return no_overlapping_node(c, root, newfrag, this, lastend);
+       }
 
-int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                         struct rb_root *tnp, struct jffs2_full_dirent **fdp,
-                         uint32_t *highest_version, uint32_t *latest_mctime,
-                         uint32_t *mctime_ver)
+       if (this->node)
+               dbg_fragtree2("dealing with frag %u-%u, phys %#08x(%d).\n",
+               this->ofs, this->ofs + this->size,
+               ref_offset(this->node->raw), ref_flags(this->node->raw));
+       else
+               dbg_fragtree2("dealing with hole frag %u-%u.\n",
+               this->ofs, this->ofs + this->size);
+
+       /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
+        * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs
+        */
+       if (newfrag->ofs > this->ofs) {
+               /* This node isn't completely obsoleted. The start of it remains valid */
+
+               /* Mark the new node and the partially covered node REF_NORMAL -- let
+                  the GC take a look at them */
+               mark_ref_normal(newfrag->node->raw);
+               if (this->node)
+                       mark_ref_normal(this->node->raw);
+
+               if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
+                       /* The new node splits 'this' frag into two */
+                       struct jffs2_node_frag *newfrag2;
+
+                       if (this->node)
+                               dbg_fragtree2("split old frag 0x%04x-0x%04x, phys 0x%08x\n",
+                                       this->ofs, this->ofs+this->size, ref_offset(this->node->raw));
+                       else
+                               dbg_fragtree2("split old hole frag 0x%04x-0x%04x\n",
+                                       this->ofs, this->ofs+this->size);
+
+                       /* New second frag pointing to this's node */
+                       newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size,
+                                               this->ofs + this->size - newfrag->ofs - newfrag->size);
+                       if (unlikely(!newfrag2))
+                               return -ENOMEM;
+                       if (this->node)
+                               this->node->frags++;
+
+                       /* Adjust size of original 'this' */
+                       this->size = newfrag->ofs - this->ofs;
+
+                       /* Now, we know there's no node with offset
+                          greater than this->ofs but smaller than
+                          newfrag2->ofs or newfrag->ofs, for obvious
+                          reasons. So we can do a tree insert from
+                          'this' to insert newfrag, and a tree insert
+                          from newfrag to insert newfrag2. */
+                       jffs2_fragtree_insert(newfrag, this);
+                       rb_insert_color(&newfrag->rb, root);
+
+                       jffs2_fragtree_insert(newfrag2, newfrag);
+                       rb_insert_color(&newfrag2->rb, root);
+
+                       return 0;
+               }
+               /* New node just reduces 'this' frag in size, doesn't split it */
+               this->size = newfrag->ofs - this->ofs;
+
+               /* Again, we know it lives down here in the tree */
+               jffs2_fragtree_insert(newfrag, this);
+               rb_insert_color(&newfrag->rb, root);
+       } else {
+               /* New frag starts at the same point as 'this' used to. Replace
+                  it in the tree without doing a delete and insertion */
+               dbg_fragtree2("inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n",
+                         newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, this, this->ofs, this->ofs+this->size);
+
+               rb_replace_node(&this->rb, &newfrag->rb, root);
+
+               if (newfrag->ofs + newfrag->size >= this->ofs+this->size) {
+                       dbg_fragtree2("obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size);
+                       jffs2_obsolete_node_frag(c, this);
+               } else {
+                       this->ofs += newfrag->size;
+                       this->size -= newfrag->size;
+
+                       jffs2_fragtree_insert(this, newfrag);
+                       rb_insert_color(&this->rb, root);
+                       return 0;
+               }
+       }
+       /* OK, now we have newfrag added in the correct place in the tree, but
+          frag_next(newfrag) may be a fragment which is overlapped by it
+       */
+       while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
+               /* 'this' frag is obsoleted completely. */
+               dbg_fragtree2("obsoleting node frag %p (%x-%x) and removing from tree\n",
+                       this, this->ofs, this->ofs+this->size);
+               rb_erase(&this->rb, root);
+               jffs2_obsolete_node_frag(c, this);
+       }
+       /* Now we're pointing at the first frag which isn't totally obsoleted by
+          the new frag */
+
+       if (!this || newfrag->ofs + newfrag->size == this->ofs)
+               return 0;
+
+       /* Still some overlap but we don't need to move it in the tree */
+       this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
+       this->ofs = newfrag->ofs + newfrag->size;
+
+       /* And mark them REF_NORMAL so the GC takes a look at them */
+       if (this->node)
+               mark_ref_normal(this->node->raw);
+       mark_ref_normal(newfrag->node->raw);
+
+       return 0;
+}
+
+/*
+ * Given an inode, probably with existing tree of fragments, add the new node
+ * to the fragment tree.
+ */
+int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
 {
-       struct jffs2_raw_node_ref *ref, *valid_ref;
-       struct jffs2_tmp_dnode_info *tn;
-       struct rb_root ret_tn = RB_ROOT;
-       struct jffs2_full_dirent *fd, *ret_fd = NULL;
-       union jffs2_node_union node;
-       size_t retlen;
-       int err;
-
-       *mctime_ver = 0;
-       
-       D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino));
+       int ret;
+       struct jffs2_node_frag *newfrag;
 
-       spin_lock(&c->erase_completion_lock);
+       if (unlikely(!fn->size))
+               return 0;
 
-       valid_ref = jffs2_first_valid_node(f->inocache->nodes);
+       newfrag = new_fragment(fn, fn->ofs, fn->size);
+       if (unlikely(!newfrag))
+               return -ENOMEM;
+       newfrag->node->frags = 1;
 
-       if (!valid_ref && (f->inocache->ino != 1))
-               printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
+       dbg_fragtree("adding node %#04x-%#04x @0x%08x on flash, newfrag *%p\n",
+                 fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag);
 
-       while (valid_ref) {
-               /* We can hold a pointer to a non-obsolete node without the spinlock,
-                  but _obsolete_ nodes may disappear at any time, if the block
-                  they're in gets erased. So if we mark 'ref' obsolete while we're
-                  not holding the lock, it can go away immediately. For that reason,
-                  we find the next valid node first, before processing 'ref'.
-               */
-               ref = valid_ref;
-               valid_ref = jffs2_first_valid_node(ref->next_in_ino);
-               spin_unlock(&c->erase_completion_lock);
+       ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag);
+       if (unlikely(ret))
+               return ret;
 
-               cond_resched();
+       /* If we now share a page with other nodes, mark either previous
+          or next node REF_NORMAL, as appropriate.  */
+       if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) {
+               struct jffs2_node_frag *prev = frag_prev(newfrag);
+
+               mark_ref_normal(fn->raw);
+               /* If we don't start at zero there's _always_ a previous */
+               if (prev->node)
+                       mark_ref_normal(prev->node->raw);
+       }
+
+       if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) {
+               struct jffs2_node_frag *next = frag_next(newfrag);
+
+               if (next) {
+                       mark_ref_normal(fn->raw);
+                       if (next->node)
+                               mark_ref_normal(next->node->raw);
+               }
+       }
+       jffs2_dbg_fragtree_paranoia_check_nolock(f);
+
+       return 0;
+}
+
+/*
+ * Check the data CRC of the node.
+ *
+ * Returns: 0 if the data CRC is correct;
+ *         1 - if incorrect;
+ *         error code if an error occured.
+ */
+static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
+{
+       struct jffs2_raw_node_ref *ref = tn->fn->raw;
+       int err = 0, pointed = 0;
+       struct jffs2_eraseblock *jeb;
+       unsigned char *buffer;
+       uint32_t crc, ofs, retlen, len;
+
+       BUG_ON(tn->csize == 0);
+
+       if (!jffs2_is_writebuffered(c))
+               goto adj_acc;
+
+       /* Calculate how many bytes were already checked */
+       ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
+       len = ofs % c->wbuf_pagesize;
+       if (likely(len))
+               len = c->wbuf_pagesize - len;
+
+       if (len >= tn->csize) {
+               dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
+                       ref_offset(ref), tn->csize, ofs);
+               goto adj_acc;
+       }
+
+       ofs += len;
+       len = tn->csize - len;
+
+       dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n",
+               ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len);
+
+#ifndef __ECOS
+       /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
+        * adding and jffs2_flash_read_end() interface. */
+       if (c->mtd->point) {
+               err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
+               if (!err && retlen < tn->csize) {
+                       JFFS2_WARNING("MTD point returned len too short: %u instead of %u.\n", retlen, tn->csize);
+                       c->mtd->unpoint(c->mtd, buffer, ofs, len);
+               } else if (err)
+                       JFFS2_WARNING("MTD point failed: error code %d.\n", err);
+               else
+                       pointed = 1; /* succefully pointed to device */
+       }
+#endif
+
+       if (!pointed) {
+               buffer = kmalloc(len, GFP_KERNEL);
+               if (unlikely(!buffer))
+                       return -ENOMEM;
 
-               /* FIXME: point() */
-               err = jffs2_flash_read(c, (ref_offset(ref)), 
-                                      min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
-                                      &retlen, (void *)&node);
+               /* TODO: this is very frequent pattern, make it a separate
+                * routine */
+               err = jffs2_flash_read(c, ofs, len, &retlen, buffer);
                if (err) {
-                       printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
+                       JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err);
                        goto free_out;
                }
-                       
 
-                       /* Check we've managed to read at least the common node header */
-               if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) {
-                       printk(KERN_WARNING "short read in get_inode_nodes()\n");
+               if (retlen != len) {
+                       JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ofs, retlen, len);
                        err = -EIO;
                        goto free_out;
                }
-                       
-               switch (je16_to_cpu(node.u.nodetype)) {
-               case JFFS2_NODETYPE_DIRENT:
-                       D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
-                       if (ref_flags(ref) == REF_UNCHECKED) {
-                               printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref));
-                               BUG();
-                       }
-                       if (retlen < sizeof(node.d)) {
-                               printk(KERN_WARNING "short read in get_inode_nodes()\n");
-                               err = -EIO;
-                               goto free_out;
-                       }
-                       /* sanity check */
-                       if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) {
-                               printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n",
-                                      ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
-                               jffs2_mark_node_obsolete(c, ref);
-                               spin_lock(&c->erase_completion_lock);
-                               continue;
-                       }
-                       if (je32_to_cpu(node.d.version) > *highest_version)
-                               *highest_version = je32_to_cpu(node.d.version);
-                       if (ref_obsolete(ref)) {
-                               /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
-                               printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n",
-                                      ref_offset(ref));
-                               BUG();
-                       }
-                       
-                       fd = jffs2_alloc_full_dirent(node.d.nsize+1);
-                       if (!fd) {
-                               err = -ENOMEM;
-                               goto free_out;
-                       }
-                       fd->raw = ref;
-                       fd->version = je32_to_cpu(node.d.version);
-                       fd->ino = je32_to_cpu(node.d.ino);
-                       fd->type = node.d.type;
-
-                       /* Pick out the mctime of the latest dirent */
-                       if(fd->version > *mctime_ver) {
-                               *mctime_ver = fd->version;
-                               *latest_mctime = je32_to_cpu(node.d.mctime);
-                       }
+       }
 
-                       /* memcpy as much of the name as possible from the raw
-                          dirent we've already read from the flash
-                       */
-                       if (retlen > sizeof(struct jffs2_raw_dirent))
-                               memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
-                               
-                       /* Do we need to copy any more of the name directly
-                          from the flash?
-                       */
-                       if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
-                               /* FIXME: point() */
-                               int already = retlen - sizeof(struct jffs2_raw_dirent);
-                                       
-                               err = jffs2_flash_read(c, (ref_offset(ref)) + retlen, 
-                                                  node.d.nsize - already, &retlen, &fd->name[already]);
-                               if (!err && retlen != node.d.nsize - already)
-                                       err = -EIO;
-                                       
-                               if (err) {
-                                       printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err);
-                                       jffs2_free_full_dirent(fd);
-                                       goto free_out;
-                               }
-                       }
-                       fd->nhash = full_name_hash(fd->name, node.d.nsize);
-                       fd->next = NULL;
-                       fd->name[node.d.nsize] = '\0';
-                               /* Wheee. We now have a complete jffs2_full_dirent structure, with
-                                  the name in it and everything. Link it into the list 
-                               */
-                       D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino));
-                       jffs2_add_fd_to_list(c, fd, &ret_fd);
-                       break;
-
-               case JFFS2_NODETYPE_INODE:
-                       D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
-                       if (retlen < sizeof(node.i)) {
-                               printk(KERN_WARNING "read too short for dnode\n");
-                               err = -EIO;
-                               goto free_out;
-                       }
-                       if (je32_to_cpu(node.i.version) > *highest_version)
-                               *highest_version = je32_to_cpu(node.i.version);
-                       D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version));
-
-                       if (ref_obsolete(ref)) {
-                               /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
-                               printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n",
-                                      ref_offset(ref));
-                               BUG();
-                       }
+       /* Continue calculating CRC */
+       crc = crc32(tn->partial_crc, buffer, len);
+       if(!pointed)
+               kfree(buffer);
+#ifndef __ECOS
+       else
+               c->mtd->unpoint(c->mtd, buffer, ofs, len);
+#endif
 
-                       /* If we've never checked the CRCs on this node, check them now. */
-                       if (ref_flags(ref) == REF_UNCHECKED) {
-                               uint32_t crc, len;
-                               struct jffs2_eraseblock *jeb;
-
-                               crc = crc32(0, &node, sizeof(node.i)-8);
-                               if (crc != je32_to_cpu(node.i.node_crc)) {
-                                       printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-                                              ref_offset(ref), je32_to_cpu(node.i.node_crc), crc);
-                                       jffs2_mark_node_obsolete(c, ref);
-                                       spin_lock(&c->erase_completion_lock);
-                                       continue;
-                               }
-                               
-                               /* sanity checks */
-                               if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) ||
-                                    PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) {
-                                       printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino  %d, version %d, isize %d, csize %d, dsize %d \n",
-                                               ref_offset(ref),  je32_to_cpu(node.i.totlen),  je32_to_cpu(node.i.ino),
-                                               je32_to_cpu(node.i.version),  je32_to_cpu(node.i.isize), 
-                                               je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize));
-                                       jffs2_mark_node_obsolete(c, ref);
-                                       spin_lock(&c->erase_completion_lock);
-                                       continue;
-                               }
+       if (crc != tn->data_crc) {
+               JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
+                       ofs, tn->data_crc, crc);
+               return 1;
+       }
 
-                               if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) {
-                                       unsigned char *buf=NULL;
-                                       uint32_t pointed = 0;
-#ifndef __ECOS
-                                       if (c->mtd->point) {
-                                               err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
-                                                                    &retlen, &buf);
-                                               if (!err && retlen < je32_to_cpu(node.i.csize)) {
-                                                       D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
-                                                       c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
-                                               } else if (err){
-                                                       D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
-                                               } else
-                                                       pointed = 1; /* succefully pointed to device */
-                                       }
-#endif                                 
-                                       if(!pointed){
-                                               buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
-                                               if (!buf)
-                                                       return -ENOMEM;
-                                               
-                                               err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
-                                                                      &retlen, buf);
-                                               if (!err && retlen != je32_to_cpu(node.i.csize))
-                                                       err = -EIO;
-                                               if (err) {
-                                                       kfree(buf);
-                                                       return err;
-                                               }
-                                       }
-                                       crc = crc32(0, buf, je32_to_cpu(node.i.csize));
-                                       if(!pointed)
-                                               kfree(buf);
+adj_acc:
+       jeb = &c->blocks[ref->flash_offset / c->sector_size];
+       len = ref_totlen(c, jeb, ref);
+
+       /*
+        * Mark the node as having been checked and fix the
+        * accounting accordingly.
+        */
+       spin_lock(&c->erase_completion_lock);
+       jeb->used_size += len;
+       jeb->unchecked_size -= len;
+       c->used_size += len;
+       c->unchecked_size -= len;
+       spin_unlock(&c->erase_completion_lock);
+
+       return 0;
+
+free_out:
+       if(!pointed)
+               kfree(buffer);
 #ifndef __ECOS
-                                       else
-                                               c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
+       else
+               c->mtd->unpoint(c->mtd, buffer, ofs, len);
 #endif
+       return err;
+}
 
-                                       if (crc != je32_to_cpu(node.i.data_crc)) {
-                                               printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-                                                      ref_offset(ref), je32_to_cpu(node.i.data_crc), crc);
-                                               jffs2_mark_node_obsolete(c, ref);
-                                               spin_lock(&c->erase_completion_lock);
-                                               continue;
-                                       }
-                                       
-                               }
+/*
+ * Helper function for jffs2_add_older_frag_to_fragtree().
+ *
+ * Checks the node if we are in the checking stage.
+ */
+static inline int check_node(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn)
+{
+       int ret;
 
-                               /* Mark the node as having been checked and fix the accounting accordingly */
-                               spin_lock(&c->erase_completion_lock);
-                               jeb = &c->blocks[ref->flash_offset / c->sector_size];
-                               len = ref_totlen(c, jeb, ref);
-
-                               jeb->used_size += len;
-                               jeb->unchecked_size -= len;
-                               c->used_size += len;
-                               c->unchecked_size -= len;
-
-                               /* If node covers at least a whole page, or if it starts at the 
-                                  beginning of a page and runs to the end of the file, or if 
-                                  it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. 
-
-                                  If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) 
-                                  when the overlapping node(s) get added to the tree anyway. 
-                               */
-                               if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) ||
-                                   ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) &&
-                                     (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) ==  je32_to_cpu(node.i.isize)))) {
-                                       D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref)));
-                                       ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
-                               } else {
-                                       D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref)));
-                                       ref->flash_offset = ref_offset(ref) | REF_NORMAL;
-                               }
-                               spin_unlock(&c->erase_completion_lock);
+       BUG_ON(ref_obsolete(tn->fn->raw));
+
+       /* We only check the data CRC of unchecked nodes */
+       if (ref_flags(tn->fn->raw) != REF_UNCHECKED)
+               return 0;
+
+       dbg_fragtree2("check node %#04x-%#04x, phys offs %#08x.\n",
+               tn->fn->ofs, tn->fn->ofs + tn->fn->size, ref_offset(tn->fn->raw));
+
+       ret = check_node_data(c, tn);
+       if (unlikely(ret < 0)) {
+               JFFS2_ERROR("check_node_data() returned error: %d.\n",
+                       ret);
+       } else if (unlikely(ret > 0)) {
+               dbg_fragtree2("CRC error, mark it obsolete.\n");
+               jffs2_mark_node_obsolete(c, tn->fn->raw);
+       }
+
+       return ret;
+}
+
+/*
+ * Helper function for jffs2_add_older_frag_to_fragtree().
+ *
+ * Called when the new fragment that is being inserted
+ * splits a hole fragment.
+ */
+static int split_hole(struct jffs2_sb_info *c, struct rb_root *root,
+                     struct jffs2_node_frag *newfrag, struct jffs2_node_frag *hole)
+{
+       dbg_fragtree2("fragment %#04x-%#04x splits the hole %#04x-%#04x\n",
+               newfrag->ofs, newfrag->ofs + newfrag->size, hole->ofs, hole->ofs + hole->size);
+
+       if (hole->ofs == newfrag->ofs) {
+               /*
+                * Well, the new fragment actually starts at the same offset as
+                * the hole.
+                */
+               if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) {
+                       /*
+                        * We replace the overlapped left part of the hole by
+                        * the new node.
+                        */
+
+                       dbg_fragtree2("insert fragment %#04x-%#04x and cut the left part of the hole\n",
+                               newfrag->ofs, newfrag->ofs + newfrag->size);
+                       rb_replace_node(&hole->rb, &newfrag->rb, root);
+
+                       hole->ofs += newfrag->size;
+                       hole->size -= newfrag->size;
+
+                       /*
+                        * We know that 'hole' should be the right hand
+                        * fragment.
+                        */
+                       jffs2_fragtree_insert(hole, newfrag);
+                       rb_insert_color(&hole->rb, root);
+               } else {
+                       /*
+                        * Ah, the new fragment is of the same size as the hole.
+                        * Relace the hole by it.
+                        */
+                       dbg_fragtree2("insert fragment %#04x-%#04x and overwrite hole\n",
+                               newfrag->ofs, newfrag->ofs + newfrag->size);
+                       rb_replace_node(&hole->rb, &newfrag->rb, root);
+                       jffs2_free_node_frag(hole);
+               }
+       } else {
+               /* The new fragment lefts some hole space at the left */
+
+               struct jffs2_node_frag * newfrag2 = NULL;
+
+               if (hole->ofs + hole->size > newfrag->ofs + newfrag->size) {
+                       /* The new frag also lefts some space at the right */
+                       newfrag2 = new_fragment(NULL, newfrag->ofs +
+                               newfrag->size, hole->ofs + hole->size
+                               - newfrag->ofs - newfrag->size);
+                       if (unlikely(!newfrag2)) {
+                               jffs2_free_node_frag(newfrag);
+                               return -ENOMEM;
                        }
+               }
+
+               hole->size = newfrag->ofs - hole->ofs;
+               dbg_fragtree2("left the hole %#04x-%#04x at the left and inserd fragment %#04x-%#04x\n",
+                       hole->ofs, hole->ofs + hole->size, newfrag->ofs, newfrag->ofs + newfrag->size);
+
+               jffs2_fragtree_insert(newfrag, hole);
+               rb_insert_color(&newfrag->rb, root);
+
+               if (newfrag2) {
+                       dbg_fragtree2("left the hole %#04x-%#04x at the right\n",
+                               newfrag2->ofs, newfrag2->ofs + newfrag2->size);
+                       jffs2_fragtree_insert(newfrag2, newfrag);
+                       rb_insert_color(&newfrag2->rb, root);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * This function is used when we build inode. It expects the nodes are passed
+ * in the decreasing version order. The whole point of this is to improve the
+ * inodes checking on NAND: we check the nodes' data CRC only when they are not
+ * obsoleted. Previously, add_frag_to_fragtree() function was used and
+ * nodes were passed to it in the increasing version ordes and CRCs of all
+ * nodes were checked.
+ *
+ * Note: tn->fn->size shouldn't be zero.
+ *
+ * Returns 0 if the node was inserted
+ *         1 if it wasn't inserted (since it is obsolete)
+ *         < 0 an if error occured
+ */
+int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                                    struct jffs2_tmp_dnode_info *tn)
+{
+       struct jffs2_node_frag *this, *newfrag;
+       uint32_t lastend;
+       struct jffs2_full_dnode *fn = tn->fn;
+       struct rb_root *root = &f->fragtree;
+       uint32_t fn_size = fn->size, fn_ofs = fn->ofs;
+       int err, checked = 0;
+       int ref_flag;
+
+       dbg_fragtree("insert fragment %#04x-%#04x, ver %u\n", fn_ofs, fn_ofs + fn_size, tn->version);
+
+       /* Skip all the nodes which are completed before this one starts */
+       this = jffs2_lookup_node_frag(root, fn_ofs);
+       if (this)
+               dbg_fragtree2("'this' found %#04x-%#04x (%s)\n", this->ofs, this->ofs + this->size, this->node ? "data" : "hole");
+
+       if (this)
+               lastend = this->ofs + this->size;
+       else
+               lastend = 0;
+
+       /* Detect the preliminary type of node */
+       if (fn->size >= PAGE_CACHE_SIZE)
+               ref_flag = REF_PRISTINE;
+       else
+               ref_flag = REF_NORMAL;
+
+       /* See if we ran off the end of the root */
+       if (lastend <= fn_ofs) {
+               /* We did */
+
+               /*
+                * We are going to insert the new node into the
+                * fragment tree, so check it.
+                */
+               err = check_node(c, f, tn);
+               if (err != 0)
+                       return err;
+
+               fn->frags = 1;
+
+               newfrag = new_fragment(fn, fn_ofs, fn_size);
+               if (unlikely(!newfrag))
+                       return -ENOMEM;
+
+               err = no_overlapping_node(c, root, newfrag, this, lastend);
+               if (unlikely(err != 0)) {
+                       jffs2_free_node_frag(newfrag);
+                       return err;
+               }
+
+               goto out_ok;
+       }
 
-                       tn = jffs2_alloc_tmp_dnode_info();
-                       if (!tn) {
-                               D1(printk(KERN_DEBUG "alloc tn failed\n"));
-                               err = -ENOMEM;
-                               goto free_out;
+       fn->frags = 0;
+
+       while (1) {
+               /*
+                * Here we have:
+                * fn_ofs < this->ofs + this->size && fn_ofs >= this->ofs.
+                *
+                * Remember, 'this' has higher version, any non-hole node
+                * which is already in the fragtree is newer then the newly
+                * inserted.
+                */
+               if (!this->node) {
+                       /*
+                        * 'this' is the hole fragment, so at least the
+                        * beginning of the new fragment is valid.
+                        */
+
+                       /*
+                        * We are going to insert the new node into the
+                        * fragment tree, so check it.
+                        */
+                       if (!checked) {
+                               err = check_node(c, f, tn);
+                               if (unlikely(err != 0))
+                                       return err;
+                               checked = 1;
                        }
 
-                       tn->fn = jffs2_alloc_full_dnode();
-                       if (!tn->fn) {
-                               D1(printk(KERN_DEBUG "alloc fn failed\n"));
-                               err = -ENOMEM;
-                               jffs2_free_tmp_dnode_info(tn);
-                               goto free_out;
+                       if (this->ofs + this->size >= fn_ofs + fn_size) {
+                               /* We split the hole on two parts */
+
+                               fn->frags += 1;
+                               newfrag = new_fragment(fn, fn_ofs, fn_size);
+                               if (unlikely(!newfrag))
+                                       return -ENOMEM;
+
+                               err = split_hole(c, root, newfrag, this);
+                               if (unlikely(err))
+                                       return err;
+                               goto out_ok;
                        }
-                       tn->version = je32_to_cpu(node.i.version);
-                       tn->fn->ofs = je32_to_cpu(node.i.offset);
-                       /* There was a bug where we wrote hole nodes out with
-                          csize/dsize swapped. Deal with it */
-                       if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize))
-                               tn->fn->size = je32_to_cpu(node.i.csize);
-                       else // normal case...
-                               tn->fn->size = je32_to_cpu(node.i.dsize);
-                       tn->fn->raw = ref;
-                       D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n",
-                                 ref_offset(ref), je32_to_cpu(node.i.version),
-                                 je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize)));
-                       jffs2_add_tn_to_tree(tn, &ret_tn);
-                       break;
-
-               default:
-                       if (ref_flags(ref) == REF_UNCHECKED) {
-                               struct jffs2_eraseblock *jeb;
-                               uint32_t len;
-
-                               printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n",
-                                      je16_to_cpu(node.u.nodetype), ref_offset(ref));
-
-                               /* Mark the node as having been checked and fix the accounting accordingly */
-                               spin_lock(&c->erase_completion_lock);
-                               jeb = &c->blocks[ref->flash_offset / c->sector_size];
-                               len = ref_totlen(c, jeb, ref);
-
-                               jeb->used_size += len;
-                               jeb->unchecked_size -= len;
-                               c->used_size += len;
-                               c->unchecked_size -= len;
-
-                               mark_ref_normal(ref);
-                               spin_unlock(&c->erase_completion_lock);
+
+                       /*
+                        * The beginning of the new fragment is valid since it
+                        * overlaps the hole node.
+                        */
+
+                       ref_flag = REF_NORMAL;
+
+                       fn->frags += 1;
+                       newfrag = new_fragment(fn, fn_ofs,
+                                       this->ofs + this->size - fn_ofs);
+                       if (unlikely(!newfrag))
+                               return -ENOMEM;
+
+                       if (fn_ofs == this->ofs) {
+                               /*
+                                * The new node starts at the same offset as
+                                * the hole and supersieds the hole.
+                                */
+                               dbg_fragtree2("add the new fragment instead of hole %#04x-%#04x, refcnt %d\n",
+                                       fn_ofs, fn_ofs + this->ofs + this->size - fn_ofs, fn->frags);
+
+                               rb_replace_node(&this->rb, &newfrag->rb, root);
+                               jffs2_free_node_frag(this);
+                       } else {
+                               /*
+                                * The hole becomes shorter as its right part
+                                * is supersieded by the new fragment.
+                                */
+                               dbg_fragtree2("reduce size of hole %#04x-%#04x to %#04x-%#04x\n",
+                                       this->ofs, this->ofs + this->size, this->ofs, this->ofs + this->size - newfrag->size);
+
+                               dbg_fragtree2("add new fragment %#04x-%#04x, refcnt %d\n", fn_ofs,
+                                       fn_ofs + this->ofs + this->size - fn_ofs, fn->frags);
+
+                               this->size -= newfrag->size;
+                               jffs2_fragtree_insert(newfrag, this);
+                               rb_insert_color(&newfrag->rb, root);
                        }
-                       node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype));
-                       if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) {
-                               /* Hmmm. This should have been caught at scan time. */
-                               printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n",
-                                      ref_offset(ref));
-                               printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n", 
-                                      je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen),
-                                      je32_to_cpu(node.u.hdr_crc));
-                               jffs2_mark_node_obsolete(c, ref);
-                       } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) {
-                       case JFFS2_FEATURE_INCOMPAT:
-                               printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-                               /* EEP */
-                               BUG();
-                               break;
-                       case JFFS2_FEATURE_ROCOMPAT:
-                               printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-                               if (!(c->flags & JFFS2_SB_FLAG_RO))
-                                       BUG();
-                               break;
-                       case JFFS2_FEATURE_RWCOMPAT_COPY:
-                               printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-                               break;
-                       case JFFS2_FEATURE_RWCOMPAT_DELETE:
-                               printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
-                               jffs2_mark_node_obsolete(c, ref);
-                               break;
+
+                       fn_ofs += newfrag->size;
+                       fn_size -= newfrag->size;
+                       this = rb_entry(rb_next(&newfrag->rb),
+                                       struct jffs2_node_frag, rb);
+
+                       dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n",
+                               this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)");
+               }
+
+               /*
+                * 'This' node is not the hole so it obsoletes the new fragment
+                * either fully or partially.
+                */
+               if (this->ofs + this->size >= fn_ofs + fn_size) {
+                       /* The new node is obsolete, drop it */
+                       if (fn->frags == 0) {
+                               dbg_fragtree2("%#04x-%#04x is obsolete, mark it obsolete\n", fn_ofs, fn_ofs + fn_size);
+                               ref_flag = REF_OBSOLETE;
                        }
+                       goto out_ok;
+               } else {
+                       struct jffs2_node_frag *new_this;
+
+                       /* 'This' node obsoletes the beginning of the new node */
+                       dbg_fragtree2("the beginning %#04x-%#04x is obsolete\n", fn_ofs, this->ofs + this->size);
+
+                       ref_flag = REF_NORMAL;
+
+                       fn_size -= this->ofs + this->size - fn_ofs;
+                       fn_ofs = this->ofs + this->size;
+                       dbg_fragtree2("now considering %#04x-%#04x\n", fn_ofs, fn_ofs + fn_size);
+
+                       new_this = rb_entry(rb_next(&this->rb), struct jffs2_node_frag, rb);
+                       if (!new_this) {
+                               /*
+                                * There is no next fragment. Add the rest of
+                                * the new node as the right-hand child.
+                                */
+                               if (!checked) {
+                                       err = check_node(c, f, tn);
+                                       if (unlikely(err != 0))
+                                               return err;
+                                       checked = 1;
+                               }
 
+                               fn->frags += 1;
+                               newfrag = new_fragment(fn, fn_ofs, fn_size);
+                               if (unlikely(!newfrag))
+                                       return -ENOMEM;
+
+                               dbg_fragtree2("there are no more fragments, insert %#04x-%#04x\n",
+                                       newfrag->ofs, newfrag->ofs + newfrag->size);
+                               rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
+                               rb_insert_color(&newfrag->rb, root);
+                               goto out_ok;
+                       } else {
+                               this = new_this;
+                               dbg_fragtree2("switch to the next 'this' fragment: %#04x-%#04x %s\n",
+                                       this->ofs, this->ofs + this->size, this->node ? "(data)" : "(hole)");
+                       }
                }
-               spin_lock(&c->erase_completion_lock);
+       }
+
+out_ok:
+       BUG_ON(fn->size < PAGE_CACHE_SIZE && ref_flag == REF_PRISTINE);
 
+       if (ref_flag == REF_OBSOLETE) {
+               dbg_fragtree2("the node is obsolete now\n");
+               /* jffs2_mark_node_obsolete() will adjust space accounting */
+               jffs2_mark_node_obsolete(c, fn->raw);
+               return 1;
        }
+
+       dbg_fragtree2("the node is \"%s\" now\n", ref_flag == REF_NORMAL ? "REF_NORMAL" : "REF_PRISTINE");
+
+       /* Space accounting was adjusted at check_node_data() */
+       spin_lock(&c->erase_completion_lock);
+       fn->raw->flash_offset = ref_offset(fn->raw) | ref_flag;
        spin_unlock(&c->erase_completion_lock);
-       *tnp = ret_tn;
-       *fdp = ret_fd;
 
        return 0;
-
- free_out:
-       jffs2_free_tmp_dnode_info_list(&ret_tn);
-       jffs2_free_full_dirent_list(ret_fd);
-       return err;
 }
 
 void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state)
@@ -499,24 +862,21 @@ void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache
 
 /* During mount, this needs no locking. During normal operation, its
    callers want to do other stuff while still holding the inocache_lock.
-   Rather than introducing special case get_ino_cache functions or 
+   Rather than introducing special case get_ino_cache functions or
    callbacks, we just let the caller do the locking itself. */
-   
+
 struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
 {
        struct jffs2_inode_cache *ret;
 
-       D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino));
-
        ret = c->inocache_list[ino % INOCACHE_HASHSIZE];
        while (ret && ret->ino < ino) {
                ret = ret->next;
        }
-       
+
        if (ret && ret->ino != ino)
                ret = NULL;
 
-       D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino));
        return ret;
 }
 
@@ -528,7 +888,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new
        if (!new->ino)
                new->ino = ++c->highest_ino;
 
-       D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
+       dbg_inocache("add %p (ino #%u)\n", new, new->ino);
 
        prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE];
 
@@ -544,11 +904,12 @@ 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;
-       D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
+
+       dbg_inocache("del %p (ino #%u)\n", old, old->ino);
        spin_lock(&c->inocache_lock);
-       
+
        prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE];
-       
+
        while ((*prev) && (*prev)->ino < old->ino) {
                prev = &(*prev)->next;
        }
@@ -558,7 +919,7 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
 
        /* 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 
+          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)
@@ -571,7 +932,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c)
 {
        int i;
        struct jffs2_inode_cache *this, *next;
-       
+
        for (i=0; i<INOCACHE_HASHSIZE; i++) {
                this = c->inocache_list[i];
                while (this) {
@@ -598,38 +959,30 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
                c->blocks[i].first_node = c->blocks[i].last_node = NULL;
        }
 }
-       
+
 struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
 {
-       /* The common case in lookup is that there will be a node 
+       /* The common case in lookup is that there will be a node
           which precisely matches. So we go looking for that first */
        struct rb_node *next;
        struct jffs2_node_frag *prev = NULL;
        struct jffs2_node_frag *frag = NULL;
 
-       D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset));
+       dbg_fragtree2("root %p, offset %d\n", fragtree, offset);
 
        next = fragtree->rb_node;
 
        while(next) {
                frag = rb_entry(next, struct jffs2_node_frag, rb);
 
-               D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n",
-                         frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right));
                if (frag->ofs + frag->size <= offset) {
-                       D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n",
-                                 frag->ofs, frag->ofs+frag->size));
                        /* Remember the closest smaller match on the way down */
                        if (!prev || frag->ofs > prev->ofs)
                                prev = frag;
                        next = frag->rb.rb_right;
                } else if (frag->ofs > offset) {
-                       D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n",
-                                 frag->ofs, frag->ofs+frag->size));
                        next = frag->rb.rb_left;
                } else {
-                       D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n",
-                                 frag->ofs, frag->ofs+frag->size));
                        return frag;
                }
        }
@@ -638,11 +991,11 @@ struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_
           and return the closest smaller one */
 
        if (prev)
-               D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n",
-                         prev->ofs, prev->ofs+prev->size));
-       else 
-               D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n"));
-       
+               dbg_fragtree2("no match. Returning frag %#04x-%#04x, closest previous\n",
+                         prev->ofs, prev->ofs+prev->size);
+       else
+               dbg_fragtree2("returning NULL, empty fragtree\n");
+
        return prev;
 }
 
@@ -656,39 +1009,32 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
        if (!root->rb_node)
                return;
 
-       frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb));
+       dbg_fragtree("killing\n");
 
+       frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb));
        while(frag) {
                if (frag->rb.rb_left) {
-                       D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n", 
-                                 frag, frag->ofs, frag->ofs+frag->size));
                        frag = frag_left(frag);
                        continue;
                }
                if (frag->rb.rb_right) {
-                       D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n", 
-                                 frag, frag->ofs, frag->ofs+frag->size));
                        frag = frag_right(frag);
                        continue;
                }
 
-               D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n",
-                         frag->ofs, frag->ofs+frag->size, frag->node,
-                         frag->node?frag->node->frags:0));
-                       
                if (frag->node && !(--frag->node->frags)) {
-                       /* Not a hole, and it's the final remaining frag 
+                       /* Not a hole, and it's the final remaining frag
                           of this node. Free the node */
                        if (c)
                                jffs2_mark_node_obsolete(c, frag->node->raw);
-                       
+
                        jffs2_free_full_dnode(frag->node);
                }
                parent = frag_parent(frag);
                if (parent) {
                        if (frag_left(parent) == frag)
                                parent->rb.rb_left = NULL;
-                       else 
+                       else
                                parent->rb.rb_right = NULL;
                }
 
@@ -698,29 +1044,3 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
                cond_resched();
        }
 }
-
-void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
-{
-       struct rb_node *parent = &base->rb;
-       struct rb_node **link = &parent;
-
-       D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag, 
-                 newfrag->ofs, newfrag->ofs+newfrag->size, base));
-
-       while (*link) {
-               parent = *link;
-               base = rb_entry(parent, struct jffs2_node_frag, rb);
-       
-               D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs));
-               if (newfrag->ofs > base->ofs)
-                       link = &base->rb.rb_right;
-               else if (newfrag->ofs < base->ofs)
-                       link = &base->rb.rb_left;
-               else {
-                       printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
-                       BUG();
-               }
-       }
-
-       rb_link_node(&newfrag->rb, &base->rb, link);
-}
index b34c397909efd0ae3f53beca3c6dd69c6c49ff56..23a67bb3052f916fb60aee403aa48cf802c0c517 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.131 2005/07/05 21:03:07 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $
  *
  */
 
 #include <linux/jffs2.h>
 #include <linux/jffs2_fs_sb.h>
 #include <linux/jffs2_fs_i.h>
+#include "summary.h"
 
 #ifdef __ECOS
 #include "os-ecos.h"
 #else
-#include <linux/mtd/compatmac.h> /* For min/max in older kernels */
+#include <linux/mtd/compatmac.h> /* For compatibility with older kernels */
 #include "os-linux.h"
 #endif
 
-#ifndef CONFIG_JFFS2_FS_DEBUG
-#define CONFIG_JFFS2_FS_DEBUG 1
-#endif
-
-#if CONFIG_JFFS2_FS_DEBUG > 0
-#define D1(x) x
-#else
-#define D1(x)
-#endif
-
-#if CONFIG_JFFS2_FS_DEBUG > 1
-#define D2(x) x
-#else
-#define D2(x)
-#endif
-
 #define JFFS2_NATIVE_ENDIAN
 
 /* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
 #define je16_to_cpu(x) (le16_to_cpu(x.v16))
 #define je32_to_cpu(x) (le32_to_cpu(x.v32))
 #define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
-#else 
+#else
 #error wibble
 #endif
 
+/* The minimal node header size */
+#define JFFS2_MIN_NODE_HEADER sizeof(struct jffs2_raw_dirent)
+
 /*
   This is all we need to keep in-core for each raw node during normal
   operation. As and when we do read_inode on a particular inode, we can
-  scan the nodes which are listed for it and build up a proper map of 
+  scan the nodes which are listed for it and build up a proper map of
   which nodes are currently valid. JFFSv1 always used to keep that whole
   map in core for each inode.
 */
@@ -97,7 +85,7 @@ struct jffs2_raw_node_ref
 
         /* flash_offset & 3 always has to be zero, because nodes are
           always aligned at 4 bytes. So we have a couple of extra bits
-          to play with, which indicate the node's status; see below: */ 
+          to play with, which indicate the node's status; see below: */
 #define REF_UNCHECKED  0       /* We haven't yet checked the CRC or built its inode */
 #define REF_OBSOLETE   1       /* Obsolete, can be completely ignored */
 #define REF_PRISTINE   2       /* Completely clean. GC without looking */
@@ -110,7 +98,7 @@ struct jffs2_raw_node_ref
 /* For each inode in the filesystem, we need to keep a record of
    nlink, because it would be a PITA to scan the whole directory tree
    at read_inode() time to calculate it, and to keep sufficient information
-   in the raw_node_ref (basically both parent and child inode number for 
+   in the raw_node_ref (basically both parent and child inode number for
    dirent nodes) would take more space than this does. We also keep
    a pointer to the first physical node which is part of this inode, too.
 */
@@ -140,7 +128,7 @@ struct jffs2_inode_cache {
 #define INOCACHE_HASHSIZE 128
 
 /*
-  Larger representation of a raw node, kept in-core only when the 
+  Larger representation of a raw node, kept in-core only when the
   struct inode for this particular ino is instantiated.
 */
 
@@ -150,11 +138,11 @@ struct jffs2_full_dnode
        uint32_t ofs; /* The offset to which the data of this node belongs */
        uint32_t size;
        uint32_t frags; /* Number of fragments which currently refer
-                       to this node. When this reaches zero, 
+                       to this node. When this reaches zero,
                        the node is obsolete.  */
 };
 
-/* 
+/*
    Even larger representation of a raw node, kept in-core only while
    we're actually building up the original map of which nodes go where,
    in read_inode()
@@ -164,7 +152,10 @@ struct jffs2_tmp_dnode_info
        struct rb_node rb;
        struct jffs2_full_dnode *fn;
        uint32_t version;
-};       
+       uint32_t data_crc;
+       uint32_t partial_crc;
+       uint32_t csize;
+};
 
 struct jffs2_full_dirent
 {
@@ -178,7 +169,7 @@ struct jffs2_full_dirent
 };
 
 /*
-  Fragments - used to build a map of which raw node to obtain 
+  Fragments - used to build a map of which raw node to obtain
   data from for each part of the ino
 */
 struct jffs2_node_frag
@@ -207,86 +198,18 @@ struct jffs2_eraseblock
        struct jffs2_raw_node_ref *gc_node;     /* Next node to be garbage collected */
 };
 
-#define ACCT_SANITY_CHECK(c, jeb) do { \
-               struct jffs2_eraseblock *___j = jeb; \
-               if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \
-               printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \
-               printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \
-               ___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \
-               BUG(); \
-       } \
-       if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \
-               printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \
-               printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x + wasted %08x + unchecked %08x != total %08x\n", \
-               c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->wasted_size, c->unchecked_size, c->flash_size); \
-               BUG(); \
-       } \
-} while(0)
-
-static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb)
+static inline int jffs2_blocks_use_vmalloc(struct jffs2_sb_info *c)
 {
-       struct jffs2_raw_node_ref *ref;
-       int i=0;
-
-       printk(KERN_NOTICE);
-       for (ref = jeb->first_node; ref; ref = ref->next_phys) {
-               printk("%08x->", ref_offset(ref));
-               if (++i == 8) {
-                       i = 0;
-                       printk("\n" KERN_NOTICE);
-               }
-       }
-       printk("\n");
+       return ((c->flash_size / c->sector_size) * sizeof (struct jffs2_eraseblock)) > (128 * 1024);
 }
 
-
-#define ACCT_PARANOIA_CHECK(jeb) do { \
-               uint32_t my_used_size = 0; \
-               uint32_t my_unchecked_size = 0; \
-               struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
-               while (ref2) { \
-                       if (unlikely(ref2->flash_offset < jeb->offset || \
-                                    ref2->flash_offset > jeb->offset + c->sector_size)) { \
-                               printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \
-                                      ref_offset(ref2), jeb->offset); \
-                               paranoia_failed_dump(jeb); \
-                               BUG(); \
-                       } \
-                       if (ref_flags(ref2) == REF_UNCHECKED) \
-                               my_unchecked_size += ref_totlen(c, jeb, ref2); \
-                       else if (!ref_obsolete(ref2)) \
-                               my_used_size += ref_totlen(c, jeb, ref2); \
-                       if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \
-                                if (!ref2->next_phys) \
-                                      printk("ref for node at %p (phys %08x) has next_phys->%p (----), last_node->%p (phys %08x)\n", \
-                                            ref2, ref_offset(ref2), ref2->next_phys, \
-                                            jeb->last_node, ref_offset(jeb->last_node)); \
-                                else \
-                                       printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \
-                                            ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \
-                                            jeb->last_node, ref_offset(jeb->last_node)); \
-                               paranoia_failed_dump(jeb); \
-                               BUG(); \
-                       } \
-                       ref2 = ref2->next_phys; \
-               } \
-               if (my_used_size != jeb->used_size) { \
-                       printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \
-                       BUG(); \
-               } \
-               if (my_unchecked_size != jeb->unchecked_size) { \
-                       printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \
-                       BUG(); \
-               } \
-       } while(0)
-
 /* Calculate totlen from surrounding nodes or eraseblock */
 static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
                                    struct jffs2_eraseblock *jeb,
                                    struct jffs2_raw_node_ref *ref)
 {
        uint32_t ref_end;
-       
+
        if (ref->next_phys)
                ref_end = ref_offset(ref->next_phys);
        else {
@@ -306,11 +229,13 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c,
 {
        uint32_t ret;
 
-       D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
+#if CONFIG_JFFS2_FS_DEBUG > 0
+       if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
                printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
                       jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
                BUG();
-       })
+       }
+#endif
 
 #if 1
        ret = ref->__totlen;
@@ -323,14 +248,13 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c,
                       ret, ref->__totlen);
                if (!jeb)
                        jeb = &c->blocks[ref->flash_offset / c->sector_size];
-               paranoia_failed_dump(jeb);
+               jffs2_dbg_dump_node_refs_nolock(c, jeb);
                BUG();
        }
 #endif
        return ret;
 }
 
-
 #define ALLOC_NORMAL   0       /* Normal allocation */
 #define ALLOC_DELETION 1       /* Deletion node. Best to allow it */
 #define ALLOC_GC       2       /* Space requested for GC. Give it or die */
@@ -340,7 +264,7 @@ static inline uint32_t ref_totlen(struct jffs2_sb_info *c,
 #define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
 
 /* check if dirty space is more than 255 Byte */
-#define ISDIRTY(size) ((size) >  sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) 
+#define ISDIRTY(size) ((size) >  sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)
 
 #define PAD(x) (((x)+3)&~3)
 
@@ -384,12 +308,7 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
 #define frag_erase(frag, list) rb_erase(&frag->rb, list);
 
 /* nodelist.c */
-D2(void jffs2_print_frag_list(struct jffs2_inode_info *f));
 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
-int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                         struct rb_root *tnp, struct jffs2_full_dirent **fdp,
-                         uint32_t *highest_version, uint32_t *latest_mctime,
-                         uint32_t *mctime_ver);
 void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
 struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
 void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new);
@@ -398,19 +317,23 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c);
 void jffs2_free_raw_node_refs(struct jffs2_sb_info *c);
 struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset);
 void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete);
-void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base);
 struct rb_node *rb_next(struct rb_node *);
 struct rb_node *rb_prev(struct rb_node *);
 void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
+void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this);
+int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
+void jffs2_truncate_fragtree (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
+int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_tmp_dnode_info *tn);
 
 /* nodemgmt.c */
 int jffs2_thread_should_wake(struct jffs2_sb_info *c);
-int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
-int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+                       uint32_t *len, int prio, uint32_t sumsize);
+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+                       uint32_t *len, uint32_t sumsize);
 int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
 void jffs2_complete_reservation(struct jffs2_sb_info *c);
 void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw);
-void jffs2_dump_block_lists(struct jffs2_sb_info *c);
 
 /* write.c */
 int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri);
@@ -418,17 +341,15 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
 struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode);
 struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_dirent *rd, const unsigned char *name, uint32_t namelen, uint32_t flash_ofs, int alloc_mode);
 int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                           struct jffs2_raw_inode *ri, unsigned char *buf, 
+                           struct jffs2_raw_inode *ri, unsigned char *buf,
                            uint32_t offset, uint32_t writelen, uint32_t *retlen);
 int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const char *name, int namelen);
-int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f);
-int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen);
+int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, const char *name, int namelen, struct jffs2_inode_info *dead_f, uint32_t time);
+int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen, uint32_t time);
 
 
 /* readinode.c */
-void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
-int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
-int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 
+int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                        uint32_t ino, struct jffs2_raw_inode *latest_node);
 int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic);
 void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
@@ -468,6 +389,10 @@ char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
 /* scan.c */
 int jffs2_scan_medium(struct jffs2_sb_info *c);
 void jffs2_rotate_lists(struct jffs2_sb_info *c);
+int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf,
+                               uint32_t ofs, uint32_t len);
+struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 
 /* build.c */
 int jffs2_do_mount_fs(struct jffs2_sb_info *c);
@@ -483,4 +408,6 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 #endif
 
+#include "debug.h"
+
 #endif /* __JFFS2_NODELIST_H__ */
index c1d8b5ed9ab95221b89b2af4bbcdd985de16775f..49127a1f045861324bab8e79570b895b7b1ab4c5 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodemgmt.c,v 1.122 2005/05/06 09:30:27 dedekind Exp $
+ * $Id: nodemgmt.c,v 1.127 2005/09/20 15:49:12 dedekind Exp $
  *
  */
 
@@ -17,6 +17,7 @@
 #include <linux/compiler.h>
 #include <linux/sched.h> /* For cond_resched() */
 #include "nodelist.h"
+#include "debug.h"
 
 /**
  *     jffs2_reserve_space - request physical space to write nodes to flash
  *     for the requested allocation.
  */
 
-static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, uint32_t *ofs, uint32_t *len);
+static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize,
+                                       uint32_t *ofs, uint32_t *len, uint32_t sumsize);
 
-int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio)
+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+                       uint32_t *len, int prio, uint32_t sumsize)
 {
        int ret = -EAGAIN;
        int blocksneeded = c->resv_blocks_write;
@@ -85,12 +88,12 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
                                up(&c->alloc_sem);
                                return -ENOSPC;
                        }
-                       
+
                        /* Calc possibly available space. Possibly available means that we
                         * don't know, if unchecked size contains obsoleted nodes, which could give us some
                         * more usable space. This will affect the sum only once, as gc first finishes checking
                         * of nodes.
-                        + Return -ENOSPC, if the maximum possibly available space is less or equal than 
+                        + Return -ENOSPC, if the maximum possibly available space is less or equal than
                         * blocksneeded * sector_size.
                         * This blocks endless gc looping on a filesystem, which is nearly full, even if
                         * the check above passes.
@@ -115,7 +118,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
                                  c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
                                  c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
                        spin_unlock(&c->erase_completion_lock);
-                       
+
                        ret = jffs2_garbage_collect_pass(c);
                        if (ret)
                                return ret;
@@ -129,7 +132,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
                        spin_lock(&c->erase_completion_lock);
                }
 
-               ret = jffs2_do_reserve_space(c, minsize, ofs, len);
+               ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
                if (ret) {
                        D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
                }
@@ -140,7 +143,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
        return ret;
 }
 
-int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len)
+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+                       uint32_t *len, uint32_t sumsize)
 {
        int ret = -EAGAIN;
        minsize = PAD(minsize);
@@ -149,7 +153,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
 
        spin_lock(&c->erase_completion_lock);
        while(ret == -EAGAIN) {
-               ret = jffs2_do_reserve_space(c, minsize, ofs, len);
+               ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
                if (ret) {
                        D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
                }
@@ -158,105 +162,185 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
        return ret;
 }
 
-/* Called with alloc sem _and_ erase_completion_lock */
-static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, uint32_t *ofs, uint32_t *len)
+
+/* Classify nextblock (clean, dirty of verydirty) and force to select an other one */
+
+static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
-       struct jffs2_eraseblock *jeb = c->nextblock;
-       
- restart:
-       if (jeb && minsize > jeb->free_size) {
-               /* Skip the end of this block and file it as having some dirty space */
-               /* If there's a pending write to it, flush now */
-               if (jffs2_wbuf_dirty(c)) {
+
+       /* Check, if we have a dirty block now, or if it was dirty already */
+       if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
+               c->dirty_size += jeb->wasted_size;
+               c->wasted_size -= jeb->wasted_size;
+               jeb->dirty_size += jeb->wasted_size;
+               jeb->wasted_size = 0;
+               if (VERYDIRTY(c, jeb->dirty_size)) {
+                       D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+                         jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+                       list_add_tail(&jeb->list, &c->very_dirty_list);
+               } else {
+                       D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+                         jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+                       list_add_tail(&jeb->list, &c->dirty_list);
+               }
+       } else {
+               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));
+               list_add_tail(&jeb->list, &c->clean_list);
+       }
+       c->nextblock = NULL;
+
+}
+
+/* Select a new jeb for nextblock */
+
+static int jffs2_find_nextblock(struct jffs2_sb_info *c)
+{
+       struct list_head *next;
+
+       /* Take the next block off the 'free' list */
+
+       if (list_empty(&c->free_list)) {
+
+               if (!c->nr_erasing_blocks &&
+                       !list_empty(&c->erasable_list)) {
+                       struct jffs2_eraseblock *ejeb;
+
+                       ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
+                       list_del(&ejeb->list);
+                       list_add_tail(&ejeb->list, &c->erase_pending_list);
+                       c->nr_erasing_blocks++;
+                       jffs2_erase_pending_trigger(c);
+                       D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n",
+                                 ejeb->offset));
+               }
+
+               if (!c->nr_erasing_blocks &&
+                       !list_empty(&c->erasable_pending_wbuf_list)) {
+                       D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n"));
+                       /* c->nextblock is NULL, no update to c->nextblock allowed */
                        spin_unlock(&c->erase_completion_lock);
-                       D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));                           
                        jffs2_flush_wbuf_pad(c);
                        spin_lock(&c->erase_completion_lock);
-                       jeb = c->nextblock;
-                       goto restart;
+                       /* Have another go. It'll be on the erasable_list now */
+                       return -EAGAIN;
                }
-               c->wasted_size += jeb->free_size;
-               c->free_size -= jeb->free_size;
-               jeb->wasted_size += jeb->free_size;
-               jeb->free_size = 0;
-               
-               /* Check, if we have a dirty block now, or if it was dirty already */
-               if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
-                       c->dirty_size += jeb->wasted_size;
-                       c->wasted_size -= jeb->wasted_size;
-                       jeb->dirty_size += jeb->wasted_size;
-                       jeb->wasted_size = 0;
-                       if (VERYDIRTY(c, jeb->dirty_size)) {
-                               D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-                                 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-                               list_add_tail(&jeb->list, &c->very_dirty_list);
-                       } else {
-                               D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
-                                 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
-                               list_add_tail(&jeb->list, &c->dirty_list);
-                       }
-               } else { 
-                       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));
-                       list_add_tail(&jeb->list, &c->clean_list);
+
+               if (!c->nr_erasing_blocks) {
+                       /* Ouch. We're in GC, or we wouldn't have got here.
+                          And there's no space left. At all. */
+                       printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
+                                  c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
+                                  list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
+                       return -ENOSPC;
                }
-               c->nextblock = jeb = NULL;
+
+               spin_unlock(&c->erase_completion_lock);
+               /* Don't wait for it; just erase one right now */
+               jffs2_erase_pending_blocks(c, 1);
+               spin_lock(&c->erase_completion_lock);
+
+               /* An erase may have failed, decreasing the
+                  amount of free space available. So we must
+                  restart from the beginning */
+               return -EAGAIN;
        }
-       
-       if (!jeb) {
-               struct list_head *next;
-               /* Take the next block off the 'free' list */
 
-               if (list_empty(&c->free_list)) {
+       next = c->free_list.next;
+       list_del(next);
+       c->nextblock = list_entry(next, struct jffs2_eraseblock, list);
+       c->nr_free_blocks--;
 
-                       if (!c->nr_erasing_blocks && 
-                           !list_empty(&c->erasable_list)) {
-                               struct jffs2_eraseblock *ejeb;
+       jffs2_sum_reset_collected(c->summary); /* reset collected summary */
 
-                               ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
-                               list_del(&ejeb->list);
-                               list_add_tail(&ejeb->list, &c->erase_pending_list);
-                               c->nr_erasing_blocks++;
-                               jffs2_erase_pending_trigger(c);
-                               D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n",
-                                         ejeb->offset));
+       D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset));
+
+       return 0;
+}
+
+/* Called with alloc sem _and_ erase_completion_lock */
+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize)
+{
+       struct jffs2_eraseblock *jeb = c->nextblock;
+       uint32_t reserved_size;                         /* for summary information at the end of the jeb */
+       int ret;
+
+ restart:
+       reserved_size = 0;
+
+       if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) {
+                                                       /* NOSUM_SIZE means not to generate summary */
+
+               if (jeb) {
+                       reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE);
+                       dbg_summary("minsize=%d , jeb->free=%d ,"
+                                               "summary->size=%d , sumsize=%d\n",
+                                               minsize, jeb->free_size,
+                                               c->summary->sum_size, sumsize);
+               }
+
+               /* Is there enough space for writing out the current node, or we have to
+                  write out summary information now, close this jeb and select new nextblock? */
+               if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize +
+                                       JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) {
+
+                       /* Has summary been disabled for this jeb? */
+                       if (jffs2_sum_is_disabled(c->summary)) {
+                               sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
+                               goto restart;
                        }
 
-                       if (!c->nr_erasing_blocks && 
-                           !list_empty(&c->erasable_pending_wbuf_list)) {
-                               D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
-                               /* c->nextblock is NULL, no update to c->nextblock allowed */                       
+                       /* Writing out the collected summary information */
+                       dbg_summary("generating summary for 0x%08x.\n", jeb->offset);
+                       ret = jffs2_sum_write_sumnode(c);
+
+                       if (ret)
+                               return ret;
+
+                       if (jffs2_sum_is_disabled(c->summary)) {
+                               /* jffs2_write_sumnode() couldn't write out the summary information
+                                  diabling summary for this jeb and free the collected information
+                                */
+                               sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
+                               goto restart;
+                       }
+
+                       jffs2_close_nextblock(c, jeb);
+                       jeb = NULL;
+                       /* keep always valid value in reserved_size */
+                       reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE);
+               }
+       } else {
+               if (jeb && minsize > jeb->free_size) {
+                       /* Skip the end of this block and file it as having some dirty space */
+                       /* If there's a pending write to it, flush now */
+
+                       if (jffs2_wbuf_dirty(c)) {
                                spin_unlock(&c->erase_completion_lock);
+                               D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
                                jffs2_flush_wbuf_pad(c);
                                spin_lock(&c->erase_completion_lock);
-                               /* Have another go. It'll be on the erasable_list now */
-                               return -EAGAIN;
+                               jeb = c->nextblock;
+                               goto restart;
                        }
 
-                       if (!c->nr_erasing_blocks) {
-                               /* Ouch. We're in GC, or we wouldn't have got here.
-                                  And there's no space left. At all. */
-                               printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", 
-                                      c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", 
-                                      list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
-                               return -ENOSPC;
-                       }
-
-                       spin_unlock(&c->erase_completion_lock);
-                       /* Don't wait for it; just erase one right now */
-                       jffs2_erase_pending_blocks(c, 1);
-                       spin_lock(&c->erase_completion_lock);
+                       c->wasted_size += jeb->free_size;
+                       c->free_size -= jeb->free_size;
+                       jeb->wasted_size += jeb->free_size;
+                       jeb->free_size = 0;
 
-                       /* An erase may have failed, decreasing the
-                          amount of free space available. So we must
-                          restart from the beginning */
-                       return -EAGAIN;
+                       jffs2_close_nextblock(c, jeb);
+                       jeb = NULL;
                }
+       }
+
+       if (!jeb) {
 
-               next = c->free_list.next;
-               list_del(next);
-               c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
-               c->nr_free_blocks--;
+               ret = jffs2_find_nextblock(c);
+               if (ret)
+                       return ret;
+
+               jeb = c->nextblock;
 
                if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
                        printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
@@ -266,13 +350,13 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, ui
        /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
           enough space */
        *ofs = jeb->offset + (c->sector_size - jeb->free_size);
-       *len = jeb->free_size;
+       *len = jeb->free_size - reserved_size;
 
        if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
            !jeb->first_node->next_in_ino) {
-               /* Only node in it beforehand was a CLEANMARKER node (we think). 
+               /* Only node in it beforehand was a CLEANMARKER node (we think).
                   So mark it obsolete now that there's going to be another node
-                  in the block. This will reduce used_size to zero but We've 
+                  in the block. This will reduce used_size to zero but We've
                   already set c->nextblock so that jffs2_mark_node_obsolete()
                   won't try to refile it to the dirty_list.
                */
@@ -292,12 +376,12 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, ui
  *     @len: length of this physical node
  *     @dirty: dirty flag for new node
  *
- *     Should only be used to report nodes for which space has been allocated 
+ *     Should only be used to report nodes for which space has been allocated
  *     by jffs2_reserve_space.
  *
  *     Must be called with the alloc_sem held.
  */
+
 int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new)
 {
        struct jffs2_eraseblock *jeb;
@@ -349,8 +433,8 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
                list_add_tail(&jeb->list, &c->clean_list);
                c->nextblock = NULL;
        }
-       ACCT_SANITY_CHECK(c,jeb);
-       D1(ACCT_PARANOIA_CHECK(jeb));
+       jffs2_dbg_acct_sanity_check_nolock(c,jeb);
+       jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
 
        spin_unlock(&c->erase_completion_lock);
 
@@ -404,8 +488,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
 
        if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) &&
            !(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 
+               /* 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
                   any jffs2_raw_node_refs. So we don't need to stop erases from
                   happening, or protect against people holding an obsolete
@@ -430,7 +514,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                               ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
                        BUG();
                })
-               D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
+               D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %#x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
                jeb->used_size -= ref_totlen(c, jeb, ref);
                c->used_size -= ref_totlen(c, jeb, ref);
        }
@@ -462,18 +546,17 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                D1(printk(KERN_DEBUG "Wasting\n"));
                addedsize = 0;
                jeb->wasted_size += ref_totlen(c, jeb, ref);
-               c->wasted_size += ref_totlen(c, jeb, ref);      
+               c->wasted_size += ref_totlen(c, jeb, ref);
        }
        ref->flash_offset = ref_offset(ref) | REF_OBSOLETE;
-       
-       ACCT_SANITY_CHECK(c, jeb);
 
-       D1(ACCT_PARANOIA_CHECK(jeb));
+       jffs2_dbg_acct_sanity_check_nolock(c, jeb);
+       jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
 
        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 
+                  obliterate nodes that look obsolete. If they weren't
                   marked obsolete on the flash at the time they _became_
                   obsolete, there was probably a reason for that. */
                spin_unlock(&c->erase_completion_lock);
@@ -507,7 +590,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                                   immediately reused, and we spread the load a bit. */
                                D1(printk(KERN_DEBUG "...and adding to erasable_list\n"));
                                list_add_tail(&jeb->list, &c->erasable_list);
-                       }                               
+                       }
                }
                D1(printk(KERN_DEBUG "Done OK\n"));
        } else if (jeb == c->gcblock) {
@@ -525,8 +608,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                list_add_tail(&jeb->list, &c->very_dirty_list);
        } else {
                D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n",
-                         jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); 
-       }                               
+                         jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+       }
 
        spin_unlock(&c->erase_completion_lock);
 
@@ -573,11 +656,11 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
 
        /* Nodes which have been marked obsolete no longer need to be
           associated with any inode. Remove them from the per-inode list.
-          
-          Note we can't do this for NAND at the moment because we need 
+
+          Note we can't do this for NAND at the moment because we need
           obsolete dirent nodes to stay on the lists, because of the
           horridness in jffs2_garbage_collect_deletion_dirent(). Also
-          because we delete the inocache, and on NAND we need that to 
+          because we delete the inocache, and on NAND we need that to
           stay around until all the nodes are actually erased, in order
           to stop us from giving the same inode number to another newly
           created inode. */
@@ -606,7 +689,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
        if (ref->next_phys && ref_obsolete(ref->next_phys) &&
            !ref->next_phys->next_in_ino) {
                struct jffs2_raw_node_ref *n = ref->next_phys;
-               
+
                spin_lock(&c->erase_completion_lock);
 
                ref->__totlen += n->__totlen;
@@ -620,7 +703,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
 
                jffs2_free_raw_node_ref(n);
        }
-       
+
        /* Also merge with the previous node in the list, if there is one
           and that one is obsolete */
        if (ref != jeb->first_node ) {
@@ -630,7 +713,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
 
                while (p->next_phys != ref)
                        p = p->next_phys;
-               
+
                if (ref_obsolete(p) && !ref->next_in_ino) {
                        p->__totlen += ref->__totlen;
                        if (jeb->last_node == ref) {
@@ -649,164 +732,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
        up(&c->erase_free_sem);
 }
 
-#if CONFIG_JFFS2_FS_DEBUG >= 2
-void jffs2_dump_block_lists(struct jffs2_sb_info *c)
-{
-
-
-       printk(KERN_DEBUG "jffs2_dump_block_lists:\n");
-       printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size);
-       printk(KERN_DEBUG "used_size: %08x\n", c->used_size);
-       printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size);
-       printk(KERN_DEBUG "wasted_size: %08x\n", c->wasted_size);
-       printk(KERN_DEBUG "unchecked_size: %08x\n", c->unchecked_size);
-       printk(KERN_DEBUG "free_size: %08x\n", c->free_size);
-       printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
-       printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
-       printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size);
-       printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write);
-
-       if (c->nextblock) {
-               printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                      c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->unchecked_size, c->nextblock->free_size);
-       } else {
-               printk(KERN_DEBUG "nextblock: NULL\n");
-       }
-       if (c->gcblock) {
-               printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                      c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
-       } else {
-               printk(KERN_DEBUG "gcblock: NULL\n");
-       }
-       if (list_empty(&c->clean_list)) {
-               printk(KERN_DEBUG "clean_list: empty\n");
-       } else {
-               struct list_head *this;
-               int     numblocks = 0;
-               uint32_t dirty = 0;
-
-               list_for_each(this, &c->clean_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       numblocks ++;
-                       dirty += jeb->wasted_size;
-                       printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-               printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", numblocks, dirty, dirty / numblocks);
-       }
-       if (list_empty(&c->very_dirty_list)) {
-               printk(KERN_DEBUG "very_dirty_list: empty\n");
-       } else {
-               struct list_head *this;
-               int     numblocks = 0;
-               uint32_t dirty = 0;
-
-               list_for_each(this, &c->very_dirty_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       numblocks ++;
-                       dirty += jeb->dirty_size;
-                       printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-               printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
-                       numblocks, dirty, dirty / numblocks);
-       }
-       if (list_empty(&c->dirty_list)) {
-               printk(KERN_DEBUG "dirty_list: empty\n");
-       } else {
-               struct list_head *this;
-               int     numblocks = 0;
-               uint32_t dirty = 0;
-
-               list_for_each(this, &c->dirty_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       numblocks ++;
-                       dirty += jeb->dirty_size;
-                       printk(KERN_DEBUG "dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-               printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
-                       numblocks, dirty, dirty / numblocks);
-       }
-       if (list_empty(&c->erasable_list)) {
-               printk(KERN_DEBUG "erasable_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->erasable_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "erasable_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-       }
-       if (list_empty(&c->erasing_list)) {
-               printk(KERN_DEBUG "erasing_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->erasing_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "erasing_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-       }
-       if (list_empty(&c->erase_pending_list)) {
-               printk(KERN_DEBUG "erase_pending_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->erase_pending_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "erase_pending_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-       }
-       if (list_empty(&c->erasable_pending_wbuf_list)) {
-               printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->erasable_pending_wbuf_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "erasable_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-       }
-       if (list_empty(&c->free_list)) {
-               printk(KERN_DEBUG "free_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->free_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "free_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-       }
-       if (list_empty(&c->bad_list)) {
-               printk(KERN_DEBUG "bad_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->bad_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "bad_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-       }
-       if (list_empty(&c->bad_used_list)) {
-               printk(KERN_DEBUG "bad_used_list: empty\n");
-       } else {
-               struct list_head *this;
-
-               list_for_each(this, &c->bad_used_list) {
-                       struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
-                       printk(KERN_DEBUG "bad_used_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
-                              jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
-               }
-       }
-}
-#endif /* CONFIG_JFFS2_FS_DEBUG */
-
 int jffs2_thread_should_wake(struct jffs2_sb_info *c)
 {
        int ret = 0;
@@ -828,11 +753,11 @@ int jffs2_thread_should_wake(struct jffs2_sb_info *c)
         */
        dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
 
-       if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && 
-                       (dirty > c->nospc_dirty_size)) 
+       if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger &&
+                       (dirty > c->nospc_dirty_size))
                ret = 1;
 
-       D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", 
+       D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
                  c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
 
        return ret;
index d900c8929b09983cca227d2deeb1658ac0913b0b..59e7a393200c6877c99a7a2dc87303045b1e2644 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-linux.h,v 1.58 2005/07/12 02:34:35 tpoynor Exp $
+ * $Id: os-linux.h,v 1.64 2005/09/30 13:59:13 dedekind Exp $
  *
  */
 
@@ -57,6 +57,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
        f->fragtree = RB_ROOT;
        f->metadata = NULL;
        f->dents = NULL;
+       f->target = NULL;
        f->flags = 0;
        f->usercompr = 0;
 }
@@ -64,17 +65,24 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 
 #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
 
+#define SECTOR_ADDR(x) ( (((unsigned long)(x) / c->sector_size) * c->sector_size) )
 #ifndef CONFIG_JFFS2_FS_WRITEBUFFER
-#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
+
+
+#ifdef CONFIG_JFFS2_SUMMARY
+#define jffs2_can_mark_obsolete(c) (0)
+#else
 #define jffs2_can_mark_obsolete(c) (1)
+#endif
+
 #define jffs2_is_writebuffered(c) (0)
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
 
-#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf))
+#define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf)
 #define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
-#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
-#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
+#define jffs2_flush_wbuf_pad(c) ({ do{} while(0); (void)(c), 0; })
+#define jffs2_flush_wbuf_gc(c, i) ({ do{} while(0); (void)(c), (void) i, 0; })
 #define jffs2_write_nand_badblock(c,jeb,bad_offset) (1)
 #define jffs2_nand_flash_setup(c) (0)
 #define jffs2_nand_flash_cleanup(c) do {} while(0)
@@ -84,16 +92,26 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 #define jffs2_wbuf_process NULL
 #define jffs2_nor_ecc(c) (0)
 #define jffs2_dataflash(c) (0)
+#define jffs2_nor_wbuf_flash(c) (0)
 #define jffs2_nor_ecc_flash_setup(c) (0)
 #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
 #define jffs2_dataflash_setup(c) (0)
 #define jffs2_dataflash_cleanup(c) do {} while (0)
+#define jffs2_nor_wbuf_flash_setup(c) (0)
+#define jffs2_nor_wbuf_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)
+
+#ifdef CONFIG_JFFS2_SUMMARY
+#define jffs2_can_mark_obsolete(c) (0)
+#else
+#define jffs2_can_mark_obsolete(c) \
+  ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \
+   c->mtd->type == MTD_RAM)
+#endif
+
 #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
 
 #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
@@ -123,6 +141,10 @@ void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
 int jffs2_dataflash_setup(struct jffs2_sb_info *c);
 void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
 
+#define jffs2_nor_wbuf_flash(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_PROGRAM_REGIONS))
+int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c);
+
 #endif /* WRITEBUFFER */
 
 /* erase.c */
@@ -169,20 +191,21 @@ void jffs2_gc_release_inode(struct jffs2_sb_info *c,
 struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
                                              int inum, int nlink);
 
-unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
-                                  struct jffs2_inode_info *f, 
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
+                                  struct jffs2_inode_info *f,
                                   unsigned long offset,
                                   unsigned long *priv);
 void jffs2_gc_release_page(struct jffs2_sb_info *c,
                           unsigned char *pg,
                           unsigned long *priv);
 void jffs2_flash_cleanup(struct jffs2_sb_info *c);
-     
+
 
 /* writev.c */
-int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, 
+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
                       unsigned long count, loff_t to, size_t *retlen);
-
+int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
+                       size_t *retlen, const u_char *buf);
 
 #endif /* __JFFS2_OS_LINUX_H__ */
 
index c7f9068907cfa6a6f4b13e2694b788ed389cdd11..f3b86da833baedc2e206d4ba85d25e4a65069fe8 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $
+ * $Id: read.c,v 1.42 2005/11/07 11:14:41 gleixner Exp $
  *
  */
 
@@ -43,7 +43,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
        }
        if (readlen != sizeof(*ri)) {
                jffs2_free_raw_inode(ri);
-               printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", 
+               printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n",
                       ref_offset(fd->raw), sizeof(*ri), readlen);
                return -EIO;
        }
@@ -61,7 +61,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
        }
        /* There was a bug where we wrote hole nodes out with csize/dsize
           swapped. Deal with it */
-       if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && 
+       if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) &&
            je32_to_cpu(ri->csize)) {
                ri->dsize = ri->csize;
                ri->csize = cpu_to_je32(0);
@@ -74,7 +74,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                goto out_ri;
        });
 
-       
+
        if (ri->compr == JFFS2_COMPR_ZERO) {
                memset(buf, 0, len);
                goto out_ri;
@@ -82,8 +82,8 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 
        /* Cases:
           Reading whole node and it's uncompressed - read directly to buffer provided, check CRC.
-          Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided 
-          Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy 
+          Reading whole node and it's compressed - read into comprbuf, check CRC and decompress to buffer provided
+          Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy
           Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy
        */
        if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) {
@@ -129,7 +129,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
        D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc));
        if (ri->compr != JFFS2_COMPR_NONE) {
                D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
-                         je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); 
+                         je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf));
                ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
                if (ret) {
                        printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
@@ -174,7 +174,6 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                        if (frag) {
                                D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
                                holesize = min(holesize, frag->ofs - offset);
-                               D2(jffs2_print_frag_list(f));
                        }
                        D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
                        memset(buf, 0, holesize);
@@ -192,7 +191,7 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                } else {
                        uint32_t readlen;
                        uint32_t fragofs; /* offset within the frag to start reading */
-                       
+
                        fragofs = offset - frag->ofs;
                        readlen = min(frag->size - fragofs, end - offset);
                        D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n",
index 1a96903e3ef3786362d459d2089d5ee01750e45c..5f0652df5d47dab051839cf88218e2c353c28733 100644 (file)
@@ -7,11 +7,12 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.125 2005/07/10 13:13:55 dedekind Exp $
+ * $Id: readinode.c,v 1.143 2005/11/07 11:14:41 gleixner Exp $
  *
  */
 
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/crc32.h>
 #include <linux/compiler.h>
 #include "nodelist.h"
 
-static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag);
-
-#if CONFIG_JFFS2_FS_DEBUG >= 2
-static void jffs2_print_fragtree(struct rb_root *list, int permitbug)
+/*
+ * Put a new tmp_dnode_info into the temporaty RB-tree, keeping the list in
+ * order of increasing version.
+ */
+static void jffs2_add_tn_to_tree(struct jffs2_tmp_dnode_info *tn, struct rb_root *list)
 {
-       struct jffs2_node_frag *this = frag_first(list);
-       uint32_t lastofs = 0;
-       int buggy = 0;
-
-       while(this) {
-               if (this->node)
-                       printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n",
-                              this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw),
-                              this, frag_left(this), frag_right(this), frag_parent(this));
-               else 
-                       printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs, 
-                              this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this));
-               if (this->ofs != lastofs)
-                       buggy = 1;
-               lastofs = this->ofs+this->size;
-               this = frag_next(this);
+       struct rb_node **p = &list->rb_node;
+       struct rb_node * parent = NULL;
+       struct jffs2_tmp_dnode_info *this;
+
+       while (*p) {
+               parent = *p;
+               this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
+
+               /* There may actually be a collision here, but it doesn't
+                  actually matter. As long as the two nodes with the same
+                  version are together, it's all fine. */
+               if (tn->version > this->version)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
        }
-       if (buggy && !permitbug) {
-               printk(KERN_CRIT "Frag tree got a hole in it\n");
-               BUG();
+
+       rb_link_node(&tn->rb, parent, p);
+       rb_insert_color(&tn->rb, list);
+}
+
+static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
+{
+       struct rb_node *this;
+       struct jffs2_tmp_dnode_info *tn;
+
+       this = list->rb_node;
+
+       /* Now at bottom of tree */
+       while (this) {
+               if (this->rb_left)
+                       this = this->rb_left;
+               else if (this->rb_right)
+                       this = this->rb_right;
+               else {
+                       tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb);
+                       jffs2_free_full_dnode(tn->fn);
+                       jffs2_free_tmp_dnode_info(tn);
+
+                       this = this->rb_parent;
+                       if (!this)
+                               break;
+
+                       if (this->rb_left == &tn->rb)
+                               this->rb_left = NULL;
+                       else if (this->rb_right == &tn->rb)
+                               this->rb_right = NULL;
+                       else BUG();
+               }
        }
+       list->rb_node = NULL;
 }
 
-void jffs2_print_frag_list(struct jffs2_inode_info *f)
+static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
 {
-       jffs2_print_fragtree(&f->fragtree, 0);
+       struct jffs2_full_dirent *next;
 
-       if (f->metadata) {
-               printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
+       while (fd) {
+               next = fd->next;
+               jffs2_free_full_dirent(fd);
+               fd = next;
        }
 }
-#endif
 
-#if CONFIG_JFFS2_FS_DEBUG >= 1
-static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f)
+/* Returns first valid node after 'ref'. May return 'ref' */
+static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref)
 {
-       struct jffs2_node_frag *frag;
-       int bitched = 0;
-
-       for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
+       while (ref && ref->next_in_ino) {
+               if (!ref_obsolete(ref))
+                       return ref;
+               dbg_noderef("node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref));
+               ref = ref->next_in_ino;
+       }
+       return NULL;
+}
 
-               struct jffs2_full_dnode *fn = frag->node;
-               if (!fn || !fn->raw)
-                       continue;
+/*
+ * Helper function for jffs2_get_inode_nodes().
+ * It is called every time an directory entry node is found.
+ *
+ * Returns: 0 on succes;
+ *         1 if the node should be marked obsolete;
+ *         negative error code on failure.
+ */
+static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
+                               struct jffs2_raw_dirent *rd, uint32_t read, struct jffs2_full_dirent **fdp,
+                               uint32_t *latest_mctime, uint32_t *mctime_ver)
+{
+       struct jffs2_full_dirent *fd;
+
+       /* The direntry nodes are checked during the flash scanning */
+       BUG_ON(ref_flags(ref) == REF_UNCHECKED);
+       /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
+       BUG_ON(ref_obsolete(ref));
+
+       /* Sanity check */
+       if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
+               JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
+                      ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
+               return 1;
+       }
 
-               if (ref_flags(fn->raw) == REF_PRISTINE) {
+       fd = jffs2_alloc_full_dirent(rd->nsize + 1);
+       if (unlikely(!fd))
+               return -ENOMEM;
 
-                       if (fn->frags > 1) {
-                               printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags);
-                               bitched = 1;
-                       }
-                       /* A hole node which isn't multi-page should be garbage-collected
-                          and merged anyway, so we just check for the frag size here,
-                          rather than mucking around with actually reading the node
-                          and checking the compression type, which is the real way
-                          to tell a hole node. */
-                       if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
-                               printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
-                                      ref_offset(fn->raw));
-                               bitched = 1;
-                       }
+       fd->raw = ref;
+       fd->version = je32_to_cpu(rd->version);
+       fd->ino = je32_to_cpu(rd->ino);
+       fd->type = rd->type;
 
-                       if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
-                               printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
-                                      ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
-                               bitched = 1;
-                       }
-               }
+       /* Pick out the mctime of the latest dirent */
+       if(fd->version > *mctime_ver && je32_to_cpu(rd->mctime)) {
+               *mctime_ver = fd->version;
+               *latest_mctime = je32_to_cpu(rd->mctime);
        }
-       
-       if (bitched) {
-               struct jffs2_node_frag *thisfrag;
-
-               printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino);
-               thisfrag = frag_first(&f->fragtree);
-               while (thisfrag) {
-                       if (!thisfrag->node) {
-                               printk("Frag @0x%x-0x%x; node-less hole\n",
-                                      thisfrag->ofs, thisfrag->size + thisfrag->ofs);
-                       } else if (!thisfrag->node->raw) {
-                               printk("Frag @0x%x-0x%x; raw-less hole\n",
-                                      thisfrag->ofs, thisfrag->size + thisfrag->ofs);
-                       } else {
-                               printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n",
-                                      thisfrag->ofs, thisfrag->size + thisfrag->ofs,
-                                      ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw),
-                                      thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size);
-                       }
-                       thisfrag = frag_next(thisfrag);
-               }
-       }
-       return bitched;
-}
-#endif /* D1 */
 
-static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
-{
-       if (this->node) {
-               this->node->frags--;
-               if (!this->node->frags) {
-                       /* The node has no valid frags left. It's totally obsoleted */
-                       D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n",
-                                 ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size));
-                       jffs2_mark_node_obsolete(c, this->node->raw);
-                       jffs2_free_full_dnode(this->node);
-               } else {
-                       D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n",
-                                 ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size,
-                                 this->node->frags));
-                       mark_ref_normal(this->node->raw);
+       /*
+        * Copy as much of the name as possible from the raw
+        * dirent we've already read from the flash.
+        */
+       if (read > sizeof(*rd))
+               memcpy(&fd->name[0], &rd->name[0],
+                      min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) ));
+
+       /* Do we need to copy any more of the name directly from the flash? */
+       if (rd->nsize + sizeof(*rd) > read) {
+               /* FIXME: point() */
+               int err;
+               int already = read - sizeof(*rd);
+
+               err = jffs2_flash_read(c, (ref_offset(ref)) + read,
+                               rd->nsize - already, &read, &fd->name[already]);
+               if (unlikely(read != rd->nsize - already) && likely(!err))
+                       return -EIO;
+
+               if (unlikely(err)) {
+                       JFFS2_ERROR("read remainder of name: error %d\n", err);
+                       jffs2_free_full_dirent(fd);
+                       return -EIO;
                }
-               
        }
-       jffs2_free_node_frag(this);
+
+       fd->nhash = full_name_hash(fd->name, rd->nsize);
+       fd->next = NULL;
+       fd->name[rd->nsize] = '\0';
+
+       /*
+        * Wheee. We now have a complete jffs2_full_dirent structure, with
+        * the name in it and everything. Link it into the list
+        */
+       jffs2_add_fd_to_list(c, fd, fdp);
+
+       return 0;
 }
 
-/* Given an inode, probably with existing list of fragments, add the new node
- * to the fragment list.
+/*
+ * Helper function for jffs2_get_inode_nodes().
+ * It is called every time an inode node is found.
+ *
+ * Returns: 0 on succes;
+ *         1 if the node should be marked obsolete;
+ *         negative error code on failure.
  */
-int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn)
+static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
+                            struct jffs2_raw_inode *rd, struct rb_root *tnp, int rdlen,
+                            uint32_t *latest_mctime, uint32_t *mctime_ver)
 {
-       int ret;
-       struct jffs2_node_frag *newfrag;
-
-       D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
+       struct jffs2_tmp_dnode_info *tn;
+       uint32_t len, csize;
+       int ret = 1;
 
-       if (unlikely(!fn->size))
-               return 0;
+       /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
+       BUG_ON(ref_obsolete(ref));
 
-       newfrag = jffs2_alloc_node_frag();
-       if (unlikely(!newfrag))
+       tn = jffs2_alloc_tmp_dnode_info();
+       if (!tn) {
+               JFFS2_ERROR("failed to allocate tn (%d bytes).\n", sizeof(*tn));
                return -ENOMEM;
+       }
 
-       D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n",
-                 fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag));
-       
-       newfrag->ofs = fn->ofs;
-       newfrag->size = fn->size;
-       newfrag->node = fn;
-       newfrag->node->frags = 1;
+       tn->partial_crc = 0;
+       csize = je32_to_cpu(rd->csize);
 
-       ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag);
-       if (ret)
-               return ret;
+       /* If we've never checked the CRCs on this node, check them now */
+       if (ref_flags(ref) == REF_UNCHECKED) {
+               uint32_t crc;
 
-       /* If we now share a page with other nodes, mark either previous
-          or next node REF_NORMAL, as appropriate.  */
-       if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) {
-               struct jffs2_node_frag *prev = frag_prev(newfrag);
+               crc = crc32(0, rd, sizeof(*rd) - 8);
+               if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
+                       JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
+                                       ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
+                       goto free_out;
+               }
 
-               mark_ref_normal(fn->raw);
-               /* If we don't start at zero there's _always_ a previous */     
-               if (prev->node)
-                       mark_ref_normal(prev->node->raw);
-       }
+               /* Sanity checks */
+               if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||
+                   unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) {
+                               JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref));
+                               jffs2_dbg_dump_node(c, ref_offset(ref));
+                       goto free_out;
+               }
 
-       if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) {
-               struct jffs2_node_frag *next = frag_next(newfrag);
-               
-               if (next) {
-                       mark_ref_normal(fn->raw);
-                       if (next->node)
-                               mark_ref_normal(next->node->raw);
+               if (jffs2_is_writebuffered(c) && csize != 0) {
+                       /* At this point we are supposed to check the data CRC
+                        * of our unchecked node. But thus far, we do not
+                        * know whether the node is valid or obsolete. To
+                        * figure this out, we need to walk all the nodes of
+                        * the inode and build the inode fragtree. We don't
+                        * want to spend time checking data of nodes which may
+                        * later be found to be obsolete. So we put off the full
+                        * data CRC checking until we have read all the inode
+                        * nodes and have started building the fragtree.
+                        *
+                        * The fragtree is being built starting with nodes
+                        * having the highest version number, so we'll be able
+                        * to detect whether a node is valid (i.e., it is not
+                        * overlapped by a node with higher version) or not.
+                        * And we'll be able to check only those nodes, which
+                        * are not obsolete.
+                        *
+                        * Of course, this optimization only makes sense in case
+                        * of NAND flashes (or other flashes whith
+                        * !jffs2_can_mark_obsolete()), since on NOR flashes
+                        * nodes are marked obsolete physically.
+                        *
+                        * Since NAND flashes (or other flashes with
+                        * jffs2_is_writebuffered(c)) are anyway read by
+                        * fractions of c->wbuf_pagesize, and we have just read
+                        * the node header, it is likely that the starting part
+                        * of the node data is also read when we read the
+                        * header. So we don't mind to check the CRC of the
+                        * starting part of the data of the node now, and check
+                        * the second part later (in jffs2_check_node_data()).
+                        * Of course, we will not need to re-read and re-check
+                        * the NAND page which we have just read. This is why we
+                        * read the whole NAND page at jffs2_get_inode_nodes(),
+                        * while we needed only the node header.
+                        */
+                       unsigned char *buf;
+
+                       /* 'buf' will point to the start of data */
+                       buf = (unsigned char *)rd + sizeof(*rd);
+                       /* len will be the read data length */
+                       len = min_t(uint32_t, rdlen - sizeof(*rd), csize);
+                       tn->partial_crc = crc32(0, buf, len);
+
+                       dbg_readinode("Calculates CRC (%#08x) for %d bytes, csize %d\n", tn->partial_crc, len, csize);
+
+                       /* If we actually calculated the whole data CRC
+                        * and it is wrong, drop the node. */
+                       if (len >= csize && unlikely(tn->partial_crc != je32_to_cpu(rd->data_crc))) {
+                               JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
+                                       ref_offset(ref), tn->partial_crc, je32_to_cpu(rd->data_crc));
+                               goto free_out;
+                       }
+
+               } else if (csize == 0) {
+                       /*
+                        * We checked the header CRC. If the node has no data, adjust
+                        * the space accounting now. For other nodes this will be done
+                        * later either when the node is marked obsolete or when its
+                        * data is checked.
+                        */
+                       struct jffs2_eraseblock *jeb;
+
+                       dbg_readinode("the node has no data.\n");
+                       jeb = &c->blocks[ref->flash_offset / c->sector_size];
+                       len = ref_totlen(c, jeb, ref);
+
+                       spin_lock(&c->erase_completion_lock);
+                       jeb->used_size += len;
+                       jeb->unchecked_size -= len;
+                       c->used_size += len;
+                       c->unchecked_size -= len;
+                       ref->flash_offset = ref_offset(ref) | REF_NORMAL;
+                       spin_unlock(&c->erase_completion_lock);
                }
        }
-       D2(if (jffs2_sanitycheck_fragtree(f)) {
-                  printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n",
-                         fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag);
-                  return 0;
-          })
-       D2(jffs2_print_frag_list(f));
+
+       tn->fn = jffs2_alloc_full_dnode();
+       if (!tn->fn) {
+               JFFS2_ERROR("alloc fn failed\n");
+               ret = -ENOMEM;
+               goto free_out;
+       }
+
+       tn->version = je32_to_cpu(rd->version);
+       tn->fn->ofs = je32_to_cpu(rd->offset);
+       tn->data_crc = je32_to_cpu(rd->data_crc);
+       tn->csize = csize;
+       tn->fn->raw = ref;
+
+       /* There was a bug where we wrote hole nodes out with
+          csize/dsize swapped. Deal with it */
+       if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && csize)
+               tn->fn->size = csize;
+       else // normal case...
+               tn->fn->size = je32_to_cpu(rd->dsize);
+
+       dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n",
+                 ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize);
+
+       jffs2_add_tn_to_tree(tn, tnp);
+
        return 0;
+
+free_out:
+       jffs2_free_tmp_dnode_info(tn);
+       return ret;
 }
 
-/* Doesn't set inode->i_size */
-static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag)
+/*
+ * Helper function for jffs2_get_inode_nodes().
+ * It is called every time an unknown node is found.
+ *
+ * Returns: 0 on succes;
+ *         1 if the node should be marked obsolete;
+ *         negative error code on failure.
+ */
+static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un)
 {
-       struct jffs2_node_frag *this;
-       uint32_t lastend;
+       /* We don't mark unknown nodes as REF_UNCHECKED */
+       BUG_ON(ref_flags(ref) == REF_UNCHECKED);
 
-       /* Skip all the nodes which are completed before this one starts */
-       this = jffs2_lookup_node_frag(list, newfrag->node->ofs);
+       un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype));
 
-       if (this) {
-               D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
-                         this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this));
-               lastend = this->ofs + this->size;
+       if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) {
+               /* Hmmm. This should have been caught at scan time. */
+               JFFS2_NOTICE("node header CRC failed at %#08x. But it must have been OK earlier.\n", ref_offset(ref));
+               jffs2_dbg_dump_node(c, ref_offset(ref));
+               return 1;
        } else {
-               D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n"));
-               lastend = 0;
-       }
-                         
-       /* See if we ran off the end of the list */
-       if (lastend <= newfrag->ofs) {
-               /* We did */
-
-               /* Check if 'this' node was on the same page as the new node.
-                  If so, both 'this' and the new node get marked REF_NORMAL so
-                  the GC can take a look.
-               */
-               if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
-                       if (this->node)
-                               mark_ref_normal(this->node->raw);
-                       mark_ref_normal(newfrag->node->raw);
-               }
+               switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) {
 
-               if (lastend < newfrag->node->ofs) {
-                       /* ... and we need to put a hole in before the new node */
-                       struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag();
-                       if (!holefrag) {
-                               jffs2_free_node_frag(newfrag);
-                               return -ENOMEM;
-                       }
-                       holefrag->ofs = lastend;
-                       holefrag->size = newfrag->node->ofs - lastend;
-                       holefrag->node = NULL;
-                       if (this) {
-                               /* By definition, the 'this' node has no right-hand child, 
-                                  because there are no frags with offset greater than it.
-                                  So that's where we want to put the hole */
-                               D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this));
-                               rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
-                       } else {
-                               D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag));
-                               rb_link_node(&holefrag->rb, NULL, &list->rb_node);
-                       }
-                       rb_insert_color(&holefrag->rb, list);
-                       this = holefrag;
-               }
-               if (this) {
-                       /* By definition, the 'this' node has no right-hand child, 
-                          because there are no frags with offset greater than it.
-                          So that's where we want to put the hole */
-                       D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this));
-                       rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);                      
-               } else {
-                       D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag));
-                       rb_link_node(&newfrag->rb, NULL, &list->rb_node);
+               case JFFS2_FEATURE_INCOMPAT:
+                       JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n",
+                               je16_to_cpu(un->nodetype), ref_offset(ref));
+                       /* EEP */
+                       BUG();
+                       break;
+
+               case JFFS2_FEATURE_ROCOMPAT:
+                       JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n",
+                                       je16_to_cpu(un->nodetype), ref_offset(ref));
+                       BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO));
+                       break;
+
+               case JFFS2_FEATURE_RWCOMPAT_COPY:
+                       JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n",
+                                       je16_to_cpu(un->nodetype), ref_offset(ref));
+                       break;
+
+               case JFFS2_FEATURE_RWCOMPAT_DELETE:
+                       JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",
+                                       je16_to_cpu(un->nodetype), ref_offset(ref));
+                       return 1;
                }
-               rb_insert_color(&newfrag->rb, list);
-               return 0;
        }
 
-       D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", 
-                 this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this));
+       return 0;
+}
 
-       /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
-        * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs  
-        */
-       if (newfrag->ofs > this->ofs) {
-               /* This node isn't completely obsoleted. The start of it remains valid */
-
-               /* Mark the new node and the partially covered node REF_NORMAL -- let
-                  the GC take a look at them */
-               mark_ref_normal(newfrag->node->raw);
-               if (this->node)
-                       mark_ref_normal(this->node->raw);
-
-               if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
-                       /* The new node splits 'this' frag into two */
-                       struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag();
-                       if (!newfrag2) {
-                               jffs2_free_node_frag(newfrag);
-                               return -ENOMEM;
-                       }
-                       D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
-                       if (this->node)
-                               printk("phys 0x%08x\n", ref_offset(this->node->raw));
-                       else 
-                               printk("hole\n");
-                          )
-                       
-                       /* New second frag pointing to this's node */
-                       newfrag2->ofs = newfrag->ofs + newfrag->size;
-                       newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
-                       newfrag2->node = this->node;
-                       if (this->node)
-                               this->node->frags++;
-
-                       /* Adjust size of original 'this' */
-                       this->size = newfrag->ofs - this->ofs;
-
-                       /* Now, we know there's no node with offset
-                          greater than this->ofs but smaller than
-                          newfrag2->ofs or newfrag->ofs, for obvious
-                          reasons. So we can do a tree insert from
-                          'this' to insert newfrag, and a tree insert
-                          from newfrag to insert newfrag2. */
-                       jffs2_fragtree_insert(newfrag, this);
-                       rb_insert_color(&newfrag->rb, list);
-                       
-                       jffs2_fragtree_insert(newfrag2, newfrag);
-                       rb_insert_color(&newfrag2->rb, list);
-                       
-                       return 0;
-               }
-               /* New node just reduces 'this' frag in size, doesn't split it */
-               this->size = newfrag->ofs - this->ofs;
+/*
+ * Helper function for jffs2_get_inode_nodes().
+ * The function detects whether more data should be read and reads it if yes.
+ *
+ * Returns: 0 on succes;
+ *         negative error code on failure.
+ */
+static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
+                    int right_size, int *rdlen, unsigned char *buf, unsigned char *bufstart)
+{
+       int right_len, err, len;
+       size_t retlen;
+       uint32_t offs;
 
-               /* Again, we know it lives down here in the tree */
-               jffs2_fragtree_insert(newfrag, this);
-               rb_insert_color(&newfrag->rb, list);
-       } else {
-               /* New frag starts at the same point as 'this' used to. Replace 
-                  it in the tree without doing a delete and insertion */
-               D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n",
-                         newfrag, newfrag->ofs, newfrag->ofs+newfrag->size,
-                         this, this->ofs, this->ofs+this->size));
-       
-               rb_replace_node(&this->rb, &newfrag->rb, list);
-               
-               if (newfrag->ofs + newfrag->size >= this->ofs+this->size) {
-                       D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size));
-                       jffs2_obsolete_node_frag(c, this);
-               } else {
-                       this->ofs += newfrag->size;
-                       this->size -= newfrag->size;
+       if (jffs2_is_writebuffered(c)) {
+               right_len = c->wbuf_pagesize - (bufstart - buf);
+               if (right_size + (int)(bufstart - buf) > c->wbuf_pagesize)
+                       right_len += c->wbuf_pagesize;
+       } else
+               right_len = right_size;
 
-                       jffs2_fragtree_insert(this, newfrag);
-                       rb_insert_color(&this->rb, list);
-                       return 0;
-               }
+       if (*rdlen == right_len)
+               return 0;
+
+       /* We need to read more data */
+       offs = ref_offset(ref) + *rdlen;
+       if (jffs2_is_writebuffered(c)) {
+               bufstart = buf + c->wbuf_pagesize;
+               len = c->wbuf_pagesize;
+       } else {
+               bufstart = buf + *rdlen;
+               len = right_size - *rdlen;
        }
-       /* OK, now we have newfrag added in the correct place in the tree, but
-          frag_next(newfrag) may be a fragment which is overlapped by it 
-       */
-       while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
-               /* 'this' frag is obsoleted completely. */
-               D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size));
-               rb_erase(&this->rb, list);
-               jffs2_obsolete_node_frag(c, this);
+
+       dbg_readinode("read more %d bytes\n", len);
+
+       err = jffs2_flash_read(c, offs, len, &retlen, bufstart);
+       if (err) {
+               JFFS2_ERROR("can not read %d bytes from 0x%08x, "
+                       "error code: %d.\n", len, offs, err);
+               return err;
        }
-       /* Now we're pointing at the first frag which isn't totally obsoleted by 
-          the new frag */
 
-       if (!this || newfrag->ofs + newfrag->size == this->ofs) {
-               return 0;
+       if (retlen < len) {
+               JFFS2_ERROR("short read at %#08x: %d instead of %d.\n",
+                               offs, retlen, len);
+               return -EIO;
        }
-       /* Still some overlap but we don't need to move it in the tree */
-       this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
-       this->ofs = newfrag->ofs + newfrag->size;
 
-       /* And mark them REF_NORMAL so the GC takes a look at them */
-       if (this->node)
-               mark_ref_normal(this->node->raw);
-       mark_ref_normal(newfrag->node->raw);
+       *rdlen = right_len;
 
        return 0;
 }
 
-void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
+/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
+   with this ino, returning the former in order of version */
+static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                                struct rb_root *tnp, struct jffs2_full_dirent **fdp,
+                                uint32_t *highest_version, uint32_t *latest_mctime,
+                                uint32_t *mctime_ver)
 {
-       struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
+       struct jffs2_raw_node_ref *ref, *valid_ref;
+       struct rb_root ret_tn = RB_ROOT;
+       struct jffs2_full_dirent *ret_fd = NULL;
+       unsigned char *buf = NULL;
+       union jffs2_node_union *node;
+       size_t retlen;
+       int len, err;
+
+       *mctime_ver = 0;
+
+       dbg_readinode("ino #%u\n", f->inocache->ino);
+
+       if (jffs2_is_writebuffered(c)) {
+               /*
+                * If we have the write buffer, we assume the minimal I/O unit
+                * is c->wbuf_pagesize. We implement some optimizations which in
+                * this case and we need a temporary buffer of size =
+                * 2*c->wbuf_pagesize bytes (see comments in read_dnode()).
+                * Basically, we want to read not only the node header, but the
+                * whole wbuf (NAND page in case of NAND) or 2, if the node
+                * header overlaps the border between the 2 wbufs.
+                */
+               len = 2*c->wbuf_pagesize;
+       } else {
+               /*
+                * When there is no write buffer, the size of the temporary
+                * buffer is the size of the larges node header.
+                */
+               len = sizeof(union jffs2_node_union);
+       }
 
-       D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size));
+       /* FIXME: in case of NOR and available ->point() this
+        * needs to be fixed. */
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
-       /* We know frag->ofs <= size. That's what lookup does for us */
-       if (frag && frag->ofs != size) {
-               if (frag->ofs+frag->size >= size) {
-                       D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
-                       frag->size = size - frag->ofs;
+       spin_lock(&c->erase_completion_lock);
+       valid_ref = jffs2_first_valid_node(f->inocache->nodes);
+       if (!valid_ref && f->inocache->ino != 1)
+               JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino);
+       while (valid_ref) {
+               unsigned char *bufstart;
+
+               /* We can hold a pointer to a non-obsolete node without the spinlock,
+                  but _obsolete_ nodes may disappear at any time, if the block
+                  they're in gets erased. So if we mark 'ref' obsolete while we're
+                  not holding the lock, it can go away immediately. For that reason,
+                  we find the next valid node first, before processing 'ref'.
+               */
+               ref = valid_ref;
+               valid_ref = jffs2_first_valid_node(ref->next_in_ino);
+               spin_unlock(&c->erase_completion_lock);
+
+               cond_resched();
+
+               /*
+                * At this point we don't know the type of the node we're going
+                * to read, so we do not know the size of its header. In order
+                * to minimize the amount of flash IO we assume the node has
+                * size = JFFS2_MIN_NODE_HEADER.
+                */
+               if (jffs2_is_writebuffered(c)) {
+                       /*
+                        * We treat 'buf' as 2 adjacent wbufs. We want to
+                        * adjust bufstart such as it points to the
+                        * beginning of the node within this wbuf.
+                        */
+                       bufstart = buf + (ref_offset(ref) % c->wbuf_pagesize);
+                       /* We will read either one wbuf or 2 wbufs. */
+                       len = c->wbuf_pagesize - (bufstart - buf);
+                       if (JFFS2_MIN_NODE_HEADER + (int)(bufstart - buf) > c->wbuf_pagesize) {
+                               /* The header spans the border of the first wbuf */
+                               len += c->wbuf_pagesize;
+                       }
+               } else {
+                       bufstart = buf;
+                       len = JFFS2_MIN_NODE_HEADER;
                }
-               frag = frag_next(frag);
-       }
-       while (frag && frag->ofs >= size) {
-               struct jffs2_node_frag *next = frag_next(frag);
 
-               D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
-               frag_erase(frag, list);
-               jffs2_obsolete_node_frag(c, frag);
-               frag = next;
-       }
-}
+               dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref));
 
-/* Scan the list of all nodes present for this ino, build map of versions, etc. */
+               /* FIXME: point() */
+               err = jffs2_flash_read(c, ref_offset(ref), len,
+                                      &retlen, bufstart);
+               if (err) {
+                       JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", len, ref_offset(ref), err);
+                       goto free_out;
+               }
 
-static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, 
-                                       struct jffs2_inode_info *f,
-                                       struct jffs2_raw_inode *latest_node);
+               if (retlen < len) {
+                       JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ref_offset(ref), retlen, len);
+                       err = -EIO;
+                       goto free_out;
+               }
 
-int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, 
-                       uint32_t ino, struct jffs2_raw_inode *latest_node)
-{
-       D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n"));
+               node = (union jffs2_node_union *)bufstart;
 
- retry_inocache:
-       spin_lock(&c->inocache_lock);
-       f->inocache = jffs2_get_ino_cache(c, ino);
+               switch (je16_to_cpu(node->u.nodetype)) {
 
-       D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache));
+               case JFFS2_NODETYPE_DIRENT:
+
+                       if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) {
+                               err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf, bufstart);
+                               if (unlikely(err))
+                                       goto free_out;
+                       }
+
+                       err = read_direntry(c, ref, &node->d, retlen, &ret_fd, latest_mctime, mctime_ver);
+                       if (err == 1) {
+                               jffs2_mark_node_obsolete(c, ref);
+                               break;
+                       } else if (unlikely(err))
+                               goto free_out;
+
+                       if (je32_to_cpu(node->d.version) > *highest_version)
+                               *highest_version = je32_to_cpu(node->d.version);
 
-       if (f->inocache) {
-               /* Check its state. We may need to wait before we can use it */
-               switch(f->inocache->state) {
-               case INO_STATE_UNCHECKED:
-               case INO_STATE_CHECKEDABSENT:
-                       f->inocache->state = INO_STATE_READING;
                        break;
-                       
-               case INO_STATE_CHECKING:
-               case INO_STATE_GC:
-                       /* If it's in either of these states, we need
-                          to wait for whoever's got it to finish and
-                          put it back. */
-                       D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n",
-                                 ino, f->inocache->state));
-                       sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
-                       goto retry_inocache;
 
-               case INO_STATE_READING:
-               case INO_STATE_PRESENT:
-                       /* Eep. This should never happen. It can
-                       happen if Linux calls read_inode() again
-                       before clear_inode() has finished though. */
-                       printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state);
-                       /* Fail. That's probably better than allowing it to succeed */
-                       f->inocache = NULL;
+               case JFFS2_NODETYPE_INODE:
+
+                       if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) {
+                               err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf, bufstart);
+                               if (unlikely(err))
+                                       goto free_out;
+                       }
+
+                       err = read_dnode(c, ref, &node->i, &ret_tn, len, latest_mctime, mctime_ver);
+                       if (err == 1) {
+                               jffs2_mark_node_obsolete(c, ref);
+                               break;
+                       } else if (unlikely(err))
+                               goto free_out;
+
+                       if (je32_to_cpu(node->i.version) > *highest_version)
+                               *highest_version = je32_to_cpu(node->i.version);
+
                        break;
 
                default:
-                       BUG();
-               }
-       }
-       spin_unlock(&c->inocache_lock);
+                       if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) {
+                               err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf, bufstart);
+                               if (unlikely(err))
+                                       goto free_out;
+                       }
+
+                       err = read_unknown(c, ref, &node->u);
+                       if (err == 1) {
+                               jffs2_mark_node_obsolete(c, ref);
+                               break;
+                       } else if (unlikely(err))
+                               goto free_out;
 
-       if (!f->inocache && ino == 1) {
-               /* Special case - no root inode on medium */
-               f->inocache = jffs2_alloc_inode_cache();
-               if (!f->inocache) {
-                       printk(KERN_CRIT "jffs2_do_read_inode(): Cannot allocate inocache for root inode\n");
-                       return -ENOMEM;
                }
-               D1(printk(KERN_DEBUG "jffs2_do_read_inode(): Creating inocache for root inode\n"));
-               memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
-               f->inocache->ino = f->inocache->nlink = 1;
-               f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
-               f->inocache->state = INO_STATE_READING;
-               jffs2_add_ino_cache(c, f->inocache);
+               spin_lock(&c->erase_completion_lock);
        }
-       if (!f->inocache) {
-               printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino);
-               return -ENOENT;
-       }
-
-       return jffs2_do_read_inode_internal(c, f, latest_node);
-}
 
-int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-{
-       struct jffs2_raw_inode n;
-       struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL);
-       int ret;
+       spin_unlock(&c->erase_completion_lock);
+       *tnp = ret_tn;
+       *fdp = ret_fd;
+       kfree(buf);
 
-       if (!f)
-               return -ENOMEM;
-
-       memset(f, 0, sizeof(*f));
-       init_MUTEX_LOCKED(&f->sem);
-       f->inocache = ic;
+       dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n",
+                       f->inocache->ino, *highest_version, *latest_mctime, *mctime_ver);
+       return 0;
 
-       ret = jffs2_do_read_inode_internal(c, f, &n);
-       if (!ret) {
-               up(&f->sem);
-               jffs2_do_clear_inode(c, f);
-       }
-       kfree(f);
-       return ret;
+ free_out:
+       jffs2_free_tmp_dnode_info_list(&ret_tn);
+       jffs2_free_full_dirent_list(ret_fd);
+       kfree(buf);
+       return err;
 }
 
-static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, 
+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                                        struct jffs2_inode_info *f,
                                        struct jffs2_raw_inode *latest_node)
 {
-       struct jffs2_tmp_dnode_info *tn = NULL;
+       struct jffs2_tmp_dnode_info *tn;
        struct rb_root tn_list;
        struct rb_node *rb, *repl_rb;
        struct jffs2_full_dirent *fd_list;
-       struct jffs2_full_dnode *fn = NULL;
+       struct jffs2_full_dnode *fn, *first_fn = NULL;
        uint32_t crc;
        uint32_t latest_mctime, mctime_ver;
-       uint32_t mdata_ver = 0;
        size_t retlen;
        int ret;
 
-       D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink));
+       dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink);
 
        /* Grab all nodes relevant to this ino */
        ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
 
        if (ret) {
-               printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret);
+               JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret);
                if (f->inocache->state == INO_STATE_READING)
                        jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
                return ret;
@@ -525,42 +655,33 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
        rb = rb_first(&tn_list);
 
        while (rb) {
+               cond_resched();
                tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb);
                fn = tn->fn;
-
-               if (f->metadata) {
-                       if (likely(tn->version >= mdata_ver)) {
-                               D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw)));
-                               jffs2_mark_node_obsolete(c, f->metadata->raw);
-                               jffs2_free_full_dnode(f->metadata);
-                               f->metadata = NULL;
-                               
-                               mdata_ver = 0;
-                       } else {
-                               /* This should never happen. */
-                               printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n",
-                                         ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw));
-                               jffs2_mark_node_obsolete(c, fn->raw);
-                               jffs2_free_full_dnode(fn);
-                               /* Fill in latest_node from the metadata, not this one we're about to free... */
-                               fn = f->metadata;
-                               goto next_tn;
-                       }
-               }
+               ret = 1;
+               dbg_readinode("consider node ver %u, phys offset "
+                       "%#08x(%d), range %u-%u.\n", tn->version,
+                       ref_offset(fn->raw), ref_flags(fn->raw),
+                       fn->ofs, fn->ofs + fn->size);
 
                if (fn->size) {
-                       jffs2_add_full_dnode_to_inode(c, f, fn);
-               } else {
-                       /* Zero-sized node at end of version list. Just a metadata update */
-                       D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version));
+                       ret = jffs2_add_older_frag_to_fragtree(c, f, tn);
+                       /* TODO: the error code isn't checked, check it */
+                       jffs2_dbg_fragtree_paranoia_check_nolock(f);
+                       BUG_ON(ret < 0);
+                       if (!first_fn && ret == 0)
+                               first_fn = fn;
+               } else if (!first_fn) {
+                       first_fn = fn;
                        f->metadata = fn;
-                       mdata_ver = tn->version;
-               }
-       next_tn:
+                       ret = 0; /* Prevent freeing the metadata update node */
+               } else
+                       jffs2_mark_node_obsolete(c, fn->raw);
+
                BUG_ON(rb->rb_left);
                if (rb->rb_parent && rb->rb_parent->rb_left == rb) {
                        /* We were then left-hand child of our parent. We need
-                          to move our own right-hand child into our place. */
+                        * to move our own right-hand child into our place. */
                        repl_rb = rb->rb_right;
                        if (repl_rb)
                                repl_rb->rb_parent = rb->rb_parent;
@@ -570,7 +691,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                rb = rb_next(rb);
 
                /* Remove the spent tn from the tree; don't bother rebalancing
-                  but put our right-hand child in our own place. */
+                * but put our right-hand child in our own place. */
                if (tn->rb.rb_parent) {
                        if (tn->rb.rb_parent->rb_left == &tn->rb)
                                tn->rb.rb_parent->rb_left = repl_rb;
@@ -581,19 +702,27 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                        tn->rb.rb_right->rb_parent = NULL;
 
                jffs2_free_tmp_dnode_info(tn);
+               if (ret) {
+                       dbg_readinode("delete dnode %u-%u.\n",
+                               fn->ofs, fn->ofs + fn->size);
+                       jffs2_free_full_dnode(fn);
+               }
        }
-       D1(jffs2_sanitycheck_fragtree(f));
+       jffs2_dbg_fragtree_paranoia_check_nolock(f);
 
-       if (!fn) {
+       BUG_ON(first_fn && ref_obsolete(first_fn->raw));
+
+       fn = first_fn;
+       if (unlikely(!first_fn)) {
                /* No data nodes for this inode. */
                if (f->inocache->ino != 1) {
-                       printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino);
+                       JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino);
                        if (!fd_list) {
                                if (f->inocache->state == INO_STATE_READING)
                                        jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
                                return -EIO;
                        }
-                       printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n");
+                       JFFS2_NOTICE("but it has children so we fake some modes for it\n");
                }
                latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);
                latest_node->version = cpu_to_je32(0);
@@ -608,8 +737,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
 
        ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node);
        if (ret || retlen != sizeof(*latest_node)) {
-               printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n",
-                      ret, retlen, sizeof(*latest_node));
+               JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n",
+                       ret, retlen, sizeof(*latest_node));
                /* FIXME: If this fails, there seems to be a memory leak. Find it. */
                up(&f->sem);
                jffs2_do_clear_inode(c, f);
@@ -618,7 +747,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
 
        crc = crc32(0, latest_node, sizeof(*latest_node)-8);
        if (crc != je32_to_cpu(latest_node->node_crc)) {
-               printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw));
+               JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n",
+                       f->inocache->ino, ref_offset(fn->raw));
                up(&f->sem);
                jffs2_do_clear_inode(c, f);
                return -EIO;
@@ -633,10 +763,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                }
                break;
 
-                       
+
        case S_IFREG:
                /* If it was a regular file, truncate it to the latest node's isize */
-               jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize));
+               jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize));
                break;
 
        case S_IFLNK:
@@ -649,37 +779,33 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
 
                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));
+                        * keep in RAM to facilitate quick follow symlink
+                        * operation. */
+                       f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
+                       if (!f->target) {
+                               JFFS2_ERROR("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);
-                       
+                                               je32_to_cpu(latest_node->csize), &retlen, (char *)f->target);
+
                        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;
+                               kfree(f->target);
+                               f->target = 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));
+                       f->target[je32_to_cpu(latest_node->csize)] = '\0';
+                       dbg_readinode("symlink's target '%s' cached\n", f->target);
                }
-               
+
                /* fall through... */
 
        case S_IFBLK:
@@ -687,14 +813,14 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                /* Certain inode types should have only one data node, and it's
                   kept as the metadata node */
                if (f->metadata) {
-                       printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n",
+                       JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n",
                               f->inocache->ino, jemode_to_cpu(latest_node->mode));
                        up(&f->sem);
                        jffs2_do_clear_inode(c, f);
                        return -EIO;
                }
                if (!frag_first(&f->fragtree)) {
-                       printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n",
+                       JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n",
                               f->inocache->ino, jemode_to_cpu(latest_node->mode));
                        up(&f->sem);
                        jffs2_do_clear_inode(c, f);
@@ -702,7 +828,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                }
                /* ASSERT: f->fraglist != NULL */
                if (frag_next(frag_first(&f->fragtree))) {
-                       printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n",
+                       JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n",
                               f->inocache->ino, jemode_to_cpu(latest_node->mode));
                        /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
                        up(&f->sem);
@@ -721,6 +847,93 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
        return 0;
 }
 
+/* Scan the list of all nodes present for this ino, build map of versions, etc. */
+int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                       uint32_t ino, struct jffs2_raw_inode *latest_node)
+{
+       dbg_readinode("read inode #%u\n", ino);
+
+ retry_inocache:
+       spin_lock(&c->inocache_lock);
+       f->inocache = jffs2_get_ino_cache(c, ino);
+
+       if (f->inocache) {
+               /* Check its state. We may need to wait before we can use it */
+               switch(f->inocache->state) {
+               case INO_STATE_UNCHECKED:
+               case INO_STATE_CHECKEDABSENT:
+                       f->inocache->state = INO_STATE_READING;
+                       break;
+
+               case INO_STATE_CHECKING:
+               case INO_STATE_GC:
+                       /* If it's in either of these states, we need
+                          to wait for whoever's got it to finish and
+                          put it back. */
+                       dbg_readinode("waiting for ino #%u in state %d\n", ino, f->inocache->state);
+                       sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+                       goto retry_inocache;
+
+               case INO_STATE_READING:
+               case INO_STATE_PRESENT:
+                       /* Eep. This should never happen. It can
+                       happen if Linux calls read_inode() again
+                       before clear_inode() has finished though. */
+                       JFFS2_ERROR("Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state);
+                       /* Fail. That's probably better than allowing it to succeed */
+                       f->inocache = NULL;
+                       break;
+
+               default:
+                       BUG();
+               }
+       }
+       spin_unlock(&c->inocache_lock);
+
+       if (!f->inocache && ino == 1) {
+               /* Special case - no root inode on medium */
+               f->inocache = jffs2_alloc_inode_cache();
+               if (!f->inocache) {
+                       JFFS2_ERROR("cannot allocate inocache for root inode\n");
+                       return -ENOMEM;
+               }
+               dbg_readinode("creating inocache for root inode\n");
+               memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
+               f->inocache->ino = f->inocache->nlink = 1;
+               f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
+               f->inocache->state = INO_STATE_READING;
+               jffs2_add_ino_cache(c, f->inocache);
+       }
+       if (!f->inocache) {
+               JFFS2_ERROR("requestied to read an nonexistent ino %u\n", ino);
+               return -ENOENT;
+       }
+
+       return jffs2_do_read_inode_internal(c, f, latest_node);
+}
+
+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+{
+       struct jffs2_raw_inode n;
+       struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL);
+       int ret;
+
+       if (!f)
+               return -ENOMEM;
+
+       memset(f, 0, sizeof(*f));
+       init_MUTEX_LOCKED(&f->sem);
+       f->inocache = ic;
+
+       ret = jffs2_do_read_inode_internal(c, f, &n);
+       if (!ret) {
+               up(&f->sem);
+               jffs2_do_clear_inode(c, f);
+       }
+       kfree (f);
+       return ret;
+}
+
 void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
 {
        struct jffs2_full_dirent *fd, *fds;
@@ -740,18 +953,16 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
 
        jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
 
-       /* For symlink inodes we us f->dents to store the target path name */
-       if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) {
-               kfree(f->dents);
-               f->dents = NULL;
-       } else {
-               fds = f->dents;
+       if (f->target) {
+               kfree(f->target);
+               f->target = NULL;
+       }
 
-               while(fds) {
-                       fd = fds;
-                       fds = fd->next;
-                       jffs2_free_full_dirent(fd);
-               }
+       fds = f->dents;
+       while(fds) {
+               fd = fds;
+               fds = fd->next;
+               jffs2_free_full_dirent(fd);
        }
 
        if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
index b63160f83bab8fe693d23025f275157840b0f2d6..0e7456ec99fd05a778738da5ab69ec57cd1629a4 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $
+ * $Id: scan.c,v 1.125 2005/09/30 13:59:13 dedekind Exp $
  *
  */
 #include <linux/kernel.h>
 #include <linux/crc32.h>
 #include <linux/compiler.h>
 #include "nodelist.h"
+#include "summary.h"
+#include "debug.h"
 
 #define DEFAULT_EMPTY_SCAN_SIZE 1024
 
-#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
-               c->free_size -= _x; c->dirty_size += _x; \
-               jeb->free_size -= _x ; jeb->dirty_size += _x; \
-               }while(0)
-#define USED_SPACE(x) do { typeof(x) _x = (x); \
-               c->free_size -= _x; c->used_size += _x; \
-               jeb->free_size -= _x ; jeb->used_size += _x; \
-               }while(0)
-#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
-               c->free_size -= _x; c->unchecked_size += _x; \
-               jeb->free_size -= _x ; jeb->unchecked_size += _x; \
-               }while(0)
-
 #define noisy_printk(noise, args...) do { \
        if (*(noise)) { \
                printk(KERN_NOTICE args); \
 static uint32_t pseudo_random;
 
 static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-                                 unsigned char *buf, uint32_t buf_size);
+                                 unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s);
 
-/* These helper functions _must_ increase ofs and also do the dirty/used space accounting. 
+/* These helper functions _must_ increase ofs and also do the dirty/used space accounting.
  * Returning an error will abort the mount - bad checksums etc. should just mark the space
  * as dirty.
  */
-static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
-                                struct jffs2_raw_inode *ri, uint32_t ofs);
+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+                                struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s);
 static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-                                struct jffs2_raw_dirent *rd, uint32_t ofs);
-
-#define BLK_STATE_ALLFF                0
-#define BLK_STATE_CLEAN                1
-#define BLK_STATE_PARTDIRTY    2
-#define BLK_STATE_CLEANMARKER  3
-#define BLK_STATE_ALLDIRTY     4
-#define BLK_STATE_BADBLOCK     5
+                                struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s);
 
 static inline int min_free(struct jffs2_sb_info *c)
 {
@@ -89,6 +71,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        uint32_t empty_blocks = 0, bad_blocks = 0;
        unsigned char *flashbuf = NULL;
        uint32_t buf_size = 0;
+       struct jffs2_summary *s = NULL; /* summary info collected by the scan process */
 #ifndef __ECOS
        size_t pointlen;
 
@@ -122,21 +105,34 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                        return -ENOMEM;
        }
 
+       if (jffs2_sum_active()) {
+               s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
+               if (!s) {
+                       JFFS2_WARNING("Can't allocate memory for summary\n");
+                       return -ENOMEM;
+               }
+               memset(s, 0, sizeof(struct jffs2_summary));
+       }
+
        for (i=0; i<c->nr_blocks; i++) {
                struct jffs2_eraseblock *jeb = &c->blocks[i];
 
-               ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size);
+               /* reset summary info for next eraseblock scan */
+               jffs2_sum_reset_collected(s);
+
+               ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+                                               buf_size, s);
 
                if (ret < 0)
                        goto out;
 
-               ACCT_PARANOIA_CHECK(jeb);
+               jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
 
                /* Now decide which list to put it on */
                switch(ret) {
                case BLK_STATE_ALLFF:
-                       /* 
-                        * Empty block.   Since we can't be sure it 
+                       /*
+                        * Empty block.   Since we can't be sure it
                         * was entirely erased, we just queue it for erase
                         * again.  It will be marked as such when the erase
                         * is complete.  Meanwhile we still count it as empty
@@ -162,18 +158,18 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                        break;
 
                case BLK_STATE_CLEAN:
-                        /* Full (or almost full) of clean data. Clean list */
-                        list_add(&jeb->list, &c->clean_list);
+                       /* Full (or almost full) of clean data. Clean list */
+                       list_add(&jeb->list, &c->clean_list);
                        break;
 
                case BLK_STATE_PARTDIRTY:
-                        /* Some data, but not full. Dirty list. */
-                        /* We want to remember the block with most free space
-                           and stick it in the 'nextblock' position to start writing to it. */
-                        if (jeb->free_size > min_free(c) && 
-                           (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
-                                /* Better candidate for the next writes to go to */
-                                if (c->nextblock) {
+                       /* Some data, but not full. Dirty list. */
+                       /* We want to remember the block with most free space
+                       and stick it in the 'nextblock' position to start writing to it. */
+                       if (jeb->free_size > min_free(c) &&
+                                       (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
+                               /* Better candidate for the next writes to go to */
+                               if (c->nextblock) {
                                        c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
                                        c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
                                        c->free_size -= c->nextblock->free_size;
@@ -184,9 +180,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                                        } else {
                                                list_add(&c->nextblock->list, &c->dirty_list);
                                        }
+                                       /* deleting summary information of the old nextblock */
+                                       jffs2_sum_reset_collected(c->summary);
                                }
-                                c->nextblock = jeb;
-                        } else {
+                               /* update collected summary infromation for the current nextblock */
+                               jffs2_sum_move_collected(c, s);
+                               D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset));
+                               c->nextblock = jeb;
+                       } else {
                                jeb->dirty_size += jeb->free_size + jeb->wasted_size;
                                c->dirty_size += jeb->free_size + jeb->wasted_size;
                                c->free_size -= jeb->free_size;
@@ -197,30 +198,33 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                                } else {
                                        list_add(&jeb->list, &c->dirty_list);
                                }
-                        }
+                       }
                        break;
 
                case BLK_STATE_ALLDIRTY:
                        /* Nothing valid - not even a clean marker. Needs erasing. */
-                        /* For now we just put it on the erasing list. We'll start the erases later */
+                       /* For now we just put it on the erasing list. We'll start the erases later */
                        D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset));
-                        list_add(&jeb->list, &c->erase_pending_list);
+                       list_add(&jeb->list, &c->erase_pending_list);
                        c->nr_erasing_blocks++;
                        break;
-                       
+
                case BLK_STATE_BADBLOCK:
                        D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset));
-                        list_add(&jeb->list, &c->bad_list);
+                       list_add(&jeb->list, &c->bad_list);
                        c->bad_size += c->sector_size;
                        c->free_size -= c->sector_size;
                        bad_blocks++;
                        break;
                default:
                        printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n");
-                       BUG();  
+                       BUG();
                }
        }
-       
+
+       if (jffs2_sum_active() && s)
+               kfree(s);
+
        /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
        if (c->nextblock && (c->nextblock->dirty_size)) {
                c->nextblock->wasted_size += c->nextblock->dirty_size;
@@ -229,12 +233,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
                c->nextblock->dirty_size = 0;
        }
 #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 
+       if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size % c->wbuf_pagesize)) {
+               /* If we're going to start writing into a block which already
                   contains data, and the end of the data isn't page-aligned,
                   skip a little and align it. */
 
-               uint32_t skip = c->nextblock->free_size & (c->wbuf_pagesize-1);
+               uint32_t skip = c->nextblock->free_size % c->wbuf_pagesize;
 
                D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n",
                          skip));
@@ -246,7 +250,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        }
 #endif
        if (c->nr_erasing_blocks) {
-               if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { 
+               if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) {
                        printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
                        printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks);
                        ret = -EIO;
@@ -259,13 +263,13 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
        if (buf_size)
                kfree(flashbuf);
 #ifndef __ECOS
-       else 
+       else
                c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
 #endif
        return ret;
 }
 
-static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
+int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf,
                                uint32_t ofs, uint32_t len)
 {
        int ret;
@@ -286,14 +290,36 @@ static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
        return 0;
 }
 
+int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+{
+       if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
+               && (!jeb->first_node || !jeb->first_node->next_phys) )
+               return BLK_STATE_CLEANMARKER;
+
+       /* move blocks with max 4 byte dirty space to cleanlist */
+       else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
+               c->dirty_size -= jeb->dirty_size;
+               c->wasted_size += jeb->dirty_size;
+               jeb->wasted_size += jeb->dirty_size;
+               jeb->dirty_size = 0;
+               return BLK_STATE_CLEAN;
+       } else if (jeb->used_size || jeb->unchecked_size)
+               return BLK_STATE_PARTDIRTY;
+       else
+               return BLK_STATE_ALLDIRTY;
+}
+
 static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
-                                 unsigned char *buf, uint32_t buf_size) {
+                               unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
        struct jffs2_unknown_node *node;
        struct jffs2_unknown_node crcnode;
+       struct jffs2_sum_marker *sm;
        uint32_t ofs, prevofs;
        uint32_t hdr_crc, buf_ofs, buf_len;
        int err;
        int noise = 0;
+
+
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        int cleanmarkerfound = 0;
 #endif
@@ -319,17 +345,53 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
                }
        }
 #endif
+
+       if (jffs2_sum_active()) {
+               sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL);
+               if (!sm) {
+                       return -ENOMEM;
+               }
+
+               err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size -
+                                       sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker));
+               if (err) {
+                       kfree(sm);
+                       return err;
+               }
+
+               if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) {
+                       err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random);
+                       if (err) {
+                               kfree(sm);
+                               return err;
+                       }
+               }
+
+               kfree(sm);
+
+               ofs = jeb->offset;
+               prevofs = jeb->offset - 1;
+       }
+
        buf_ofs = jeb->offset;
 
        if (!buf_size) {
                buf_len = c->sector_size;
+
+               if (jffs2_sum_active()) {
+                       /* must reread because of summary test */
+                       err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
+                       if (err)
+                               return err;
+               }
+
        } else {
                buf_len = EMPTY_SCAN_SIZE(c->sector_size);
                err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
                if (err)
                        return err;
        }
-       
+
        /* We temporarily use 'ofs' as a pointer into the buffer/jeb */
        ofs = 0;
 
@@ -367,10 +429,12 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
 
        noise = 10;
 
-scan_more:     
+       dbg_summary("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset);
+
+scan_more:
        while(ofs < jeb->offset + c->sector_size) {
 
-               D1(ACCT_PARANOIA_CHECK(jeb));
+               jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
 
                cond_resched();
 
@@ -432,7 +496,7 @@ 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) && 
+                       if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_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;
@@ -441,7 +505,7 @@ scan_more:
                        /* See how much more there is to read in this eraseblock... */
                        buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
                        if (!buf_len) {
-                               /* No more to read. Break out of main loop without marking 
+                               /* No more to read. Break out of main loop without marking
                                   this range of empty space as dirty (because it's not) */
                                D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
                                          empty_start));
@@ -476,8 +540,8 @@ scan_more:
                }
                if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
                        /* OK. We're out of possibilities. Whinge and move on */
-                       noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", 
-                                    JFFS2_MAGIC_BITMASK, ofs, 
+                       noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
+                                    JFFS2_MAGIC_BITMASK, ofs,
                                     je16_to_cpu(node->magic));
                        DIRTY_SPACE(4);
                        ofs += 4;
@@ -492,7 +556,7 @@ scan_more:
                if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
                        noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
                                     ofs, je16_to_cpu(node->magic),
-                                    je16_to_cpu(node->nodetype), 
+                                    je16_to_cpu(node->nodetype),
                                     je32_to_cpu(node->totlen),
                                     je32_to_cpu(node->hdr_crc),
                                     hdr_crc);
@@ -501,7 +565,7 @@ scan_more:
                        continue;
                }
 
-               if (ofs + je32_to_cpu(node->totlen) > 
+               if (ofs + je32_to_cpu(node->totlen) >
                    jeb->offset + c->sector_size) {
                        /* Eep. Node goes over the end of the erase block. */
                        printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
@@ -532,11 +596,11 @@ scan_more:
                                buf_ofs = ofs;
                                node = (void *)buf;
                        }
-                       err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs);
+                       err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s);
                        if (err) return err;
                        ofs += PAD(je32_to_cpu(node->totlen));
                        break;
-                       
+
                case JFFS2_NODETYPE_DIRENT:
                        if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
                                buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
@@ -548,7 +612,7 @@ scan_more:
                                buf_ofs = ofs;
                                node = (void *)buf;
                        }
-                       err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs);
+                       err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s);
                        if (err) return err;
                        ofs += PAD(je32_to_cpu(node->totlen));
                        break;
@@ -556,7 +620,7 @@ scan_more:
                case JFFS2_NODETYPE_CLEANMARKER:
                        D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
                        if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
-                               printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", 
+                               printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
                                       ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
                                DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
                                ofs += PAD(sizeof(struct jffs2_unknown_node));
@@ -575,13 +639,15 @@ scan_more:
                                marker_ref->flash_offset = ofs | REF_NORMAL;
                                marker_ref->__totlen = c->cleanmarker_size;
                                jeb->first_node = jeb->last_node = marker_ref;
-                            
+
                                USED_SPACE(PAD(c->cleanmarker_size));
                                ofs += PAD(c->cleanmarker_size);
                        }
                        break;
 
                case JFFS2_NODETYPE_PADDING:
+                       if (jffs2_sum_active())
+                               jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
                        DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
                        ofs += PAD(je32_to_cpu(node->totlen));
                        break;
@@ -616,8 +682,15 @@ scan_more:
                }
        }
 
+       if (jffs2_sum_active()) {
+               if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) {
+                       dbg_summary("There is not enough space for "
+                               "summary information, disabling for this jeb!\n");
+                       jffs2_sum_disable_collecting(s);
+               }
+       }
 
-       D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, 
+       D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset,
                  jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));
 
        /* mark_node_obsolete can add to wasted !! */
@@ -628,24 +701,10 @@ scan_more:
                jeb->wasted_size = 0;
        }
 
-       if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size 
-               && (!jeb->first_node || !jeb->first_node->next_phys) )
-               return BLK_STATE_CLEANMARKER;
-               
-       /* move blocks with max 4 byte dirty space to cleanlist */      
-       else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
-               c->dirty_size -= jeb->dirty_size;
-               c->wasted_size += jeb->dirty_size; 
-               jeb->wasted_size += jeb->dirty_size;
-               jeb->dirty_size = 0;
-               return BLK_STATE_CLEAN;
-       } else if (jeb->used_size || jeb->unchecked_size)
-               return BLK_STATE_PARTDIRTY;
-       else
-               return BLK_STATE_ALLDIRTY;
+       return jffs2_scan_classify_jeb(c, jeb);
 }
 
-static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
+struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
 {
        struct jffs2_inode_cache *ic;
 
@@ -671,8 +730,8 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
        return ic;
 }
 
-static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
-                                struct jffs2_raw_inode *ri, uint32_t ofs)
+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+                                struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s)
 {
        struct jffs2_raw_node_ref *raw;
        struct jffs2_inode_cache *ic;
@@ -681,11 +740,11 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
        D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
 
        /* We do very little here now. Just check the ino# to which we should attribute
-          this node; we can do all the CRC checking etc. later. There's a tradeoff here -- 
+          this node; we can do all the CRC checking etc. later. There's a tradeoff here --
           we used to scan the flash once only, reading everything we want from it into
           memory, then building all our in-core data structures and freeing the extra
           information. Now we allow the first part of the mount to complete a lot quicker,
-          but we have to go _back_ to the flash in order to finish the CRC checking, etc. 
+          but we have to go _back_ to the flash in order to finish the CRC checking, etc.
           Which means that the _full_ amount of time to get to proper write mode with GC
           operational may actually be _longer_ than before. Sucks to be me. */
 
@@ -731,7 +790,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
                jeb->last_node->next_phys = raw;
        jeb->last_node = raw;
 
-       D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", 
+       D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n",
                  je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
                  je32_to_cpu(ri->offset),
                  je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize)));
@@ -739,11 +798,16 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
        pseudo_random += je32_to_cpu(ri->version);
 
        UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
+
+       if (jffs2_sum_active()) {
+               jffs2_sum_add_inode_mem(s, ri, ofs - jeb->offset);
+       }
+
        return 0;
 }
 
-static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
-                                 struct jffs2_raw_dirent *rd, uint32_t ofs)
+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+                                 struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s)
 {
        struct jffs2_raw_node_ref *raw;
        struct jffs2_full_dirent *fd;
@@ -776,7 +840,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
        crc = crc32(0, fd->name, rd->nsize);
        if (crc != je32_to_cpu(rd->name_crc)) {
                printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
-                      ofs, je32_to_cpu(rd->name_crc), crc);    
+                      ofs, je32_to_cpu(rd->name_crc), crc);
                D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)));
                jffs2_free_full_dirent(fd);
                /* FIXME: Why do we believe totlen? */
@@ -796,7 +860,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
                jffs2_free_raw_node_ref(raw);
                return -ENOMEM;
        }
-       
+
        raw->__totlen = PAD(je32_to_cpu(rd->totlen));
        raw->flash_offset = ofs | REF_PRISTINE;
        raw->next_phys = NULL;
@@ -817,6 +881,10 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
        USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
        jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
 
+       if (jffs2_sum_active()) {
+               jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset);
+       }
+
        return 0;
 }
 
@@ -852,76 +920,34 @@ void jffs2_rotate_lists(struct jffs2_sb_info *c)
        x = count_list(&c->clean_list);
        if (x) {
                rotateby = pseudo_random % x;
-               D1(printk(KERN_DEBUG "Rotating clean_list by %d\n", rotateby));
-
                rotate_list((&c->clean_list), rotateby);
-
-               D1(printk(KERN_DEBUG "Erase block at front of clean_list is at %08x\n",
-                         list_entry(c->clean_list.next, struct jffs2_eraseblock, list)->offset));
-       } else {
-               D1(printk(KERN_DEBUG "Not rotating empty clean_list\n"));
        }
 
        x = count_list(&c->very_dirty_list);
        if (x) {
                rotateby = pseudo_random % x;
-               D1(printk(KERN_DEBUG "Rotating very_dirty_list by %d\n", rotateby));
-
                rotate_list((&c->very_dirty_list), rotateby);
-
-               D1(printk(KERN_DEBUG "Erase block at front of very_dirty_list is at %08x\n",
-                         list_entry(c->very_dirty_list.next, struct jffs2_eraseblock, list)->offset));
-       } else {
-               D1(printk(KERN_DEBUG "Not rotating empty very_dirty_list\n"));
        }
 
        x = count_list(&c->dirty_list);
        if (x) {
                rotateby = pseudo_random % x;
-               D1(printk(KERN_DEBUG "Rotating dirty_list by %d\n", rotateby));
-
                rotate_list((&c->dirty_list), rotateby);
-
-               D1(printk(KERN_DEBUG "Erase block at front of dirty_list is at %08x\n",
-                         list_entry(c->dirty_list.next, struct jffs2_eraseblock, list)->offset));
-       } else {
-               D1(printk(KERN_DEBUG "Not rotating empty dirty_list\n"));
        }
 
        x = count_list(&c->erasable_list);
        if (x) {
                rotateby = pseudo_random % x;
-               D1(printk(KERN_DEBUG "Rotating erasable_list by %d\n", rotateby));
-
                rotate_list((&c->erasable_list), rotateby);
-
-               D1(printk(KERN_DEBUG "Erase block at front of erasable_list is at %08x\n",
-                         list_entry(c->erasable_list.next, struct jffs2_eraseblock, list)->offset));
-       } else {
-               D1(printk(KERN_DEBUG "Not rotating empty erasable_list\n"));
        }
 
        if (c->nr_erasing_blocks) {
                rotateby = pseudo_random % c->nr_erasing_blocks;
-               D1(printk(KERN_DEBUG "Rotating erase_pending_list by %d\n", rotateby));
-
                rotate_list((&c->erase_pending_list), rotateby);
-
-               D1(printk(KERN_DEBUG "Erase block at front of erase_pending_list is at %08x\n",
-                         list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list)->offset));
-       } else {
-               D1(printk(KERN_DEBUG "Not rotating empty erase_pending_list\n"));
        }
 
        if (c->nr_free_blocks) {
                rotateby = pseudo_random % c->nr_free_blocks;
-               D1(printk(KERN_DEBUG "Rotating free_list by %d\n", rotateby));
-
                rotate_list((&c->free_list), rotateby);
-
-               D1(printk(KERN_DEBUG "Erase block at front of free_list is at %08x\n",
-                         list_entry(c->free_list.next, struct jffs2_eraseblock, list)->offset));
-       } else {
-               D1(printk(KERN_DEBUG "Not rotating empty free_list\n"));
        }
 }
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
new file mode 100644 (file)
index 0000000..fb9cec6
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: summary.c,v 1.4 2005/09/26 11:37:21 havasi Exp $
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/pagemap.h>
+#include <linux/crc32.h>
+#include <linux/compiler.h>
+#include <linux/vmalloc.h>
+#include "nodelist.h"
+#include "debug.h"
+
+int jffs2_sum_init(struct jffs2_sb_info *c)
+{
+       c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
+
+       if (!c->summary) {
+               JFFS2_WARNING("Can't allocate memory for summary information!\n");
+               return -ENOMEM;
+       }
+
+       memset(c->summary, 0, sizeof(struct jffs2_summary));
+
+       c->summary->sum_buf = vmalloc(c->sector_size);
+
+       if (!c->summary->sum_buf) {
+               JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n");
+               kfree(c->summary);
+               return -ENOMEM;
+       }
+
+       dbg_summary("returned succesfully\n");
+
+       return 0;
+}
+
+void jffs2_sum_exit(struct jffs2_sb_info *c)
+{
+       dbg_summary("called\n");
+
+       jffs2_sum_disable_collecting(c->summary);
+
+       vfree(c->summary->sum_buf);
+       c->summary->sum_buf = NULL;
+
+       kfree(c->summary);
+       c->summary = NULL;
+}
+
+static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
+{
+       if (!s->sum_list_head)
+               s->sum_list_head = (union jffs2_sum_mem *) item;
+       if (s->sum_list_tail)
+               s->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
+       s->sum_list_tail = (union jffs2_sum_mem *) item;
+
+       switch (je16_to_cpu(item->u.nodetype)) {
+               case JFFS2_NODETYPE_INODE:
+                       s->sum_size += JFFS2_SUMMARY_INODE_SIZE;
+                       s->sum_num++;
+                       dbg_summary("inode (%u) added to summary\n",
+                                               je32_to_cpu(item->i.inode));
+                       break;
+               case JFFS2_NODETYPE_DIRENT:
+                       s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
+                       s->sum_num++;
+                       dbg_summary("dirent (%u) added to summary\n",
+                                               je32_to_cpu(item->d.ino));
+                       break;
+               default:
+                       JFFS2_WARNING("UNKNOWN node type %u\n",
+                                           je16_to_cpu(item->u.nodetype));
+                       return 1;
+       }
+       return 0;
+}
+
+
+/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */
+
+int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size)
+{
+       dbg_summary("called with %u\n", size);
+       s->sum_padded += size;
+       return 0;
+}
+
+int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri,
+                               uint32_t ofs)
+{
+       struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
+
+       if (!temp)
+               return -ENOMEM;
+
+       temp->nodetype = ri->nodetype;
+       temp->inode = ri->ino;
+       temp->version = ri->version;
+       temp->offset = cpu_to_je32(ofs); /* relative offset from the begining of the jeb */
+       temp->totlen = ri->totlen;
+       temp->next = NULL;
+
+       return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
+}
+
+int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd,
+                               uint32_t ofs)
+{
+       struct jffs2_sum_dirent_mem *temp =
+               kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
+
+       if (!temp)
+               return -ENOMEM;
+
+       temp->nodetype = rd->nodetype;
+       temp->totlen = rd->totlen;
+       temp->offset = cpu_to_je32(ofs);        /* relative from the begining of the jeb */
+       temp->pino = rd->pino;
+       temp->version = rd->version;
+       temp->ino = rd->ino;
+       temp->nsize = rd->nsize;
+       temp->type = rd->type;
+       temp->next = NULL;
+
+       memcpy(temp->name, rd->name, rd->nsize);
+
+       return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
+}
+
+/* Cleanup every collected summary information */
+
+static void jffs2_sum_clean_collected(struct jffs2_summary *s)
+{
+       union jffs2_sum_mem *temp;
+
+       if (!s->sum_list_head) {
+               dbg_summary("already empty\n");
+       }
+       while (s->sum_list_head) {
+               temp = s->sum_list_head;
+               s->sum_list_head = s->sum_list_head->u.next;
+               kfree(temp);
+       }
+       s->sum_list_tail = NULL;
+       s->sum_padded = 0;
+       s->sum_num = 0;
+}
+
+void jffs2_sum_reset_collected(struct jffs2_summary *s)
+{
+       dbg_summary("called\n");
+       jffs2_sum_clean_collected(s);
+       s->sum_size = 0;
+}
+
+void jffs2_sum_disable_collecting(struct jffs2_summary *s)
+{
+       dbg_summary("called\n");
+       jffs2_sum_clean_collected(s);
+       s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
+}
+
+int jffs2_sum_is_disabled(struct jffs2_summary *s)
+{
+       return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE);
+}
+
+/* Move the collected summary information into sb (called from scan.c) */
+
+void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s)
+{
+       dbg_summary("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n",
+                               c->summary->sum_size, c->summary->sum_num,
+                               s->sum_size, s->sum_num);
+
+       c->summary->sum_size = s->sum_size;
+       c->summary->sum_num = s->sum_num;
+       c->summary->sum_padded = s->sum_padded;
+       c->summary->sum_list_head = s->sum_list_head;
+       c->summary->sum_list_tail = s->sum_list_tail;
+
+       s->sum_list_head = s->sum_list_tail = NULL;
+}
+
+/* Called from wbuf.c to collect writed node info */
+
+int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
+                               unsigned long count, uint32_t ofs)
+{
+       union jffs2_node_union *node;
+       struct jffs2_eraseblock *jeb;
+
+       node = invecs[0].iov_base;
+       jeb = &c->blocks[ofs / c->sector_size];
+       ofs -= jeb->offset;
+
+       switch (je16_to_cpu(node->u.nodetype)) {
+               case JFFS2_NODETYPE_INODE: {
+                       struct jffs2_sum_inode_mem *temp =
+                               kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
+
+                       if (!temp)
+                               goto no_mem;
+
+                       temp->nodetype = node->i.nodetype;
+                       temp->inode = node->i.ino;
+                       temp->version = node->i.version;
+                       temp->offset = cpu_to_je32(ofs);
+                       temp->totlen = node->i.totlen;
+                       temp->next = NULL;
+
+                       return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
+               }
+
+               case JFFS2_NODETYPE_DIRENT: {
+                       struct jffs2_sum_dirent_mem *temp =
+                               kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
+
+                       if (!temp)
+                               goto no_mem;
+
+                       temp->nodetype = node->d.nodetype;
+                       temp->totlen = node->d.totlen;
+                       temp->offset = cpu_to_je32(ofs);
+                       temp->pino = node->d.pino;
+                       temp->version = node->d.version;
+                       temp->ino = node->d.ino;
+                       temp->nsize = node->d.nsize;
+                       temp->type = node->d.type;
+                       temp->next = NULL;
+
+                       switch (count) {
+                               case 1:
+                                       memcpy(temp->name,node->d.name,node->d.nsize);
+                                       break;
+
+                               case 2:
+                                       memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
+                                       break;
+
+                               default:
+                                       BUG();  /* impossible count value */
+                                       break;
+                       }
+
+                       return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
+               }
+
+               case JFFS2_NODETYPE_PADDING:
+                       dbg_summary("node PADDING\n");
+                       c->summary->sum_padded += je32_to_cpu(node->u.totlen);
+                       break;
+
+               case JFFS2_NODETYPE_CLEANMARKER:
+                       dbg_summary("node CLEANMARKER\n");
+                       break;
+
+               case JFFS2_NODETYPE_SUMMARY:
+                       dbg_summary("node SUMMARY\n");
+                       break;
+
+               default:
+                       /* If you implement a new node type you should also implement
+                          summary support for it or disable summary.
+                       */
+                       BUG();
+                       break;
+       }
+
+       return 0;
+
+no_mem:
+       JFFS2_WARNING("MEMORY ALLOCATION ERROR!");
+       return -ENOMEM;
+}
+
+
+/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
+
+static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+                               struct jffs2_raw_summary *summary, uint32_t *pseudo_random)
+{
+       struct jffs2_raw_node_ref *raw;
+       struct jffs2_inode_cache *ic;
+       struct jffs2_full_dirent *fd;
+       void *sp;
+       int i, ino;
+
+       sp = summary->sum;
+
+       for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
+               dbg_summary("processing summary index %d\n", i);
+
+               switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
+                       case JFFS2_NODETYPE_INODE: {
+                               struct jffs2_sum_inode_flash *spi;
+                               spi = sp;
+
+                               ino = je32_to_cpu(spi->inode);
+
+                               dbg_summary("Inode at 0x%08x\n",
+                                                       jeb->offset + je32_to_cpu(spi->offset));
+
+                               raw = jffs2_alloc_raw_node_ref();
+                               if (!raw) {
+                                       JFFS2_NOTICE("allocation of node reference failed\n");
+                                       kfree(summary);
+                                       return -ENOMEM;
+                               }
+
+                               ic = jffs2_scan_make_ino_cache(c, ino);
+                               if (!ic) {
+                                       JFFS2_NOTICE("scan_make_ino_cache failed\n");
+                                       jffs2_free_raw_node_ref(raw);
+                                       kfree(summary);
+                                       return -ENOMEM;
+                               }
+
+                               raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED;
+                               raw->__totlen = PAD(je32_to_cpu(spi->totlen));
+                               raw->next_phys = NULL;
+                               raw->next_in_ino = ic->nodes;
+
+                               ic->nodes = raw;
+                               if (!jeb->first_node)
+                                       jeb->first_node = raw;
+                               if (jeb->last_node)
+                                       jeb->last_node->next_phys = raw;
+                               jeb->last_node = raw;
+                               *pseudo_random += je32_to_cpu(spi->version);
+
+                               UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen)));
+
+                               sp += JFFS2_SUMMARY_INODE_SIZE;
+
+                               break;
+                       }
+
+                       case JFFS2_NODETYPE_DIRENT: {
+                               struct jffs2_sum_dirent_flash *spd;
+                               spd = sp;
+
+                               dbg_summary("Dirent at 0x%08x\n",
+                                                       jeb->offset + je32_to_cpu(spd->offset));
+
+                               fd = jffs2_alloc_full_dirent(spd->nsize+1);
+                               if (!fd) {
+                                       kfree(summary);
+                                       return -ENOMEM;
+                               }
+
+                               memcpy(&fd->name, spd->name, spd->nsize);
+                               fd->name[spd->nsize] = 0;
+
+                               raw = jffs2_alloc_raw_node_ref();
+                               if (!raw) {
+                                       jffs2_free_full_dirent(fd);
+                                       JFFS2_NOTICE("allocation of node reference failed\n");
+                                       kfree(summary);
+                                       return -ENOMEM;
+                               }
+
+                               ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
+                               if (!ic) {
+                                       jffs2_free_full_dirent(fd);
+                                       jffs2_free_raw_node_ref(raw);
+                                       kfree(summary);
+                                       return -ENOMEM;
+                               }
+
+                               raw->__totlen = PAD(je32_to_cpu(spd->totlen));
+                               raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE;
+                               raw->next_phys = NULL;
+                               raw->next_in_ino = ic->nodes;
+                               ic->nodes = raw;
+                               if (!jeb->first_node)
+                                       jeb->first_node = raw;
+                               if (jeb->last_node)
+                                       jeb->last_node->next_phys = raw;
+                               jeb->last_node = raw;
+
+                               fd->raw = raw;
+                               fd->next = NULL;
+                               fd->version = je32_to_cpu(spd->version);
+                               fd->ino = je32_to_cpu(spd->ino);
+                               fd->nhash = full_name_hash(fd->name, spd->nsize);
+                               fd->type = spd->type;
+                               USED_SPACE(PAD(je32_to_cpu(spd->totlen)));
+                               jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
+
+                               *pseudo_random += je32_to_cpu(spd->version);
+
+                               sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
+
+                               break;
+                       }
+
+                       default : {
+                               JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
+                               kfree(summary);
+                               return -EIO;
+                       }
+               }
+       }
+
+       kfree(summary);
+       return 0;
+}
+
+/* Process the summary node - called from jffs2_scan_eraseblock() */
+
+int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+                               uint32_t ofs, uint32_t *pseudo_random)
+{
+       struct jffs2_unknown_node crcnode;
+       struct jffs2_raw_node_ref *cache_ref;
+       struct jffs2_raw_summary *summary;
+       int ret, sumsize;
+       uint32_t crc;
+
+       sumsize = c->sector_size - ofs;
+       ofs += jeb->offset;
+
+       dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
+                               jeb->offset, ofs, sumsize);
+
+       summary = kmalloc(sumsize, GFP_KERNEL);
+
+       if (!summary) {
+               return -ENOMEM;
+       }
+
+       ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
+
+       if (ret) {
+               kfree(summary);
+               return ret;
+       }
+
+       /* OK, now check for node validity and CRC */
+       crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+       crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+       crcnode.totlen = summary->totlen;
+       crc = crc32(0, &crcnode, sizeof(crcnode)-4);
+
+       if (je32_to_cpu(summary->hdr_crc) != crc) {
+               dbg_summary("Summary node header is corrupt (bad CRC or "
+                               "no summary at all)\n");
+               goto crc_err;
+       }
+
+       if (je32_to_cpu(summary->totlen) != sumsize) {
+               dbg_summary("Summary node is corrupt (wrong erasesize?)\n");
+               goto crc_err;
+       }
+
+       crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8);
+
+       if (je32_to_cpu(summary->node_crc) != crc) {
+               dbg_summary("Summary node is corrupt (bad CRC)\n");
+               goto crc_err;
+       }
+
+       crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary));
+
+       if (je32_to_cpu(summary->sum_crc) != crc) {
+               dbg_summary("Summary node data is corrupt (bad CRC)\n");
+               goto crc_err;
+       }
+
+       if ( je32_to_cpu(summary->cln_mkr) ) {
+
+               dbg_summary("Summary : CLEANMARKER node \n");
+
+               if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
+                       dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
+                               je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
+                       UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
+               } else if (jeb->first_node) {
+                       dbg_summary("CLEANMARKER node not first node in block "
+                                       "(0x%08x)\n", jeb->offset);
+                       UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
+               } else {
+                       struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
+
+                       if (!marker_ref) {
+                               JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
+                               kfree(summary);
+                               return -ENOMEM;
+                       }
+
+                       marker_ref->next_in_ino = NULL;
+                       marker_ref->next_phys = NULL;
+                       marker_ref->flash_offset = jeb->offset | REF_NORMAL;
+                       marker_ref->__totlen = je32_to_cpu(summary->cln_mkr);
+                       jeb->first_node = jeb->last_node = marker_ref;
+
+                       USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) );
+               }
+       }
+
+       if (je32_to_cpu(summary->padded)) {
+               DIRTY_SPACE(je32_to_cpu(summary->padded));
+       }
+
+       ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
+       if (ret)
+               return ret;
+
+       /* for PARANOIA_CHECK */
+       cache_ref = jffs2_alloc_raw_node_ref();
+
+       if (!cache_ref) {
+               JFFS2_NOTICE("Failed to allocate node ref for cache\n");
+               return -ENOMEM;
+       }
+
+       cache_ref->next_in_ino = NULL;
+       cache_ref->next_phys = NULL;
+       cache_ref->flash_offset = ofs | REF_NORMAL;
+       cache_ref->__totlen = sumsize;
+
+       if (!jeb->first_node)
+               jeb->first_node = cache_ref;
+       if (jeb->last_node)
+               jeb->last_node->next_phys = cache_ref;
+       jeb->last_node = cache_ref;
+
+       USED_SPACE(sumsize);
+
+       jeb->wasted_size += jeb->free_size;
+       c->wasted_size += jeb->free_size;
+       c->free_size -= jeb->free_size;
+       jeb->free_size = 0;
+
+       return jffs2_scan_classify_jeb(c, jeb);
+
+crc_err:
+       JFFS2_WARNING("Summary node crc error, skipping summary information.\n");
+
+       return 0;
+}
+
+/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
+
+static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+                                       uint32_t infosize, uint32_t datasize, int padsize)
+{
+       struct jffs2_raw_summary isum;
+       union jffs2_sum_mem *temp;
+       struct jffs2_sum_marker *sm;
+       struct kvec vecs[2];
+       void *wpage;
+       int ret;
+       size_t retlen;
+
+       memset(c->summary->sum_buf, 0xff, datasize);
+       memset(&isum, 0, sizeof(isum));
+
+       isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+       isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
+       isum.totlen = cpu_to_je32(infosize);
+       isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
+       isum.padded = cpu_to_je32(c->summary->sum_padded);
+       isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
+       isum.sum_num = cpu_to_je32(c->summary->sum_num);
+       wpage = c->summary->sum_buf;
+
+       while (c->summary->sum_num) {
+
+               switch (je16_to_cpu(c->summary->sum_list_head->u.nodetype)) {
+                       case JFFS2_NODETYPE_INODE: {
+                               struct jffs2_sum_inode_flash *sino_ptr = wpage;
+
+                               sino_ptr->nodetype = c->summary->sum_list_head->i.nodetype;
+                               sino_ptr->inode = c->summary->sum_list_head->i.inode;
+                               sino_ptr->version = c->summary->sum_list_head->i.version;
+                               sino_ptr->offset = c->summary->sum_list_head->i.offset;
+                               sino_ptr->totlen = c->summary->sum_list_head->i.totlen;
+
+                               wpage += JFFS2_SUMMARY_INODE_SIZE;
+
+                               break;
+                       }
+
+                       case JFFS2_NODETYPE_DIRENT: {
+                               struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
+
+                               sdrnt_ptr->nodetype = c->summary->sum_list_head->d.nodetype;
+                               sdrnt_ptr->totlen = c->summary->sum_list_head->d.totlen;
+                               sdrnt_ptr->offset = c->summary->sum_list_head->d.offset;
+                               sdrnt_ptr->pino = c->summary->sum_list_head->d.pino;
+                               sdrnt_ptr->version = c->summary->sum_list_head->d.version;
+                               sdrnt_ptr->ino = c->summary->sum_list_head->d.ino;
+                               sdrnt_ptr->nsize = c->summary->sum_list_head->d.nsize;
+                               sdrnt_ptr->type = c->summary->sum_list_head->d.type;
+
+                               memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name,
+                                                       c->summary->sum_list_head->d.nsize);
+
+                               wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize);
+
+                               break;
+                       }
+
+                       default : {
+                               BUG();  /* unknown node in summary information */
+                       }
+               }
+
+               temp = c->summary->sum_list_head;
+               c->summary->sum_list_head = c->summary->sum_list_head->u.next;
+               kfree(temp);
+
+               c->summary->sum_num--;
+       }
+
+       jffs2_sum_reset_collected(c->summary);
+
+       wpage += padsize;
+
+       sm = wpage;
+       sm->offset = cpu_to_je32(c->sector_size - jeb->free_size);
+       sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC);
+
+       isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize));
+       isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
+
+       vecs[0].iov_base = &isum;
+       vecs[0].iov_len = sizeof(isum);
+       vecs[1].iov_base = c->summary->sum_buf;
+       vecs[1].iov_len = datasize;
+
+       dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n",
+                       jeb->offset + c->sector_size - jeb->free_size);
+
+       spin_unlock(&c->erase_completion_lock);
+       ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size -
+                               jeb->free_size, &retlen, 0);
+       spin_lock(&c->erase_completion_lock);
+
+
+       if (ret || (retlen != infosize)) {
+               JFFS2_WARNING("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
+                       infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen);
+
+               c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
+               WASTED_SPACE(infosize);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/* Write out summary information - called from jffs2_do_reserve_space */
+
+int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
+{
+       struct jffs2_raw_node_ref *summary_ref;
+       int datasize, infosize, padsize, ret;
+       struct jffs2_eraseblock *jeb;
+
+       dbg_summary("called\n");
+
+       jeb = c->nextblock;
+
+       if (!c->summary->sum_num || !c->summary->sum_list_head) {
+               JFFS2_WARNING("Empty summary info!!!\n");
+               BUG();
+       }
+
+       datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker);
+       infosize = sizeof(struct jffs2_raw_summary) + datasize;
+       padsize = jeb->free_size - infosize;
+       infosize += padsize;
+       datasize += padsize;
+
+       /* Is there enough space for summary? */
+       if (padsize < 0) {
+               /* don't try to write out summary for this jeb */
+               jffs2_sum_disable_collecting(c->summary);
+
+               JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize);
+               return 0;
+       }
+
+       ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize);
+       if (ret)
+               return 0; /* can't write out summary, block is marked as NOSUM_SIZE */
+
+       /* for ACCT_PARANOIA_CHECK */
+       spin_unlock(&c->erase_completion_lock);
+       summary_ref = jffs2_alloc_raw_node_ref();
+       spin_lock(&c->erase_completion_lock);
+
+       if (!summary_ref) {
+               JFFS2_NOTICE("Failed to allocate node ref for summary\n");
+               return -ENOMEM;
+       }
+
+       summary_ref->next_in_ino = NULL;
+       summary_ref->next_phys = NULL;
+       summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL;
+       summary_ref->__totlen = infosize;
+
+       if (!jeb->first_node)
+               jeb->first_node = summary_ref;
+       if (jeb->last_node)
+               jeb->last_node->next_phys = summary_ref;
+       jeb->last_node = summary_ref;
+
+       USED_SPACE(infosize);
+
+       return 0;
+}
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h
new file mode 100644 (file)
index 0000000..b7a678b
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                     Zoltan Sogor <weth@inf.u-szeged.hu>,
+ *                     Patrik Kluba <pajko@halom.u-szeged.hu>,
+ *                     University of Szeged, Hungary
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: summary.h,v 1.2 2005/09/26 11:37:21 havasi Exp $
+ *
+ */
+
+#ifndef JFFS2_SUMMARY_H
+#define JFFS2_SUMMARY_H
+
+#include <linux/uio.h>
+#include <linux/jffs2.h>
+
+#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
+               c->free_size -= _x; c->dirty_size += _x; \
+               jeb->free_size -= _x ; jeb->dirty_size += _x; \
+               }while(0)
+#define USED_SPACE(x) do { typeof(x) _x = (x); \
+               c->free_size -= _x; c->used_size += _x; \
+               jeb->free_size -= _x ; jeb->used_size += _x; \
+               }while(0)
+#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
+               c->free_size -= _x; c->wasted_size += _x; \
+               jeb->free_size -= _x ; jeb->wasted_size += _x; \
+               }while(0)
+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
+               c->free_size -= _x; c->unchecked_size += _x; \
+               jeb->free_size -= _x ; jeb->unchecked_size += _x; \
+               }while(0)
+
+#define BLK_STATE_ALLFF                0
+#define BLK_STATE_CLEAN                1
+#define BLK_STATE_PARTDIRTY    2
+#define BLK_STATE_CLEANMARKER  3
+#define BLK_STATE_ALLDIRTY     4
+#define BLK_STATE_BADBLOCK     5
+
+#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
+#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
+#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
+
+/* Summary structures used on flash */
+
+struct jffs2_sum_unknown_flash
+{
+       jint16_t nodetype;      /* node type */
+};
+
+struct jffs2_sum_inode_flash
+{
+       jint16_t nodetype;      /* node type */
+       jint32_t inode;         /* inode number */
+       jint32_t version;       /* inode version */
+       jint32_t offset;        /* offset on jeb */
+       jint32_t totlen;        /* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_flash
+{
+       jint16_t nodetype;      /* == JFFS_NODETYPE_DIRENT */
+       jint32_t totlen;        /* record length */
+       jint32_t offset;        /* offset on jeb */
+       jint32_t pino;          /* parent inode */
+       jint32_t version;       /* dirent version */
+       jint32_t ino;           /* == zero for unlink */
+       uint8_t nsize;          /* dirent name size */
+       uint8_t type;           /* dirent type */
+       uint8_t name[0];        /* dirent name */
+} __attribute__((packed));
+
+union jffs2_sum_flash
+{
+       struct jffs2_sum_unknown_flash u;
+       struct jffs2_sum_inode_flash i;
+       struct jffs2_sum_dirent_flash d;
+};
+
+/* Summary structures used in the memory */
+
+struct jffs2_sum_unknown_mem
+{
+       union jffs2_sum_mem *next;
+       jint16_t nodetype;      /* node type */
+};
+
+struct jffs2_sum_inode_mem
+{
+       union jffs2_sum_mem *next;
+       jint16_t nodetype;      /* node type */
+       jint32_t inode;         /* inode number */
+       jint32_t version;       /* inode version */
+       jint32_t offset;        /* offset on jeb */
+       jint32_t totlen;        /* record length */
+} __attribute__((packed));
+
+struct jffs2_sum_dirent_mem
+{
+       union jffs2_sum_mem *next;
+       jint16_t nodetype;      /* == JFFS_NODETYPE_DIRENT */
+       jint32_t totlen;        /* record length */
+       jint32_t offset;        /* ofset on jeb */
+       jint32_t pino;          /* parent inode */
+       jint32_t version;       /* dirent version */
+       jint32_t ino;           /* == zero for unlink */
+       uint8_t nsize;          /* dirent name size */
+       uint8_t type;           /* dirent type */
+       uint8_t name[0];        /* dirent name */
+} __attribute__((packed));
+
+union jffs2_sum_mem
+{
+       struct jffs2_sum_unknown_mem u;
+       struct jffs2_sum_inode_mem i;
+       struct jffs2_sum_dirent_mem d;
+};
+
+/* Summary related information stored in superblock */
+
+struct jffs2_summary
+{
+       uint32_t sum_size;      /* collected summary information for nextblock */
+       uint32_t sum_num;
+       uint32_t sum_padded;
+       union jffs2_sum_mem *sum_list_head;
+       union jffs2_sum_mem *sum_list_tail;
+
+       jint32_t *sum_buf;      /* buffer for writing out summary */
+};
+
+/* Summary marker is stored at the end of every sumarized erase block */
+
+struct jffs2_sum_marker
+{
+       jint32_t offset;        /* offset of the summary node in the jeb */
+       jint32_t magic;         /* == JFFS2_SUM_MAGIC */
+};
+
+#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker))
+
+#ifdef CONFIG_JFFS2_SUMMARY    /* SUMMARY SUPPORT ENABLED */
+
+#define jffs2_sum_active() (1)
+int jffs2_sum_init(struct jffs2_sb_info *c);
+void jffs2_sum_exit(struct jffs2_sb_info *c);
+void jffs2_sum_disable_collecting(struct jffs2_summary *s);
+int jffs2_sum_is_disabled(struct jffs2_summary *s);
+void jffs2_sum_reset_collected(struct jffs2_summary *s);
+void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s);
+int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
+                       unsigned long count,  uint32_t to);
+int jffs2_sum_write_sumnode(struct jffs2_sb_info *c);
+int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size);
+int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs);
+int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs);
+int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
+                       uint32_t ofs, uint32_t *pseudo_random);
+
+#else                          /* SUMMARY DISABLED */
+
+#define jffs2_sum_active() (0)
+#define jffs2_sum_init(a) (0)
+#define jffs2_sum_exit(a)
+#define jffs2_sum_disable_collecting(a)
+#define jffs2_sum_is_disabled(a) (0)
+#define jffs2_sum_reset_collected(a)
+#define jffs2_sum_add_kvec(a,b,c,d) (0)
+#define jffs2_sum_move_collected(a,b)
+#define jffs2_sum_write_sumnode(a) (0)
+#define jffs2_sum_add_padding_mem(a,b)
+#define jffs2_sum_add_inode_mem(a,b,c)
+#define jffs2_sum_add_dirent_mem(a,b,c)
+#define jffs2_sum_scan_sumnode(a,b,c,d) (0)
+
+#endif /* CONFIG_JFFS2_SUMMARY */
+
+#endif /* JFFS2_SUMMARY_H */
index aaf9475cfb6ad866e05660121fd1a516650345b0..9e0b5458d9c072bc76e4fa6825e2b02163e4e0c4 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: super.c,v 1.107 2005/07/12 16:37:08 dedekind Exp $
+ * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $
  *
  */
 
@@ -62,7 +62,7 @@ static int jffs2_sync_fs(struct super_block *sb, int wait)
 
        down(&c->alloc_sem);
        jffs2_flush_wbuf_pad(c);
-       up(&c->alloc_sem);      
+       up(&c->alloc_sem);
        return 0;
 }
 
@@ -112,7 +112,7 @@ static int jffs2_sb_set(struct super_block *sb, void *data)
 }
 
 static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
-                                             int flags, const char *dev_name, 
+                                             int flags, const char *dev_name,
                                              void *data, struct mtd_info *mtd)
 {
        struct super_block *sb;
@@ -172,7 +172,7 @@ static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type,
 }
 
 static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
-                                             int flags, const char *dev_name, 
+                                             int flags, const char *dev_name,
                                              void *data, int mtdnr)
 {
        struct mtd_info *mtd;
@@ -201,7 +201,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
 
        /* The preferred way of mounting in future; especially when
           CONFIG_BLK_DEV is implemented - we specify the underlying
-          MTD device by number or by name, so that we don't require 
+          MTD device by number or by name, so that we don't require
           block device support to be present in the kernel. */
 
        /* FIXME: How to do the root fs this way? */
@@ -225,7 +225,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
                } else if (isdigit(dev_name[3])) {
                        /* Mount by MTD device number name */
                        char *endptr;
-                       
+
                        mtdnr = simple_strtoul(dev_name+3, &endptr, 0);
                        if (!*endptr) {
                                /* It was a valid number */
@@ -235,7 +235,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type,
                }
        }
 
-       /* Try the old way - the hack where we allowed users to mount 
+       /* Try the old way - the hack where we allowed users to mount
           /dev/mtdblock$(n) but didn't actually _use_ the blkdev */
 
        err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
@@ -282,9 +282,12 @@ static void jffs2_put_super (struct super_block *sb)
        down(&c->alloc_sem);
        jffs2_flush_wbuf_pad(c);
        up(&c->alloc_sem);
+
+       jffs2_sum_exit(c);
+
        jffs2_free_ino_caches(c);
        jffs2_free_raw_node_refs(c);
-       if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
+       if (jffs2_blocks_use_vmalloc(c))
                vfree(c->blocks);
        else
                kfree(c->blocks);
@@ -320,6 +323,9 @@ static int __init init_jffs2_fs(void)
        printk(KERN_INFO "JFFS2 version 2.2."
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
               " (NAND)"
+#endif
+#ifdef CONFIG_JFFS2_SUMMARY
+              " (SUMMARY) "
 #endif
               " (C) 2001-2003 Red Hat, Inc.\n");
 
@@ -370,5 +376,5 @@ module_exit(exit_jffs2_fs);
 
 MODULE_DESCRIPTION("The Journalling Flash File System, v2");
 MODULE_AUTHOR("Red Hat, Inc.");
-MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for 
+MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
                       // the sake of this tag. It's Free Software.
index 82ef484f5e12337ba1cc190e30275e0ebe7a9e16..d55754fe8925c537ac2ff5e117007c0370a41ee0 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $
+ * $Id: symlink.c,v 1.19 2005/11/07 11:14:42 gleixner Exp $
  *
  */
 
@@ -21,7 +21,7 @@
 static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
 
 struct inode_operations jffs2_symlink_inode_operations =
-{      
+{
        .readlink =     generic_readlink,
        .follow_link =  jffs2_follow_link,
        .setattr =      jffs2_setattr
@@ -30,35 +30,33 @@ struct inode_operations jffs2_symlink_inode_operations =
 static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
-       char *p = (char *)f->dents;
-       
+       char *p = (char *)f->target;
+
        /*
         * 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.
+        * use is f->target.
         *
-        * 1. If we are here the inode has already built and f->dents has
+        * 1. If we are here the inode has already built and f->target 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
+        * 2. Nobody uses f->target (if the inode is symlink's inode). The
+        * exception is inode freeing function which frees f->target. 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
+        * stopped using our f->target string which we provide by means of
         * nd_set_link() call.
         */
-       
+
        if (!p) {
                printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
                p = ERR_PTR(-EIO);
-       } else {
-               D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents));
        }
+       D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target));
 
        nd_set_link(nd, p);
-       
+
        /*
-        * 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.
+        * We will unlock the f->sem mutex but VFS will use the f->target string. This is safe
+        * since the only way that may cause f->target to be changed is iput() operation.
+        * But VFS will not use f->target after iput() has been called.
         */
        return NULL;
 }
index 7bc7f2d571f68f9bca429d23a41e0754ad9274f9..4cebf0e57c465bbf130b7077ea667ded3bac0b08 100644 (file)
@@ -9,7 +9,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $
+ * $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $
  *
  */
 
 static unsigned char *brokenbuf;
 #endif
 
+#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) )
+
 /* max. erase failures before we mark a block bad */
 #define MAX_ERASE_FAILURES     2
 
-/* two seconds timeout for timed wbuf-flushing */
-#define WBUF_FLUSH_TIMEOUT     2 * HZ
-
 struct jffs2_inodirty {
        uint32_t ino;
        struct jffs2_inodirty *next;
@@ -139,7 +139,6 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock
 {
        D1(printk("About to refile bad block at %08x\n", jeb->offset));
 
-       D2(jffs2_dump_block_lists(c));
        /* File the existing block on the bad_used_list.... */
        if (c->nextblock == jeb)
                c->nextblock = NULL;
@@ -156,7 +155,6 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock
                c->nr_erasing_blocks++;
                jffs2_erase_pending_trigger(c);
        }
-       D2(jffs2_dump_block_lists(c));
 
        /* Adjust its size counts accordingly */
        c->wasted_size += jeb->free_size;
@@ -164,8 +162,9 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock
        jeb->wasted_size += jeb->free_size;
        jeb->free_size = 0;
 
-       ACCT_SANITY_CHECK(c,jeb);
-       D1(ACCT_PARANOIA_CHECK(jeb));
+       jffs2_dbg_dump_block_lists_nolock(c);
+       jffs2_dbg_acct_sanity_check_nolock(c,jeb);
+       jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
 }
 
 /* Recover from failure to write wbuf. Recover the nodes up to the
@@ -189,7 +188,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
        /* Find the first node to be recovered, by skipping over every
           node which ends before the wbuf starts, or which is obsolete. */
        first_raw = &jeb->first_node;
-       while (*first_raw && 
+       while (*first_raw &&
               (ref_obsolete(*first_raw) ||
                (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) {
                D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
@@ -238,7 +237,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
                        ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
                else
                        ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf);
-               
+
                if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) {
                        /* ECC recovered */
                        ret = 0;
@@ -266,7 +265,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
 
        /* ... and get an allocation of space from a shiny new block instead */
-       ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
+       ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE);
        if (ret) {
                printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
                kfree(buf);
@@ -275,15 +274,15 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
        if (end-start >= c->wbuf_pagesize) {
                /* 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 
+                  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",
                          towrite, ofs));
-         
+
 #ifdef BREAKMEHEADER
                static int breakme;
                if (breakme++ == 20) {
@@ -391,11 +390,11 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
        else
                jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys);
 
-       ACCT_SANITY_CHECK(c,jeb);
-        D1(ACCT_PARANOIA_CHECK(jeb));
+       jffs2_dbg_acct_sanity_check_nolock(c, jeb);
+        jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
 
-       ACCT_SANITY_CHECK(c,new_jeb);
-        D1(ACCT_PARANOIA_CHECK(new_jeb));
+       jffs2_dbg_acct_sanity_check_nolock(c, new_jeb);
+        jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb);
 
        spin_unlock(&c->erase_completion_lock);
 
@@ -434,15 +433,15 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
           this happens, if we have a change to a new block,
           or if fsync forces us to flush the writebuffer.
           if we have a switch to next page, we will not have
-          enough remaining space for this. 
+          enough remaining space for this.
        */
-       if (pad && !jffs2_dataflash(c)) {
+       if (pad ) {
                c->wbuf_len = PAD(c->wbuf_len);
 
                /* Pad with JFFS2_DIRTY_BITMASK initially.  this helps out ECC'd NOR
                   with 8 byte page size */
                memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
-               
+
                if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
                        struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
                        padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -453,7 +452,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
        }
        /* else jffs2_flash_writev has actually filled in the rest of the
           buffer for us, and will deal with the node refs etc. later. */
-       
+
 #ifdef BREAKME
        static int breakme;
        if (breakme++ == 20) {
@@ -462,9 +461,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
                c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,
                                        &retlen, brokenbuf, NULL, c->oobinfo);
                ret = -EIO;
-       } else 
+       } else
 #endif
-       
+
        if (jffs2_cleanmarker_oob(c))
                ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
        else
@@ -487,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 && !jffs2_dataflash(c)) {
+       if (pad) {
                struct jffs2_eraseblock *jeb;
 
                jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
@@ -495,7 +494,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
                D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
                          (jeb==c->nextblock)?"next":"", jeb->offset));
 
-               /* wbuf_pagesize - wbuf_len is the amount of space that's to be 
+               /* wbuf_pagesize - wbuf_len is the amount of space that's to be
                   padded. If there is less free space in the block than that,
                   something screwed up */
                if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
@@ -523,9 +522,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
        return 0;
 }
 
-/* Trigger garbage collection to flush the write-buffer. 
+/* Trigger garbage collection to flush the write-buffer.
    If ino arg is zero, do it if _any_ real (i.e. not GC) writes are
-   outstanding. If ino arg non-zero, do it only if a write for the 
+   outstanding. If ino arg non-zero, do it only if a write for the
    given inode is outstanding. */
 int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
 {
@@ -604,15 +603,6 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
 
        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];
@@ -629,13 +619,13 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
        /* If not NAND flash, don't bother */
        if (!jffs2_is_writebuffered(c))
                return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
-       
+
        down_write(&c->wbuf_sem);
 
        /* If wbuf_ofs is not initialized, set it to target address */
        if (c->wbuf_ofs == 0xFFFFFFFF) {
                c->wbuf_ofs = PAGE_DIV(to);
-               c->wbuf_len = PAGE_MOD(to);                     
+               c->wbuf_len = PAGE_MOD(to);
                memset(c->wbuf,0xff,c->wbuf_pagesize);
        }
 
@@ -649,10 +639,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
                        memset(c->wbuf,0xff,c->wbuf_pagesize);
                }
        }
-       
-       /* Sanity checks on target address. 
-          It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), 
-          and it's permitted to write at the beginning of a new 
+
+       /* Sanity checks on target address.
+          It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs),
+          and it's permitted to write at the beginning of a new
           erase block. Anything else, and you die.
           New block starts at xxx000c (0-b = block header)
        */
@@ -670,8 +660,8 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
                }
                /* set pointer to new block */
                c->wbuf_ofs = PAGE_DIV(to);
-               c->wbuf_len = PAGE_MOD(to);                     
-       } 
+               c->wbuf_len = PAGE_MOD(to);
+       }
 
        if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
                /* We're not writing immediately after the writebuffer. Bad. */
@@ -691,21 +681,21 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
        invec = 0;
        outvec = 0;
 
-       /* Fill writebuffer first, if already in use */ 
+       /* Fill writebuffer first, if already in use */
        if (c->wbuf_len) {
                uint32_t invec_ofs = 0;
 
-               /* adjust alignment offset */ 
+               /* adjust alignment offset */
                if (c->wbuf_len != PAGE_MOD(to)) {
                        c->wbuf_len = PAGE_MOD(to);
                        /* take care of alignment to next page */
                        if (!c->wbuf_len)
                                c->wbuf_len = c->wbuf_pagesize;
                }
-               
+
                while(c->wbuf_len < c->wbuf_pagesize) {
                        uint32_t thislen;
-                       
+
                        if (invec == count)
                                goto alldone;
 
@@ -713,17 +703,17 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
 
                        if (thislen >= invecs[invec].iov_len)
                                thislen = invecs[invec].iov_len;
-       
+
                        invec_ofs = thislen;
 
                        memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen);
                        c->wbuf_len += thislen;
                        donelen += thislen;
                        /* Get next invec, if actual did not fill the buffer */
-                       if (c->wbuf_len < c->wbuf_pagesize) 
+                       if (c->wbuf_len < c->wbuf_pagesize)
                                invec++;
-               }                       
-               
+               }
+
                /* write buffer is full, flush buffer */
                ret = __jffs2_flush_wbuf(c, NOPAD);
                if (ret) {
@@ -782,10 +772,10 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
 
                /* We did cross a page boundary, so we write some now */
                if (jffs2_cleanmarker_oob(c))
-                       ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); 
+                       ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo);
                else
                        ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen);
-               
+
                if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
                        /* At this point we have no problem,
                           c->wbuf is empty. However refile nextblock to avoid
@@ -802,7 +792,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
                        spin_unlock(&c->erase_completion_lock);
                        goto exit;
                }
-               
+
                donelen += wbuf_retlen;
                c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen);
 
@@ -836,11 +826,17 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
 alldone:
        *retlen = donelen;
 
+       if (jffs2_sum_active()) {
+               int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to);
+               if (res)
+                       return res;
+       }
+
        if (c->wbuf_len && ino)
                jffs2_wbuf_dirties_inode(c, ino);
 
        ret = 0;
-       
+
 exit:
        up_write(&c->wbuf_sem);
        return ret;
@@ -855,7 +851,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_is_writebuffered(c))
-               return c->mtd->write(c->mtd, ofs, len, retlen, buf);
+               return jffs2_flash_direct_write(c, ofs, len, retlen, buf);
 
        vecs[0].iov_base = (unsigned char *) buf;
        vecs[0].iov_len = len;
@@ -883,18 +879,18 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
        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 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  
+                * 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)
@@ -909,16 +905,16 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
                if (owbf > c->wbuf_len)         /* is read beyond write buffer ? */
                        goto exit;
                lwbf = c->wbuf_len - owbf;      /* number of bytes to copy */
-               if (lwbf > len) 
+               if (lwbf > len)
                        lwbf = len;
-       } else {        
+       } else {
                orbf = (c->wbuf_ofs - ofs);     /* offset in read buffer */
                if (orbf > len)                 /* is write beyond write buffer ? */
                        goto exit;
                lwbf = len - orbf;              /* number of bytes to copy */
-               if (lwbf > c->wbuf_len) 
+               if (lwbf > c->wbuf_len)
                        lwbf = c->wbuf_len;
-       }       
+       }
        if (lwbf > 0)
                memcpy(buf+orbf,c->wbuf+owbf,lwbf);
 
@@ -946,7 +942,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
                printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n");
                return -ENOMEM;
        }
-       /* 
+       /*
         * if mode = 0, we scan for a total empty oob area, else we have
         * to take care of the cleanmarker in the first page of the block
        */
@@ -955,41 +951,41 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
                D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
                goto out;
        }
-       
+
        if (retlen < len) {
                D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read "
                          "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset));
                ret = -EIO;
                goto out;
        }
-       
+
        /* Special check for first page */
        for(i = 0; i < oob_size ; i++) {
                /* Yeah, we know about the cleanmarker. */
-               if (mode && i >= c->fsdata_pos && 
+               if (mode && i >= c->fsdata_pos &&
                    i < c->fsdata_pos + c->fsdata_len)
                        continue;
 
                if (buf[i] != 0xFF) {
                        D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
-                                 buf[page+i], page+i, jeb->offset));
-                       ret = 1; 
+                                 buf[i], i, jeb->offset));
+                       ret = 1;
                        goto out;
                }
        }
 
-       /* we know, we are aligned :) */        
+       /* we know, we are aligned :) */
        for (page = oob_size; page < len; page += sizeof(long)) {
                unsigned long dat = *(unsigned long *)(&buf[page]);
                if(dat != -1) {
-                       ret = 1; 
+                       ret = 1;
                        goto out;
                }
        }
 
 out:
-       kfree(buf);     
-       
+       kfree(buf);
+
        return ret;
 }
 
@@ -1071,7 +1067,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
        n.totlen = cpu_to_je32(8);
 
        ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n);
-       
+
        if (ret) {
                D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
                return ret;
@@ -1083,7 +1079,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
        return 0;
 }
 
-/* 
+/*
  * On NAND we try to mark this block bad. If the block was erased more
  * than MAX_ERASE_FAILURES we mark it finaly bad.
  * Don't care about failures. This block remains on the erase-pending
@@ -1104,7 +1100,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
 
        D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset));
        ret = c->mtd->block_markbad(c->mtd, bad_offset);
-       
+
        if (ret) {
                D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
                return ret;
@@ -1128,7 +1124,7 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c)
        /* Do this only, if we have an oob buffer */
        if (!c->mtd->oobsize)
                return 0;
-       
+
        /* Cleanmarker is out-of-band, so inline size zero */
        c->cleanmarker_size = 0;
 
@@ -1154,7 +1150,7 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c)
                        c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
                        c->badblock_pos = 15;
                        break;
-       
+
                default:
                        D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n"));
                        return -EINVAL;
@@ -1171,7 +1167,7 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
        init_rwsem(&c->wbuf_sem);
        c->wbuf_pagesize = c->mtd->oobblock;
        c->wbuf_ofs = 0xFFFFFFFF;
-       
+
        c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
        if (!c->wbuf)
                return -ENOMEM;
@@ -1197,17 +1193,41 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
 
 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_pagesize =  c->mtd->erasesize;
+
+       /* Find a suitable c->sector_size
+        * - Not too much sectors
+        * - Sectors have to be at least 4 K + some bytes
+        * - All known dataflashes have erase sizes of 528 or 1056
+        * - we take at least 8 eraseblocks and want to have at least 8K size
+        * - The concatenation should be a power of 2
+       */
+
+       c->sector_size = 8 * c->mtd->erasesize;
+
+       while (c->sector_size < 8192) {
+               c->sector_size *= 2;
+       }
+
+       /* It may be necessary to adjust the flash size */
+       c->flash_size = c->mtd->size;
+
+       if ((c->flash_size % c->sector_size) != 0) {
+               c->flash_size = (c->flash_size / c->sector_size) * c->sector_size;
+               printk(KERN_WARNING "JFFS2 flash size adjusted to %dKiB\n", c->flash_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);
+       printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);
 
        return 0;
 }
@@ -1235,3 +1255,23 @@ 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);
 }
+
+int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
+       /* Cleanmarker currently occupies a whole programming region */
+       c->cleanmarker_size = MTD_PROGREGION_SIZE(c->mtd);
+
+       /* Initialize write buffer */
+       init_rwsem(&c->wbuf_sem);
+       c->wbuf_pagesize = MTD_PROGREGION_SIZE(c->mtd);
+       c->wbuf_ofs = 0xFFFFFFFF;
+
+       c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+       if (!c->wbuf)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) {
+       kfree(c->wbuf);
+}
index 69100615d9aef17535f808ed6e5e805b404f6eb2..1342f0158e9b0d0da2565c99c18eb5f088c501a5 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.92 2005/04/13 13:22:35 dwmw2 Exp $
+ * $Id: write.c,v 1.97 2005/11/07 11:14:42 gleixner Exp $
  *
  */
 
@@ -54,35 +54,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
        return 0;
 }
 
-#if CONFIG_JFFS2_FS_DEBUG > 0
-static void writecheck(struct jffs2_sb_info *c, uint32_t ofs)
-{
-       unsigned char buf[16];
-       size_t retlen;
-       int ret, i;
-
-       ret = jffs2_flash_read(c, ofs, 16, &retlen, buf);
-       if (ret || (retlen != 16)) {
-               D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen));
-               return;
-       }
-       ret = 0;
-       for (i=0; i<16; i++) {
-               if (buf[i] != 0xff)
-                       ret = 1;
-       }
-       if (ret) {
-               printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there are data already there:\n", ofs);
-               printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", 
-                      ofs,
-                      buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
-                      buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
-       }
-}
-#endif
-
-
-/* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, 
+/* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it,
    write it to the flash, link it into the existing inode/fragment list */
 
 struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *ri, const unsigned char *data, uint32_t datalen, uint32_t flash_ofs, int alloc_mode)
@@ -106,7 +78,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
        vecs[1].iov_base = (unsigned char *)data;
        vecs[1].iov_len = datalen;
 
-       D1(writecheck(c, flash_ofs));
+       jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len);
 
        if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) {
                printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen);
@@ -114,7 +86,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
        raw = jffs2_alloc_raw_node_ref();
        if (!raw)
                return ERR_PTR(-ENOMEM);
-       
+
        fn = jffs2_alloc_full_dnode();
        if (!fn) {
                jffs2_free_raw_node_ref(raw);
@@ -138,7 +110,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
        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", 
+                               "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));
@@ -148,7 +120,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
                                 (alloc_mode==ALLOC_GC)?0:f->inocache->ino);
 
        if (ret || (retlen != sizeof(*ri) + datalen)) {
-               printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", 
+               printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
                       sizeof(*ri)+datalen, flash_ofs, ret, retlen);
 
                /* Mark the space as dirtied */
@@ -156,10 +128,10 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
                        /* Doesn't belong to any inode */
                        raw->next_in_ino = NULL;
 
-                       /* Don't change raw->size to match retlen. We may have 
+                       /* Don't change raw->size to match retlen. We may have
                           written the node header already, and only the data will
                           seem corrupted, in which case the scan would skip over
-                          any node we write before the original intended end of 
+                          any node we write before the original intended end of
                           this node */
                        raw->flash_offset |= REF_OBSOLETE;
                        jffs2_add_physical_node_ref(c, raw);
@@ -176,26 +148,28 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
                        retried = 1;
 
                        D1(printk(KERN_DEBUG "Retrying failed write.\n"));
-                       
-                       ACCT_SANITY_CHECK(c,jeb);
-                       D1(ACCT_PARANOIA_CHECK(jeb));
+
+                       jffs2_dbg_acct_sanity_check(c,jeb);
+                       jffs2_dbg_acct_paranoia_check(c, jeb);
 
                        if (alloc_mode == ALLOC_GC) {
-                               ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy);
+                               ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs,
+                                                       &dummy, JFFS2_SUMMARY_INODE_SIZE);
                        } else {
                                /* Locking pain */
                                up(&f->sem);
                                jffs2_complete_reservation(c);
-                       
-                               ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode);
+
+                               ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs,
+                                                       &dummy, alloc_mode, JFFS2_SUMMARY_INODE_SIZE);
                                down(&f->sem);
                        }
 
                        if (!ret) {
                                D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
 
-                               ACCT_SANITY_CHECK(c,jeb);
-                               D1(ACCT_PARANOIA_CHECK(jeb));
+                               jffs2_dbg_acct_sanity_check(c,jeb);
+                               jffs2_dbg_acct_paranoia_check(c, jeb);
 
                                goto retry;
                        }
@@ -207,9 +181,9 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
                return ERR_PTR(ret?ret:-EIO);
        }
        /* Mark the space used */
-       /* If node covers at least a whole page, or if it starts at the 
-          beginning of a page and runs to the end of the file, or if 
-          it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. 
+       /* If node covers at least a whole page, or if it starts at the
+          beginning of a page and runs to the end of the file, or if
+          it's a hole node, mark it REF_PRISTINE, else REF_NORMAL.
        */
        if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) ||
            ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) &&
@@ -227,12 +201,12 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
        spin_unlock(&c->erase_completion_lock);
 
        D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
-                 flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), 
+                 flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize),
                  je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc),
                  je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen)));
 
        if (retried) {
-               ACCT_SANITY_CHECK(c,NULL);
+               jffs2_dbg_acct_sanity_check(c,NULL);
        }
 
        return fn;
@@ -247,10 +221,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
        int retried = 0;
        int ret;
 
-       D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", 
+       D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
                  je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
                  je32_to_cpu(rd->name_crc)));
-       D1(writecheck(c, flash_ofs));
 
        D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
                printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
@@ -262,7 +235,9 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
        vecs[0].iov_len = sizeof(*rd);
        vecs[1].iov_base = (unsigned char *)name;
        vecs[1].iov_len = namelen;
-       
+
+       jffs2_dbg_prewrite_paranoia_check(c, flash_ofs, vecs[0].iov_len + vecs[1].iov_len);
+
        raw = jffs2_alloc_raw_node_ref();
 
        if (!raw)
@@ -301,7 +276,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
        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)) {
-               printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", 
+               printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
                               sizeof(*rd)+namelen, flash_ofs, ret, retlen);
                /* Mark the space as dirtied */
                if (retlen) {
@@ -322,24 +297,26 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
 
                        D1(printk(KERN_DEBUG "Retrying failed write.\n"));
 
-                       ACCT_SANITY_CHECK(c,jeb);
-                       D1(ACCT_PARANOIA_CHECK(jeb));
+                       jffs2_dbg_acct_sanity_check(c,jeb);
+                       jffs2_dbg_acct_paranoia_check(c, jeb);
 
                        if (alloc_mode == ALLOC_GC) {
-                               ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy);
+                               ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs,
+                                                       &dummy, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
                        } else {
                                /* Locking pain */
                                up(&f->sem);
                                jffs2_complete_reservation(c);
-                       
-                               ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode);
+
+                               ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs,
+                                                       &dummy, alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
                                down(&f->sem);
                        }
 
                        if (!ret) {
                                D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs));
-                               ACCT_SANITY_CHECK(c,jeb);
-                               D1(ACCT_PARANOIA_CHECK(jeb));
+                               jffs2_dbg_acct_sanity_check(c,jeb);
+                               jffs2_dbg_acct_paranoia_check(c, jeb);
                                goto retry;
                        }
                        D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
@@ -359,7 +336,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
        spin_unlock(&c->erase_completion_lock);
 
        if (retried) {
-               ACCT_SANITY_CHECK(c,NULL);
+               jffs2_dbg_acct_sanity_check(c,NULL);
        }
 
        return fd;
@@ -369,7 +346,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
    we don't have to go digging in struct inode or its equivalent. It should set:
    mode, uid, gid, (starting)isize, atime, ctime, mtime */
 int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
-                           struct jffs2_raw_inode *ri, unsigned char *buf, 
+                           struct jffs2_raw_inode *ri, unsigned char *buf,
                            uint32_t offset, uint32_t writelen, uint32_t *retlen)
 {
        int ret = 0;
@@ -377,7 +354,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
 
                D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n",
                  f->inocache->ino, offset, writelen));
-               
+
        while(writelen) {
                struct jffs2_full_dnode *fn;
                unsigned char *comprbuf = NULL;
@@ -389,7 +366,8 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
        retry:
                D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
 
-               ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL);
+               ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
+                                       &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
                if (ret) {
                        D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
                        break;
@@ -473,10 +451,11 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
        uint32_t alloclen, phys_ofs;
        int ret;
 
-       /* Try to reserve enough space for both node and dirent. 
-        * Just the node will do for now, though 
+       /* Try to reserve enough space for both node and dirent.
+        * Just the node will do for now, though
         */
-       ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL,
+                               JFFS2_SUMMARY_INODE_SIZE);
        D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
        if (ret) {
                up(&f->sem);
@@ -498,15 +477,16 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
                jffs2_complete_reservation(c);
                return PTR_ERR(fn);
        }
-       /* No data here. Only a metadata node, which will be 
+       /* No data here. Only a metadata node, which will be
           obsoleted by the first data write
        */
        f->metadata = fn;
 
        up(&f->sem);
        jffs2_complete_reservation(c);
-       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
-               
+       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+                               ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
+
        if (ret) {
                /* Eep. */
                D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
@@ -539,9 +519,9 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
        fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
 
        jffs2_free_raw_dirent(rd);
-       
+
        if (IS_ERR(fd)) {
-               /* dirent failed to write. Delete the inode normally 
+               /* dirent failed to write. Delete the inode normally
                   as if it were the final unlink() */
                jffs2_complete_reservation(c);
                up(&dir_f->sem);
@@ -560,14 +540,15 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
 
 
 int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
-                   const char *name, int namelen, struct jffs2_inode_info *dead_f)
+                   const char *name, int namelen, struct jffs2_inode_info *dead_f,
+                   uint32_t time)
 {
        struct jffs2_raw_dirent *rd;
        struct jffs2_full_dirent *fd;
        uint32_t alloclen, phys_ofs;
        int ret;
 
-       if (1 /* alternative branch needs testing */ || 
+       if (1 /* alternative branch needs testing */ ||
            !jffs2_can_mark_obsolete(c)) {
                /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
 
@@ -575,7 +556,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                if (!rd)
                        return -ENOMEM;
 
-               ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
+               ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+                                       ALLOC_DELETION, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
                if (ret) {
                        jffs2_free_raw_dirent(rd);
                        return ret;
@@ -588,18 +570,18 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
                rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
                rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
-               
+
                rd->pino = cpu_to_je32(dir_f->inocache->ino);
                rd->version = cpu_to_je32(++dir_f->highest_version);
                rd->ino = cpu_to_je32(0);
-               rd->mctime = cpu_to_je32(get_seconds());
+               rd->mctime = cpu_to_je32(time);
                rd->nsize = namelen;
                rd->type = DT_UNKNOWN;
                rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
                rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
 
                fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
-               
+
                jffs2_free_raw_dirent(rd);
 
                if (IS_ERR(fd)) {
@@ -618,7 +600,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                down(&dir_f->sem);
 
                while ((*prev) && (*prev)->nhash <= nhash) {
-                       if ((*prev)->nhash == nhash && 
+                       if ((*prev)->nhash == nhash &&
                            !memcmp((*prev)->name, name, namelen) &&
                            !(*prev)->name[namelen]) {
                                struct jffs2_full_dirent *this = *prev;
@@ -639,7 +621,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
        /* dead_f is NULL if this was a rename not a real unlink */
        /* Also catch the !f->inocache case, where there was a dirent
           pointing to an inode which didn't exist. */
-       if (dead_f && dead_f->inocache) { 
+       if (dead_f && dead_f->inocache) {
 
                down(&dead_f->sem);
 
@@ -647,9 +629,9 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
                        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);
@@ -673,7 +655,7 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
 }
 
 
-int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen)
+int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint32_t ino, uint8_t type, const char *name, int namelen, uint32_t time)
 {
        struct jffs2_raw_dirent *rd;
        struct jffs2_full_dirent *fd;
@@ -684,12 +666,13 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
        if (!rd)
                return -ENOMEM;
 
-       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+                               ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
        if (ret) {
                jffs2_free_raw_dirent(rd);
                return ret;
        }
-       
+
        down(&dir_f->sem);
 
        /* Build a deletion node */
@@ -701,7 +684,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
        rd->pino = cpu_to_je32(dir_f->inocache->ino);
        rd->version = cpu_to_je32(++dir_f->highest_version);
        rd->ino = cpu_to_je32(ino);
-       rd->mctime = cpu_to_je32(get_seconds());
+       rd->mctime = cpu_to_je32(time);
        rd->nsize = namelen;
 
        rd->type = type;
@@ -710,7 +693,7 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
        rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
 
        fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL);
-       
+
        jffs2_free_raw_dirent(rd);
 
        if (IS_ERR(fd)) {
index f079f83885663386703666df657a7466264ed5ff..c638ae1008de74bc022ecf4cb5faf1ef8de0b692 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: writev.c,v 1.6 2004/11/16 20:36:12 dwmw2 Exp $
+ * $Id: writev.c,v 1.8 2005/09/09 15:11:58 havasi Exp $
  *
  */
 
@@ -42,9 +42,40 @@ static inline int mtd_fake_writev(struct mtd_info *mtd, const struct kvec *vecs,
 int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
                              unsigned long count, loff_t to, size_t *retlen)
 {
+       if (!jffs2_is_writebuffered(c)) {
+               if (jffs2_sum_active()) {
+                       int res;
+                       res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to);
+                       if (res) {
+                               return res;
+                       }
+               }
+       }
+
        if (c->mtd->writev)
                return c->mtd->writev(c->mtd, vecs, count, to, retlen);
-       else
+       else {
                return mtd_fake_writev(c->mtd, vecs, count, to, retlen);
+       }
 }
 
+int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
+                       size_t *retlen, const u_char *buf)
+{
+       int ret;
+       ret = c->mtd->write(c->mtd, ofs, len, retlen, buf);
+
+       if (jffs2_sum_active()) {
+               struct kvec vecs[1];
+               int res;
+
+               vecs[0].iov_base = (unsigned char *) buf;
+               vecs[0].iov_len = len;
+
+               res = jffs2_sum_add_kvec(c, vecs, 1, (uint32_t) ofs);
+               if (res) {
+                       return res;
+               }
+       }
+       return ret;
+}
index 419fc953ac16ee0d52e67ebaa258efd578bfb7b9..cf792bb3c72655beafc28d29c72f25f14bf96a4b 100644 (file)
@@ -5,10 +5,10 @@
  *
  * Created by David Woodhouse <dwmw2@infradead.org>
  *
- * For licensing information, see the file 'LICENCE' in the 
+ * For licensing information, see the file 'LICENCE' in the
  * jffs2 directory.
  *
- * $Id: jffs2.h,v 1.34 2004/11/16 20:36:14 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $
  *
  */
 
@@ -28,6 +28,9 @@
 #define JFFS2_EMPTY_BITMASK 0xffff
 #define JFFS2_DIRTY_BITMASK 0x0000
 
+/* Summary node MAGIC marker */
+#define JFFS2_SUM_MAGIC        0x02851885
+
 /* We only allow a single char for length, and 0xFF is empty flash so
    we don't want it confused with a real length. Hence max 254.
 */
@@ -43,8 +46,6 @@
 #define JFFS2_COMPR_COPY       0x04
 #define JFFS2_COMPR_DYNRUBIN   0x05
 #define JFFS2_COMPR_ZLIB       0x06
-#define JFFS2_COMPR_LZO         0x07
-#define JFFS2_COMPR_LZARI       0x08
 /* Compatibility flags. */
 #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
 #define JFFS2_NODE_ACCURATE 0x2000
 #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
 
+#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
+
 // Maybe later...
 //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
 //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
 
 
-#define JFFS2_INO_FLAG_PREREAD   1     /* Do read_inode() for this one at 
-                                          mount time, don't wait for it to 
+#define JFFS2_INO_FLAG_PREREAD   1     /* Do read_inode() for this one at
+                                          mount time, don't wait for it to
                                           happen later */
-#define JFFS2_INO_FLAG_USERCOMPR  2    /* User has requested a specific 
+#define JFFS2_INO_FLAG_USERCOMPR  2    /* User has requested a specific
                                           compression type */
 
 
@@ -101,7 +104,7 @@ struct jffs2_unknown_node
 struct jffs2_raw_dirent
 {
        jint16_t magic;
-       jint16_t nodetype;      /* == JFFS_NODETYPE_DIRENT */
+       jint16_t nodetype;      /* == JFFS2_NODETYPE_DIRENT */
        jint32_t totlen;
        jint32_t hdr_crc;
        jint32_t pino;
@@ -117,7 +120,7 @@ struct jffs2_raw_dirent
 } __attribute__((packed));
 
 /* The JFFS2 raw inode structure: Used for storage on physical media.  */
-/* The uid, gid, atime, mtime and ctime members could be longer, but 
+/* The uid, gid, atime, mtime and ctime members could be longer, but
    are left like this for space efficiency. If and when people decide
    they really need them extended, it's simple enough to add support for
    a new type of raw node.
@@ -125,7 +128,7 @@ struct jffs2_raw_dirent
 struct jffs2_raw_inode
 {
        jint16_t magic;      /* A constant magic number.  */
-       jint16_t nodetype;   /* == JFFS_NODETYPE_INODE */
+       jint16_t nodetype;   /* == JFFS2_NODETYPE_INODE */
        jint32_t totlen;     /* Total length of this node (inc data, etc.) */
        jint32_t hdr_crc;
        jint32_t ino;        /* Inode number.  */
@@ -148,9 +151,25 @@ struct jffs2_raw_inode
        uint8_t data[0];
 } __attribute__((packed));
 
-union jffs2_node_union {
+struct jffs2_raw_summary
+{
+       jint16_t magic;
+       jint16_t nodetype;      /* = JFFS2_NODETYPE_SUMMARY */
+       jint32_t totlen;
+       jint32_t hdr_crc;
+       jint32_t sum_num;       /* number of sum entries*/
+       jint32_t cln_mkr;       /* clean marker size, 0 = no cleanmarker */
+       jint32_t padded;        /* sum of the size of padding nodes */
+       jint32_t sum_crc;       /* summary information crc */
+       jint32_t node_crc;      /* node crc */
+       jint32_t sum[0];        /* inode summary info */
+} __attribute__((packed));
+
+union jffs2_node_union
+{
        struct jffs2_raw_inode i;
        struct jffs2_raw_dirent d;
+       struct jffs2_raw_summary s;
        struct jffs2_unknown_node u;
 };
 
index 6dbb1cce66460504deeb0bd15245eadfe3ed64ec..ef85ab56302b990f1b884f42deca2aeee3a4ec12 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_i.h,v 1.17 2004/11/11 23:51:27 dwmw2 Exp $ */
+/* $Id: jffs2_fs_i.h,v 1.19 2005/11/07 11:14:52 gleixner Exp $ */
 
 #ifndef _JFFS2_FS_I
 #define _JFFS2_FS_I
@@ -25,13 +25,16 @@ struct jffs2_inode_info {
        /* There may be one datanode which isn't referenced by any of the
           above fragments, if it contains a metadata update but no actual
           data - or if this is a directory inode */
-       /* This also holds the _only_ dnode for symlinks/device nodes, 
+       /* This also holds the _only_ dnode for symlinks/device nodes,
           etc. */
        struct jffs2_full_dnode *metadata;
 
        /* Directory entries */
        struct jffs2_full_dirent *dents;
 
+       /* The target path if this is the inode of a symlink */
+       unsigned char *target;
+
        /* Some stuff we just have to keep in-core at all times, for each inode. */
        struct jffs2_inode_cache *inocache;
 
index 1e21546622de3b0bb2269550141774b5c5919402..4bcfb5570221a6fe7e1fa4347c9f5e78f6fc3b68 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.52 2005/05/19 16:12:17 gleixner Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.54 2005/09/21 13:37:34 dedekind Exp $ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
@@ -20,7 +20,7 @@
 struct jffs2_inodirty;
 
 /* A struct for the overall file system control.  Pointers to
-   jffs2_sb_info structs are named `c' in the source code.  
+   jffs2_sb_info structs are named `c' in the source code.
    Nee jffs_control
 */
 struct jffs2_sb_info {
@@ -35,7 +35,7 @@ struct jffs2_sb_info {
        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 
+       struct semaphore alloc_sem;     /* Used to protect all the following
                                           fields, and also to protect against
                                           out-of-order writing of nodes. And GC. */
        uint32_t cleanmarker_size;      /* Size of an _inline_ CLEANMARKER
@@ -64,7 +64,7 @@ struct jffs2_sb_info {
        uint32_t nospc_dirty_size;
 
        uint32_t nr_blocks;
-       struct jffs2_eraseblock *blocks;        /* The whole array of blocks. Used for getting blocks 
+       struct jffs2_eraseblock *blocks;        /* The whole array of blocks. Used for getting blocks
                                                 * from the offset (blocks[ofs / sector_size]) */
        struct jffs2_eraseblock *nextblock;     /* The block we're currently filling */
 
@@ -82,25 +82,26 @@ struct jffs2_sb_info {
        struct list_head bad_list;              /* Bad blocks. */
        struct list_head bad_used_list;         /* Bad blocks with valid data in. */
 
-       spinlock_t erase_completion_lock;       /* Protect free_list and erasing_list 
+       spinlock_t erase_completion_lock;       /* Protect free_list and erasing_list
                                                   against erase completion handler */
        wait_queue_head_t erase_wait;           /* For waiting for erases to complete */
 
        wait_queue_head_t inocache_wq;
        struct jffs2_inode_cache **inocache_list;
        spinlock_t inocache_lock;
-       
+
        /* Sem to allow jffs2_garbage_collect_deletion_dirent to
-          drop the erase_completion_lock while it's holding a pointer 
+          drop the erase_completion_lock while it's holding a pointer
           to an obsoleted node. I don't like this. Alternatives welcomed. */
        struct semaphore erase_free_sem;
 
+       uint32_t wbuf_pagesize; /* 0 for NOR and other flashes with no wbuf */
+
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        /* Write-behind buffer for NAND flash */
        unsigned char *wbuf;
        uint32_t wbuf_ofs;
        uint32_t wbuf_len;
-       uint32_t wbuf_pagesize;
        struct jffs2_inodirty *wbuf_inodes;
 
        struct rw_semaphore wbuf_sem;   /* Protects the write buffer */
@@ -112,6 +113,8 @@ struct jffs2_sb_info {
        uint32_t fsdata_len;
 #endif
 
+       struct jffs2_summary *summary;          /* Summary information */
+
        /* OS-private pointer for getting back to master superblock info */
        void *os_priv;
 };
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
new file mode 100644 (file)
index 0000000..7a7fbe8
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *  linux/include/linux/mtd/bbm.h
+ *
+ *  NAND family Bad Block Management (BBM) header file
+ *    - Bad Block Table (BBT) implementation
+ *
+ *  Copyright (c) 2005 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ *  Copyright (c) 2000-2005
+ *  Thomas Gleixner <tglx@linuxtronix.de>
+ *
+ */
+#ifndef __LINUX_MTD_BBM_H
+#define __LINUX_MTD_BBM_H
+
+/* The maximum number of NAND chips in an array */
+#define NAND_MAX_CHIPS         8
+
+/**
+ * struct nand_bbt_descr - bad block table descriptor
+ * @param options      options for this descriptor
+ * @param pages                the page(s) where we find the bbt, used with
+ *                     option BBT_ABSPAGE when bbt is searched,
+ *                     then we store the found bbts pages here.
+ *                     Its an array and supports up to 8 chips now
+ * @param offs         offset of the pattern in the oob area of the page
+ * @param veroffs      offset of the bbt version counter in the oob are of the page
+ * @param version      version read from the bbt page during scan
+ * @param len          length of the pattern, if 0 no pattern check is performed
+ * @param maxblocks    maximum number of blocks to search for a bbt. This number of
+ *                     blocks is reserved at the end of the device
+ *                     where the tables are written.
+ * @param reserved_block_code  if non-0, this pattern denotes a reserved
+ *                     (rather than bad) block in the stored bbt
+ * @param pattern      pattern to identify bad block table or factory marked
+ *                     good / bad blocks, can be NULL, if len = 0
+ *
+ * Descriptor for the bad block table marker and the descriptor for the
+ * pattern which identifies good and bad blocks. The assumption is made
+ * that the pattern and the version count are always located in the oob area
+ * of the first block.
+ */
+struct nand_bbt_descr {
+       int options;
+       int pages[NAND_MAX_CHIPS];
+       int offs;
+       int veroffs;
+       uint8_t version[NAND_MAX_CHIPS];
+       int len;
+       int maxblocks;
+       int reserved_block_code;
+       uint8_t *pattern;
+};
+
+/* Options for the bad block table descriptors */
+
+/* The number of bits used per block in the bbt on the device */
+#define NAND_BBT_NRBITS_MSK    0x0000000F
+#define NAND_BBT_1BIT          0x00000001
+#define NAND_BBT_2BIT          0x00000002
+#define NAND_BBT_4BIT          0x00000004
+#define NAND_BBT_8BIT          0x00000008
+/* The bad block table is in the last good block of the device */
+#define NAND_BBT_LASTBLOCK     0x00000010
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_ABSPAGE       0x00000020
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_SEARCH                0x00000040
+/* bbt is stored per chip on multichip devices */
+#define NAND_BBT_PERCHIP       0x00000080
+/* bbt has a version counter at offset veroffs */
+#define NAND_BBT_VERSION       0x00000100
+/* Create a bbt if none axists */
+#define NAND_BBT_CREATE                0x00000200
+/* Search good / bad pattern through all pages of a block */
+#define NAND_BBT_SCANALLPAGES  0x00000400
+/* Scan block empty during good / bad block scan */
+#define NAND_BBT_SCANEMPTY     0x00000800
+/* Write bbt if neccecary */
+#define NAND_BBT_WRITE         0x00001000
+/* Read and write back block contents when writing bbt */
+#define NAND_BBT_SAVECONTENT   0x00002000
+/* Search good / bad pattern on the first and the second page */
+#define NAND_BBT_SCAN2NDPAGE   0x00004000
+
+/* The maximum number of blocks to scan for a bbt */
+#define NAND_BBT_SCAN_MAXBLOCKS        4
+
+/*
+ * Constants for oob configuration
+ */
+#define ONENAND_BADBLOCK_POS   0
+
+/**
+ * struct bbt_info - [GENERIC] Bad Block Table data structure
+ * @param bbt_erase_shift      [INTERN] number of address bits in a bbt entry
+ * @param badblockpos          [INTERN] position of the bad block marker in the oob area
+ * @param bbt                  [INTERN] bad block table pointer
+ * @param badblock_pattern     [REPLACEABLE] bad block scan pattern used for initial bad block scan
+ * @param priv                 [OPTIONAL] pointer to private bbm date
+ */
+struct bbm_info {
+       int bbt_erase_shift;
+       int badblockpos;
+       int options;
+
+       uint8_t *bbt;
+
+       int (*isbad_bbt)(struct mtd_info *mtd, loff_t ofs, int allowbbt);
+
+       /* TODO Add more NAND specific fileds */
+       struct nand_bbt_descr *badblock_pattern;
+
+       void *priv;
+};
+
+/* OneNAND BBT interface */
+extern int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
+extern int onenand_default_bbt(struct mtd_info *mtd);
+
+#endif /* __LINUX_MTD_BBM_H */
index 4ebc2e5a16e28463a5894345affa226b659c5b96..f46afec6fbf8977d58097a2222cb681f0050d7ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: blktrans.h,v 1.5 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: blktrans.h,v 1.6 2005/11/07 11:14:54 gleixner Exp $
  *
  * (C) 2003 David Woodhouse <dwmw2@infradead.org>
  *
@@ -67,6 +67,6 @@ extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr);
 extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr);
 extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
 extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
-                                
+
 
 #endif /* __MTD_TRANS_H__ */
index e6b6a1c66bd5ded3bbca6dff3838585beef868e5..39f1430bd6d5fc2bee1702d96c6d0c11f78e8875 100644 (file)
@@ -1,7 +1,7 @@
 
-/* Common Flash Interface structures 
+/* Common Flash Interface structures
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.54 2005/06/06 23:04:36 tpoynor Exp $
+ * $Id: cfi.h,v 1.56 2005/11/07 11:14:54 gleixner Exp $
  */
 
 #ifndef __MTD_CFI_H__
@@ -82,8 +82,8 @@ static inline int cfi_interleave_supported(int i)
 }
 
 
-/* NB: these values must represents the number of bytes needed to meet the 
- *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes. 
+/* NB: these values must represents the number of bytes needed to meet the
+ *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes.
  *     These numbers are used in calculations.
  */
 #define CFI_DEVICETYPE_X8  (8 / 8)
@@ -173,6 +173,15 @@ struct cfi_intelext_regioninfo {
        struct cfi_intelext_blockinfo BlockTypes[1];
 } __attribute__((packed));
 
+struct cfi_intelext_programming_regioninfo {
+       uint8_t  ProgRegShift;
+       uint8_t  Reserved1;
+       uint8_t  ControlValid;
+       uint8_t  Reserved2;
+       uint8_t  ControlInvalid;
+       uint8_t  Reserved3;
+} __attribute__((packed));
+
 /* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
 
 struct cfi_pri_amdstd {
@@ -250,7 +259,7 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int
 /*
  * Transforms the CFI command for the given geometry (bus width & interleave).
  * It looks too long to be inline, but in the common case it should almost all
- * get optimised away. 
+ * get optimised away.
  */
 static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
 {
@@ -259,7 +268,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf
        unsigned long onecmd;
        int i;
 
-       /* We do it this way to give the compiler a fighting chance 
+       /* 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 */
@@ -270,7 +279,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf
                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);
 
@@ -289,7 +298,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf
                break;
        }
 
-       /* Now replicate it across the size of an unsigned long, or 
+       /* Now replicate it across the size of an unsigned long, or
           just to the bus width as appropriate */
        switch (chips_per_word) {
        default: BUG();
@@ -305,7 +314,7 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf
                ;
        }
 
-       /* And finally, for the multi-word case, replicate it 
+       /* And finally, for the multi-word case, replicate it
           in all words in the structure */
        for (i=0; i < words_per_bus; i++) {
                val.x[i] = onecmd;
@@ -316,14 +325,14 @@ static inline map_word cfi_build_cmd(u_long 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, 
+static inline unsigned long 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 
+       /* 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 */
@@ -334,7 +343,7 @@ static inline unsigned char cfi_merge_status(map_word val, struct map_info *map,
                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);
 
index 953e64fb8ac5d7193cb680a289428c1d67ab12bf..386a52cf8b1b4e0faccb7ee1ba8eee8b08c5ab90 100644 (file)
@@ -1,12 +1,12 @@
-/* 
+/*
  * Linux driver for Disk-On-Chip devices
  *
- * Copyright (C) 1999 Machine Vision Holdings, Inc.   
+ * Copyright (C) 1999 Machine Vision Holdings, Inc.
  * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org>
  * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com>
  * Copyright (C) 2002-2003 SnapGear Inc
  *
- * $Id: doc2000.h,v 1.24 2005/01/05 12:40:38 dwmw2 Exp $ 
+ * $Id: doc2000.h,v 1.25 2005/11/07 11:14:54 gleixner Exp $
  *
  * Released under GPL
  */
 #define DoC_Mplus_CtrlConfirm          0x1076
 #define DoC_Mplus_Power                        0x1fff
 
-/* How to access the device? 
- * On ARM, it'll be mmap'd directly with 32-bit wide accesses. 
+/* How to access the device?
+ * On ARM, it'll be mmap'd directly with 32-bit wide accesses.
  * On PPC, it's mmap'd and 16-bit wide.
- * Others use readb/writeb 
+ * Others use readb/writeb
  */
 #if defined(__arm__)
 #define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
@@ -172,7 +172,7 @@ struct DiskOnChip {
        unsigned long totlen;
        unsigned char ChipID; /* Type of DiskOnChip */
        int ioreg;
-       
+
        unsigned long mfr; /* Flash IDs - only one type of flash per device */
        unsigned long id;
        int chipshift;
@@ -180,10 +180,10 @@ struct DiskOnChip {
        char pageadrlen;
        char interleave; /* Internal interleaving - Millennium Plus style */
        unsigned long erasesize;
-       
+
        int curfloor;
        int curchip;
-       
+
        int numchips;
        struct Nand *chips;
        struct mtd_info *nextdoc;
index 675776fa3e27159a85b4a4792ca00986b4417eb1..a293a3b78e05741ff372229959aee31fb5b5e834 100644 (file)
@@ -1,12 +1,12 @@
 
-/* 
+/*
  * struct flchip definition
- * 
- * Contains information about the location and state of a given flash device 
+ *
+ * Contains information about the location and state of a given flash device
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.17 2005/03/14 18:27:15 bjd Exp $
+ * $Id: flashchip.h,v 1.18 2005/11/07 11:14:54 gleixner Exp $
  *
  */
 
 
 /* For spinlocks. sched.h includes spinlock.h from whichever directory it
  * happens to be in - so we don't have to care whether we're on 2.2, which
- * has asm/spinlock.h, or 2.4, which has linux/spinlock.h 
+ * has asm/spinlock.h, or 2.4, which has linux/spinlock.h
  */
 #include <linux/sched.h>
 
-typedef enum { 
+typedef enum {
        FL_READY,
        FL_STATUS,
        FL_CFI_QUERY,
@@ -45,7 +45,7 @@ typedef enum {
 
 
 
-/* NOTE: confusingly, this can be used to refer to more than one chip at a time, 
+/* NOTE: confusingly, this can be used to refer to more than one chip at a time,
    if they're interleaved.  This can even refer to individual partitions on
    the same physical chip when present. */
 
index 3678459b4535ec66c32c6f4981475eb004bd5f2d..d996091133076141ab35abef365017fd956ae556 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * $Id: ftl.h,v 1.6 2003/01/24 13:20:04 dwmw2 Exp $
- * 
+ * $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $
+ *
  * Derived from (and probably identical to):
  * ftl.h 1.7 1999/10/25 20:23:17
  *
@@ -12,7 +12,7 @@
  * Software distributed under the License is distributed on an "AS IS"
  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  * the License for the specific language governing rights and
- * limitations under the License. 
+ * limitations under the License.
  *
  * The initial developer of the original code is David A. Hinds
  * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
index 3d7bdec14f976e5bc455bc1b47a4347d40519609..256e7342ed1eead34a474f13d762f7b91885127b 100644 (file)
@@ -1,14 +1,14 @@
 /*
  * (C) 2001, 2001 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.h,v 1.3 2004/10/20 22:10:33 dwmw2 Exp $
+ * $Id: gen_probe.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $
  */
 
 #ifndef __LINUX_MTD_GEN_PROBE_H__
 #define __LINUX_MTD_GEN_PROBE_H__
 
 #include <linux/mtd/flashchip.h>
-#include <linux/mtd/map.h> 
+#include <linux/mtd/map.h>
 #include <linux/mtd/cfi.h>
 #include <linux/bitops.h>
 
index 2ba0f700ddbcfe03c09d1dcf20e49554ae717ed5..9006feb218b93f36ac994917d3ae696d12c80318 100644 (file)
@@ -1,13 +1,13 @@
 
 /* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is 
+ * This is an older type of interface for self programming flash. It is
  * commonly use in older AMD chips and is obsolete compared with CFI.
  * It is called JEDEC because the JEDEC association distributes the ID codes
  * for the chips.
  *
  * See the AMD flash databook for information on how to operate the interface.
  *
- * $Id: jedec.h,v 1.3 2003/05/21 11:51:01 dwmw2 Exp $
+ * $Id: jedec.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $
  */
 
 #ifndef __LINUX_MTD_JEDEC_H__
@@ -33,16 +33,16 @@ struct jedec_flash_chip
    __u16 jedec;
    unsigned long size;
    unsigned long sectorsize;
-   
+
    // *(__u8*)(base + (adder << addrshift)) = data << datashift
    // Address size = size << addrshift
    unsigned long base;           // Byte 0 of the flash, will be unaligned
    unsigned int datashift;       // Useful for 32bit/16bit accesses
    unsigned int addrshift;
    unsigned long offset;         // linerized start. base==offset for unbanked, uninterleaved flash
-   
+
    __u32 capabilities;
-   
+
    // These markers are filled in by the flash_chip_scan function
    unsigned long start;
    unsigned long length;
@@ -51,16 +51,16 @@ struct jedec_flash_chip
 struct jedec_private
 {
    unsigned long size;         // Total size of all the devices
-   
+
    /* Bank handling. If sum(bank_fill) == size then this is linear flash.
       Otherwise the mapping has holes in it. bank_fill may be used to
-      find the holes, but in the common symetric case 
-      bank_fill[0] == bank_fill[*], thus addresses may be computed 
+      find the holes, but in the common symetric case
+      bank_fill[0] == bank_fill[*], thus addresses may be computed
       mathmatically. bank_fill must be powers of two */
    unsigned is_banked;
    unsigned long bank_fill[MAX_JEDEC_CHIPS];
-   
-   struct jedec_flash_chip chips[MAX_JEDEC_CHIPS];  
+
+   struct jedec_flash_chip chips[MAX_JEDEC_CHIPS];
 };
 
 #endif
index fc28841f340975181d6813c5f5d701921aad9219..fedfbc8a287ff64228dee5a0f9fe551026988ea0 100644 (file)
@@ -1,6 +1,6 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.52 2005/05/25 10:29:41 gleixner Exp $ */
+/* $Id: map.h,v 1.54 2005/11/07 11:14:54 gleixner Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #define __LINUX_MTD_MAP_H__
@@ -170,14 +170,14 @@ typedef union {
    to a chip probe routine -- either JEDEC or CFI probe or both -- via
    do_map_probe(). If a chip is recognised, the probe code will invoke the
    appropriate chip driver (if present) and return a struct mtd_info.
-   At which point, you fill in the mtd->module with your own module 
+   At which point, you fill in the mtd->module with your own module
    address, and register it with the MTD core code. Or you could partition
    it and register the partitions instead, or keep it for your own private
    use; whatever.
-   
+
    The mtd->priv field will point to the struct map_info, and any further
-   private data required by the chip driver is linked from the 
-   mtd->priv->fldrv_priv field. This allows the map driver to get at 
+   private data required by the chip driver is linked from the
+   mtd->priv->fldrv_priv field. This allows the map driver to get at
    the destructor function map->fldrv_destroy() when it's tired
    of living.
 */
@@ -214,7 +214,7 @@ struct map_info {
           If there is no cache to care about this can be set to NULL. */
        void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
 
-       /* set_vpp() must handle being reentered -- enable, enable, disable 
+       /* set_vpp() must handle being reentered -- enable, enable, disable
           must leave it enabled. */
        void (*set_vpp)(struct map_info *, int);
 
@@ -353,7 +353,7 @@ static inline map_word map_word_ff(struct map_info *map)
 {
        map_word r;
        int i;
-       
+
        if (map_bankwidth(map) < MAP_FF_LIMIT) {
                int bw = 8 * map_bankwidth(map);
                r.x[0] = (1 << bw) - 1;
index c50c3f3927d959ceda9e1ad2539e9df785219139..e95d0463a3e5a5237007455c02f8bba71367eee4 100644 (file)
@@ -1,5 +1,5 @@
-/* 
- * $Id: mtd.h,v 1.59 2005/04/11 10:19:02 gleixner Exp $
+/*
+ * $Id: mtd.h,v 1.61 2005/11/07 11:14:54 gleixner Exp $
  *
  * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
  *
@@ -72,7 +72,17 @@ struct mtd_info {
        u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
        u_int32_t ecctype;
        u_int32_t eccsize;
-       
+
+       /*
+        * Reuse some of the above unused fields in the case of NOR flash
+        * with configurable programming regions to avoid modifying the
+        * user visible structure layout/size.  Only valid when the
+        * MTD_PROGRAM_REGIONS flag is set.
+        * (Maybe we should have an union for those?)
+        */
+#define MTD_PROGREGION_SIZE(mtd)  (mtd)->oobblock
+#define MTD_PROGREGION_CTRLMODE_VALID(mtd)  (mtd)->oobsize
+#define MTD_PROGREGION_CTRLMODE_INVALID(mtd)  (mtd)->ecctype
 
        // Kernel-only stuff starts here.
        char *name;
@@ -80,13 +90,13 @@ 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 
+       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. 
+        * it means that the whole device has erasesize as given above.
         */
        int numeraseregions;
-       struct mtd_erase_region_info *eraseregions; 
+       struct mtd_erase_region_info *eraseregions;
 
        /* This really shouldn't be here. It can go away in 2.5 */
        u_int32_t bank_size;
@@ -109,10 +119,10 @@ struct mtd_info {
        int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
        int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
 
-       /* 
-        * Methods to access the protection register area, present in some 
+       /*
+        * Methods to access the protection register area, present in some
         * flash devices. The user data is one time programmable but the
-        * factory data is read only. 
+        * factory data is read only.
         */
        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);
@@ -123,14 +133,14 @@ struct mtd_info {
 
        /* kvec-based read/write methods. We need these especially for NAND flash,
           with its limited number of write cycles per erase.
-          NB: The 'count' parameter is the number of _vectors_, each of 
+          NB: The 'count' parameter is the number of _vectors_, each of
           which contains an (ofs, len) tuple.
        */
        int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen);
-       int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, 
+       int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from,
                size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
        int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
-       int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, 
+       int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to,
                size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
 
        /* Sync */
@@ -194,7 +204,7 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
 #define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args)
 #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args)
 #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)
-#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd);  } while (0) 
+#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd);  } while (0)
 
 
 #ifdef CONFIG_MTD_PARTITIONS
index 9b5b762175849e13274d84f54788aad309fcefd4..da5e67b3fc70ec8851f5aee64ce9a9b4f7ea6686 100644 (file)
@@ -5,7 +5,7 @@
  *                     Steven J. Hill <sjhill@realitydiluted.com>
  *                    Thomas Gleixner <tglx@linutronix.de>
  *
- * $Id: nand.h,v 1.73 2005/05/31 19:39:17 gleixner Exp $
+ * $Id: nand.h,v 1.74 2005/09/15 13:58:50 vwool 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
@@ -24,7 +24,7 @@
  *                     bat later if I did something naughty.
  *   10-11-2000 SJH     Added private NAND flash structure for driver
  *   10-24-2000 SJH     Added prototype for 'nand_scan' function
- *   10-29-2001 TG     changed nand_chip structure to support 
+ *   10-29-2001 TG     changed nand_chip structure to support
  *                     hardwarespecific function for accessing control lines
  *   02-21-2002 TG     added support for different read/write adress and
  *                     ready/busy line access function
  *                     CONFIG_MTD_NAND_ECC_JFFS2 is not set
  *   08-10-2002 TG     extensions to nand_chip structure to support HW-ECC
  *
- *   08-29-2002 tglx   nand_chip structure: data_poi for selecting 
+ *   08-29-2002 tglx   nand_chip structure: data_poi for selecting
  *                     internal / fs-driver buffer
  *                     support for 6byte/512byte hardware ECC
  *                     read_ecc, write_ecc extended for different oob-layout
  *                     oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB,
  *                     NAND_YAFFS_OOB
  *  11-25-2002 tglx    Added Manufacturer code FUJITSU, NATIONAL
- *                     Split manufacturer and device ID structures 
+ *                     Split manufacturer and device ID structures
  *
  *  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 
+ *  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 
+ *  01-20-2005 dmarlin added optional pointer to hardware specific callback for
  *                     extra error status checks.
  */
 #ifndef __LINUX_MTD_NAND_H
@@ -120,8 +120,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
 #define NAND_CMD_CACHEDPROG    0x15
 
 /* Extended commands for AG-AND device */
-/* 
- * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but 
+/*
+ * 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.
@@ -145,7 +145,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
 #define NAND_STATUS_READY      0x40
 #define NAND_STATUS_WP         0x80
 
-/* 
+/*
  * Constants for ECC_MODES
  */
 
@@ -191,12 +191,12 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
 #define NAND_CACHEPRG          0x00000008
 /* Chip has copy back function */
 #define NAND_COPYBACK          0x00000010
-/* AND Chip which has 4 banks and a confusing page / block 
+/* AND Chip which has 4 banks and a confusing page / block
  * assignment. See Renesas datasheet for further information */
 #define NAND_IS_AND            0x00000020
 /* Chip has a array of 4 pages which can be read without
  * additional ready /busy waits */
-#define NAND_4PAGE_ARRAY       0x00000040 
+#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.  */
@@ -219,8 +219,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
 /* Use a flash based bad block table. This option is passed to the
  * default bad block table function. */
 #define NAND_USE_FLASH_BBT     0x00010000
-/* The hw ecc generator provides a syndrome instead a ecc value on read 
- * This can only work if we have the ecc bytes directly behind the 
+/* The hw ecc generator provides a syndrome instead a ecc value on read
+ * 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. */
@@ -244,6 +244,7 @@ typedef enum {
        FL_ERASING,
        FL_SYNCING,
        FL_CACHEDPRG,
+       FL_PM_SUSPENDED,
 } nand_state_t;
 
 /* Keep gcc happy */
@@ -251,7 +252,7 @@ struct nand_chip;
 
 /**
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices
- * @lock:               protection lock  
+ * @lock:               protection lock
  * @active:            the mtd device which holds the controller currently
  * @wq:                        wait queue to sleep on if a NAND operation is in progress
  *                      used instead of the per chip wait queue when a hw controller is available
@@ -264,8 +265,8 @@ struct nand_hw_control {
 
 /**
  * struct nand_chip - NAND Private Flash Chip Data
- * @IO_ADDR_R:         [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device 
- * @IO_ADDR_W:         [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device 
+ * @IO_ADDR_R:         [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device
+ * @IO_ADDR_W:         [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device
  * @read_byte:         [REPLACEABLE] read one byte from the chip
  * @write_byte:                [REPLACEABLE] write one byte to the chip
  * @read_word:         [REPLACEABLE] read one word from the chip
@@ -288,7 +289,7 @@ struct nand_hw_control {
  *                     be provided if a hardware ECC is available
  * @erase_cmd:         [INTERN] erase command write function, selectable due to AND support
  * @scan_bbt:          [REPLACEABLE] function to scan bad block table
- * @eccmode:           [BOARDSPECIFIC] mode of ecc, see defines 
+ * @eccmode:           [BOARDSPECIFIC] mode of ecc, see defines
  * @eccsize:           [INTERN] databytes used per ecc-calculation
  * @eccbytes:          [INTERN] number of ecc bytes per ecc-calculation step
  * @eccsteps:          [INTERN] number of ecc calculation steps per page
@@ -300,7 +301,7 @@ struct nand_hw_control {
  * @phys_erase_shift:  [INTERN] number of address bits in a physical eraseblock
  * @bbt_erase_shift:   [INTERN] number of address bits in a bbt entry
  * @chip_shift:                [INTERN] number of address bits in one chip
- * @data_buf:          [INTERN] internal buffer for one page + oob 
+ * @data_buf:          [INTERN] internal buffer for one page + oob
  * @oob_buf:           [INTERN] oob buffer for one eraseblock
  * @oobdirty:          [INTERN] indicates that oob_buf must be reinitialized
  * @data_poi:          [INTERN] pointer to a data buffer
@@ -315,22 +316,22 @@ struct nand_hw_control {
  * @bbt:               [INTERN] bad block table pointer
  * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash lookup
  * @bbt_md:            [REPLACEABLE] bad block table mirror descriptor
- * @badblock_pattern:  [REPLACEABLE] bad block scan pattern used for initial bad block scan 
+ * @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 
+ * @errstat:           [OPTIONAL] hardware specific function to perform additional error status checks
  *                     (determine if errors are correctable)
  */
+
 struct nand_chip {
        void  __iomem   *IO_ADDR_R;
        void  __iomem   *IO_ADDR_W;
-       
+
        u_char          (*read_byte)(struct mtd_info *mtd);
        void            (*write_byte)(struct mtd_info *mtd, u_char byte);
        u16             (*read_word)(struct mtd_info *mtd);
        void            (*write_word)(struct mtd_info *mtd, u16 word);
-       
+
        void            (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
        void            (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
        int             (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
@@ -395,7 +396,7 @@ struct nand_chip {
  * @name:      Identify the device type
  * @id:        device ID code
  * @pagesize:          Pagesize in bytes. Either 256 or 512 or 0
- *             If the pagesize is 0, then the real pagesize 
+ *             If the pagesize is 0, then the real pagesize
  *             and the eraseize are determined from the
  *             extended id bytes in the chip
  * @erasesize:         Size of an erase block in the flash device.
@@ -424,7 +425,7 @@ struct nand_manufacturers {
 extern struct nand_flash_dev nand_flash_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 
-/** 
+/**
  * struct nand_bbt_descr - bad block table descriptor
  * @options:   options for this descriptor
  * @pages:     the page(s) where we find the bbt, used with option BBT_ABSPAGE
@@ -435,14 +436,14 @@ extern struct nand_manufacturers nand_manuf_ids[];
  * @version:   version read from the bbt page during scan
  * @len:       length of the pattern, if 0 no pattern check is performed
  * @maxblocks: maximum number of blocks to search for a bbt. This number of
- *             blocks is reserved at the end of the device where the tables are 
+ *             blocks is reserved at the end of the device where the tables are
  *             written.
  * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
  *              bad) block in the stored bbt
- * @pattern:   pattern to identify bad block table or factory marked good / 
+ * @pattern:   pattern to identify bad block table or factory marked good /
  *             bad blocks, can be NULL, if len = 0
  *
- * Descriptor for the bad block table marker and the descriptor for the 
+ * Descriptor for the bad block table marker and the descriptor for the
  * pattern which identifies good and bad blocks. The assumption is made
  * that the pattern and the version count are always located in the oob area
  * of the first block.
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
new file mode 100644 (file)
index 0000000..f1fd421
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *  linux/include/linux/mtd/onenand.h
+ *
+ *  Copyright (C) 2005 Samsung Electronics
+ *  Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MTD_ONENAND_H
+#define __LINUX_MTD_ONENAND_H
+
+#include <linux/spinlock.h>
+#include <linux/mtd/onenand_regs.h>
+#include <linux/mtd/bbm.h>
+
+#define MAX_BUFFERRAM          2
+#define MAX_ONENAND_PAGESIZE   (2048 + 64)
+
+/* Scan and identify a OneNAND device */
+extern int onenand_scan(struct mtd_info *mtd, int max_chips);
+/* Free resources held by the OneNAND device */
+extern void onenand_release(struct mtd_info *mtd);
+
+/**
+ * onenand_state_t - chip states
+ * Enumeration for OneNAND flash chip state
+ */
+typedef enum {
+       FL_READY,
+       FL_READING,
+       FL_WRITING,
+       FL_ERASING,
+       FL_SYNCING,
+       FL_UNLOCKING,
+       FL_LOCKING,
+       FL_PM_SUSPENDED,
+} onenand_state_t;
+
+/**
+ * struct onenand_bufferram - OneNAND BufferRAM Data
+ * @param block                block address in BufferRAM
+ * @param page         page address in BufferRAM
+ * @param valid                valid flag
+ */
+struct onenand_bufferram {
+       int block;
+       int page;
+       int valid;
+};
+
+/**
+ * struct onenand_chip - OneNAND Private Flash Chip Data
+ * @param base         [BOARDSPECIFIC] address to access OneNAND
+ * @param chipsize     [INTERN] the size of one chip for multichip arrays
+ * @param device_id    [INTERN] device ID
+ * @param verstion_id  [INTERN] version ID
+ * @param options      [BOARDSPECIFIC] various chip options. They can partly be set to inform onenand_scan about
+ * @param erase_shift  [INTERN] number of address bits in a block
+ * @param page_shift   [INTERN] number of address bits in a page
+ * @param ppb_shift    [INTERN] number of address bits in a pages per block
+ * @param page_mask    [INTERN] a page per block mask
+ * @param bufferam_index       [INTERN] BufferRAM index
+ * @param bufferam     [INTERN] BufferRAM info
+ * @param readw                [REPLACEABLE] hardware specific function for read short
+ * @param writew       [REPLACEABLE] hardware specific function for write short
+ * @param command      [REPLACEABLE] hardware specific function for writing commands to the chip
+ * @param wait         [REPLACEABLE] hardware specific function for wait on ready
+ * @param read_bufferram       [REPLACEABLE] hardware specific function for BufferRAM Area
+ * @param write_bufferram      [REPLACEABLE] hardware specific function for BufferRAM Area
+ * @param read_word    [REPLACEABLE] hardware specific function for read register of OneNAND
+ * @param write_word   [REPLACEABLE] hardware specific function for write register of OneNAND
+ * @param scan_bbt     [REPLACEALBE] hardware specific function for scaning Bad block Table
+ * @param chip_lock    [INTERN] spinlock used to protect access to this structure and the chip
+ * @param wq           [INTERN] wait queue to sleep on if a OneNAND operation is in progress
+ * @param state                [INTERN] the current state of the OneNAND device
+ * @param autooob      [REPLACEABLE] the default (auto)placement scheme
+ * @param bbm          [REPLACEABLE] pointer to Bad Block Management
+ * @param priv         [OPTIONAL] pointer to private chip date
+ */
+struct onenand_chip {
+       void __iomem            *base;
+       unsigned int            chipsize;
+       unsigned int            device_id;
+       unsigned int            density_mask;
+       unsigned int            options;
+
+       unsigned int            erase_shift;
+       unsigned int            page_shift;
+       unsigned int            ppb_shift;      /* Pages per block shift */
+       unsigned int            page_mask;
+
+       unsigned int            bufferram_index;
+       struct onenand_bufferram        bufferram[MAX_BUFFERRAM];
+
+       int (*command)(struct mtd_info *mtd, int cmd, loff_t address, size_t len);
+       int (*wait)(struct mtd_info *mtd, int state);
+       int (*read_bufferram)(struct mtd_info *mtd, int area,
+                       unsigned char *buffer, int offset, size_t count);
+       int (*write_bufferram)(struct mtd_info *mtd, int area,
+                       const unsigned char *buffer, int offset, size_t count);
+       unsigned short (*read_word)(void __iomem *addr);
+       void (*write_word)(unsigned short value, void __iomem *addr);
+       void (*mmcontrol)(struct mtd_info *mtd, int sync_read);
+       int (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+       int (*scan_bbt)(struct mtd_info *mtd);
+
+       spinlock_t              chip_lock;
+       wait_queue_head_t       wq;
+       onenand_state_t         state;
+
+       struct nand_oobinfo     *autooob;
+
+       void                    *bbm;
+
+       void                    *priv;
+};
+
+/*
+ * Helper macros
+ */
+#define ONENAND_CURRENT_BUFFERRAM(this)                (this->bufferram_index)
+#define ONENAND_NEXT_BUFFERRAM(this)           (this->bufferram_index ^ 1)
+#define ONENAND_SET_NEXT_BUFFERRAM(this)       (this->bufferram_index ^= 1)
+
+#define ONENAND_GET_SYS_CFG1(this)                                     \
+       (this->read_word(this->base + ONENAND_REG_SYS_CFG1))
+#define ONENAND_SET_SYS_CFG1(v, this)                                  \
+       (this->write_word(v, this->base + ONENAND_REG_SYS_CFG1))
+
+/*
+ * Options bits
+ */
+#define ONENAND_CONT_LOCK              (0x0001)
+
+
+/*
+ * OneNAND Flash Manufacturer ID Codes
+ */
+#define ONENAND_MFR_SAMSUNG    0xec
+#define ONENAND_MFR_UNKNOWN    0x00
+
+/**
+ * struct nand_manufacturers - NAND Flash Manufacturer ID Structure
+ * @param name:                Manufacturer name
+ * @param id:          manufacturer ID code of device.
+*/
+struct onenand_manufacturers {
+        int id;
+        char *name;
+};
+
+#endif /* __LINUX_MTD_ONENAND_H */
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
new file mode 100644 (file)
index 0000000..d7832ef
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ *  linux/include/linux/mtd/onenand_regs.h
+ *
+ *  OneNAND Register header file
+ *
+ *  Copyright (C) 2005 Samsung Electronics
+ *
+ * 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 __ONENAND_REG_H
+#define __ONENAND_REG_H
+
+/* Memory Address Map Translation (Word order) */
+#define ONENAND_MEMORY_MAP(x)          ((x) << 1)
+
+/*
+ * External BufferRAM area
+ */
+#define        ONENAND_BOOTRAM                 ONENAND_MEMORY_MAP(0x0000)
+#define        ONENAND_DATARAM                 ONENAND_MEMORY_MAP(0x0200)
+#define        ONENAND_SPARERAM                ONENAND_MEMORY_MAP(0x8010)
+
+/*
+ * OneNAND Registers
+ */
+#define ONENAND_REG_MANUFACTURER_ID    ONENAND_MEMORY_MAP(0xF000)
+#define ONENAND_REG_DEVICE_ID          ONENAND_MEMORY_MAP(0xF001)
+#define ONENAND_REG_VERSION_ID         ONENAND_MEMORY_MAP(0xF002)
+#define ONENAND_REG_DATA_BUFFER_SIZE   ONENAND_MEMORY_MAP(0xF003)
+#define ONENAND_REG_BOOT_BUFFER_SIZE   ONENAND_MEMORY_MAP(0xF004)
+#define ONENAND_REG_NUM_BUFFERS                ONENAND_MEMORY_MAP(0xF005)
+#define ONENAND_REG_TECHNOLOGY         ONENAND_MEMORY_MAP(0xF006)
+
+#define ONENAND_REG_START_ADDRESS1     ONENAND_MEMORY_MAP(0xF100)
+#define ONENAND_REG_START_ADDRESS2     ONENAND_MEMORY_MAP(0xF101)
+#define ONENAND_REG_START_ADDRESS3     ONENAND_MEMORY_MAP(0xF102)
+#define ONENAND_REG_START_ADDRESS4     ONENAND_MEMORY_MAP(0xF103)
+#define ONENAND_REG_START_ADDRESS5     ONENAND_MEMORY_MAP(0xF104)
+#define ONENAND_REG_START_ADDRESS6     ONENAND_MEMORY_MAP(0xF105)
+#define ONENAND_REG_START_ADDRESS7     ONENAND_MEMORY_MAP(0xF106)
+#define ONENAND_REG_START_ADDRESS8     ONENAND_MEMORY_MAP(0xF107)
+
+#define ONENAND_REG_START_BUFFER       ONENAND_MEMORY_MAP(0xF200)
+#define ONENAND_REG_COMMAND            ONENAND_MEMORY_MAP(0xF220)
+#define ONENAND_REG_SYS_CFG1           ONENAND_MEMORY_MAP(0xF221)
+#define ONENAND_REG_SYS_CFG2           ONENAND_MEMORY_MAP(0xF222)
+#define ONENAND_REG_CTRL_STATUS                ONENAND_MEMORY_MAP(0xF240)
+#define ONENAND_REG_INTERRUPT          ONENAND_MEMORY_MAP(0xF241)
+#define ONENAND_REG_START_BLOCK_ADDRESS        ONENAND_MEMORY_MAP(0xF24C)
+#define ONENAND_REG_END_BLOCK_ADDRESS  ONENAND_MEMORY_MAP(0xF24D)
+#define ONENAND_REG_WP_STATUS          ONENAND_MEMORY_MAP(0xF24E)
+
+#define ONENAND_REG_ECC_STATUS         ONENAND_MEMORY_MAP(0xFF00)
+#define ONENAND_REG_ECC_M0             ONENAND_MEMORY_MAP(0xFF01)
+#define ONENAND_REG_ECC_S0             ONENAND_MEMORY_MAP(0xFF02)
+#define ONENAND_REG_ECC_M1             ONENAND_MEMORY_MAP(0xFF03)
+#define ONENAND_REG_ECC_S1             ONENAND_MEMORY_MAP(0xFF04)
+#define ONENAND_REG_ECC_M2             ONENAND_MEMORY_MAP(0xFF05)
+#define ONENAND_REG_ECC_S2             ONENAND_MEMORY_MAP(0xFF06)
+#define ONENAND_REG_ECC_M3             ONENAND_MEMORY_MAP(0xFF07)
+#define ONENAND_REG_ECC_S3             ONENAND_MEMORY_MAP(0xFF08)
+
+/*
+ * Device ID Register F001h (R)
+ */
+#define ONENAND_DEVICE_DENSITY_SHIFT   (4)
+#define ONENAND_DEVICE_IS_DDP          (1 << 3)
+#define ONENAND_DEVICE_IS_DEMUX                (1 << 2)
+#define ONENAND_DEVICE_VCC_MASK                (0x3)
+
+#define ONENAND_DEVICE_DENSITY_512Mb   (0x002)
+
+/*
+ * Version ID Register F002h (R)
+ */
+#define ONENAND_VERSION_PROCESS_SHIFT  (8)
+
+/*
+ * Start Address 1 F100h (R/W)
+ */
+#define ONENAND_DDP_SHIFT              (15)
+
+/*
+ * Start Address 8 F107h (R/W)
+ */
+#define ONENAND_FPA_MASK               (0x3f)
+#define ONENAND_FPA_SHIFT              (2)
+#define ONENAND_FSA_MASK               (0x03)
+
+/*
+ * Start Buffer Register F200h (R/W)
+ */
+#define ONENAND_BSA_MASK               (0x03)
+#define ONENAND_BSA_SHIFT              (8)
+#define ONENAND_BSA_BOOTRAM            (0 << 2)
+#define ONENAND_BSA_DATARAM0           (2 << 2)
+#define ONENAND_BSA_DATARAM1           (3 << 2)
+#define ONENAND_BSC_MASK               (0x03)
+
+/*
+ * Command Register F220h (R/W)
+ */
+#define ONENAND_CMD_READ               (0x00)
+#define ONENAND_CMD_READOOB            (0x13)
+#define ONENAND_CMD_PROG               (0x80)
+#define ONENAND_CMD_PROGOOB            (0x1A)
+#define ONENAND_CMD_UNLOCK             (0x23)
+#define ONENAND_CMD_LOCK               (0x2A)
+#define ONENAND_CMD_LOCK_TIGHT         (0x2C)
+#define ONENAND_CMD_ERASE              (0x94)
+#define ONENAND_CMD_RESET              (0xF0)
+#define ONENAND_CMD_READID             (0x90)
+
+/* NOTE: Those are not *REAL* commands */
+#define ONENAND_CMD_BUFFERRAM          (0x1978)
+
+/*
+ * System Configuration 1 Register F221h (R, R/W)
+ */
+#define ONENAND_SYS_CFG1_SYNC_READ     (1 << 15)
+#define ONENAND_SYS_CFG1_BRL_7         (7 << 12)
+#define ONENAND_SYS_CFG1_BRL_6         (6 << 12)
+#define ONENAND_SYS_CFG1_BRL_5         (5 << 12)
+#define ONENAND_SYS_CFG1_BRL_4         (4 << 12)
+#define ONENAND_SYS_CFG1_BRL_3         (3 << 12)
+#define ONENAND_SYS_CFG1_BRL_10                (2 << 12)
+#define ONENAND_SYS_CFG1_BRL_9         (1 << 12)
+#define ONENAND_SYS_CFG1_BRL_8         (0 << 12)
+#define ONENAND_SYS_CFG1_BRL_SHIFT     (12)
+#define ONENAND_SYS_CFG1_BL_32         (4 << 9)
+#define ONENAND_SYS_CFG1_BL_16         (3 << 9)
+#define ONENAND_SYS_CFG1_BL_8          (2 << 9)
+#define ONENAND_SYS_CFG1_BL_4          (1 << 9)
+#define ONENAND_SYS_CFG1_BL_CONT       (0 << 9)
+#define ONENAND_SYS_CFG1_BL_SHIFT      (9)
+#define ONENAND_SYS_CFG1_NO_ECC                (1 << 8)
+#define ONENAND_SYS_CFG1_RDY           (1 << 7)
+#define ONENAND_SYS_CFG1_INT           (1 << 6)
+#define ONENAND_SYS_CFG1_IOBE          (1 << 5)
+#define ONENAND_SYS_CFG1_RDY_CONF      (1 << 4)
+
+/*
+ * Controller Status Register F240h (R)
+ */
+#define ONENAND_CTRL_ONGO              (1 << 15)
+#define ONENAND_CTRL_LOCK              (1 << 14)
+#define ONENAND_CTRL_LOAD              (1 << 13)
+#define ONENAND_CTRL_PROGRAM           (1 << 12)
+#define ONENAND_CTRL_ERASE             (1 << 11)
+#define ONENAND_CTRL_ERROR             (1 << 10)
+#define ONENAND_CTRL_RSTB              (1 << 7)
+
+/*
+ * Interrupt Status Register F241h (R)
+ */
+#define ONENAND_INT_MASTER             (1 << 15)
+#define ONENAND_INT_READ               (1 << 7)
+#define ONENAND_INT_WRITE              (1 << 6)
+#define ONENAND_INT_ERASE              (1 << 5)
+#define ONENAND_INT_RESET              (1 << 4)
+#define ONENAND_INT_CLEAR              (0 << 0)
+
+/*
+ * NAND Flash Write Protection Status Register F24Eh (R)
+ */
+#define ONENAND_WP_US                  (1 << 2)
+#define ONENAND_WP_LS                  (1 << 1)
+#define ONENAND_WP_LTS                 (1 << 0)
+
+/*
+ * ECC Status Reigser FF00h (R)
+ */
+#define ONENAND_ECC_1BIT               (1 << 0)
+#define ONENAND_ECC_2BIT               (1 << 1)
+#define ONENAND_ECC_2BIT_ALL           (0xAAAA)
+
+#endif /* __ONENAND_REG_H */
index 50b2edfc8f11d8d44ac3dc8e62aae217c0a3a6d2..b03f512d51b9c96d865cebd5cf4cb85596b4d436 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: partitions.h,v 1.16 2004/11/16 18:34:40 dwmw2 Exp $
+ * $Id: partitions.h,v 1.17 2005/11/07 11:14:55 gleixner Exp $
  */
 
 #ifndef MTD_PARTITIONS_H
 
 /*
  * Partition definition structure:
- * 
+ *
  * An array of struct partition is passed along with a MTD object to
  * add_mtd_partitions() to create them.
  *
  * For each partition, these fields are available:
  * name: string that will be used to label the partition's MTD device.
- * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition 
+ * size: the partition size; if defined as MTDPART_SIZ_FULL, the partition
  *     will extend to the end of the master MTD device.
- * offset: absolute starting position within the master MTD device; if 
- *     defined as MTDPART_OFS_APPEND, the partition will start where the 
+ * offset: absolute starting position within the master MTD device; if
+ *     defined as MTDPART_OFS_APPEND, the partition will start where the
  *     previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block.
- * mask_flags: contains flags that have to be masked (removed) from the 
+ * mask_flags: contains flags that have to be masked (removed) from the
  *     master MTD flag set for the corresponding MTD partition.
- *     For example, to force a read-only partition, simply adding 
+ *     For example, to force a read-only partition, simply adding
  *     MTD_WRITEABLE to the mask_flags will do the trick.
  *
- * Note: writeable partitions require their size and offset be 
+ * Note: writeable partitions require their size and offset be
  * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
- */ 
+ */
 
 struct mtd_partition {
        char *name;                     /* identifier string */
@@ -66,7 +66,7 @@ struct mtd_part_parser {
 
 extern int register_mtd_parser(struct mtd_part_parser *parser);
 extern int deregister_mtd_parser(struct mtd_part_parser *parser);
-extern int parse_mtd_partitions(struct mtd_info *master, const char **types, 
+extern int parse_mtd_partitions(struct mtd_info *master, const char **types,
                                struct mtd_partition **pparts, unsigned long origin);
 
 #define put_partition_parser(p) do { module_put((p)->owner); } while(0)
index 05aa4970677f6aaeab52b68191f09ebef98abe2d..c7b8bcdef013bfd6629a62cf8899ac5153305a82 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * For boards with physically mapped flash and using 
+ * For boards with physically mapped flash and using
  * drivers/mtd/maps/physmap.c mapping driver.
  *
- * $Id: physmap.h,v 1.3 2004/07/21 00:16:15 jwboyer Exp $
+ * $Id: physmap.h,v 1.4 2005/11/07 11:14:55 gleixner Exp $
  *
  * Copyright (C) 2003 MontaVista Software Inc.
  * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
@@ -18,7 +18,7 @@
 
 #include <linux/config.h>
 
-#if defined(CONFIG_MTD_PHYSMAP) 
+#if defined(CONFIG_MTD_PHYSMAP)
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -44,12 +44,12 @@ static inline void physmap_configure(unsigned long addr, unsigned long size, int
 #if defined(CONFIG_MTD_PARTITIONS)
 
 /*
- * Machines that wish to do flash partition may want to call this function in 
- * their setup routine.  
+ * Machines that wish to do flash partition may want to call this function in
+ * their setup routine.
  *
  *     physmap_set_partitions(mypartitions, num_parts);
  *
- * Note that one can always override this hard-coded partition with 
+ * Note that one can always override this hard-coded partition with
  * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS).
  */
 void physmap_set_partitions(struct mtd_partition *parts, int num_parts);
index 113e3087f68a74a8d5a12856d0832b3828295bf1..a7f6d20ad407bf7dcbb5859ed6dc78a6a2cfc7d7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $
+ * $Id: pmc551.h,v 1.6 2005/11/07 11:14:55 gleixner Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
@@ -7,7 +7,7 @@
  *       Mark Ferrell
  *       Copyright 1999,2000 Nortel Networks
  *
- * License: 
+ * License:
  *      As part of this driver was derrived from the slram.c driver it falls
  *      under the same license, which is GNU General Public License v2
  */
@@ -17,7 +17,7 @@
 
 #include <linux/mtd/mtd.h>
 
-#define PMC551_VERSION "$Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $\n"\
+#define PMC551_VERSION "$Id: pmc551.h,v 1.6 2005/11/07 11:14:55 gleixner Exp $\n"\
        "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"
 
 /*
@@ -30,7 +30,7 @@ struct mypriv {
         u32    curr_map0;
         u32    asize;
        struct mtd_info *nextpmc551;
-};                       
+};
 
 /*
  * Function Prototypes
@@ -39,7 +39,7 @@ static int pmc551_erase(struct mtd_info *, struct erase_info *);
 static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
 static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
 static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);        
+static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 
 
 /*
@@ -50,7 +50,7 @@ static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_cha
 #endif
 
 #ifndef PCI_DEVICE_ID_V3_SEMI_V370PDC
-#define PCI_DEVICE_ID_V3_SEMI_V370PDC     0x0200  
+#define PCI_DEVICE_ID_V3_SEMI_V370PDC     0x0200
 #endif
 
 
index 7b7deef6b180a920fd491f1d1d1660cf2b848745..220d50bb71cd06bd86625e55b98fc77a03543598 100644 (file)
@@ -12,7 +12,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $
+ * $Id: xip.h,v 1.5 2005/11/07 11:14:55 gleixner Exp $
  */
 
 #ifndef __LINUX_MTD_XIP_H__
 
 #ifdef CONFIG_MTD_XIP
 
-/*
- * Function that are modifying the flash state away from array mode must
- * obviously not be running from flash.  The __xipram is therefore marking
- * those functions so they get relocated to ram.
- */
-#define __xipram __attribute__ ((__section__ (".data")))
-
 /*
  * We really don't want gcc to guess anything.
  * We absolutely _need_ proper inlining.
  */
 #include <linux/compiler.h>
 
+/*
+ * Function that are modifying the flash state away from array mode must
+ * obviously not be running from flash.  The __xipram is therefore marking
+ * those functions so they get relocated to ram.
+ */
+#define __xipram noinline __attribute__ ((__section__ (".data")))
+
 /*
  * Each architecture has to provide the following macros.  They must access
  * the hardware directly and not rely on any other (XIP) functions since they
@@ -60,9 +60,9 @@
  *             overflowing.
  *
  * xip_iprefetch()
- *  
+ *
  *      Macro to fill instruction prefetch
- *     e.g. a series of nops:  asm volatile (".rep 8; nop; .endr"); 
+ *     e.g. a series of nops:  asm volatile (".rep 8; nop; .endr");
  */
 
 #include <asm/mtd-xip.h>
index 980c8f74d8dc3d4dcce517720fd686c725241c10..ace25acfdc97375d0d403afb4bf12c08443e6309 100644 (file)
@@ -1,15 +1,15 @@
-/* 
+/*
  * include/linux/rslib.h
  *
  * Overview:
  *   Generic Reed Solomon encoder / decoder library
- *   
+ *
  * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
  *
  * RS code lifted from reed solomon library written by Phil Karn
  * Copyright 2002 Phil Karn, KA9Q
  *
- * $Id: rslib.h,v 1.3 2004/10/05 22:08:22 gleixner Exp $
+ * $Id: rslib.h,v 1.4 2005/11/07 11:14:52 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
 
 #include <linux/list.h>
 
-/** 
+/**
  * struct rs_control - rs control structure
- * 
+ *
  * @mm:                Bits per symbol
  * @nn:                Symbols per block (= (1<<mm)-1)
  * @alpha_to:  log lookup table
  * @index_of:  Antilog lookup table
- * @genpoly:   Generator polynomial 
+ * @genpoly:   Generator polynomial
  * @nroots:    Number of generator roots = number of parity symbols
  * @fcr:       First consecutive root, index form
- * @prim:      Primitive element, index form 
- * @iprim:     prim-th root of 1, index form 
- * @gfpoly:    The primitive generator polynominal 
- * @users:     Users of this structure 
+ * @prim:      Primitive element, index form
+ * @iprim:     prim-th root of 1, index form
+ * @gfpoly:    The primitive generator polynominal
+ * @users:     Users of this structure
  * @list:      List entry for the rs control list
 */
 struct rs_control {
@@ -58,7 +58,7 @@ int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
               uint16_t invmsk);
 #endif
 #ifdef CONFIG_REED_SOLOMON_DEC8
-int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len, 
+int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
                uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
               uint16_t *corr);
 #endif
@@ -75,7 +75,7 @@ int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
 #endif
 
 /* Create or get a matching rs control structure */
-struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, 
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                           int nroots);
 
 /* Release a rs control structure */
@@ -87,9 +87,9 @@ void free_rs(struct rs_control *rs);
  *  @x:                the value to reduce
  *
  *  where
- *  rs->mm = number of bits per symbol 
+ *  rs->mm = number of bits per symbol
  *  rs->nn = (2^rs->mm) - 1
- *  
+ *
  *  Simple arithmetic modulo would return a wrong result for values
  *  >= 3 * rs->nn
 */
index bda4f2c8f7284d67848aab6dbd3c60be4f6ef6fe..9b1e2526b45ec2be45e58768f8ad3e801dc8dcd5 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: inftl-user.h,v 1.1 2004/05/05 15:17:00 dwmw2 Exp $
+ * $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
  *
- * Parts of INFTL headers shared with userspace 
+ * Parts of INFTL headers shared with userspace
  *
  */
 
index 428d9122940b131dd4450edbd45e614ba70de33d..b5994ea56a5a19ba6aae6f297e370ea9bd1b4d60 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: mtd-abi.h,v 1.11 2005/05/19 16:08:58 gleixner Exp $
+ * $Id: mtd-abi.h,v 1.13 2005/11/07 11:14:56 gleixner Exp $
  *
- * Portions of MTD ABI definition which are shared by kernel and user space 
+ * Portions of MTD ABI definition which are shared by kernel and user space
  */
 
 #ifndef __MTD_ABI_H__
@@ -42,6 +42,7 @@ struct mtd_oob_buf {
 #define MTD_OOB                        64      // Out-of-band data (NAND flash)
 #define MTD_ECC                        128     // Device capable of automatic ECC
 #define MTD_NO_VIRTBLOCKS      256     // Virtual blocks not allowed
+#define MTD_PROGRAM_REGIONS    512     // Configurable Programming Regions
 
 // Some common devices / combinations of capabilities
 #define MTD_CAP_ROM            0
@@ -80,7 +81,7 @@ struct mtd_info_user {
 };
 
 struct region_info_user {
-       uint32_t offset;                /* At which this region starts, 
+       uint32_t offset;                /* At which this region starts,
                                         * from the beginning of the MTD */
        uint32_t erasesize;             /* For this region */
        uint32_t numblocks;             /* Number of blocks in this region */
index 924ec0459e9c09600ce2820954cdf9b4c8b14eb4..b2bca18e7311bf1670271b3cf5988b0c933278fe 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $Id: nftl-user.h,v 1.1 2004/05/05 14:44:57 dwmw2 Exp $
+ * $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
  *
- * Parts of NFTL headers shared with userspace 
+ * Parts of NFTL headers shared with userspace
  *
  */
 
index 747a2de293465943d1e68cd233d0b07051360c90..c3d7136827edd9ec7d44b44a59ad3910b1a7d0e7 100644 (file)
@@ -1,5 +1,5 @@
 #
-# This is a modified version of reed solomon lib, 
+# This is a modified version of reed solomon lib,
 #
 
 obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o
index d401decd62890ba52e135659e279b139fbe385ab..a58df56f09b6093f06a038f9a38675936ec3fa88 100644 (file)
@@ -1,22 +1,22 @@
-/* 
+/*
  * lib/reed_solomon/decode_rs.c
  *
  * Overview:
  *   Generic Reed Solomon encoder / decoder library
- *   
+ *
  * Copyright 2002, Phil Karn, KA9Q
  * May be used under the terms of the GNU General Public License (GPL)
  *
  * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
  *
- * $Id: decode_rs.c,v 1.6 2004/10/22 15:41:47 gleixner Exp $
+ * $Id: decode_rs.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $
  *
  */
 
-/* Generic data width independent code which is included by the 
+/* Generic data width independent code which is included by the
  * wrappers.
  */
-{ 
+{
        int deg_lambda, el, deg_omega;
        int i, j, r, k, pad;
        int nn = rs->nn;
@@ -41,9 +41,9 @@
        pad = nn - nroots - len;
        if (pad < 0 || pad >= nn)
                return -ERANGE;
-               
+
        /* Does the caller provide the syndrome ? */
-       if (s != NULL) 
+       if (s != NULL)
                goto decode;
 
        /* form the syndromes; i.e., evaluate data(x) at roots of
        for (j = 1; j < len; j++) {
                for (i = 0; i < nroots; i++) {
                        if (syn[i] == 0) {
-                               syn[i] = (((uint16_t) data[j]) ^ 
+                               syn[i] = (((uint16_t) data[j]) ^
                                          invmsk) & msk;
                        } else {
                                syn[i] = ((((uint16_t) data[j]) ^
-                                          invmsk) & msk) ^ 
+                                          invmsk) & msk) ^
                                        alpha_to[rs_modnn(rs, index_of[syn[i]] +
                                                       (fcr + i) * prim)];
                        }
@@ -70,7 +70,7 @@
                        if (syn[i] == 0) {
                                syn[i] = ((uint16_t) par[j]) & msk;
                        } else {
-                               syn[i] = (((uint16_t) par[j]) & msk) ^ 
+                               syn[i] = (((uint16_t) par[j]) & msk) ^
                                        alpha_to[rs_modnn(rs, index_of[syn[i]] +
                                                       (fcr+i)*prim)];
                        }
 
        if (no_eras > 0) {
                /* Init lambda to be the erasure locator polynomial */
-               lambda[1] = alpha_to[rs_modnn(rs, 
+               lambda[1] = alpha_to[rs_modnn(rs,
                                              prim * (nn - 1 - eras_pos[0]))];
                for (i = 1; i < no_eras; i++) {
                        u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
                        for (j = i + 1; j > 0; j--) {
                                tmp = index_of[lambda[j - 1]];
                                if (tmp != nn) {
-                                       lambda[j] ^= 
+                                       lambda[j] ^=
                                                alpha_to[rs_modnn(rs, u + tmp)];
                                }
                        }
                discr_r = 0;
                for (i = 0; i < r; i++) {
                        if ((lambda[i] != 0) && (s[r - i - 1] != nn)) {
-                               discr_r ^= 
-                                       alpha_to[rs_modnn(rs, 
+                               discr_r ^=
+                                       alpha_to[rs_modnn(rs,
                                                          index_of[lambda[i]] +
                                                          s[r - i - 1])];
                        }
                        t[0] = lambda[0];
                        for (i = 0; i < nroots; i++) {
                                if (b[i] != nn) {
-                                       t[i + 1] = lambda[i + 1] ^ 
+                                       t[i + 1] = lambda[i + 1] ^
                                                alpha_to[rs_modnn(rs, discr_r +
                                                                  b[i])];
                                } else
                num1 = 0;
                for (i = deg_omega; i >= 0; i--) {
                        if (omega[i] != nn)
-                               num1 ^= alpha_to[rs_modnn(rs, omega[i] + 
+                               num1 ^= alpha_to[rs_modnn(rs, omega[i] +
                                                        i * root[j])];
                }
                num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
                 * lambda_pr of lambda[i] */
                for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) {
                        if (lambda[i + 1] != nn) {
-                               den ^= alpha_to[rs_modnn(rs, lambda[i + 1] + 
+                               den ^= alpha_to[rs_modnn(rs, lambda[i + 1] +
                                                       i * root[j])];
                        }
                }
                /* Apply error to data */
                if (num1 != 0 && loc[j] >= pad) {
-                       uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + 
+                       uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] +
                                                       index_of[num2] +
                                                       nn - index_of[den])];
                        /* Store the error correction pattern, if a
index 237bf65ae88688935bfc7a2d1da209d645ec4ef3..0b5b1a6728ec03892078689ab6f651ab873550d5 100644 (file)
@@ -1,19 +1,19 @@
-/* 
+/*
  * lib/reed_solomon/encode_rs.c
  *
  * Overview:
  *   Generic Reed Solomon encoder / decoder library
- *   
+ *
  * Copyright 2002, Phil Karn, KA9Q
  * May be used under the terms of the GNU General Public License (GPL)
  *
  * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
  *
- * $Id: encode_rs.c,v 1.4 2004/10/22 15:41:47 gleixner Exp $
+ * $Id: encode_rs.c,v 1.5 2005/11/07 11:14:59 gleixner Exp $
  *
  */
 
-/* Generic data width independent code which is included by the 
+/* Generic data width independent code which is included by the
  * wrappers.
  * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par)
  */
        for (i = 0; i < len; i++) {
                fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]];
                /* feedback term is non-zero */
-               if (fb != nn) { 
+               if (fb != nn) {
                        for (j = 1; j < nroots; j++) {
-                               par[j] ^= alpha_to[rs_modnn(rs, fb + 
+                               par[j] ^= alpha_to[rs_modnn(rs, fb +
                                                         genpoly[nroots - j])];
                        }
                }
                /* Shift */
                memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1));
                if (fb != nn) {
-                       par[nroots - 1] = alpha_to[rs_modnn(rs, 
+                       par[nroots - 1] = alpha_to[rs_modnn(rs,
                                                            fb + genpoly[0])];
                } else {
                        par[nroots - 1] = 0;
index 6604e3b1940c191cde247723e5bb436450f549ce..f5fef948a415e0cb3118b0a22eaab4f374e044b3 100644 (file)
@@ -1,22 +1,22 @@
-/* 
+/*
  * lib/reed_solomon/rslib.c
  *
  * Overview:
  *   Generic Reed Solomon encoder / decoder library
- *   
+ *
  * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
  *
  * Reed Solomon code lifted from reed solomon library written by Phil Karn
  * Copyright 2002 Phil Karn, KA9Q
  *
- * $Id: rslib.c,v 1.5 2004/10/22 15:41:47 gleixner Exp $
+ * $Id: rslib.c,v 1.7 2005/11/07 11:14: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
  * published by the Free Software Foundation.
  *
  * Description:
- *     
+ *
  * The generic Reed Solomon library provides runtime configurable
  * encoding / decoding of RS codes.
  * Each user must call init_rs to get a pointer to a rs_control
  * If a structure is generated then the polynomial arrays for
  * fast encoding / decoding are built. This can take some time so
  * make sure not to call this function from a time critical path.
- * Usually a module / driver should initialize the necessary 
+ * Usually a module / driver should initialize the necessary
  * rs_control structure on module / driver init and release it
  * on exit.
- * The encoding puts the calculated syndrome into a given syndrome 
- * buffer. 
+ * The encoding puts the calculated syndrome into a given syndrome
+ * buffer.
  * The decoding is a two step process. The first step calculates
  * the syndrome over the received (data + syndrome) and calls the
  * second stage, which does the decoding / error correction itself.
@@ -51,7 +51,7 @@ static LIST_HEAD (rslist);
 /* Protection for the list */
 static DECLARE_MUTEX(rslistlock);
 
-/** 
+/**
  * rs_init - Initialize a Reed-Solomon codec
  *
  * @symsize:   symbol size, bits (1-8)
@@ -63,7 +63,7 @@ static DECLARE_MUTEX(rslistlock);
  * Allocate a control structure and the polynom arrays for faster
  * en/decoding. Fill the arrays according to the given parameters
  */
-static struct rs_control *rs_init(int symsize, int gfpoly, int fcr, 
+static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
                                   int prim, int nroots)
 {
        struct rs_control *rs;
@@ -124,15 +124,15 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
                /* Multiply rs->genpoly[] by  @**(root + x) */
                for (j = i; j > 0; j--) {
                        if (rs->genpoly[j] != 0) {
-                               rs->genpoly[j] = rs->genpoly[j -1] ^ 
-                                       rs->alpha_to[rs_modnn(rs, 
+                               rs->genpoly[j] = rs->genpoly[j -1] ^
+                                       rs->alpha_to[rs_modnn(rs,
                                        rs->index_of[rs->genpoly[j]] + root)];
                        } else
                                rs->genpoly[j] = rs->genpoly[j - 1];
                }
                /* rs->genpoly[0] can never be zero */
-               rs->genpoly[0] = 
-                       rs->alpha_to[rs_modnn(rs, 
+               rs->genpoly[0] =
+                       rs->alpha_to[rs_modnn(rs,
                                rs->index_of[rs->genpoly[0]] + root)];
        }
        /* convert rs->genpoly[] to index form for quicker encoding */
@@ -153,7 +153,7 @@ errrs:
 }
 
 
-/** 
+/**
  *  free_rs - Free the rs control structure, if its not longer used
  *
  *  @rs:       the control structure which is not longer used by the
@@ -173,19 +173,19 @@ void free_rs(struct rs_control *rs)
        up(&rslistlock);
 }
 
-/** 
+/**
  * init_rs - Find a matching or allocate a new rs control structure
  *
  *  @symsize:  the symbol size (number of bits)
  *  @gfpoly:   the extended Galois field generator polynomial coefficients,
  *             with the 0th coefficient in the low order bit. The polynomial
  *             must be primitive;
- *  @fcr:      the first consecutive root of the rs code generator polynomial 
+ *  @fcr:      the first consecutive root of the rs code generator polynomial
  *             in index form
  *  @prim:     primitive element to generate polynomial roots
  *  @nroots:   RS code generator polynomial degree (number of roots)
  */
-struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim, 
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                           int nroots)
 {
        struct list_head        *tmp;
@@ -198,9 +198,9 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                return NULL;
        if (prim <= 0 || prim >= (1<<symsize))
                return NULL;
-       if (nroots < 0 || nroots >= (1<<symsize) || nroots > 8)
+       if (nroots < 0 || nroots >= (1<<symsize))
                return NULL;
-       
+
        down(&rslistlock);
 
        /* Walk through the list and look for a matching entry */
@@ -211,9 +211,9 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                if (gfpoly != rs->gfpoly)
                        continue;
                if (fcr != rs->fcr)
-                       continue;       
+                       continue;
                if (prim != rs->prim)
-                       continue;       
+                       continue;
                if (nroots != rs->nroots)
                        continue;
                /* We have a matching one already */
@@ -227,18 +227,18 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
                rs->users = 1;
                list_add(&rs->list, &rslist);
        }
-out:   
+out:
        up(&rslistlock);
        return rs;
 }
 
 #ifdef CONFIG_REED_SOLOMON_ENC8
-/** 
+/**
  *  encode_rs8 - Calculate the parity for data values (8bit data width)
  *
  *  @rs:       the rs control structure
  *  @data:     data field of a given type
- *  @len:      data length 
+ *  @len:      data length
  *  @par:      parity data, must be initialized by caller (usually all 0)
  *  @invmsk:   invert data mask (will be xored on data)
  *
@@ -246,7 +246,7 @@ out:
  *  symbol size > 8. The calling code must take care of encoding of the
  *  syndrome result for storage itself.
  */
-int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par, 
+int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
               uint16_t invmsk)
 {
 #include "encode_rs.c"
@@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(encode_rs8);
 #endif
 
 #ifdef CONFIG_REED_SOLOMON_DEC8
-/** 
+/**
  *  decode_rs8 - Decode codeword (8bit data width)
  *
  *  @rs:       the rs control structure
@@ -273,7 +273,7 @@ EXPORT_SYMBOL_GPL(encode_rs8);
  *  syndrome result and the received parity before calling this code.
  */
 int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
-              uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, 
+              uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
               uint16_t *corr)
 {
 #include "decode_rs.c"
@@ -287,13 +287,13 @@ EXPORT_SYMBOL_GPL(decode_rs8);
  *
  *  @rs:       the rs control structure
  *  @data:     data field of a given type
- *  @len:      data length 
+ *  @len:      data length
  *  @par:      parity data, must be initialized by caller (usually all 0)
  *  @invmsk:   invert data mask (will be xored on data, not on parity!)
  *
  *  Each field in the data array contains up to symbol size bits of valid data.
  */
-int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par, 
+int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
        uint16_t invmsk)
 {
 #include "encode_rs.c"
@@ -302,7 +302,7 @@ EXPORT_SYMBOL_GPL(encode_rs16);
 #endif
 
 #ifdef CONFIG_REED_SOLOMON_DEC16
-/** 
+/**
  *  decode_rs16 - Decode codeword (16bit data width)
  *
  *  @rs:       the rs control structure
@@ -312,13 +312,13 @@ EXPORT_SYMBOL_GPL(encode_rs16);
  *  @s:                syndrome data field (if NULL, syndrome is calculated)
  *  @no_eras:  number of erasures
  *  @eras_pos: position of erasures, can be NULL
- *  @invmsk:   invert data mask (will be xored on data, not on parity!) 
+ *  @invmsk:   invert data mask (will be xored on data, not on parity!)
  *  @corr:     buffer to store correction bitmask on eras_pos
  *
  *  Each field in the data array contains up to symbol size bits of valid data.
  */
 int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
-               uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, 
+               uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
                uint16_t *corr)
 {
 #include "decode_rs.c"