bk://linux-mtd.bkbits.net/mtd-2.6
dedekind@infradead.org|ChangeSet|20041129225833|54013 dedekind

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/11/29 20:22:56-08:00 akpm@bix.(none) 
#   Merge bk://linux-mtd.bkbits.net/mtd-2.6 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/11/29 20:22:53-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/29 20:20:14-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/11/29 20:20:10-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/29 22:58:33+00:00 dedekind@infradead.org 
#   JFFS2: jffs2_get_inode_nodes(): Remove gratuitous memset on new nodes.
#   
#   We're about to set every field in the node structure. No need to spend
#   time filling it with zeroes. This is a fairly hot path.
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/nodelist.c
#   2004/11/29 22:58:12+00:00 dedekind@infradead.org +2 -2
#   Remove unneeded memset
# 
# ChangeSet
#   2004/11/29 22:55:00+00:00 dedekind@infradead.org 
#   JFFS2: Include vmalloc.h to fix compile warning.
#   
#   The previous fixes to use vmalloc for the eraseblock array missed it.
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/fs.c
#   2004/11/29 22:54:38+00:00 dedekind@infradead.org +2 -1
#   Include vmalloc.h header to prevent warning.
# 
# ChangeSet
#   2004/11/29 22:43:46+00:00 bunk@stusta.de 
#   MTD: Use select in Kconfig where appropriate.
#   
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/nand/Kconfig
#   2004/11/29 22:43:24+00:00 bunk@stusta.de +2 -3
#   The patch below switches options to use select where appropriate.
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
# 
# drivers/mtd/devices/Kconfig
#   2004/11/29 22:43:24+00:00 bunk@stusta.de +8 -9
#   The patch below switches options to use select where appropriate.
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
# 
# drivers/mtd/chips/Kconfig
#   2004/11/29 22:43:24+00:00 bunk@stusta.de +6 -5
#   The patch below switches options to use select where appropriate.
#   Signed-off-by: Adrian Bunk <bunk@stusta.de>
# 
# ChangeSet
#   2004/11/29 22:34:26+00:00 dwmw2@shinybook.infradead.org 
#   Merge linux-mtd@bkbits.net:mtd-2.6
#   into shinybook.infradead.org:/home/dwmw2/bk/mtd-2.6
# 
# MAINTAINERS
#   2004/11/29 22:34:18+00:00 dwmw2@shinybook.infradead.org +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/28 22:06:36-08:00 akpm@bix.(none) 
#   Merge bk://linux-mtd.bkbits.net/mtd-2.6 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/11/28 22:06:32-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/28 19:18:16+00:00 dwmw2@dwmw2.baythorne.internal 
#   Merge dwmw2.baythorne.internal:/inst/bk/linus-2.6
#   into dwmw2.baythorne.internal:/inst/bk/mtd-2.6
# 
# drivers/mtd/maps/ts5500_flash.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -4
#   Auto merged
# 
# drivers/mtd/maps/scx200_docflash.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -2
#   Auto merged
# 
# drivers/mtd/maps/scb2_flash.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -2
#   Auto merged
# 
# drivers/mtd/maps/sc520cdp.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -6
#   Auto merged
# 
# drivers/mtd/maps/sbc_gxx.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -2
#   Auto merged
# 
# drivers/mtd/maps/physmap.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3
#   Auto merged
# 
# drivers/mtd/maps/pci.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3
#   Auto merged
# 
# drivers/mtd/maps/nettel.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -2
#   Auto merged
# 
# drivers/mtd/maps/netsc520.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3
#   Auto merged
# 
# drivers/mtd/maps/l440gx.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3
#   Auto merged
# 
# drivers/mtd/maps/ichxrom.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3
#   Auto merged
# 
# drivers/mtd/maps/elan-104nc.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -1
#   Auto merged
# 
# drivers/mtd/maps/ebony.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -6
#   Auto merged
# 
# drivers/mtd/maps/dilnetpc.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3
#   Auto merged
# 
# drivers/mtd/maps/amd76xrom.c
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3
#   Auto merged
# 
# MAINTAINERS
#   2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/28 19:16:07+00:00 dwmw2@dwmw2.baythorne.internal 
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/maps/ts5500_flash.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +5 -5
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/scx200_docflash.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +3 -3
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/scb2_flash.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +3 -3
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/sc520cdp.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +7 -7
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/sbc_gxx.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +3 -3
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/physmap.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/pci.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/nettel.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +3 -3
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/netsc520.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/l440gx.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/ichxrom.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/elan-104nc.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +2 -2
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/ebony.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +7 -8
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/dilnetpc.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# drivers/mtd/maps/amd76xrom.c
#   2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4
#           NULL noise removal, missing __iomem in a couple of declarations,
#   removal of bogus cast to void * in iounmap() calls.
#   Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
# 
# ChangeSet
#   2004/11/28 00:40:38+00:00 dwmw2@shinybook.infradead.org 
#   Merge shinybook.infradead.org:/home/dwmw2/bk/linus-2.6
#   into shinybook.infradead.org:/home/dwmw2/bk/mtd-2.6
# 
# MAINTAINERS
#   2004/11/28 00:40:30+00:00 dwmw2@shinybook.infradead.org +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/28 00:33:43+00:00 dwmw2@shinybook.infradead.org 
#   rslib: Spelling fixes.
#   
#   Some of the fixes from Joe Perches <joe@perches.com> got missed out
#   of the last update.
#   
#   Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# lib/reed_solomon/reed_solomon.c
#   2004/11/28 00:33:19+00:00 dwmw2@shinybook.infradead.org +8 -8
#   revision 1.5
#   date: 2004/10/22 15:41:47;  author: gleixner;  state: Exp;  lines: +8 -8
#   Joe Perches <joe@perches.com> provided the spelling and
#   grammar fixes for Documentation.
#   I'm happy if somebody takes care of my language related
#   nescience. :)
# 
# ChangeSet
#   2004/11/28 00:19:24+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Allow NAND driver to disable virtual eraseblocks.
#   
#   In order to keep the RAM usage down with large devices and smaller
#   erase block sizes, we were using blocks in JFFS2 larger than the 
#   physical erase size. This means that bad blocks lose a lot more space
#   though; allow it to be disabled.
#   
#   Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# include/mtd/mtd-abi.h
#   2004/11/28 00:19:02+00:00 dwmw2@shinybook.infradead.org +2 -1
#   revision 1.7
#   date: 2004/11/23 15:37:32;  author: gleixner;  state: Exp;  lines: +2 -1
#   Disable virtual eraseblocks on request (MTD_NO_VIRTBLOCKS) is set. Be careful this can eat up a lot of memory
# 
# fs/jffs2/super.c
#   2004/11/28 00:19:01+00:00 dwmw2@shinybook.infradead.org +5 -2
#   revision 1.104
#   date: 2004/11/23 15:37:31;  author: gleixner;  state: Exp;  lines: +5 -2
#   Disable virtual eraseblocks on request (MTD_NO_VIRTBLOCKS) is set. Be careful this can eat up a lot of memory
# 
# fs/jffs2/fs.c
#   2004/11/28 00:19:01+00:00 dwmw2@shinybook.infradead.org +12 -7
#   revision 1.50
#   date: 2004/11/23 15:37:31;  author: gleixner;  state: Exp;  lines: +12 -7
#   Disable virtual eraseblocks on request (MTD_NO_VIRTBLOCKS) is set. Be careful this can eat up a lot of memory
# 
# fs/jffs2/build.c
#   2004/11/28 00:19:01+00:00 dwmw2@shinybook.infradead.org +7 -2
#   revision 1.68
#   date: 2004/11/27 13:38:10;  author: gleixner;  state: Exp;  lines: +3 -1
#   include headers to make it build
#   ----------------------------
#   revision 1.67
#   date: 2004/11/23 15:37:31;  author: gleixner;  state: Exp;  lines: +5 -2
#   Disable virtual eraseblocks on request (MTD_NO_VIRTBLOCKS) is set. Be careful this can eat up a lot of memory
# 
# ChangeSet
#   2004/11/28 00:15:04+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Split eraseblock refiling into separate function
#   
#   ...in preparation for further cleanups from Estelle Hammache which
#   will need to call it from elsewhere.
#   
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/wbuf.c
#   2004/11/28 00:14:42+00:00 dwmw2@shinybook.infradead.org +21 -16
#   revision 1.82
#   date: 2004/11/20 22:08:31;  author: dwmw2;  state: Exp;  lines: +21 -16
#   separate out block refiling
# 
# ChangeSet
#   2004/11/28 00:11:59+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Initialise bad_count for each eraseblock correctly.
#   
#   Patch from Estelle Hammache <estelle.hammache@st.com>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/build.c
#   2004/11/28 00:11:36+00:00 dwmw2@shinybook.infradead.org +2 -1
#   revision 1.66
#   date: 2004/11/20 19:18:07;  author: dwmw2;  state: Exp;  lines: +2 -1
#   Patch from Estelle Hammache: initialise bad_count.
# 
# ChangeSet
#   2004/11/28 00:07:08+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Various fixes for recent RAM use reduction.
#   
#   We recently started trying to merge the jffs2_raw_node_ref structures
#   for adjacent obsolete nodes. Fix a bunch of problems in that:
#    - Free inode cache structure for a dead inode which is now completely gone.
#    - Fix races vs. erase code which also walks the same lists.
#    - Fix BUG() when trying to merge with a node which still belongs to an inode.
#   
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/nodemgmt.c
#   2004/11/28 00:06:46+00:00 dwmw2@shinybook.infradead.org +60 -16
#   revision 1.115
#   date: 2004/11/22 11:07:21;  author: dwmw2;  state: Exp;  lines: +5 -5
#   Fix another bug in the merging of obsolete nodes
#   ----------------------------
#   revision 1.114
#   date: 2004/11/20 16:39:59;  author: dwmw2;  state: Exp;  lines: +6 -2
#   Add another reason why we can't currently merge obsolete node refs on
#   NAND.
#   ----------------------------
#   revision 1.113
#   date: 2004/11/20 16:25:19;  author: dwmw2;  state: Exp;  lines: +7 -1
#   Free inocache if it's all gone.
#   ----------------------------
#   revision 1.112
#   date: 2004/11/20 14:25:05;  author: dwmw2;  state: Exp;  lines: +46 -12
#   Fix race in jffs2_mark_node_obsolete(). There was nothing preventing the
#   block from being erased and 'ref' from being freed before we even got
#   around to marking it obsolete and then trying to merge nodes.
# 
# fs/jffs2/build.c
#   2004/11/28 00:06:46+00:00 dwmw2@shinybook.infradead.org +5 -2
#   revision 1.65
#   date: 2004/11/20 16:19:38;  author: dwmw2;  state: Exp;  lines: +5 -2
#   Fix freeing of refs belonging to unlinked inode
# 
# ChangeSet
#   2004/11/27 23:58:00+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Fix oops in read_inode.
#   
#   If the node with lowest version in a file was in the range
#   0xfffff000 onwards, we oopsed because our rounding was bogus.
#   
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/readinode.c
#   2004/11/27 23:57:39+00:00 dwmw2@shinybook.infradead.org +2 -2
#   revision 1.117
#   date: 2004/11/20 18:06:54;  author: dwmw2;  state: Exp;  lines: +2 -2
#   Fix oops if we happen to have a node in the range 0xfffff000 onwards as the
#   lowest versioned node in the inode.
# 
# ChangeSet
#   2004/11/27 23:36:47+00:00 dwmw2@shinybook.infradead.org 
#   MTD: NAND flash simulator
#   
#   We want to contribute the NAND flash simulator which we successfully use 
#   when developing JFFS2. It is very useful tool which helps to develop 
#   without real flash.
#   
#   It supports several options which allow to select which flash type to 
#   emulate (just flash IDs which are in nand_ids.c file). See modinfo for 
#   other options.
#   
#   Signed-off-by: Artem B. Bityuckiy <dedekind@yandex.ru>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/nand/nandsim.c
#   2004/11/27 23:36:22+00:00 dwmw2@shinybook.infradead.org +1619 -0
# 
# drivers/mtd/nand/nandsim.c
#   2004/11/27 23:36:22+00:00 dwmw2@shinybook.infradead.org +0 -0
#   BitKeeper file /home/dwmw2/bk/mtd-2.6/drivers/mtd/nand/nandsim.c
# 
# drivers/mtd/nand/Makefile
#   2004/11/27 23:36:22+00:00 dwmw2@shinybook.infradead.org +2 -1
#   revision 1.15
#   date: 2004/11/26 12:28:22;  author: dedekind;  state: Exp;  lines: +2 -1
#   Add the NAND simulator's records
# 
# drivers/mtd/nand/Kconfig
#   2004/11/27 23:36:22+00:00 dwmw2@shinybook.infradead.org +9 -1
#   revision 1.24
#   date: 2004/11/26 12:28:22;  author: dedekind;  state: Exp;  lines: +9 -1
#   Add the NAND simulator's records
# 
# ChangeSet
#   2004/11/27 23:18:34+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Support NOR and NAND flash on Sharp SL Series PDAs.
#   
#   Signed-off-by: Richard Purdie <rpurdie@rpsys.net>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/nand/sharpsl.c
#   2004/11/27 23:18:12+00:00 dwmw2@shinybook.infradead.org +273 -0
# 
# drivers/mtd/nand/sharpsl.c
#   2004/11/27 23:18:12+00:00 dwmw2@shinybook.infradead.org +0 -0
#   BitKeeper file /home/dwmw2/bk/mtd-2.6/drivers/mtd/nand/sharpsl.c
# 
# drivers/mtd/maps/sharpsl-flash.c
#   2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +101 -0
# 
# drivers/mtd/nand/Makefile
#   2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +2 -1
#   revision 1.14
#   date: 2004/11/24 19:33:56;  author: rpurdie;  state: Exp;  lines: +2 -1
#   Add the sharpsl nand driver. This supports the NAND chip on the Sharp SL Series
#   of PDAs.
# 
# drivers/mtd/nand/Kconfig
#   2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +6 -1
#   revision 1.23
#   date: 2004/11/24 19:33:56;  author: rpurdie;  state: Exp;  lines: +6 -1
#   Add the sharpsl nand driver. This supports the NAND chip on the Sharp SL Series
#   of PDAs.
# 
# drivers/mtd/maps/sharpsl-flash.c
#   2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +0 -0
#   BitKeeper file /home/dwmw2/bk/mtd-2.6/drivers/mtd/maps/sharpsl-flash.c
# 
# drivers/mtd/maps/Makefile
#   2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +2 -1
#   revision 1.20
#   date: 2004/11/24 19:42:51;  author: rpurdie;  state: Exp;  lines: +2 -1
#   Add mapping for the flash chip on Sharp SL Series PDAs.
# 
# drivers/mtd/maps/Kconfig
#   2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +7 -1
#   revision 1.38
#   date: 2004/11/24 19:42:51;  author: rpurdie;  state: Exp;  lines: +7 -1
#   Add mapping for the flash chip on Sharp SL Series PDAs.
# 
# ChangeSet
#   2004/11/27 23:02:48+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Fix timing setup for NAND flash on Samsung S3C2410.
#   
#   Spotted by Shannon Holland.
#   
#   Signed-off-by: Ben Dooks <ben@simtec.co.uk>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/nand/s3c2410.c
#   2004/11/27 23:02:28+00:00 dwmw2@shinybook.infradead.org +2 -2
#   revision 1.6
#   date: 2004/11/24 12:25:48;  author: bjd;  state: Exp;  lines: +2 -2
#   correct timing setup to use plat->twrph1 instead of
#   plat->twrph0 for timing setup for the NAND controllers
#   twrph1 configuration
#   
#   Thanks to Shannon Holland for pointing this out
# 
# ChangeSet
#   2004/11/27 22:59:41+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Fix oops on erase in NFTL/INFTL (again).
#   
#   Only this time, set the field we were dereferencing _after_ we zero it not before.
#   
#   Signed-off-by: Kalev Lember <kalev@colleduc.ee>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/nftlmount.c
#   2004/11/27 22:59:16+00:00 dwmw2@shinybook.infradead.org +3 -4
#   revision 1.40
#   date: 2004/11/22 14:38:29;  author: kalev;  state: Exp;  lines: +3 -4
#   fix oops
# 
# drivers/mtd/inftlmount.c
#   2004/11/27 22:59:16+00:00 dwmw2@shinybook.infradead.org +3 -4
#   revision 1.16
#   date: 2004/11/22 13:50:53;  author: kalev;  state: Exp;  lines: +3 -4
#   fix oops
#   (the instr was zeroed _after_  setting instr->mtd)
# 
# ChangeSet
#   2004/11/27 22:53:43+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Make phram work again
#   
#   o Add simple usage example.
#   o Fix up unit handling (k, M. G).
#   o Use correct size limit for setup string.
#   o Remove pointless printk message.
#   o Fix mtdblock to not allocate a read-modify-write buffer for CAP_RAM
#     devices (and fail to do so, returning an error).
#   
#   Signed-off-by: J�rn Engel <joern@wohnheim.fh-wedel.de>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/mtdblock.c
#   2004/11/27 22:53:20+00:00 dwmw2@shinybook.infradead.org +2 -2
#   revision 1.66
#   date: 2004/11/25 13:52:52;  author: joern;  state: Exp;  lines: +2 -2
#   Fix up slram and phram.
# 
# drivers/mtd/devices/phram.c
#   2004/11/27 22:53:20+00:00 dwmw2@shinybook.infradead.org +10 -6
#   revision 1.6
#   date: 2004/11/25 16:51:09;  author: joern;  state: Exp;  lines: +2 -2
#   Brown Paperbag category.  Patch should be self-explaining to anyone who
#   knows how to deal with multi-dimensional arrays in c (i.e. not me).
#   ----------------------------
#   revision 1.5
#   date: 2004/11/25 13:54:09;  author: joern;  state: Exp;  lines: +6 -4
#   Make dwmw2 happy and add an i to [kMG].
#   ----------------------------
#   revision 1.4
#   date: 2004/11/25 13:52:53;  author: joern;  state: Exp;  lines: +7 -5
#   Fix up slram and phram.
# 
# ChangeSet
#   2004/11/27 22:47:33+00:00 dwmw2@shinybook.infradead.org 
#   MTD: mtdpart_setup() is used from platform code. Remove 'static'.
#   
#   Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/cmdlinepart.c
#   2004/11/27 22:47:11+00:00 dwmw2@shinybook.infradead.org +4 -2
#   revision 1.17
#   date: 2004/11/26 11:18:47;  author: lavinen;  state: Exp;  lines: +4 -2
#   Changed mtdpart_setup() back to public,
# 
# ChangeSet
#   2004/11/27 22:42:45+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Fix RedBoot FIS table detection.
#   
#   The redboot partitioning code currently searches for a FIS table entry
#   named "RedBoot" (including the trailing \0) in one of the first three
#   entries to try and verify that the sector it is looking at really is a
#   FIS partition table.
#   
#   Firstly it fails when RedBoot is stored in some other Flash chip such as
#   a boot PROM, in this case there is no "RedBoot" entry in the partition
#   table. However there will always be a "FIS directory" entry in any valid
#   FIS directory.
#           
#   Secondly it can fail since the RedBoot entry is not always in the first
#   3 slots -- this can happen for example on an x86 based platform where
#   the processor expects the boot device to be at the top of memory rather
#   than the bottom and so RedBoot is at the end of the flash device.
#   Equally when using "FIS directory" as the entry to search for it very
#   likely is not in the first three since the directory is typically at the
#   end of the flash.
#   
#   Signed-off-by: Ian Campbell <icampbell@arcom.com>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/redboot.c
#   2004/11/27 22:42:22+00:00 dwmw2@shinybook.infradead.org +24 -8
#   revision 1.17
#   date: 2004/11/22 11:33:56;  author: ijc;  state: Exp;  lines: +14 -3
#   RedBoot has a compile time configuration option called
#   CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK. Add a similar option
#   to the redboot parsing code.
#   ----------------------------
#   revision 1.16
#   date: 2004/11/22 11:32:13;  author: ijc;  state: Exp;  lines: +11 -6
#   Search for a directory entry named "FIS directory" rather the "RedBoot"
#   since RedBoot can potentially be in another device but there should
#   always be a FIS directory present (or we wouldn't be looking for it...).
#   
#   Also search all blocks not just the first 3 since the directory is often at
#   the end of flash rather than the beginning.
# 
# drivers/mtd/Kconfig
#   2004/11/27 22:42:22+00:00 dwmw2@shinybook.infradead.org +20 -3
#   revision 1.7
#   date: 2004/11/22 11:33:56;  author: ijc;  state: Exp;  lines: +20 -3
#   RedBoot has a compile time configuration option called
#   CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK. Add a similar option
#   to the redboot parsing code.
# 
# ChangeSet
#   2004/11/27 13:26:24-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/11/27 13:26:19-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/20 12:53:46+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Use msleep() in cfi_udelay() helper function.
#   
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# include/linux/mtd/cfi.h
#   2004/11/20 12:53:23+00:00 dwmw2@shinybook.infradead.org +6 -8
#   revision 1.50
#   date: 2004/11/20 12:46:51;  author: dwmw2;  state: Exp;  lines: +6 -8
#   Fix cfi_udelay() to use msleep()
# 
# ChangeSet
#   2004/11/20 12:48:27+00:00 dwmw2@shinybook.infradead.org 
#   MTD NOR chip drivers: use msleep()
#   
#   Description: Use msleep() instead of schedule_timeout()
#   to guarantee the task delays as expected.
#   
#   Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
#   Signed-off-by: Maximilian Attems <janitor@sternwelten.at>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/chips/cfi_cmdset_0020.c
#   2004/11/20 12:48:03+00:00 dwmw2@shinybook.infradead.org +4 -4
#   Description: Use msleep() instead of schedule_timeout()
#   to guarantee the task delays as expected.
# 
# drivers/mtd/chips/cfi_cmdset_0002.c
#   2004/11/20 12:48:03+00:00 dwmw2@shinybook.infradead.org +3 -5
#   Description: Use msleep() instead of schedule_timeout()
#   to guarantee the task delays as expected.
# 
# drivers/mtd/chips/amd_flash.c
#   2004/11/20 12:48:02+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Description: Use msleep() instead of schedule_timeout()
#   to guarantee the task delays as expected.
# 
# ChangeSet
#   2004/11/20 12:25:45+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Fix race on read access to NAND write-buffer.
#   
#   With SMP or preempt, we could attempt to read data from the wbuf 
#   while it was being updated. Introduce a new rwsem to prevent this,
#   and update the documentation accordingly
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# include/linux/jffs2_fs_sb.h
#   2004/11/20 12:25:23+00:00 dwmw2@shinybook.infradead.org +5 -4
#   revision 1.48
#   date: 2004/11/20 10:41:12;  author: dwmw2;  state: Exp;  lines: +4 -2
#   include rwsem.h and make wbuf_sem nand-only
#   ----------------------------
#   revision 1.47
#   date: 2004/11/19 13:41:17;  author: dedekind;  state: Exp;  lines: +3 -4
#   Bugfix: fix the race bug when a writed and reader concurrently access
#   the wbuf. Introduce new rw semaphore to fix this.
# 
# fs/jffs2/wbuf.c
#   2004/11/20 12:25:23+00:00 dwmw2@shinybook.infradead.org +41 -19
#   revision 1.81
#   date: 2004/11/20 10:44:07;  author: dwmw2;  state: Exp;  lines: +3 -2
#   wbuf_sem is now nand-only
#   ----------------------------
#   revision 1.80
#   date: 2004/11/20 10:35:40;  author: dwmw2;  state: Exp;  lines: +23 -15
#   Clean up wbuf_sem a bit, document it.
#   ----------------------------
#   revision 1.79
#   date: 2004/11/20 10:21:40;  author: dwmw2;  state: Exp;  lines: +2 -2
#   Fix deadlock on wbuf_sem if jffs2_flash_writev() is writing to a new
#   block and flushes the wbuf on the old.
#   ----------------------------
#   revision 1.78
#   date: 2004/11/19 13:41:16;  author: dedekind;  state: Exp;  lines: +33 -20
#   Bugfix: fix the race bug when a writed and reader concurrently access
#   the wbuf. Introduce new rw semaphore to fix this.
# 
# fs/jffs2/README.Locking
#   2004/11/20 12:25:23+00:00 dwmw2@shinybook.infradead.org +14 -1
#   revision 1.9
#   date: 2004/11/20 10:35:40;  author: dwmw2;  state: Exp;  lines: +14 -1
#   Clean up wbuf_sem a bit, document it.
# 
# ChangeSet
#   2004/11/20 10:58:16+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Fix memory leak if jffs2_scan_medium() fails.
#   
#   We weren't releasing all the temporary dirent structures we may have
#   built up during the first part of the scan.
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/build.c
#   2004/11/20 10:57:52+00:00 dwmw2@shinybook.infradead.org +17 -6
#   revision 1.64
#   date: 2004/11/20 10:44:07;  author: dwmw2;  state: Exp;  lines: +1 -2
#   wbuf_sem is now nand-only
#   ----------------------------
#   revision 1.63
#   date: 2004/11/20 08:45:15;  author: dwmw2;  state: Exp;  lines: +2 -2
#   remove double semicolon
#   ----------------------------
#   revision 1.62
#   date: 2004/11/19 13:41:16;  author: dedekind;  state: Exp;  lines: +2 -1
#   Bugfix: fix the race bug when a writed and reader concurrently access
#   the wbuf. Introduce new rw semaphore to fix this.
#   ----------------------------
#   revision 1.61
#   date: 2004/11/18 11:17:41;  author: dedekind;  state: Exp;  lines: +17 -6
#   Bugfix: do not forget to free memory if the jffs2_scan_inode_node()
#   fails.
# 
# ChangeSet
#   2004/11/20 09:08:57+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Discard dirents which point to non-existent inodes.
#   
#   If a directory entry refers to an inode which doesn't actually exist,
#   we weren't marking it obsolete, so it was still visible in the file
#   system, and would give EIO if you ever tried to stat it. Once upon
#   a time, perl -e 'unlink' and rm -f would manage to unlink such things
#   but nowadays they both try to stat it first and stupidly refuse to 
#   even attempt the unlink if the stat fails, and this is more of a 
#   problem. So we throw it away ourselves. 
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/build.c
#   2004/11/20 09:08:37+00:00 dwmw2@shinybook.infradead.org +4 -3
#   revision 1.60
#   date: 2004/11/17 17:13:13;  author: dedekind;  state: Exp;  lines: +3 -3
#   Do the pass1 with the JFFS2_SB_FLAG_MOUNTING flag set in order to preven
#   the physical flash writing if we have found the inode-less direntry.
#   ----------------------------
#   revision 1.59
#   date: 2004/11/17 12:56:15;  author: dedekind;  state: Exp;  lines: +2 -2
#   Fix the last bugfix: use the jffs2_mark_node_obsolete() function instead
#   of directly marking the node obsolete. This will not break the
#   free/dirty space counters.
#   ----------------------------
#   revision 1.58
#   date: 2004/11/17 11:47:08;  author: dedekind;  state: Exp;  lines: +2 -1
#   Bugfix: when we have found an inodeless direntry, mark the correspondent
#   node_ref as obsolete in order to let the GC to kill this direntry.
# 
# ChangeSet
#   2004/11/20 09:00:26+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Remove obsolete structure definitions and update comments.
#   
#   New eyes are looking over ancient code and comments which were put
#   in as the design was first coming together... and which don't make
#   even the slightest bit of sense any more.
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/scan.c
#   2004/11/20 09:00:03+00:00 dwmw2@shinybook.infradead.org +3 -6
#   revision 1.115
#   date: 2004/11/17 12:59:08;  author: dedekind;  state: Exp;  lines: +3 -6
#   Change/remove old and depricated comments.
# 
# fs/jffs2/nodelist.h
#   2004/11/20 09:00:03+00:00 dwmw2@shinybook.infradead.org +5 -23
#   revision 1.126
#   date: 2004/11/19 15:06:29;  author: dedekind;  state: Exp;  lines: +1 -19
#   Remove archaic outdated stuff.
#   ----------------------------
#   revision 1.125
#   date: 2004/11/17 12:59:08;  author: dedekind;  state: Exp;  lines: +5 -5
#   Change/remove old and depricated comments.
# 
# ChangeSet
#   2004/11/20 08:52:36+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Fix JEDEC probe of chips which don't require unlock sequence
#   
#   Signed-off-by: Thayne Harbaugh <tharbaugh@lnxi.com>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/chips/jedec_probe.c
#   2004/11/20 08:52:15+00:00 dwmw2@shinybook.infradead.org +6 -3
#   revision 1.61
#   date: 2004/11/19 20:52:16;  author: thayne;  state: Exp;  lines: +6 -1
#   Make sure that every enum uaddr has an entry in unlock_addrs[]
# 
# ChangeSet
#   2004/11/19 19:48:43-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/11/19 19:48:39-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/17 10:45:15+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Fix chip ident definition for AMD 29F002T devices.
#   
#   They were missing unlock address and command set fields.
#   
#   From: David Vrabel <dvrabel@arcom.com>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# drivers/mtd/chips/jedec_probe.c
#   2004/11/17 10:44:46+00:00 dwmw2@shinybook.infradead.org +43 -28
#   revision 1.59
#   date: 2004/11/17 09:46:24;  author: dvrabel;  state: Exp;  lines: +43 -28
#   Add missing uddr and CmdSet fields to the entries for the 29F002T devices.
# 
# ChangeSet
#   2004/11/17 09:36:39+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Remove definition of obsolete struct jffs2_scan_info
#   
#   We no longer use this, since we rewrote the mount code to behave
#   entirely differently and not build up all the trees on mount.
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/nodelist.h
#   2004/11/17 09:36:16+00:00 dwmw2@shinybook.infradead.org +1 -8
#   revision 1.124
#   date: 2004/11/17 09:30:02;  author: dedekind;  state: Exp;  lines: +1 -8
#   Remove unused depricated struct jffs2_scan_info definition,
# 
# ChangeSet
#   2004/11/17 00:10:01-08:00 akpm@bix.(none) 
#   Merge bk://linux-mtd.bkbits.net/mtd-2.6 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/11/17 00:09:56-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/11/17 00:09:56-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/16 20:53:10+00:00 dwmw2@shinybook.infradead.org 
#   Email address update.
#   
#   The work address is increasingly unreliable and incompetently run.
#   Time to remove all visible instances of it and rely only on one 
#   which isn't run by crack-monkeys.
#   
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# kernel/workqueue.c
#   2004/11/16 20:52:49+00:00 dwmw2@shinybook.infradead.org +1 -1
#   Update email address to one at a competently-run domain.
# 
# include/linux/jffs2.h
#   2004/11/16 20:52:49+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/writev.c
#   2004/11/16 20:52:49+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/write.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/wbuf.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/symlink.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/super.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/scan.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/readinode.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/read.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/pushpull.h
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/os-linux.h
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/nodemgmt.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/nodelist.h
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/nodelist.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/malloc.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/ioctl.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/gc.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/fs.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/file.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/erase.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/dir.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/compr_zlib.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/build.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# fs/jffs2/background.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Update email address to one at a competently-run domain.
# 
# drivers/char/applicom.c
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +1 -1
#   Update email address to one at a competently-run domain.
# 
# MAINTAINERS
#   2004/11/16 20:52:48+00:00 dwmw2@shinybook.infradead.org +1 -1
#   Update email address to one at a competently-run domain.
# 
# CREDITS
#   2004/11/16 20:52:47+00:00 dwmw2@shinybook.infradead.org +0 -1
#   Update email address to one at a competently-run domain.
# 
# ChangeSet
#   2004/11/16 20:12:00+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Add notes on inocache_lock spinlock to README.Locking
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/README.Locking
#   2004/11/16 20:11:36+00:00 dwmw2@shinybook.infradead.org +26 -7
#   revision 1.8
#   date: 2004/11/14 11:43:41;  author: dedekind;  state: Exp;  lines: +3 -3
#   Fix typos in the newly added text.
#   ----------------------------
#   revision 1.7
#   date: 2004/11/14 11:38:54;  author: dedekind;  state: Exp;  lines: +20 -1
#   Add some information about the inocache_lock spinlock.
# 
# ChangeSet
#   2004/11/16 19:04:30+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Move very noisy debugging messages from level 1 to level 2.
#   
#   Signed-off-by: Artem Bityuckiy <dedekind@infradead.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# fs/jffs2/readinode.c
#   2004/11/16 19:04:09+00:00 dwmw2@shinybook.infradead.org +4 -2
#   Nove very noisy debugging messages from level 1 to level 2.
# 
# fs/jffs2/read.c
#   2004/11/16 19:04:09+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Nove very noisy debugging messages from level 1 to level 2.
# 
# fs/jffs2/nodemgmt.c
#   2004/11/16 19:04:09+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Nove very noisy debugging messages from level 1 to level 2.
# 
# fs/jffs2/nodelist.h
#   2004/11/16 19:04:09+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Nove very noisy debugging messages from level 1 to level 2.
# 
# fs/jffs2/gc.c
#   2004/11/16 19:04:09+00:00 dwmw2@shinybook.infradead.org +3 -3
#   Nove very noisy debugging messages from level 1 to level 2.
# 
# fs/jffs2/fs.c
#   2004/11/16 19:04:09+00:00 dwmw2@shinybook.infradead.org +2 -2
#   Nove very noisy debugging messages from level 1 to level 2.
# 
# fs/jffs2/build.c
#   2004/11/16 19:04:09+00:00 dwmw2@shinybook.infradead.org +3 -3
#   Nove very noisy debugging messages from level 1 to level 2.
# 
# ChangeSet
#   2004/11/16 19:02:03+00:00 dwmw2@shinybook.infradead.org 
#   MTD: NAND driver updates
#   
#    - Support 2048-byte HW ECC (from Juha Yrj�l� <juha.yrjola@nokia.com>)
#    - Allow board drivers to provide pattern for bad block scanning
#   
#   Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# include/linux/mtd/nand.h
#   2004/11/16 19:01:44+00:00 dwmw2@shinybook.infradead.org +7 -1
#   revision 1.68
#   date: 2004/11/12 10:40:37;  author: gleixner;  state: Exp;  lines: +3 -1
#   Allow board drivers to provide their own scan pattern for bad block scanning
#   ----------------------------
#   revision 1.67
#   date: 2004/11/01 20:03:59;  author: gleixner;  state: Exp;  lines: +5 -1
#   Cleanup HW-ECC. Calc ecc bytes during setup. Add HW12_2048 ECC mode (Initial Patch provided by Juha Yrjola <juha.yrjola@nokia.com>)
# 
# drivers/mtd/nand/nand_bbt.c
#   2004/11/16 19:01:44+00:00 dwmw2@shinybook.infradead.org +12 -10
#   revision 1.28
#   date: 2004/11/13 10:19:09;  author: gleixner;  state: Exp;  lines: +9 -5
#   Do not enforce flahsbased bad block tables. Stupid me
#   ----------------------------
#   revision 1.27
#   date: 2004/11/12 10:40:36;  author: gleixner;  state: Exp;  lines: +8 -10
#   Allow board drivers to provide their own scan pattern for bad block scanning
# 
# drivers/mtd/nand/nand_base.c
#   2004/11/16 19:01:44+00:00 dwmw2@shinybook.infradead.org +48 -51
#   revision 1.123
#   date: 2004/11/02 22:36:59;  author: gleixner;  state: Exp;  lines: +2 -2
#   Fix typo. Hmm, I start to adopt dwmw2's bad habits. Pointed out by Ed Berube <eberube@gmail.com>
#   ----------------------------
#   revision 1.122
#   date: 2004/11/01 20:03:57;  author: gleixner;  state: Exp;  lines: +48 -51
#   Cleanup HW-ECC. Calc ecc bytes during setup. Add HW12_2048 ECC mode (Initial Patch provided by Juha Yrjola <juha.yrjola@nokia.com>)
# 
# ChangeSet
#   2004/11/16 18:58:15+00:00 dwmw2@shinybook.infradead.org 
#   MTD: Provide XIP support for Intel flash chips.
#   
#   This allows for MTD support to be used on flash memory which is also used
#   for XIP purposes, either XIP kernel or XIP userspace.  The whole idea is
#   to relocate functions actually modifying the flash state away from array mode
#   to ram and run them with interrupt disabled.  When the flash needs some time
#   to complete a certain operation, we poll the processor for pending (but still
#   masked) interrupts, and when they occur we suspend the flash operation in order
#   to unmask interrupts and let the system run again.
#   
#   Signed-off-by: Nicolas Pitre <nico@cam.org>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# include/linux/mtd/xip.h
#   2004/11/16 18:57:52+00:00 dwmw2@shinybook.infradead.org +99 -0
# 
# include/linux/mtd/xip.h
#   2004/11/16 18:57:52+00:00 dwmw2@shinybook.infradead.org +0 -0
#   BitKeeper file /home/dwmw2/bk/mtd-2.6/include/linux/mtd/xip.h
# 
# include/linux/mtd/flashchip.h
#   2004/11/16 18:57:52+00:00 dwmw2@shinybook.infradead.org +3 -1
#   revision 1.15
#   date: 2004/11/05 22:41:06;  author: nico;  state: Exp;  lines: +3 -1
#   This allows for MTD support to be used on flash memory which is also used
#   for XIP purposes, either XIP kernel or XIP userspace.  The whole idea is
#   to relocate functions actually modifying the flash state away from array mode
#   to ram and run them with interrupt disabled.  When the flash needs some time
#   to complete a certain operation, we poll the processor for pending (but still
#   masked) interrupts, and when they occur we suspend the flash operation in order
#   to unmask interrupts and let the system run again.
# 
# drivers/mtd/chips/cfi_util.c
#   2004/11/16 18:57:51+00:00 dwmw2@shinybook.infradead.org +22 -13
#   revision 1.7
#   date: 2004/11/05 22:41:05;  author: nico;  state: Exp;  lines: +13 -2
#   This allows for MTD support to be used on flash memory which is also used
#   for XIP purposes, either XIP kernel or XIP userspace.  The whole idea is
#   to relocate functions actually modifying the flash state away from array mode
#   to ram and run them with interrupt disabled.  When the flash needs some time
#   to complete a certain operation, we poll the processor for pending (but still
#   masked) interrupts, and when they occur we suspend the flash operation in order
#   to unmask interrupts and let the system run again.
#   ----------------------------
#   revision 1.6
#   date: 2004/11/01 06:02:24;  author: nico;  state: Exp;  lines: +10 -12
#   Prerequisite cleanup for the upcoming patch.
#   This should not have changed the code logic at all.  Sue me if it did.
# 
# drivers/mtd/chips/cfi_probe.c
#   2004/11/16 18:57:51+00:00 dwmw2@shinybook.infradead.org +77 -31
#   revision 1.83
#   date: 2004/11/16 18:19:02;  author: nico;  state: Exp;  lines: +2 -2
#   fix bogus comment
#   ----------------------------
#   revision 1.81
#   date: 2004/11/05 22:41:05;  author: nico;  state: Exp;  lines: +54 -7
#   This allows for MTD support to be used on flash memory which is also used
#   for XIP purposes, either XIP kernel or XIP userspace.  The whole idea is
#   to relocate functions actually modifying the flash state away from array mode
#   to ram and run them with interrupt disabled.  When the flash needs some time
#   to complete a certain operation, we poll the processor for pending (but still
#   masked) interrupts, and when they occur we suspend the flash operation in order
#   to unmask interrupts and let the system run again.
#   ----------------------------
#   revision 1.80
#   date: 2004/11/01 06:02:24;  author: nico;  state: Exp;  lines: +23 -24
#   Prerequisite cleanup for the upcoming patch.
#   This should not have changed the code logic at all.  Sue me if it did.
# 
# drivers/mtd/chips/cfi_cmdset_0001.c
#   2004/11/16 18:57:51+00:00 dwmw2@shinybook.infradead.org +291 -30
#   revision 1.163
#   date: 2004/11/15 20:56:31;  author: nico;  state: Exp;  lines: +106 -26
#   Determine number of hw partitions from extended query data instead of
#   hardcoding it.
#   ----------------------------
#   revision 1.162
#   date: 2004/11/11 11:13:19;  author: dwmw2;  state: Exp;  lines: +12 -2
#   Restore oldstate to FL_READY on resume (or suspend failure).
#   ----------------------------
#   revision 1.161
#   date: 2004/11/05 22:41:04;  author: nico;  state: Exp;  lines: +289 -27
#   This allows for MTD support to be used on flash memory which is also used
#   for XIP purposes, either XIP kernel or XIP userspace.  The whole idea is
#   to relocate functions actually modifying the flash state away from array mode
#   to ram and run them with interrupt disabled.  When the flash needs some time
#   to complete a certain operation, we poll the processor for pending (but still
#   masked) interrupts, and when they occur we suspend the flash operation in order
#   to unmask interrupts and let the system run again.
# 
# drivers/mtd/chips/Kconfig
#   2004/11/16 18:57:51+00:00 dwmw2@shinybook.infradead.org +10 -1
#   revision 1.10
#   date: 2004/11/05 22:41:04;  author: nico;  state: Exp;  lines: +10 -1
#   This allows for MTD support to be used on flash memory which is also used
#   for XIP purposes, either XIP kernel or XIP userspace.  The whole idea is
#   to relocate functions actually modifying the flash state away from array mode
#   to ram and run them with interrupt disabled.  When the flash needs some time
#   to complete a certain operation, we poll the processor for pending (but still
#   masked) interrupts, and when they occur we suspend the flash operation in order
#   to unmask interrupts and let the system run again.
# 
# ChangeSet
#   2004/11/16 18:54:16+00:00 dwmw2@shinybook.infradead.org 
#   JFFS2: Add support for bizarre NOR flash with ECC. 
#   
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# include/linux/jffs2_fs_sb.h
#   2004/11/16 18:53:54+00:00 dwmw2@shinybook.infradead.org +2 -2
#   revision 1.46
#   date: 2004/11/03 12:57:39;  author: jwboyer;  state: Exp;  lines: +2 -2
#   Adding ECC'd NOR support to JFFS2.  Works with cfi_cmdset_0020.c
#    
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
# 
# fs/jffs2/wbuf.c
#   2004/11/16 18:53:54+00:00 dwmw2@shinybook.infradead.org +59 -9
#   revision 1.76
#   date: 2004/11/05 12:41:10;  author: jwboyer;  state: Exp;  lines: +3 -1
#   Fixed compilation with NAND=y but NOR_ECC=n.  Ferenc was right in the first
#   place.  Perhaps my stupidity is a reason to remove these config options finally
#   ----------------------------
#   revision 1.75
#   date: 2004/11/04 22:10:28;  author: jwboyer;  state: Exp;  lines: +1 -5
#   Fixup the fix from Ferenc.  Stupid me
#   ----------------------------
#   revision 1.74
#   date: 2004/11/04 21:42:14;  author: havasi;  state: Exp;  lines: +5 -1
#   Make it compilable without JFFS2_FS_NOR_ECC, too
#   ----------------------------
#   revision 1.73
#   date: 2004/11/03 12:57:39;  author: jwboyer;  state: Exp;  lines: +57 -9
#   Adding ECC'd NOR support to JFFS2.  Works with cfi_cmdset_0020.c
#    
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
# 
# fs/jffs2/scan.c
#   2004/11/16 18:53:54+00:00 dwmw2@shinybook.infradead.org +3 -3
#   revision 1.113
#   date: 2004/11/03 12:57:39;  author: jwboyer;  state: Exp;  lines: +3 -3
#   Adding ECC'd NOR support to JFFS2.  Works with cfi_cmdset_0020.c
#    
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
#   ----------------------------
# 
# fs/jffs2/os-linux.h
#   2004/11/16 18:53:54+00:00 dwmw2@shinybook.infradead.org +18 -4
#   revision 1.50
#   date: 2004/11/04 22:10:28;  author: jwboyer;  state: Exp;  lines: +5 -2
#   Fixup the fix from Ferenc.  Stupid me
#   ----------------------------
#   revision 1.49
#   date: 2004/11/04 21:42:14;  author: havasi;  state: Exp;  lines: +3 -3
#   Make it compilable without JFFS2_FS_NOR_ECC, too
#   ----------------------------
#   revision 1.48
#   date: 2004/11/03 12:57:39;  author: jwboyer;  state: Exp;  lines: +15 -4
#   Adding ECC'd NOR support to JFFS2.  Works with cfi_cmdset_0020.c
#    
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
# 
# fs/jffs2/fs.c
#   2004/11/16 18:53:54+00:00 dwmw2@shinybook.infradead.org +9 -1
#   revision 1.47
#   date: 2004/11/03 12:57:39;  author: jwboyer;  state: Exp;  lines: +9 -1
#   Adding ECC'd NOR support to JFFS2.  Works with cfi_cmdset_0020.c
#    
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
# 
# fs/jffs2/erase.c
#   2004/11/16 18:53:54+00:00 dwmw2@shinybook.infradead.org +7 -3
#   revision 1.65
#   date: 2004/11/13 10:51:47;  author: dedekind;  state: Exp;  lines: +2 -2
#   Use kvec instead of iovec structure to pass to the
#   jffs2_flash_direct_writev() function.
#   ----------------------------
#   revision 1.64
#   date: 2004/11/12 15:25:14;  author: jwboyer;  state: Exp;  lines: +5 -10
#   Make cleanmarkers on NOR always write directly.  This fixes some ECOS problems
#   as well.
#   ----------------------------
#   revision 1.63
#   date: 2004/11/11 12:38:28;  author: dwmw2;  state: Exp;  lines: +2 -1
#   Set bad_offset when erase fails under eCos
#   ----------------------------
#   revision 1.62
#   date: 2004/11/03 12:57:39;  author: jwboyer;  state: Exp;  lines: +10 -2
#   Adding ECC'd NOR support to JFFS2.  Works with cfi_cmdset_0020.c
#                                                                                   
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
# 
# fs/jffs2/Makefile
#   2004/11/16 18:53:54+00:00 dwmw2@shinybook.infradead.org +2 -1
#   revision 1.7
#   date: 2004/11/03 12:57:38;  author: jwboyer;  state: Exp;  lines: +2 -1
#   Adding ECC'd NOR support to JFFS2.  Works with cfi_cmdset_0020.c
#    
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
# 
# fs/Kconfig
#   2004/11/16 18:53:54+00:00 dwmw2@shinybook.infradead.org +9 -0
#   revision 1.8
#   date: 2004/11/03 12:57:37;  author: jwboyer;  state: Exp;  lines: +9 -0
#   Adding ECC'd NOR support to JFFS2.  Works with cfi_cmdset_0020.c
#    
#   Signed-off-by: Josh Boyer <jdub@us.ibm.com>
# 
# ChangeSet
#   2004/11/11 14:52:18-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/11/11 14:52:14-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/11/11 14:52:14-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/07 21:11:44-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/11/07 21:11:40-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/11/07 21:11:40-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/04 18:20:27-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/11/04 18:20:21-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/11/03 12:35:31-08:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/11/03 12:35:27-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/30 22:49:59-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/10/30 22:49:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/29 15:36:21-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/10/29 15:36:16-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/10/29 15:36:16-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/28 11:59:59-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/10/28 11:59:54-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/25 19:06:15-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/10/25 19:06:11-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/22 20:52:26-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/10/22 20:52:21-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/19 16:52:39-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/10/19 16:52:35-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/10/19 16:52:35-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/05 22:13:15-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/10/05 22:13:11-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/10/04 22:16:15-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/10/04 22:16:12-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/22 23:36:08-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/09/22 23:36:03-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/16 16:09:04-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/09/16 16:08:58-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/07 20:52:59-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/09/07 20:52:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/03 14:06:33-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/09/03 14:06:28-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/09/03 14:06:28-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/31 13:47:05-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/08/31 13:47:01-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/28 16:14:36-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/08/28 16:14:32-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/27 23:43:56-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/08/27 23:43:52-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/27 13:52:59-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/08/27 13:52:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/27 13:52:55-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/25 19:23:49-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/08/25 19:23:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/24 17:30:14-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/08/24 17:30:09-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/23 21:25:06-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# ChangeSet
#   2004/08/23 16:39:08-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/08/23 21:25:02-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/23 16:39:03-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/23 14:23:56-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/08/23 14:23:52-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/23 14:23:52-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/22 21:30:25-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/08/22 21:30:21-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/09 18:43:41-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/08/09 18:43:38-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/05 12:56:24-07:00 akpm@bix.(none) 
#   Merge bk://linux-mtd.bkbits.net/mtd-2.6 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/08/05 12:56:20-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/05 12:56:20-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/04 02:53:11-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/08/04 02:53:07-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/02 13:25:52-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd
# 
# MAINTAINERS
#   2004/08/02 13:25:49-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/02 01:16:16-07:00 akpm@bix.(none) 
#   Merge bk://linux-mtd.bkbits.net/mtd-2.6 into bix.(none):/usr/src/bk-mtd
# 
# fs/Kconfig
#   2004/08/02 01:16:13-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# MAINTAINERS
#   2004/08/02 01:16:12-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	2004-12-12 17:44:47 -08:00
+++ b/CREDITS	2004-12-12 17:44:47 -08:00
@@ -3569,7 +3569,6 @@
 
 N: David Woodhouse
 E: dwmw2@infradead.org
-E: dwmw2@redhat.com
 D: ARCnet stuff, Applicom board driver, SO_BINDTODEVICE,
 D: some Alpha platform porting from 2.0, Memory Technology Devices,
 D: Acquire watchdog timer, PC speaker driver maintenance,
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	2004-12-12 17:44:47 -08:00
+++ b/MAINTAINERS	2004-12-12 17:44:47 -08:00
@@ -1439,7 +1439,7 @@
 
 MEMORY TECHNOLOGY DEVICES
 P:	David Woodhouse
-M:	dwmw2@redhat.com
+M:	dwmw2@infradead.org
 W:	http://www.linux-mtd.infradead.org/
 L:	linux-mtd@lists.infradead.org
 S:	Maintained
diff -Nru a/drivers/char/applicom.c b/drivers/char/applicom.c
--- a/drivers/char/applicom.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/char/applicom.c	2004-12-12 17:44:47 -08:00
@@ -1,6 +1,6 @@
 /* Derived from Applicom driver ac.c for SCO Unix                            */
 /* Ported by David Woodhouse, Axiom (Cambridge) Ltd.                         */
-/* dwmw2@redhat.com  30/8/98                                                 */
+/* dwmw2@infradead.org 30/8/98                                               */
 /* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $			     */
 /* This module is for Linux 2.1 and 2.2 series kernels.                      */
 /*****************************************************************************/
diff -Nru a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
--- a/drivers/mtd/Kconfig	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/Kconfig	2004-12-12 17:44:47 -08:00
@@ -1,4 +1,4 @@
-# $Id: Kconfig,v 1.6 2004/08/09 13:19:42 dwmw2 Exp $
+# $Id: Kconfig,v 1.7 2004/11/22 11:33:56 ijc Exp $
 
 menu "Memory Technology Devices (MTD)"
 
@@ -54,8 +54,8 @@
 	depends on MTD_PARTITIONS
 	---help---
 	  RedBoot is a ROM monitor and bootloader which deals with multiple
-	  'images' in flash devices by putting a table in the last erase
-	  block of the device, similar to a partition table, which gives
+	  'images' in flash devices by putting a table one of the erase
+	  blocks on the device, similar to a partition table, which gives
 	  the offsets, lengths and names of all the images stored in the
 	  flash.
 
@@ -68,6 +68,23 @@
 	  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
 	  example.
 
+config MTD_REDBOOT_DIRECTORY_BLOCK
+	int "Location of RedBoot partition table"
+	depends on MTD_REDBOOT_PARTS
+	default "-1"
+	---help---
+	  This option is the Linux counterpart to the
+	  CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time
+	  option.
+
+	  The option specifies which Flash sectors holds the RedBoot
+	  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
diff -Nru a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
--- a/drivers/mtd/chips/Kconfig	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/chips/Kconfig	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.9 2004/07/16 15:32:14 dwmw2 Exp $
+# $Id: Kconfig,v 1.11 2004/11/29 22:40:44 dwmw2 Exp $
 
 menu "RAM/ROM/Flash chip drivers"
 	depends on MTD!=n
@@ -7,6 +7,7 @@
 config MTD_CFI
 	tristate "Detect flash chips by Common Flash Interface (CFI) probe"
 	depends on MTD
+	select MTD_GEN_PROBE
 	help
 	  The Common Flash Interface specification was developed by Intel,
 	  AMD and other flash manufactures that provides a universal method
@@ -18,6 +19,7 @@
 config MTD_JEDECPROBE
 	tristate "Detect non-CFI AMD/JEDEC-compatible flash chips"
 	depends on MTD
+	select MTD_GEN_PROBE
 	help
 	  This option enables JEDEC-style probing of flash chips which are not
 	  compatible with the Common Flash Interface, but will use the common
@@ -29,8 +31,6 @@
 
 config MTD_GEN_PROBE
 	tristate
-	default m if MTD_CFI!=y && !MTD_INTELPROBE && MTD_JEDECPROBE!=y && (MTD_CFI=m || MTD_JEDECPROBE=m)
-	default y if MTD_CFI=y || MTD_INTELPROBE || MTD_JEDECPROBE=y
 
 config MTD_CFI_ADV_OPTIONS
 	bool "Flash chip driver advanced configuration options"
@@ -158,6 +158,7 @@
 config MTD_CFI_INTELEXT
 	tristate "Support for Intel/Sharp flash chips"
 	depends on MTD_GEN_PROBE
+	select MTD_CFI_UTIL
 	help
 	  The Common Flash Interface defines a number of different command
 	  sets which a CFI-compliant chip may claim to implement. This code
@@ -167,6 +168,7 @@
 config MTD_CFI_AMDSTD
 	tristate "Support for AMD/Fujitsu flash chips"
 	depends on MTD_GEN_PROBE
+	select MTD_CFI_UTIL
 	help
 	  The Common Flash Interface defines a number of different command
 	  sets which a CFI-compliant chip may claim to implement. This code
@@ -197,6 +199,7 @@
 config MTD_CFI_STAA
 	tristate "Support for ST (Advanced Architecture) flash chips"
 	depends on MTD_GEN_PROBE
+	select MTD_CFI_UTIL
 	help
 	  The Common Flash Interface defines a number of different command
 	  sets which a CFI-compliant chip may claim to implement. This code
@@ -204,8 +207,6 @@
 
 config MTD_CFI_UTIL
 	tristate
-	default y if MTD_CFI_INTELEXT=y || MTD_CFI_AMDSTD=y || MTD_CFI_STAA=y
-	default m if MTD_CFI_INTELEXT=m || MTD_CFI_AMDSTD=m || MTD_CFI_STAA=m
 
 config MTD_RAM
 	tristate "Support for RAM chips in bus mapping"
@@ -271,6 +272,15 @@
 	  only called JEDEC because the JEDEC association
 	  <http://www.jedec.org/> distributes the identification codes for the
 	  chips.
+
+config MTD_XIP
+	bool "XIP aware MTD support"
+	depends on !SMP && MTD_CFI_INTELEXT && EXPERIMENTAL
+	default y if XIP_KERNEL
+	help
+	  This allows MTD support to work with flash memory which is also
+	  used for XIP purposes.  If you're not sure what this is all about
+	  then say N.
 
 endmenu
 
diff -Nru a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
--- a/drivers/mtd/chips/amd_flash.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/chips/amd_flash.c	2004-12-12 17:44:47 -08:00
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.25 2004/08/09 13:19:43 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
@@ -1122,7 +1122,7 @@
 	timeo = jiffies + (HZ * 20);
 
 	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
+	msleep(1000);
 	spin_lock_bh(chip->mutex);
 	
 	while (flash_is_busy(map, adr, private->interleave)) {
diff -Nru a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
--- a/drivers/mtd/chips/cfi_cmdset_0001.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c	2004-12-12 17:44:47 -08:00
@@ -4,9 +4,8 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.160 2004/11/01 06:02:24 nico Exp $
- * (+ suspend fix from v1.162)
- * (+ partition detection fix from v1.163)
+ * $Id: cfi_cmdset_0001.c,v 1.164 2004/11/16 18:29:00 dwmw2 Exp $
+ *
  * 
  * 10/10/2000	Nicolas Pitre <nico@cam.org>
  * 	- completely revamped method functions so they are aware and
@@ -30,6 +29,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/mtd/xip.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/compatmac.h>
@@ -37,6 +37,10 @@
 
 /* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
 
+#ifdef CONFIG_MTD_XIP
+#define CMDSET0001_DISABLE_WRITE_SUSPEND
+#endif
+
 // debugging, turns off buffer write mode if set to 1
 #define FORCE_WORD_WRITE 0
 
@@ -147,6 +151,21 @@
 }
 #endif
 
+#ifdef CMDSET0001_DISABLE_WRITE_SUSPEND
+/* The XIP config appears to have problems using write suspend at the moment */ 
+static void fixup_no_write_suspend(struct mtd_info *mtd, void* param)
+{
+	struct map_info *map = mtd->priv;
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+
+	if (cfip && (cfip->FeatureSupport&4)) {
+		cfip->FeatureSupport &= ~4;
+		printk(KERN_WARNING "cfi_cmdset_0001: write suspend disabled\n");
+	}
+}
+#endif
+
 static void fixup_st_m28w320ct(struct mtd_info *mtd, void* param)
 {
 	struct map_info *map = mtd->priv;
@@ -189,6 +208,9 @@
 #ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
 	{ 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 },
+#endif
 #if !FORCE_WORD_WRITE
 	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL },
 #endif
@@ -679,6 +701,14 @@
 		chip->state = FL_STATUS;
 		return 0;
 
+	case FL_XIP_WHILE_ERASING:
+		if (mode != FL_READY && mode != FL_POINT &&
+		    (mode != FL_WRITING || !cfip || !(cfip->SuspendCmdSupport&1)))
+			goto sleep;
+		chip->oldstate = chip->state;
+		chip->state = FL_READY;
+		return 0;
+
 	case FL_POINT:
 		/* Only if there's no operation suspended... */
 		if (mode == FL_READY && chip->oldstate == FL_READY)
@@ -746,6 +776,11 @@
 		chip->state = FL_ERASING;
 		break;
 
+	case FL_XIP_WHILE_ERASING:
+		chip->state = chip->oldstate;
+		chip->oldstate = FL_READY;
+		break;
+
 	case FL_READY:
 	case FL_STATUS:
 	case FL_JEDEC_QUERY:
@@ -758,6 +793,201 @@
 	wake_up(&chip->wq);
 }
 
+#ifdef CONFIG_MTD_XIP
+
+/*
+ * No interrupt what so ever can be serviced while the flash isn't in array
+ * mode.  This is ensured by the xip_disable() and xip_enable() functions
+ * enclosing any code path where the flash is known not to be in array mode.
+ * And within a XIP disabled code path, only functions marked with __xipram
+ * may be called and nothing else (it's a good thing to inspect generated
+ * assembly to make sure inline functions were actually inlined and that gcc
+ * didn't emit calls to its own support functions). Also configuring MTD CFI
+ * support to a single buswidth and a single interleave is also recommended.
+ * Note that not only IRQs are disabled but the preemption count is also
+ * increased to prevent other locking primitives (namely spin_unlock) from
+ * decrementing the preempt count to zero and scheduling the CPU away while
+ * not in array mode.
+ */
+
+static void xip_disable(struct map_info *map, struct flchip *chip,
+			unsigned long adr)
+{
+	/* TODO: chips with no XIP use should ignore and return */
+	(void) map_read(map, adr); /* ensure mmu mapping is up to date */
+	preempt_disable();
+	local_irq_disable();
+}
+
+static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
+				unsigned long adr)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	if (chip->state != FL_POINT && chip->state != FL_READY) {
+		map_write(map, CMD(0xff), adr);
+		chip->state = FL_READY;
+	}
+	(void) map_read(map, adr);
+	asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */
+	local_irq_enable();
+	preempt_enable();
+}
+
+/*
+ * 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 or write 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
+ * of the delay period.
+ *
+ * Warning: this function _will_ fool interrupt latency tracing tools.
+ */
+
+static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
+				unsigned long adr, int usec)
+{
+	struct cfi_private *cfi = map->fldrv_priv;
+	struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
+	map_word status, OK = CMD(0x80);
+	unsigned long suspended, start = xip_currtime();
+	flstate_t oldstate, newstate;
+
+	do {
+		cpu_relax();
+		if (xip_irqpending() && cfip &&
+		    ((chip->state == FL_ERASING && (cfip->FeatureSupport&2)) ||
+		     (chip->state == FL_WRITING && (cfip->FeatureSupport&4))) &&
+		    (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
+			/*
+			 * Let's suspend the erase or write 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
+			 * we resume the whole thing at once).  Yes, it
+			 * can happen!
+			 */
+			map_write(map, CMD(0xb0), adr);
+			map_write(map, CMD(0x70), adr);
+			usec -= xip_elapsed_since(start);
+			suspended = xip_currtime();
+			do {
+				if (xip_elapsed_since(suspended) > 100000) {
+					/*
+					 * The chip doesn't want to suspend
+					 * after waiting for 100 msecs.
+					 * This is a critical error but there
+					 * is not much we can do here.
+					 */
+					return;
+				}
+				status = map_read(map, adr);
+			} while (!map_word_andequal(map, status, OK, OK));
+
+			/* Suspend succeeded */
+			oldstate = chip->state;
+			if (oldstate == FL_ERASING) {
+				if (!map_word_bitsset(map, status, CMD(0x40)))
+					break;
+				newstate = FL_XIP_WHILE_ERASING;
+				chip->erase_suspended = 1;
+			} else {
+				if (!map_word_bitsset(map, status, CMD(0x04)))
+					break;
+				newstate = FL_XIP_WHILE_WRITING;
+				chip->write_suspended = 1;
+			}
+			chip->state = newstate;
+			map_write(map, CMD(0xff), adr);
+			(void) map_read(map, adr);
+			asm volatile (".rep 8; nop; .endr");
+			local_irq_enable();
+			preempt_enable();
+			asm volatile (".rep 8; nop; .endr");
+			cond_resched();
+
+			/*
+			 * We're back.  However someone else might have
+			 * decided to go write to the chip if we are in
+			 * a suspended erase state.  If so let's wait
+			 * until it's done.
+			 */
+			preempt_disable();
+			while (chip->state != newstate) {
+				DECLARE_WAITQUEUE(wait, current);
+				set_current_state(TASK_UNINTERRUPTIBLE);
+				add_wait_queue(&chip->wq, &wait);
+				preempt_enable();
+				schedule();
+				remove_wait_queue(&chip->wq, &wait);
+				preempt_disable();
+			}
+			/* Disallow XIP again */
+			local_irq_disable();
+
+			/* Resume the write or erase operation */
+			map_write(map, CMD(0xd0), adr);
+			map_write(map, CMD(0x70), adr);
+			chip->state = oldstate;
+			start = xip_currtime();
+		} else if (usec >= 1000000/HZ) {
+			/*
+			 * Try to save on CPU power when waiting delay
+			 * is at least a system timer tick period.
+			 * No need to be extremely accurate here.
+			 */
+			xip_cpu_idle();
+		}
+		status = map_read(map, adr);
+	} while (!map_word_andequal(map, status, OK, OK)
+		 && xip_elapsed_since(start) < usec);
+}
+
+#define UDELAY(map, chip, adr, usec)  xip_udelay(map, chip, adr, usec)
+
+/*
+ * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
+ * the flash is actively programming or erasing since we have to poll for
+ * the operation to complete anyway.  We can't do that in a generic way with
+ * a XIP setup so do it before the actual flash operation in this case.
+ */
+#undef INVALIDATE_CACHED_RANGE
+#define INVALIDATE_CACHED_RANGE(x...)
+#define XIP_INVAL_CACHED_RANGE(map, from, size) \
+	do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
+
+/*
+ * Extra notes:
+ *
+ * Activating this XIP support changes the way the code works a bit.  For
+ * example the code to suspend the current process when concurrent access
+ * happens is never executed because xip_udelay() will always return with the
+ * same chip state as it was entered with.  This is why there is no care for
+ * the presence of add_wait_queue() or schedule() calls from within a couple
+ * xip_disable()'d  areas of code, like in do_erase_oneblock for example.
+ * The queueing and scheduling are always happening within xip_udelay().
+ *
+ * Similarly, get_chip() and put_chip() just happen to always be executed
+ * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
+ * is in array mode, therefore never executing many cases therein and not
+ * causing any problem with XIP.
+ */
+
+#else
+
+#define xip_disable(map, chip, adr)
+#define xip_enable(map, chip, adr)
+
+#define UDELAY(map, chip, adr, usec)  cfi_udelay(usec)
+
+#define XIP_INVAL_CACHED_RANGE(x...)
+
+#endif
+
 static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
 {
 	unsigned long cmd_addr;
@@ -944,7 +1174,11 @@
 }
 
 #if 0
-static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
+static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd,
+						loff_t from, size_t len,
+						size_t *retlen,
+						u_char *buf,
+						int base_offst, int reg_sz)
 {
 	struct map_info *map = mtd->priv;
 	struct cfi_private *cfi = map->fldrv_priv;
@@ -973,6 +1207,8 @@
 			return (len-count)?:ret;
 		}
 
+		xip_disable(map, chip, chip->start);
+
 		if (chip->state != FL_JEDEC_QUERY) {
 			map_write(map, CMD(0x90), chip->start);
 			chip->state = FL_JEDEC_QUERY;
@@ -985,6 +1221,7 @@
 			count--;
 		}
 
+		xip_enable(map, chip, chip->start);
 		put_chip(map, chip, chip->start);
 		spin_unlock(chip->mutex);
 
@@ -1036,7 +1273,8 @@
 }
 #endif
 
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
+static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
+				     unsigned long adr, map_word datum)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	map_word status, status_OK;
@@ -1055,14 +1293,16 @@
 		return ret;
 	}
 
+	XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
 	ENABLE_VPP(map);
+	xip_disable(map, chip, adr);
 	map_write(map, CMD(0x40), adr);
 	map_write(map, datum, adr);
 	chip->state = FL_WRITING;
 
 	spin_unlock(chip->mutex);
 	INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
-	cfi_udelay(chip->word_write_time);
+	UDELAY(map, chip, adr, chip->word_write_time);
 	spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ/2);
@@ -1089,6 +1329,7 @@
 		/* OK Still waiting */
 		if (time_after(jiffies, timeo)) {
 			chip->state = FL_STATUS;
+			xip_enable(map, chip, adr);
 			printk(KERN_ERR "waiting for chip to be ready timed out in word write\n");
 			ret = -EIO;
 			goto out;
@@ -1097,7 +1338,7 @@
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock(chip->mutex);
 		z++;
-		cfi_udelay(1);
+		UDELAY(map, chip, adr, 1);
 		spin_lock(chip->mutex);
 	}
 	if (!z) {
@@ -1119,8 +1360,9 @@
 		map_write(map, CMD(0x70), adr);
 		ret = -EROFS;
 	}
- out:
-	put_chip(map, chip, adr);
+
+	xip_enable(map, chip, adr);
+ out:	put_chip(map, chip, adr);
 	spin_unlock(chip->mutex);
 
 	return ret;
@@ -1210,8 +1452,8 @@
 }
 
 
-static inline int 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 u_char *buf, int len)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	map_word status, status_OK;
@@ -1232,6 +1474,10 @@
 		return ret;
 	}
 
+	XIP_INVAL_CACHED_RANGE(map, adr, len);
+	ENABLE_VPP(map);
+	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". 
 	   So we must check here and reset those bits if they're set. Otherwise
@@ -1240,12 +1486,13 @@
 		map_write(map, CMD(0x70), cmd_adr);
 	status = map_read(map, cmd_adr);
 	if (map_word_bitsset(map, status, CMD(0x30))) {
+		xip_enable(map, chip, cmd_adr);
 		printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);
+		xip_disable(map, chip, cmd_adr);
 		map_write(map, CMD(0x50), cmd_adr);
 		map_write(map, CMD(0x70), cmd_adr);
 	}
 
-	ENABLE_VPP(map);
 	chip->state = FL_WRITING_TO_BUFFER;
 
 	z = 0;
@@ -1257,7 +1504,7 @@
 			break;
 
 		spin_unlock(chip->mutex);
-		cfi_udelay(1);
+		UDELAY(map, chip, cmd_adr, 1);
 		spin_lock(chip->mutex);
 
 		if (++z > 20) {
@@ -1269,6 +1516,7 @@
 			/* Odd. Clear status bits */
 			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]);
 			ret = -EIO;
@@ -1305,7 +1553,7 @@
 
 	spin_unlock(chip->mutex);
 	INVALIDATE_CACHED_RANGE(map, adr, len);
-	cfi_udelay(chip->buffer_write_time);
+	UDELAY(map, chip, cmd_adr, chip->buffer_write_time);
 	spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ/2);
@@ -1331,6 +1579,7 @@
 		/* OK Still waiting */
 		if (time_after(jiffies, timeo)) {
 			chip->state = FL_STATUS;
+			xip_enable(map, chip, cmd_adr);
 			printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n");
 			ret = -EIO;
 			goto out;
@@ -1338,7 +1587,7 @@
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock(chip->mutex);
-		cfi_udelay(1);
+		UDELAY(map, chip, cmd_adr, 1);
 		z++;
 		spin_lock(chip->mutex);
 	}
@@ -1362,8 +1611,8 @@
 		ret = -EROFS;
 	}
 
- out:
-	put_chip(map, chip, cmd_adr);
+	xip_enable(map, chip, cmd_adr);
+ out:	put_chip(map, chip, cmd_adr);
 	spin_unlock(chip->mutex);
 	return ret;
 }
@@ -1432,8 +1681,8 @@
 	return 0;
 }
 
-static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
-			     unsigned long adr, int len, void *thunk)
+static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
+				      unsigned long adr, int len, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	map_word status, status_OK;
@@ -1455,7 +1704,10 @@
 		return ret;
 	}
 
+	XIP_INVAL_CACHED_RANGE(map, adr, len);
 	ENABLE_VPP(map);
+	xip_disable(map, chip, adr);
+
 	/* Clear the status register first */
 	map_write(map, CMD(0x50), adr);
 
@@ -1467,7 +1719,7 @@
 
 	spin_unlock(chip->mutex);
 	INVALIDATE_CACHED_RANGE(map, adr, len);
-	msleep(chip->erase_time / 2);
+	UDELAY(map, chip, adr, chip->erase_time*1000/2);
 	spin_lock(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
@@ -1505,6 +1757,7 @@
 			/* 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]);
 			ret = -EIO;
@@ -1513,8 +1766,7 @@
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock(chip->mutex);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(1);
+		UDELAY(map, chip, adr, 1000000/HZ);
 		spin_lock(chip->mutex);
 	}
 
@@ -1530,6 +1782,7 @@
 		/* Reset the error bits */
 		map_write(map, CMD(0x50), adr);
 		map_write(map, CMD(0x70), adr);
+		xip_enable(map, chip, adr);
 
 		chipstatus = status.x[0];
 		if (!map_word_equal(map, status, CMD(chipstatus))) {
@@ -1565,6 +1818,7 @@
 			ret = -EIO;
 		}
 	} else {
+		xip_enable(map, chip, adr);
 		ret = 0;
 	}
 
@@ -1632,15 +1886,19 @@
 }
 
 #ifdef DEBUG_LOCK_BITS
-static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip,
-				       unsigned long adr, int len, void *thunk)
+static int __xipram do_printlockstatus_oneblock(struct map_info *map,
+						struct flchip *chip,
+						unsigned long adr,
+						int len, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	int status, ofs_factor = cfi->interleave * cfi->device_type;
 
+	xip_disable(map, chip, adr+(2*ofs_factor));
 	cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
 	chip->state = FL_JEDEC_QUERY;
 	status = cfi_read_query(map, adr+(2*ofs_factor));
+	xip_enable(map, chip, 0);
 	printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
 	       adr, status);
 	return 0;
@@ -1650,8 +1908,8 @@
 #define DO_XXLOCK_ONEBLOCK_LOCK		((void *) 1)
 #define DO_XXLOCK_ONEBLOCK_UNLOCK	((void *) 2)
 
-static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
-			      unsigned long adr, int len, void *thunk)
+static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
+				       unsigned long adr, int len, void *thunk)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	map_word status, status_OK;
@@ -1671,8 +1929,9 @@
 	}
 
 	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);
 		chip->state = FL_LOCKING;
@@ -1683,7 +1942,7 @@
 		BUG();
 
 	spin_unlock(chip->mutex);
-	schedule_timeout(HZ);
+	UDELAY(map, chip, adr, 1000000/HZ);
 	spin_lock(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
@@ -1702,6 +1961,7 @@
 			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]);
 			put_chip(map, chip, adr);
@@ -1711,12 +1971,13 @@
 		
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock(chip->mutex);
-		cfi_udelay(1);
+		UDELAY(map, chip, adr, 1);
 		spin_lock(chip->mutex);
 	}
 	
 	/* Done and happy. */
 	chip->state = FL_STATUS;
+	xip_enable(map, chip, adr);
 	put_chip(map, chip, adr);
 	spin_unlock(chip->mutex);
 	return 0;
@@ -1875,7 +2136,7 @@
 static char im_name_1[]="cfi_cmdset_0001";
 static char im_name_3[]="cfi_cmdset_0003";
 
-int __init cfi_intelext_init(void)
+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);
diff -Nru a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
--- a/drivers/mtd/chips/cfi_cmdset_0002.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c	2004-12-12 17:44:47 -08:00
@@ -13,7 +13,7 @@
  *
  * This code is GPL
  *
- * $Id: cfi_cmdset_0002.c,v 1.111 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.112 2004/11/20 12:49:04 dwmw2 Exp $
  *
  */
 
@@ -1173,8 +1173,7 @@
 	chip->in_progress_block_addr = adr;
 
 	cfi_spin_unlock(chip->mutex);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((chip->erase_time*HZ)/(2*1000));
+	msleep(chip->erase_time/2);
 	cfi_spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ*20);
@@ -1259,8 +1258,7 @@
 	chip->in_progress_block_addr = adr;
 	
 	cfi_spin_unlock(chip->mutex);
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout((chip->erase_time*HZ)/(2*1000));
+	msleep(chip->erase_time/2);
 	cfi_spin_lock(chip->mutex);
 
 	timeo = jiffies + (HZ*20);
diff -Nru a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
--- a/drivers/mtd/chips/cfi_cmdset_0020.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c	2004-12-12 17:44:47 -08:00
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0020.c,v 1.16 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: cfi_cmdset_0020.c,v 1.17 2004/11/20 12:49:04 dwmw2 Exp $
  * 
  * 10/10/2000	Nicolas Pitre <nico@cam.org>
  * 	- completely revamped method functions so they are aware and
@@ -788,7 +788,7 @@
 	chip->state = FL_ERASING;
 	
 	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
+	msleep(1000);
 	spin_lock_bh(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
@@ -1087,7 +1087,7 @@
 	chip->state = FL_LOCKING;
 	
 	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
+	msleep(1000);
 	spin_lock_bh(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
@@ -1236,7 +1236,7 @@
 	chip->state = FL_UNLOCKING;
 	
 	spin_unlock_bh(chip->mutex);
-	schedule_timeout(HZ);
+	msleep(1000);
 	spin_lock_bh(chip->mutex);
 
 	/* FIXME. Use a timer to check this, and return immediately. */
diff -Nru a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c
--- a/drivers/mtd/chips/cfi_probe.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/chips/cfi_probe.c	2004-12-12 17:44:47 -08:00
@@ -1,7 +1,7 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: cfi_probe.c,v 1.79 2004/10/20 23:04:01 dwmw2 Exp $
+   $Id: cfi_probe.c,v 1.83 2004/11/16 18:19:02 nico Exp $
 */
 
 #include <linux/config.h>
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 
+#include <linux/mtd/xip.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/gen_probe.h>
@@ -31,11 +32,47 @@
 
 struct mtd_info *cfi_probe(struct map_info *map);
 
+#ifdef CONFIG_MTD_XIP
+
+/* only needed for short periods, so this is rather simple */
+#define xip_disable()	local_irq_disable()
+
+#define xip_allowed(base, map) \
+do { \
+	(void) map_read(map, base); \
+	asm volatile (".rep 8; nop; .endr"); \
+	local_irq_enable(); \
+} while (0)
+
+#define xip_enable(base, map, cfi) \
+do { \
+	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); \
+	xip_allowed(base, map); \
+} while (0)
+
+#define xip_disable_qry(base, map, cfi) \
+do { \
+	xip_disable(); \
+	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); \
+	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \
+} while (0)
+
+#else
+
+#define xip_disable()			do { } while (0)
+#define xip_allowed(base, map)		do { } while (0)
+#define xip_enable(base, map, cfi)	do { } while (0)
+#define xip_disable_qry(base, map, cfi) do { } while (0)
+
+#endif
+
 /* check for QRY.
    in: interleave,type,mode
    ret: table index, <0 for error
  */
-static int qry_present(struct map_info *map, __u32 base,
+static int __xipram qry_present(struct map_info *map, __u32 base,
 				struct cfi_private *cfi)
 {
 	int osf = cfi->interleave * cfi->device_type;	// scale factor
@@ -59,11 +96,11 @@
 	if (!map_word_equal(map, qry[2], val[2]))
 		return 0;
 
-	return 1; 	// nothing found
+	return 1; 	// "QRY" found
 }
 
-static int cfi_probe_chip(struct map_info *map, __u32 base,
-			  unsigned long *chip_map, struct cfi_private *cfi)
+static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
+				   unsigned long *chip_map, struct cfi_private *cfi)
 {
 	int i;
 	
@@ -79,12 +116,16 @@
 			(unsigned long)base + 0x55, map->size -1);
 		return 0;
 	}
+
+	xip_disable();
 	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);
 	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
 
-	if (!qry_present(map,base,cfi))
+	if (!qry_present(map,base,cfi)) {
+		xip_enable(base, map, cfi);
 		return 0;
+	}
 
 	if (!cfi->numchips) {
 		/* This is the first time we're called. Set up the CFI 
@@ -110,6 +151,7 @@
 
 			/* If the QRY marker goes away, it's an alias */
 			if (!qry_present(map, start, cfi)) {
+				xip_allowed(base, map);
 				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
 				       map->name, base, start);
 				return 0;
@@ -122,6 +164,7 @@
 			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",
 				       map->name, base, start);
 				return 0;
@@ -137,6 +180,7 @@
 	/* 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);
+	xip_allowed(base, map);
 
 	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,
@@ -145,14 +189,15 @@
 	return 1;
 }
 
-static int cfi_chip_setup(struct map_info *map, 
-		   struct cfi_private *cfi)
+static int __xipram cfi_chip_setup(struct map_info *map, 
+				   struct cfi_private *cfi)
 {
 	int ofs_factor = cfi->interleave*cfi->device_type;
 	__u32 base = 0;
 	int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor);
 	int i;
 
+	xip_enable(base, map, cfi);
 #ifdef DEBUG_CFI
 	printk("Number of erase regions: %d\n", num_erase_regions);
 #endif
@@ -170,13 +215,33 @@
 	cfi->cfi_mode = CFI_MODE_CFI;
 	
 	/* Read the CFI info structure */
-	for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
+	xip_disable_qry(base, map, cfi);
+	for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++)
 		((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor);
-	}
-	
+
+	/* Note we put the device back into Read Mode BEFORE going into Auto
+	 * Select Mode, as some devices support nesting of modes, others
+	 * don't. This way should always work.
+	 * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
+	 * so should be treated as nops or illegal (and so put the device
+	 * back into Read Mode, which is a nop in this case).
+	 */
+	cfi_send_gen_cmd(0xf0,     0, base, map, cfi, cfi->device_type, NULL);
+	cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
+	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);    
+
+	/* Put it back into Read Mode */
+	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+	/* ... even if it's an Intel chip */
+	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+	xip_allowed(base, map);
+
 	/* Do any necessary byteswapping */
 	cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID);
-	
+
 	cfi->cfiq->P_ADR = le16_to_cpu(cfi->cfiq->P_ADR);
 	cfi->cfiq->A_ID = le16_to_cpu(cfi->cfiq->A_ID);
 	cfi->cfiq->A_ADR = le16_to_cpu(cfi->cfiq->A_ADR);
@@ -197,25 +262,6 @@
 		       (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
 #endif
 	}
-
-	/* Note we put the device back into Read Mode BEFORE going into Auto
-	 * Select Mode, as some devices support nesting of modes, others
-	 * don't. This way should always work.
-	 * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
-	 * so should be treated as nops or illegal (and so put the device
-	 * back into Read Mode, which is a nop in this case).
-	 */
-	cfi_send_gen_cmd(0xf0,     0, base, map, cfi, cfi->device_type, NULL);
-	cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
-	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);    
-
-	/* Put it back into Read Mode */
-	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
-	/* ... even if it's an Intel chip */
-	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
 
 	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,
diff -Nru a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c
--- a/drivers/mtd/chips/cfi_util.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/chips/cfi_util.c	2004-12-12 17:44:47 -08:00
@@ -7,7 +7,7 @@
  *
  * This code is covered by the GPL.
  *
- * $Id: cfi_util.c,v 1.5 2004/08/12 06:40:23 eric Exp $
+ * $Id: cfi_util.c,v 1.7 2004/11/05 22:41:05 nico Exp $
  *
  */
 
@@ -22,13 +22,14 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/mtd/xip.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/cfi.h>
 #include <linux/mtd/compatmac.h>
 
 struct cfi_extquery *
-cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
+__xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
 {
 	struct cfi_private *cfi = map->fldrv_priv;
 	__u32 base = 0; // cfi->chips[0].start;
@@ -40,21 +41,35 @@
 	if (!adr)
 		goto out;
 
-	/* Switch it into Query Mode */
-	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
 	extp = kmalloc(size, GFP_KERNEL);
 	if (!extp) {
 		printk(KERN_ERR "Failed to allocate memory\n");
 		goto out;
 	}
-		
+
+#ifdef CONFIG_MTD_XIP
+	local_irq_disable();
+#endif
+
+	/* Switch it into Query Mode */
+	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+
 	/* Read in the Extended Query Table */
 	for (i=0; i<size; i++) {
 		((unsigned char *)extp)[i] = 
 			cfi_read_query(map, base+((adr+i)*ofs_factor));
 	}
 
+	/* Make sure it returns to 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);
+
+#ifdef CONFIG_MTD_XIP
+	(void) map_read(map, base);
+	asm volatile (".rep 8; nop; .endr");
+	local_irq_enable();
+#endif
+
 	if (extp->MajorVersion != '1' || 
 	    (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
 		printk(KERN_WARNING "  Unknown %s Extended Query "
@@ -62,15 +77,9 @@
 		       extp->MinorVersion);
 		kfree(extp);
 		extp = NULL;
-		goto out;
 	}
 
-out:
-	/* Make sure it's in 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);
-
-	return extp;
+ out:	return extp;
 }
 
 EXPORT_SYMBOL(cfi_read_pri);
diff -Nru a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
--- a/drivers/mtd/chips/jedec_probe.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/chips/jedec_probe.c	2004-12-12 17:44:47 -08:00
@@ -1,7 +1,7 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.58 2004/11/16 18:29:00 dwmw2 Exp $
+   $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
    See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
    for the standard this probe goes back to.
 
@@ -227,6 +227,11 @@
 	[MTD_UADDR_DONT_CARE] = {
 		.addr1 = 0x0000,      /* Doesn't matter which address */
 		.addr2 = 0x0000       /* is used - must be last entry */
+	},
+
+	[MTD_UADDR_UNNECESSARY] = {
+		.addr1 = 0x0000,
+		.addr2 = 0x0000
 	}
 };
 
@@ -514,15 +519,20 @@
 			ERASEINFO(0x10000,8),
 		}
 	}, {
-		mfr_id: MANUFACTURER_AMD,
-		dev_id: AM29F002T,
-		name: "AMD AM29F002T",
-		DevSize: SIZE_256KiB,
-		NumEraseRegions: 4,
-		regions: {ERASEINFO(0x10000,3),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
+		.mfr_id		= MANUFACTURER_AMD,
+		.dev_id		= AM29F002T,
+		.name		= "AMD AM29F002T",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_256KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,3),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1),
 		}
 	}, {
 		.mfr_id		= MANUFACTURER_ATMEL,
@@ -770,15 +780,20 @@
 			ERASEINFO(0x04000,1)
 		}
 	}, {
-		mfr_id: MANUFACTURER_HYUNDAI,
-		dev_id: HY29F002T,
-		name: "Hyundai HY29F002T",
-		DevSize: SIZE_256KiB,
-		NumEraseRegions: 4,
-		regions: {ERASEINFO(0x10000,3),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
+		.mfr_id		= MANUFACTURER_HYUNDAI,
+		.dev_id		= HY29F002T,
+		.name		= "Hyundai HY29F002T",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_256KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,3),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1),
 		}
 	}, {
 		.mfr_id		= MANUFACTURER_INTEL,
@@ -1177,15 +1192,20 @@
 			ERASEINFO(0x10000,7),
 		}
 	}, {
-		mfr_id: MANUFACTURER_MACRONIX,
-		dev_id: MX29F002T,
-		name: "Macronix MX29F002T",
-		DevSize: SIZE_256KiB,
-		NumEraseRegions: 4,
-		regions: {ERASEINFO(0x10000,3),
-			  ERASEINFO(0x08000,1),
-			  ERASEINFO(0x02000,2),
-			  ERASEINFO(0x04000,1)
+		.mfr_id		= MANUFACTURER_MACRONIX,
+		.dev_id		= MX29F002T,
+		.name		= "Macronix MX29F002T",
+		.uaddr		= {
+			[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+		},
+		.DevSize	= SIZE_256KiB,
+		.CmdSet		= P_ID_AMD_STD,
+		.NumEraseRegions= 4,
+		.regions	= {
+			ERASEINFO(0x10000,3),
+			ERASEINFO(0x08000,1),
+			ERASEINFO(0x02000,2),
+			ERASEINFO(0x04000,1),
 		}
 	}, {
 		.mfr_id		= MANUFACTURER_PMC,
@@ -1780,7 +1800,6 @@
 		return 0;
 	}
 
-	/* Mask out address bits which are smaller than the device type */
 	p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
 	p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
 
@@ -1923,7 +1942,6 @@
 		if (MTD_UADDR_UNNECESSARY == uaddr_idx)
 			return 0;
 
-		/* Mask out address bits which are smaller than the device type */
 		cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
 		cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
 	}
diff -Nru a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
--- a/drivers/mtd/cmdlinepart.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/cmdlinepart.c	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 /*
- * $Id: cmdlinepart.c,v 1.16 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *
  * Read flash partition table from command line
  *
@@ -338,8 +338,10 @@
  * 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.
+ *
+ * This function needs to be visible for bootloaders.
  */
-static int mtdpart_setup(char *s)
+int mtdpart_setup(char *s)
 {
 	cmdline = s;
 	return 1;
diff -Nru a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
--- a/drivers/mtd/devices/Kconfig	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/devices/Kconfig	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.13 2004/10/01 21:47:13 gleixner Exp $
+# $Id: Kconfig,v 1.14 2004/11/29 22:40:45 dwmw2 Exp $
 
 menu "Self-contained MTD device drivers"
 	depends on MTD!=n
@@ -130,6 +130,8 @@
 config MTD_DOC2000
 	tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)"
 	depends on MTD
+	select MTD_DOCPROBE
+	select MTD_NAND_IDS
 	---help---
 	  This provides an MTD device driver for the M-Systems DiskOnChip
 	  2000 and Millennium devices.  Originally designed for the DiskOnChip
@@ -151,6 +153,8 @@
 config MTD_DOC2001
 	tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)"
 	depends on MTD
+	select MTD_DOCPROBE
+	select MTD_NAND_IDS
 	---help---
 	  This provides an alternative MTD device driver for the M-Systems 
 	  DiskOnChip Millennium devices.  Use this if you have problems with
@@ -171,6 +175,8 @@
 config MTD_DOC2001PLUS
 	tristate "M-Systems Disk-On-Chip Millennium Plus"
 	depends on MTD
+	select MTD_DOCPROBE
+	select MTD_NAND_IDS
 	---help---
 	  This provides an MTD device driver for the M-Systems DiskOnChip
 	  Millennium Plus devices.
@@ -186,17 +192,10 @@
 
 config MTD_DOCPROBE
 	tristate
-	default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MTD_DOC2001PLUS=m)
-	default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y
-	help
-	  This isn't a real config option; it's derived.
+	select MTD_DOCECC
 
 config MTD_DOCECC
 	tristate
-	default m if MTD_DOCPROBE=m
-	default y if MTD_DOCPROBE=y
-	help
-	  This isn't a real config option; it's derived.
 
 config MTD_DOCPROBE_ADVANCED
 	bool "Advanced detection options for DiskOnChip"
diff -Nru a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
--- a/drivers/mtd/devices/phram.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/devices/phram.c	2004-12-12 17:44:47 -08:00
@@ -1,6 +1,6 @@
 /**
  *
- * $Id: phram.c,v 1.3 2004/11/16 18:29:01 dwmw2 Exp $
+ * $Id: phram.c,v 1.6 2004/11/25 16:51:09 joern Exp $
  *
  * Copyright (c) Jochen Schaeuble <psionic@psionic.de>
  * 07/2003	rewritten by Joern Engel <joern@wh.fh-wedel.de>
@@ -15,9 +15,12 @@
  *   phram=<name>,<start>,<len>
  * <name> may be up to 63 characters.
  * <start> and <len> can be octal, decimal or hexadecimal.  If followed
- * by "k", "M" or "G", the numbers will be interpreted as kilo, mega or
+ * by "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or
  * gigabytes.
  *
+ * Example:
+ *	phram=swap,896Mi,110Mi phram=test,1006Mi,1Mi
+ *
  */
 
 #include <asm/io.h>
@@ -184,7 +187,9 @@
 		result *= 1024;
 	case 'k':
 		result *= 1024;
-		endp++;
+	/* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
+		if ((*endp)[1] == 'i')
+			(*endp) += 2;
 	}
 	return result;
 }
@@ -235,7 +240,7 @@
 	uint32_t len;
 	int i, ret;
 
-	if (strnlen(val, sizeof(str)) >= sizeof(str))
+	if (strnlen(val, sizeof(buf)) >= sizeof(buf))
 		parse_err("parameter too long\n");
 
 	strcpy(str, val);
@@ -283,7 +288,7 @@
 	if (!val || !val[0])
 		parse_err("no arguments to \"slram=\"\n");
 
-	if (strnlen(val, sizeof(str)) >= sizeof(str))
+	if (strnlen(val, sizeof(buf)) >= sizeof(buf))
 		parse_err("parameter too long\n");
 
 	strcpy(str, val);
@@ -342,7 +347,6 @@
 
 static int __init init_phram(void)
 {
-	printk(KERN_ERR "phram loaded\n");
 	return 0;
 }
 
diff -Nru a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
--- a/drivers/mtd/inftlmount.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/inftlmount.c	2004-12-12 17:44:47 -08:00
@@ -8,7 +8,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: inftlmount.c,v 1.15 2004/11/05 21:55:55 kalev Exp $
+ * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev 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.15 $";
+char inftlmountrev[]="$Revision: 1.16 $";
 
 /*
  * find_boot_record: Find the INFTL Media Header and its Spare copy which
@@ -389,8 +389,6 @@
 	struct erase_info *instr = &inftl->instr;
 	int physblock;
 
-	instr->mtd = inftl->mbd.mtd;
-
 	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p,"
 		"block=%d)\n", inftl, block);
 
@@ -400,6 +398,7 @@
 	   _first_? */
 
 	/* Use async erase interface, test return code */
+	instr->mtd = inftl->mbd.mtd;
 	instr->addr = block * inftl->EraseSize;
 	instr->len = inftl->mbd.mtd->erasesize;
 	/* Erase one physical eraseblock at a time, even though the NAND api
diff -Nru a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
--- a/drivers/mtd/maps/Kconfig	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/Kconfig	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.37 2004/10/20 22:57:18 dwmw2 Exp $
+# $Id: Kconfig,v 1.38 2004/11/24 19:42:51 rpurdie Exp $
 
 menu "Mapping drivers for chip access"
 	depends on MTD!=n
@@ -644,6 +644,12 @@
 	int "Maximum size for BAST flash area (MiB)"
 	depends on MTD_BAST
 	default "4"
+
+config MTD_SHARP_SL
+	bool "ROM maped on Sharp SL Series"
+	depends on MTD && ARCH_PXA
+	help
+	  This enables access to the flash chip on the Sharp SL Series of PDAs.
 
 endmenu
 
diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
--- a/drivers/mtd/maps/Makefile	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/Makefile	2004-12-12 17:44:47 -08:00
@@ -1,7 +1,7 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile.common,v 1.19 2004/09/21 14:27:16 bjd Exp $
+# $Id: Makefile.common,v 1.20 2004/11/24 19:42:51 rpurdie Exp $
 
 ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
 obj-$(CONFIG_MTD)		+= map_funcs.o
@@ -69,3 +69,4 @@
 obj-$(CONFIG_MTD_IXP2000)	+= ixp2000.o
 obj-$(CONFIG_MTD_WRSBC8260)	+= wr_sbc82xx_flash.o
 obj-$(CONFIG_MTD_DMV182)	+= dmv182.o
+obj-$(CONFIG_MTD_SHARP_SL)	+= sharpsl-flash.o
diff -Nru a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
--- a/drivers/mtd/maps/amd76xrom.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/amd76xrom.c	2004-12-12 17:44:47 -08:00
@@ -2,7 +2,7 @@
  * amd76xrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.18 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $
  */
 
 #include <linux/module.h>
diff -Nru a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c
--- a/drivers/mtd/maps/dilnetpc.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/dilnetpc.c	2004-12-12 17:44:47 -08:00
@@ -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.16 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: dilnetpc.c,v 1.17 2004/11/28 09:40:39 dwmw2 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
diff -Nru a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c
--- a/drivers/mtd/maps/ebony.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/ebony.c	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 /*
- * $Id: ebony.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
+ * $Id: ebony.c,v 1.14 2004/11/28 09:40:39 dwmw2 Exp $
  * 
  * Mapping for Ebony user flash
  *
diff -Nru a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c
--- a/drivers/mtd/maps/elan-104nc.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/elan-104nc.c	2004-12-12 17:44:47 -08:00
@@ -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: elan-104nc.c,v 1.24 2004/11/16 18:29:02 dwmw2 Exp $
+   $Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $
 
 The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
 mode.  This drivers uses the CFI probe and Intel Extended Command Set drivers.
diff -Nru a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
--- a/drivers/mtd/maps/ichxrom.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/ichxrom.c	2004-12-12 17:44:47 -08:00
@@ -2,7 +2,7 @@
  * ichxrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: ichxrom.c,v 1.15 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $
  */
 
 #include <linux/module.h>
diff -Nru a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c
--- a/drivers/mtd/maps/l440gx.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/l440gx.c	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 /*
- * $Id: l440gx.c,v 1.16 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $
  *
  * BIOS Flash chip on Intel 440GX board.
  *
diff -Nru a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c
--- a/drivers/mtd/maps/netsc520.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/netsc520.c	2004-12-12 17:44:47 -08:00
@@ -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.12 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 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
diff -Nru a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
--- a/drivers/mtd/maps/nettel.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/nettel.c	2004-12-12 17:44:47 -08:00
@@ -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.8 2004/11/04 13:24:15 gleixner Exp $
+ *	$Id: nettel.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
  */
 
 /****************************************************************************/
diff -Nru a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
--- a/drivers/mtd/maps/pci.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/pci.c	2004-12-12 17:44:47 -08:00
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- *  $Id: pci.c,v 1.8 2004/07/12 22:38:29 dwmw2 Exp $
+ *  $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
  * 
  * Generic PCI memory map driver.  We support the following boards:
  *  - Intel IQ80310 ATU.
diff -Nru a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
--- a/drivers/mtd/maps/physmap.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/physmap.c	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 /*
- * $Id: physmap.c,v 1.36 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $
  *
  * Normal mappings of chips in physical memory
  *
diff -Nru a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c
--- a/drivers/mtd/maps/sbc_gxx.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/sbc_gxx.c	2004-12-12 17:44:47 -08:00
@@ -17,7 +17,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: sbc_gxx.c,v 1.32 2004/11/16 18:29:02 dwmw2 Exp $
+   $Id: sbc_gxx.c,v 1.33 2004/11/28 09:40:40 dwmw2 Exp $
 
 The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
 Intel StrataFlash (28F320/28F640) in x8 mode.  
diff -Nru a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c
--- a/drivers/mtd/maps/sc520cdp.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/sc520cdp.c	2004-12-12 17:44:47 -08:00
@@ -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.18 2004/11/04 13:24:15 gleixner Exp $
+ * $Id: sc520cdp.c,v 1.19 2004/11/28 09:40:40 dwmw2 Exp $
  *
  *
  * The SC520CDP is an evaluation board for the Elan SC520 processor available
diff -Nru a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c
--- a/drivers/mtd/maps/scb2_flash.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/scb2_flash.c	2004-12-12 17:44:47 -08:00
@@ -1,6 +1,6 @@
 /*
  * MTD map driver for BIOS Flash on Intel SCB2 boards
- * $Id: scb2_flash.c,v 1.10 2004/11/16 18:29:02 dwmw2 Exp $
+ * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $
  * Copyright (C) 2002 Sun Microsystems, Inc.
  * Tim Hockin <thockin@sun.com>
  *
diff -Nru a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c
--- a/drivers/mtd/maps/scx200_docflash.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/scx200_docflash.c	2004-12-12 17:44:47 -08:00
@@ -2,7 +2,7 @@
 
    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
 
-   $Id: scx200_docflash.c,v 1.9 2004/11/16 18:29:02 dwmw2 Exp $ 
+   $Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $ 
 
    National Semiconductor SCx200 flash mapped with DOCCS
 */
diff -Nru a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/mtd/maps/sharpsl-flash.c	2004-12-12 17:44:47 -08:00
@@ -0,0 +1,101 @@
+/*
+ * sharpsl-flash.c
+ * 
+ * Copyright (C) 2001 Lineo Japan, Inc.
+ * Copyright (C) 2002  SHARP
+ *
+ * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $
+ *
+ * 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
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define WINDOW_ADDR 0x00000000
+#define WINDOW_SIZE 0x01000000
+#define BANK_WIDTH 2
+
+static struct mtd_info *mymtd;
+
+struct map_info sharpsl_map = {
+	.name = "sharpsl-flash",
+	.size = WINDOW_SIZE,
+	.bankwidth = BANK_WIDTH,
+	.phys = WINDOW_ADDR
+};
+
+static struct mtd_partition sharpsl_partitions[1] = {
+	{
+		name:		"Filesystem",
+		size:		0x006d0000,
+		offset:		0x00120000
+	}
+};
+
+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
+
+int __init init_sharpsl(void)
+{
+	struct mtd_partition *parts;
+	int nb_parts = 0;
+	char *part_type = "static";
+
+	printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+	sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
+	if (!sharpsl_map.virt) {
+		printk("Failed to ioremap\n");
+		return -EIO;
+	}
+	mymtd = do_map_probe("map_rom", &sharpsl_map);
+	if (!mymtd) {
+		iounmap(sharpsl_map.virt);
+		return -ENXIO;
+	}
+
+	mymtd->owner = THIS_MODULE;
+
+	parts = sharpsl_partitions;
+	nb_parts = NB_OF(sharpsl_partitions);
+
+	printk(KERN_NOTICE "Using %s partision definition\n", part_type);
+	add_mtd_partitions(mymtd, parts, nb_parts);
+
+	return 0;
+}
+
+static void __exit cleanup_sharpsl(void)
+{
+	if (mymtd) {
+		del_mtd_partitions(mymtd);
+		map_destroy(mymtd);
+	}
+	if (sharpsl_map.virt) {
+		iounmap(sharpsl_map.virt);
+		sharpsl_map.virt = 0;
+	}
+}
+
+module_init(init_sharpsl);
+module_exit(cleanup_sharpsl);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("SHARP (Original: Arnold Christensen <AKC@pel.dk>)");
+MODULE_DESCRIPTION("MTD map driver for SHARP SL series");
diff -Nru a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c
--- a/drivers/mtd/maps/ts5500_flash.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/maps/ts5500_flash.c	2004-12-12 17:44:47 -08:00
@@ -25,7 +25,7 @@
  * - 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.1 2004/09/20 15:33:26 sean Exp $
+ * $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $
  */
 
 #include <linux/config.h>
diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
--- a/drivers/mtd/mtdblock.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/mtdblock.c	2004-12-12 17:44:47 -08:00
@@ -1,7 +1,7 @@
 /* 
  * Direct MTD block device access
  *
- * $Id: mtdblock.c,v 1.65 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $
  *
  * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
  * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
@@ -248,7 +248,7 @@
 			      unsigned long block, char *buf)
 {
 	struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
-	if (unlikely(!mtdblk->cache_data)) {
+	if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) {
 		mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
 		if (!mtdblk->cache_data)
 			return -EINTR;
diff -Nru a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
--- a/drivers/mtd/nand/Kconfig	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/nand/Kconfig	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 # drivers/mtd/nand/Kconfig
-# $Id: Kconfig,v 1.22 2004/10/05 22:11:46 gleixner Exp $
+# $Id: Kconfig,v 1.25 2004/11/29 22:40:45 dwmw2 Exp $
 
 menu "NAND Flash Device Drivers"
 	depends on MTD!=n
@@ -7,6 +7,7 @@
 config MTD_NAND
 	tristate "NAND Device Support"
 	depends on MTD
+	select MTD_NAND_IDS
 	help
 	  This enables support for accessing all type of NAND flash
 	  devices. For further information see
@@ -56,8 +57,6 @@
 
 config MTD_NAND_IDS
 	tristate
-	default y if MTD_NAND = y || MTD_DOC2000 = y || MTD_DOC2001 = y || MTD_DOC2001PLUS = y
-	default m if MTD_NAND = m || MTD_DOC2000 = m || MTD_DOC2001 = m || MTD_DOC2001PLUS = m
 
 config MTD_NAND_TX4925NDFMC
 	tristate "SmartMedia Card on Toshiba RBTX4925 reference board"
@@ -192,4 +191,17 @@
 	  Even if you leave this disabled, you can enable BBT writes at module
 	  load time (assuming you build diskonchip as a module) with the module
 	  parameter "inftl_bbt_write=1".
+	  
+ config MTD_NAND_SHARPSL
+ 	bool "Support for NAND Flash on Sharp SL Series (C7xx + others)"
+ 	depends on MTD_NAND	&& ARCH_PXA
+ 
+ config MTD_NAND_NANDSIM
+ 	bool "Support for NAND Flash Simulator"
+ 	depends on MTD_NAND
+
+	help
+	  The simulator may simulate verious NAND flash chips for the
+	  MTD nand layer.
+ 
 endmenu
diff -Nru a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
--- a/drivers/mtd/nand/Makefile	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/nand/Makefile	2004-12-12 17:44:47 -08:00
@@ -1,7 +1,7 @@
 #
 # linux/drivers/nand/Makefile
 #
-# $Id: Makefile.common,v 1.13 2004/09/28 22:04:23 bjd Exp $
+# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $
 
 obj-$(CONFIG_MTD_NAND)			+= nand.o nand_ecc.o
 obj-$(CONFIG_MTD_NAND_IDS)		+= nand_ids.o
@@ -18,5 +18,7 @@
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
 obj-$(CONFIG_MTD_NAND_H1900)		+= h1910.o
 obj-$(CONFIG_MTD_NAND_RTC_FROM4)	+= rtc_from4.o
+obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
+obj-$(CONFIG_MTD_NAND_NANDSIM)		+= nandsim.o
 
 nand-objs = nand_base.o nand_bbt.o
diff -Nru a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
--- a/drivers/mtd/nand/nand_base.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/nand/nand_base.c	2004-12-12 17:44:47 -08:00
@@ -41,7 +41,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.121 2004/10/06 19:53:11 gleixner Exp $
+ * $Id: nand_base.c,v 1.123 2004/11/02 22:36: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
@@ -840,18 +840,8 @@
 		}
 		this->write_buf(mtd, this->data_poi, mtd->oobblock);
 		break;
-		
-	/* Hardware ecc 8 byte / 512 byte data */	
-	case NAND_ECC_HW8_512:	
-		eccbytes += 2;
-	/* Hardware ecc 6 byte / 512 byte data */	
-	case NAND_ECC_HW6_512:	
-		eccbytes += 3;
-	/* Hardware ecc 3 byte / 256 data */	
-	/* Hardware ecc 3 byte / 512 byte data */	
-	case NAND_ECC_HW3_256:		
-	case NAND_ECC_HW3_512:
-		eccbytes += 3;
+	default:
+		eccbytes = this->eccbytes;
 		for (; eccsteps; eccsteps--) {
 			/* enable hardware ecc logic for write */
 			this->enable_hwecc(mtd, NAND_ECC_WRITE);
@@ -864,14 +854,9 @@
 			 * the data bytes (words) */
 			if (this->options & NAND_HWECC_SYNDROME)
 				this->write_buf(mtd, ecc_code, eccbytes);
-
 			datidx += this->eccsize;
 		}
 		break;
-
-	default:
-		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-		BUG();	
 	}
 										
 	/* Write out OOB data */
@@ -1051,7 +1036,7 @@
         int eccmode, eccsteps;
 	int	*oob_config, datidx;
 	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
-	int	eccbytes = 3;
+	int	eccbytes;
 	int	compareecc = 1;
 	int	oobreadlen;
 
@@ -1092,19 +1077,9 @@
 
 	end = mtd->oobblock;
 	ecc = this->eccsize;
-	switch (eccmode) {
-	case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data  */
-		eccbytes = 6;
-		break;						
-	case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data  */
-		eccbytes = 8;
-		break;
-	case NAND_ECC_NONE:
-		compareecc = 0;
-		break;						
-	}	 
-
-	if (this->options & NAND_HWECC_SYNDROME)
+	eccbytes = this->eccbytes;
+	
+	if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
 		compareecc = 0;
 
 	oobreadlen = mtd->oobsize;
@@ -1164,13 +1139,10 @@
 			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) 
 				this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
 			break;	
-			
-		case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data */
-		case NAND_ECC_HW3_512: /* Hardware ECC 3 byte /512 byte data */	
-		case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data  */
-		case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data  */
+
+		default:
 			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {
-				this->enable_hwecc(mtd, NAND_ECC_READ);	
+				this->enable_hwecc(mtd, NAND_ECC_READ);
 				this->read_buf(mtd, &data_poi[datidx], ecc);
 
 				/* HW ecc with syndrome calculation must read the
@@ -1193,10 +1165,6 @@
 				}	
 			}
 			break;						
-
-		default:
-			printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-			BUG();	
 		}
 
 		/* read oobdata */
@@ -2433,8 +2401,19 @@
 	 * fallback to software ECC 
 	*/
 	this->eccsize = 256;	/* set default eccsize */	
+	this->eccbytes = 3;
 
 	switch (this->eccmode) {
+	case NAND_ECC_HW12_2048:
+		if (mtd->oobblock < 2048) {
+			printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
+			       mtd->oobblock);
+			this->eccmode = NAND_ECC_SOFT;
+			this->calculate_ecc = nand_calculate_ecc;
+			this->correct_data = nand_correct_data;
+		} else
+			this->eccsize = 2048;
+		break;
 
 	case NAND_ECC_HW3_512: 
 	case NAND_ECC_HW6_512: 
@@ -2444,16 +2423,13 @@
 			this->eccmode = NAND_ECC_SOFT;
 			this->calculate_ecc = nand_calculate_ecc;
 			this->correct_data = nand_correct_data;
-			break;		
 		} else 
-			this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
-
+			this->eccsize = 512; /* set eccsize to 512 */
+		break;
+			
 	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();	
-
+		break;
+		
 	case NAND_ECC_NONE: 
 		printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
 		this->eccmode = NAND_ECC_NONE;
@@ -2468,11 +2444,32 @@
 		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
 		BUG();	
 	}	
-	
+
+	/* 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: 
+		this->eccbytes += 2;
+	case NAND_ECC_HW6_512: 
+		this->eccbytes += 3;
+	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();	
+	}
+		
 	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:
+		this->eccsteps = mtd->oobblock / 2048;
+		break;
 	case NAND_ECC_HW3_512:
 	case NAND_ECC_HW6_512:
 	case NAND_ECC_HW8_512:
diff -Nru a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
--- a/drivers/mtd/nand/nand_bbt.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/nand/nand_bbt.c	2004-12-12 17:44:47 -08:00
@@ -6,7 +6,7 @@
  *   
  *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
  *
- * $Id: nand_bbt.c,v 1.26 2004/10/05 13:50:20 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 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
@@ -1001,25 +1001,27 @@
 		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) {	
 			this->bbt_td = &bbt_main_descr;
 			this->bbt_md = &bbt_mirror_descr;
-		}	
-		if (mtd->oobblock > 512)
-			return nand_scan_bbt (mtd, &largepage_flashbased);
-		else	
-			return nand_scan_bbt (mtd, &smallpage_flashbased);			
+		}
+		if (!this->badblock_pattern) {
+			this->badblock_pattern = (mtd->oobblock > 512) ?
+				&largepage_flashbased : &smallpage_flashbased;
+		}
 	} else {
 		this->bbt_td = NULL;
 		this->bbt_md = NULL;
-		if (mtd->oobblock > 512)
-			return nand_scan_bbt (mtd, &largepage_memorybased);
-		else
-			return nand_scan_bbt (mtd, &smallpage_memorybased);
+		if (!this->badblock_pattern) {
+			this->badblock_pattern = (mtd->oobblock > 512) ?
+				&largepage_memorybased : &smallpage_memorybased;
+		}
 	}
+	return nand_scan_bbt (mtd, this->badblock_pattern);
 }
 
 /**
diff -Nru a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/mtd/nand/nandsim.c	2004-12-12 17:44:47 -08:00
@@ -0,0 +1,1619 @@
+/*
+ * NAND flash simulator.
+ *
+ * Author: Artem B. Bityuckiy <dedekind@oktetlabs.ru>, <dedekind@infradead.org>
+ *
+ * Copyright (C) 2004 Nokia Corporation 
+ *
+ * Note: NS means "NAND Simulator".
+ * Note: Input means input TO flash chip, output means output FROM chip.
+ *
+ * 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, 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: nandsim.c,v 1.3 2004/11/26 13:00:24 dedekind Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/delay.h>
+#ifdef CONFIG_NS_ABS_POS
+#include <asm/io.h>
+#endif
+
+
+/* Default simulator parameters values */
+#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE)  || \
+    !defined(CONFIG_NANDSIM_SECOND_ID_BYTE) || \
+    !defined(CONFIG_NANDSIM_THIRD_ID_BYTE)  || \
+    !defined(CONFIG_NANDSIM_FOURTH_ID_BYTE)
+#define CONFIG_NANDSIM_FIRST_ID_BYTE  0x98
+#define CONFIG_NANDSIM_SECOND_ID_BYTE 0x36
+#define CONFIG_NANDSIM_THIRD_ID_BYTE  0xFF /* No byte */
+#define CONFIG_NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */
+#endif
+
+#ifndef CONFIG_NANDSIM_ACCESS_DELAY
+#define CONFIG_NANDSIM_ACCESS_DELAY 25
+#endif
+#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY
+#define CONFIG_NANDSIM_PROGRAMM_DELAY 200
+#endif
+#ifndef CONFIG_NANDSIM_ERASE_DELAY
+#define CONFIG_NANDSIM_ERASE_DELAY 2
+#endif
+#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE
+#define CONFIG_NANDSIM_OUTPUT_CYCLE 40
+#endif
+#ifndef CONFIG_NANDSIM_INPUT_CYCLE
+#define CONFIG_NANDSIM_INPUT_CYCLE  50
+#endif
+#ifndef CONFIG_NANDSIM_BUS_WIDTH
+#define CONFIG_NANDSIM_BUS_WIDTH  8
+#endif
+#ifndef CONFIG_NANDSIM_DO_DELAYS
+#define CONFIG_NANDSIM_DO_DELAYS  0
+#endif
+#ifndef CONFIG_NANDSIM_LOG
+#define CONFIG_NANDSIM_LOG        0
+#endif
+#ifndef CONFIG_NANDSIM_DBG
+#define CONFIG_NANDSIM_DBG        0
+#endif
+
+static uint first_id_byte  = CONFIG_NANDSIM_FIRST_ID_BYTE;
+static uint second_id_byte = CONFIG_NANDSIM_SECOND_ID_BYTE;
+static uint third_id_byte  = CONFIG_NANDSIM_THIRD_ID_BYTE;
+static uint fourth_id_byte = CONFIG_NANDSIM_FOURTH_ID_BYTE;
+static uint access_delay   = CONFIG_NANDSIM_ACCESS_DELAY;
+static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY;
+static uint erase_delay    = CONFIG_NANDSIM_ERASE_DELAY;
+static uint output_cycle   = CONFIG_NANDSIM_OUTPUT_CYCLE;
+static uint input_cycle    = CONFIG_NANDSIM_INPUT_CYCLE;
+static uint bus_width      = CONFIG_NANDSIM_BUS_WIDTH;
+static uint do_delays      = CONFIG_NANDSIM_DO_DELAYS;
+static uint log            = CONFIG_NANDSIM_LOG;
+static uint dbg            = CONFIG_NANDSIM_DBG;
+
+module_param(first_id_byte,  uint, 0400);
+module_param(second_id_byte, uint, 0400);
+module_param(third_id_byte,  uint, 0400);
+module_param(fourth_id_byte, uint, 0400);
+module_param(access_delay,   uint, 0400);
+module_param(programm_delay, uint, 0400);
+module_param(erase_delay,    uint, 0400);
+module_param(output_cycle,   uint, 0400);
+module_param(input_cycle,    uint, 0400);
+module_param(bus_width,      uint, 0400);
+module_param(do_delays,      uint, 0400);
+module_param(log,            uint, 0400);
+module_param(dbg,            uint, 0400);
+
+MODULE_PARM_DESC(first_id_byte,  "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)");
+MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
+MODULE_PARM_DESC(third_id_byte,  "The third byte returned by NAND Flash 'read ID' command");
+MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command");
+MODULE_PARM_DESC(access_delay,   "Initial page access delay (microiseconds)");
+MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds");
+MODULE_PARM_DESC(erase_delay,    "Sector erase delay (milliseconds)");
+MODULE_PARM_DESC(output_cycle,   "Word output (from flash) time (nanodeconds)");
+MODULE_PARM_DESC(input_cycle,    "Word input (to flash) time (nanodeconds)");
+MODULE_PARM_DESC(bus_width,      "Chip's bus width (8- or 16-bit)");
+MODULE_PARM_DESC(do_delays,      "Simulate NAND delays using busy-waits if not zero");
+MODULE_PARM_DESC(log,            "Perform logging if not zero");
+MODULE_PARM_DESC(dbg,            "Output debug information if not zero");
+
+/* 
+ * There is no macro for 0x30 command which is used in "large page"
+ * devices in standard mtd header, define it here. 
+ */
+#define NAND_CMD_READ2LP 0x30
+
+/* The largest possible page size */
+#define NS_LARGEST_PAGE_SIZE	2048
+	
+/* The prefix for simulator output */
+#define NS_OUTPUT_PREFIX "[nandsim]"
+
+/* Simulator's output macros (logging, debugging, warning, error) */
+#define NS_LOG(args...) \
+	do { if (log) printk(KERN_INFO NS_OUTPUT_PREFIX " log: " args); } while(0)
+#define NS_DBG(args...) \
+	do { if (dbg) printk(KERN_INFO NS_OUTPUT_PREFIX " debug: " args); } while(0)
+#define NS_WARN(args...) \
+	do { printk(KERN_INFO NS_OUTPUT_PREFIX " warnig: " args); } while(0)
+#define NS_ERR(args...) \
+	do { printk(KERN_INFO NS_OUTPUT_PREFIX " errorr: " args); } while(0)
+
+/* Busy-wait delay macros (microseconds, milliseconds) */
+#define NS_UDELAY(us) \
+        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)
+
+/* Good operation completion status */
+#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)) 
+
+/* 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)
+
+/* After a command is input, the simulator goes to one of the following states */
+#define STATE_CMD_READ0        0x00000001 /* read data from the beginning of page */
+#define STATE_CMD_READ1        0x00000002 /* read data from the second half of page */
+#define STATE_CMD_READ2LP      0x00000003 /* read data second command (large page devices) */
+#define STATE_CMD_PAGEPROG     0x00000004 /* start page programm */
+#define STATE_CMD_READOOB      0x00000005 /* read OOB area */
+#define STATE_CMD_ERASE1       0x00000006 /* sector erase first command */
+#define STATE_CMD_STATUS       0x00000007 /* read status */
+#define STATE_CMD_STATUS_M     0x00000008 /* read multi-plane status (isn't implemented) */
+#define STATE_CMD_SEQIN        0x00000009 /* sequential data imput */
+#define STATE_CMD_READID       0x0000000A /* read ID */
+#define STATE_CMD_ERASE2       0x0000000B /* sector erase second command */
+#define STATE_CMD_RESET        0x0000000C /* reset */
+#define STATE_CMD_MASK         0x0000000F /* command states mask */
+
+/* After an addres is input, the simulator goes to one of these states */
+#define STATE_ADDR_PAGE        0x00000010 /* full (row, column) address is accepted */
+#define STATE_ADDR_SEC         0x00000020 /* sector address was accepted */
+#define STATE_ADDR_ZERO        0x00000030 /* one byte zero address was accepted */
+#define STATE_ADDR_MASK        0x00000030 /* address states mask */
+
+/* Durind data input/output the simulator is in these states */
+#define STATE_DATAIN           0x00000100 /* waiting for data input */
+#define STATE_DATAIN_MASK      0x00000100 /* data input states mask */
+
+#define STATE_DATAOUT          0x00001000 /* waiting for page data output */
+#define STATE_DATAOUT_ID       0x00002000 /* waiting for ID bytes output */
+#define STATE_DATAOUT_STATUS   0x00003000 /* waiting for status output */
+#define STATE_DATAOUT_STATUS_M 0x00004000 /* waiting for multi-plane status output */
+#define STATE_DATAOUT_MASK     0x00007000 /* data output states mask */
+
+/* Previous operation is done, ready to accept new requests */
+#define STATE_READY            0x00000000
+
+/* This state is used to mark that the next state isn't known yet */
+#define STATE_UNKNOWN          0x10000000
+
+/* Simulator's actions bit masks */
+#define ACTION_CPY       0x00100000 /* copy page/OOB to the internal buffer */
+#define ACTION_PRGPAGE   0x00200000 /* programm the internal buffer to flash */
+#define ACTION_SECERASE  0x00300000 /* erase sector */
+#define ACTION_ZEROOFF   0x00400000 /* don't add any offset to address */
+#define ACTION_HALFOFF   0x00500000 /* add to address half of page */
+#define ACTION_OOBOFF    0x00600000 /* add to address OOB offset */
+#define ACTION_MASK      0x00700000 /* action mask */
+
+#define NS_OPER_NUM      12 /* Number of operations supported by the simulator */
+#define NS_OPER_STATES   6  /* Maximum number of states in operation */
+
+#define OPT_ANY          0xFFFFFFFF /* any chip supports this operation */
+#define OPT_PAGE256      0x00000001 /* 256-byte  page chips */
+#define OPT_PAGE512      0x00000002 /* 512-byte  page chips */
+#define OPT_PAGE2048     0x00000008 /* 2048-byte page chips */
+#define OPT_SMARTMEDIA   0x00000010 /* SmartMedia technology chips */
+#define OPT_AUTOINCR     0x00000020 /* page number auto inctimentation is possible */
+#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
+#define OPT_LARGEPAGE    (OPT_PAGE2048) /* 2048-byte page chips */
+#define OPT_SMALLPAGE    (OPT_PAGE256  | OPT_PAGE512)  /* 256 and 512-byte page chips */
+
+/* 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 {
+	struct mtd_partition part;
+
+	uint busw;              /* flash chip bus width (8 or 16) */
+	u_char ids[4];          /* chip's ID bytes */
+	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 */
+	uint16_t stateidx;      /* current state index */
+
+	/* The simulated NAND flash image */
+	union flash_media {
+		u_char *byte;
+		uint16_t    *word;
+	} mem;
+
+	/* Internal buffer of page + OOB size bytes */
+	union internal_buffer {
+		u_char *byte;    /* for byte access */
+		uint16_t *word;  /* for 16-bit word access */
+	} buf;
+
+	/* NAND flash "geometry" */
+	struct nandsin_geometry {
+		uint32_t totsz;     /* total flash size, bytes */
+		uint32_t secsz;     /* flash sector (erase block) size, bytes */
+		uint pgsz;          /* NAND flash page size, bytes */
+		uint oobsz;         /* page OOB area size, bytes */
+		uint32_t totszoob;  /* total flash size including OOB, bytes */
+		uint pgszoob;       /* page size including OOB , bytes*/
+		uint secszoob;      /* sector size including OOB, bytes */
+		uint pgnum;         /* total number of pages */
+		uint pgsec;         /* number of pages per sector */
+		uint secshift;      /* bits number in sector size */
+		uint pgshift;       /* bits number in page size */
+		uint oobshift;      /* bits number in OOB size */
+		uint pgaddrbytes;   /* bytes per page address */
+		uint secaddrbytes;  /* bytes per sector address */
+		uint idbytes;       /* the number ID bytes that this chip outputs */
+	} geom;
+
+	/* NAND flash internal registers */
+	struct nandsim_regs {
+		unsigned command; /* the command register */
+		u_char   status;  /* the status register */
+		uint     row;     /* the page number */
+		uint     column;  /* the offset within page */
+		uint     count;   /* internal counter */
+		uint     num;     /* number of bytes which must be processed */
+		uint     off;     /* fixed page offset */
+	} regs;
+
+	/* NAND flash lines state */
+        struct ns_lines_status {
+                int ce;  /* chip Enable */
+                int cle; /* command Latch Enable */
+                int ale; /* address Latch Enable */
+                int wp;  /* write Protect */
+        } lines;
+};
+
+/*
+ * Operations array. To perform any operation the simulator must pass
+ * through the correspondent states chain.
+ */
+static struct nandsim_operations {
+	uint32_t reqopts;  /* options which are required to perform the operation */
+	uint32_t states[NS_OPER_STATES]; /* operation's states */
+} ops[NS_OPER_NUM] = {
+	/* Read page + OOB from the beginning */
+	{OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY,
+			STATE_DATAOUT, STATE_READY}},
+	/* Read page + OOB from the second half */
+	{OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY,
+			STATE_DATAOUT, STATE_READY}},
+	/* Read OOB */
+	{OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY,
+			STATE_DATAOUT, STATE_READY}},
+	/* Programm page starting from the beginning */
+	{OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN,
+			STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+	/* Programm page starting from the beginning */
+	{OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE,
+			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+	/* Programm page starting from the second half */
+	{OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE,
+			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+	/* Programm OOB */
+	{OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE,
+			      STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}},
+	/* Erase sector */
+	{OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}},
+	/* Read status */
+	{OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}},
+	/* Read multi-plane status */
+	{OPT_SMARTMEDIA, {STATE_CMD_STATUS_M, STATE_DATAOUT_STATUS_M, STATE_READY}},
+	/* Read ID */
+	{OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}},
+	/* Large page devices read page */
+	{OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READ2LP | ACTION_CPY,
+			       STATE_DATAOUT, STATE_READY}}
+};
+
+/* MTD structure for NAND controller */
+static struct mtd_info *nsmtd;
+
+static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
+
+/*
+ * Initialize the nandsim structure.
+ *
+ * RETURNS: 0 if success, -ERRNO if failure.
+ */
+static int
+init_nandsim(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = (struct nand_chip *)mtd->priv;
+	struct nandsim   *ns   = (struct nandsim *)(chip->priv);
+	int i;
+
+	if (NS_IS_INITIALIZED(ns)) {
+		NS_ERR("init_nandsim: nandsim is already initialized\n");
+		return -EIO;
+	}
+
+	/* Force mtd to not do delays */
+	chip->chip_delay = 0;
+
+	/* Initialize the NAND flash parameters */
+	ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8;
+	ns->geom.totsz    = mtd->size;
+	ns->geom.pgsz     = mtd->oobblock;
+	ns->geom.oobsz    = mtd->oobsize;
+	ns->geom.secsz    = mtd->erasesize;
+	ns->geom.pgszoob  = ns->geom.pgsz + ns->geom.oobsz;
+	ns->geom.pgnum    = ns->geom.totsz / ns->geom.pgsz;
+	ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz;
+	ns->geom.secshift = ffs(ns->geom.secsz) - 1;
+	ns->geom.pgshift  = chip->page_shift;
+	ns->geom.oobshift = ffs(ns->geom.oobsz) - 1;
+	ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
+	ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
+	ns->options = 0;
+
+	if (ns->geom.pgsz == 256) {
+		ns->options |= OPT_PAGE256;
+	}
+	else if (ns->geom.pgsz == 512) {
+		ns->options |= (OPT_PAGE512 | OPT_AUTOINCR);
+		if (ns->busw == 8)
+			ns->options |= OPT_PAGE512_8BIT;
+	} else if (ns->geom.pgsz == 2048) {
+		ns->options |= OPT_PAGE2048;
+	} else {
+		NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz);
+		return -EIO;
+	}
+
+	if (ns->options & OPT_SMALLPAGE) {
+		if (ns->geom.totsz < (64 << 20)) {
+			ns->geom.pgaddrbytes  = 3;
+			ns->geom.secaddrbytes = 2;
+		} else {
+			ns->geom.pgaddrbytes  = 4;
+			ns->geom.secaddrbytes = 3;
+		}
+	} else {
+		if (ns->geom.totsz <= (128 << 20)) {
+			ns->geom.pgaddrbytes  = 5;
+			ns->geom.secaddrbytes = 2;
+		} else {
+			ns->geom.pgaddrbytes  = 5;
+			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)
+                        continue;
+		if (!(nand_flash_ids[i].options & NAND_NO_AUTOINCR))
+			ns->options |= OPT_AUTOINCR;
+	}
+
+	if (ns->busw == 16)
+		NS_WARN("16-bit flashes support wasn't tested\n");
+
+	printk("flash size: %u MiB\n",          ns->geom.totsz >> 20);
+	printk("page size: %u bytes\n",         ns->geom.pgsz);
+	printk("OOB area size: %u bytes\n",     ns->geom.oobsz);
+	printk("sector size: %u KiB\n",         ns->geom.secsz >> 10);
+	printk("pages number: %u\n",            ns->geom.pgnum);
+	printk("pages per sector: %u\n",        ns->geom.pgsec);
+	printk("bus width: %u\n",               ns->busw);
+	printk("bits in sector size: %u\n",     ns->geom.secshift);
+	printk("bits in page size: %u\n",       ns->geom.pgshift);
+	printk("bits in OOB size: %u\n",        ns->geom.oobshift);
+	printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10);
+	printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
+	printk("sector address bytes: %u\n",    ns->geom.secaddrbytes);
+	printk("options: %#x\n",                ns->options);
+
+	/* Map / allocate and initialize the flash image */
+#ifdef CONFIG_NS_ABS_POS
+	ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob);
+	if (!ns->mem.byte) {
+		NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", 
+			(void *)CONFIG_NS_ABS_POS);
+		return -ENOMEM;
+	}
+#else
+	ns->mem.byte = vmalloc(ns->geom.totszoob);
+	if (!ns->mem.byte) {
+		NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n",
+			ns->geom.totszoob);
+		return -ENOMEM;
+	}
+	memset(ns->mem.byte, 0xFF, ns->geom.totszoob);
+#endif
+
+	/* Allocate / initialize the internal buffer */
+	ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
+	if (!ns->buf.byte) {
+		NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n",
+			ns->geom.pgszoob);
+		goto error;
+	}
+	memset(ns->buf.byte, 0xFF, ns->geom.pgszoob);
+
+	/* Fill the partition_info structure */
+	ns->part.name   = "NAND simulator partition";
+	ns->part.offset = 0;
+	ns->part.size   = ns->geom.totsz;
+
+	return 0;
+
+error:
+#ifdef CONFIG_NS_ABS_POS
+	iounmap(ns->mem.byte);
+#else
+	vfree(ns->mem.byte);
+#endif
+
+	return -ENOMEM;
+}
+
+/*
+ * Free the nandsim structure.
+ */
+static void
+free_nandsim(struct nandsim *ns)
+{
+	kfree(ns->buf.byte);
+
+#ifdef CONFIG_NS_ABS_POS
+	iounmap(ns->mem.byte);
+#else
+	vfree(ns->mem.byte);
+#endif
+
+	return;
+}
+
+/*
+ * Returns the string representation of 'state' state.
+ */
+static char *
+get_state_name(uint32_t state)
+{
+	switch (NS_STATE(state)) {
+		case STATE_CMD_READ0:
+			return "STATE_CMD_READ0";
+		case STATE_CMD_READ1:
+			return "STATE_CMD_READ1";
+		case STATE_CMD_PAGEPROG:
+			return "STATE_CMD_PAGEPROG";
+		case STATE_CMD_READOOB:
+			return "STATE_CMD_READOOB";
+		case STATE_CMD_READ2LP:
+			return "STATE_CMD_READ2LP";
+		case STATE_CMD_ERASE1:
+			return "STATE_CMD_ERASE1";
+		case STATE_CMD_STATUS:
+			return "STATE_CMD_STATUS";
+		case STATE_CMD_STATUS_M:
+			return "STATE_CMD_STATUS_M";
+		case STATE_CMD_SEQIN:
+			return "STATE_CMD_SEQIN";
+		case STATE_CMD_READID:
+			return "STATE_CMD_READID";
+		case STATE_CMD_ERASE2:
+			return "STATE_CMD_ERASE2";
+		case STATE_CMD_RESET:
+			return "STATE_CMD_RESET";
+		case STATE_ADDR_PAGE:
+			return "STATE_ADDR_PAGE";
+		case STATE_ADDR_SEC:
+			return "STATE_ADDR_SEC";
+		case STATE_ADDR_ZERO:
+			return "STATE_ADDR_ZERO";
+		case STATE_DATAIN:
+			return "STATE_DATAIN";
+		case STATE_DATAOUT:
+			return "STATE_DATAOUT";
+		case STATE_DATAOUT_ID:
+			return "STATE_DATAOUT_ID";
+		case STATE_DATAOUT_STATUS:
+			return "STATE_DATAOUT_STATUS";
+		case STATE_DATAOUT_STATUS_M:
+			return "STATE_DATAOUT_STATUS_M";
+		case STATE_READY:
+			return "STATE_READY";
+		case STATE_UNKNOWN:
+			return "STATE_UNKNOWN";
+	}
+
+	NS_ERR("get_state_name: unknown state, BUG\n");
+	return NULL;
+}
+
+/*
+ * Check if command is valid.
+ *
+ * RETURNS: 1 if wrong command, 0 if right.
+ */
+static int
+check_command(int cmd)
+{
+	switch (cmd) {
+		
+	case NAND_CMD_READ0:
+	case NAND_CMD_READ2LP:
+	case NAND_CMD_PAGEPROG:
+	case NAND_CMD_READOOB:
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_STATUS:
+	case NAND_CMD_SEQIN:
+	case NAND_CMD_READID:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_RESET:
+	case NAND_CMD_READ1:
+		return 0;
+		
+	case NAND_CMD_STATUS_MULTI:
+	default:
+		return 1;
+	}
+}
+
+/*
+ * Returns state after command is accepted by command number.
+ */
+static uint32_t
+get_state_by_command(unsigned command)
+{
+	switch (command) {
+		case NAND_CMD_READ0:
+			return STATE_CMD_READ0;
+		case NAND_CMD_READ1:
+			return STATE_CMD_READ1;
+		case NAND_CMD_PAGEPROG:
+			return STATE_CMD_PAGEPROG;
+		case NAND_CMD_READ2LP:
+			return STATE_CMD_READ2LP;
+		case NAND_CMD_READOOB:
+			return STATE_CMD_READOOB;
+		case NAND_CMD_ERASE1:
+			return STATE_CMD_ERASE1;
+		case NAND_CMD_STATUS:
+			return STATE_CMD_STATUS;
+		case NAND_CMD_STATUS_MULTI:
+			return STATE_CMD_STATUS_M;
+		case NAND_CMD_SEQIN:
+			return STATE_CMD_SEQIN;
+		case NAND_CMD_READID:
+			return STATE_CMD_READID;
+		case NAND_CMD_ERASE2:
+			return STATE_CMD_ERASE2;
+		case NAND_CMD_RESET:
+			return STATE_CMD_RESET;
+	}
+
+	NS_ERR("get_state_by_command: unknown command, BUG\n");
+	return 0;
+}
+
+/*
+ * Move an address byte to the correspondent internal register.
+ */
+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 {
+		ns->regs.row |= (byte << 8 * (ns->regs.count -
+						ns->geom.pgaddrbytes +
+						ns->geom.secaddrbytes));
+	}
+
+	return;
+}
+		
+/*
+ * Switch to STATE_READY state.
+ */
+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));
+
+	ns->state       = STATE_READY;
+	ns->nxstate     = STATE_UNKNOWN;
+	ns->op          = NULL;
+	ns->npstates    = 0;
+	ns->stateidx    = 0;
+	ns->regs.num    = 0;
+	ns->regs.count  = 0;
+	ns->regs.off    = 0;
+	ns->regs.row    = 0;
+	ns->regs.column = 0;
+	ns->regs.status = status;
+}
+
+/*
+ * If the operation isn't known yet, try to find it in the global array
+ * of supported operations.
+ *
+ * Operation can be unknown because of the following.
+ *   1. New command was accepted and this is the firs call to find the
+ *      correspondent states chain. In this case ns->npstates = 0;
+ *   2. There is several operations which begin with the same command(s)
+ *      (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
+ *
+ * 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.
+ *
+ * The operation can be unknown only while commands are input to the chip.
+ * As soon as address command is accepted, the operation must be known.
+ * 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.
+ *
+ * If no matches found, the functions does the following:
+ *   1. if there are saved states present, try to ignore them and search
+ *      again only using the last command. If nothing was found, switch
+ *      to the STATE_READY state.
+ *   2. if there are no saved states, switch to the STATE_READY state.
+ *
+ * RETURNS: -2 - no matched operations found.
+ *          -1 - several matches.
+ *           0 - operation is found.
+ */
+static int
+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;
+		} else {
+			if (NS_STATE(ns->state) != NS_STATE(ops[i].states[ns->npstates]))
+				continue;
+		}
+
+		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;
+				break;
+			}
+
+		if (found) {
+			idx = i;
+			opsfound += 1;
+		}
+	}
+
+	if (opsfound == 1) {
+		/* 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
+			 * not be one of STATE_ADDR_*, but the STATE_ADDR_*
+			 * state must be the next state (ns->nxstate).
+			 */
+			ns->stateidx = ns->npstates - 1;
+		} else {
+			ns->stateidx = ns->npstates;
+		}
+		ns->npstates = 0;
+		ns->state = ns->op[ns->stateidx];
+		ns->nxstate = ns->op[ns->stateidx + 1];
+		NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n",
+				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) {
+			NS_DBG("find_operation: no operation found, try again with state %s\n",
+					get_state_name(ns->state));
+			ns->npstates = 0;
+			return find_operation(ns, 0);
+
+		}
+		NS_DBG("find_operation: no operations found\n");
+		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;
+
+	return -1;
+}
+
+/*
+ * If state has any action bit, perform this action.
+ *
+ * RETURNS: 0 if success, -1 if error.
+ */
+static int
+do_state_action(struct nandsim *ns, uint32_t action)
+{
+	int i, num;
+	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);
+		return -1;
+	}
+
+	switch (action) {
+
+	case ACTION_CPY:
+		/*
+		 * Copy page data to the internal buffer.
+		 */
+
+		/* Column shouldn't be very large */
+		if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) {
+			NS_ERR("do_state_action: column number is too large\n");
+			break;
+		}
+		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+		memcpy(ns->buf.byte, ns->mem.byte + NS_RAW_OFFSET(ns) + ns->regs.off, num);
+
+		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);
+
+		break;
+
+	case ACTION_SECERASE:
+		/*
+		 * 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:
+		/*
+		 * Programm page - move internal buffer data to the page.
+		 */
+
+		if (ns->lines.wp) {
+			NS_WARN("do_state_action: device is write-protected, programm\n");
+			return -1;
+		}
+
+		num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
+		if (num != ns->regs.count) {
+			NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n",
+					ns->regs.count, num);
+			return -1;
+		}
+
+		for (i = 0; i < num; i++)
+			ns->mem.byte[NS_RAW_OFFSET(ns) + ns->regs.off + i] &= ns->buf.byte[i];
+
+		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;
+		break;
+
+	case ACTION_HALFOFF:
+		if (!(ns->options & OPT_PAGE512_8BIT)) {
+			NS_ERR("do_state_action: BUG! can't skip half of page for non-512"
+				"byte page size 8x chips\n");
+			return -1;
+		}
+		NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2);
+		ns->regs.off = ns->geom.pgsz/2;
+		break;
+
+	case ACTION_OOBOFF:
+		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");
+	}
+
+	return 0;
+}
+
+/*
+ * Switch simulator's state.
+ */
+static void
+switch_state(struct nandsim *ns)
+{
+	if (ns->op) {
+		/*
+		 * 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];
+
+		NS_DBG("switch_state: operation is known, switch to the next state, "
+			"state: %s, nxstate: %s\n",
+			get_state_name(ns->state), get_state_name(ns->nxstate));
+
+		/* See, whether we need to do some action */
+		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
+			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.
+		 */
+		ns->state = get_state_by_command(ns->regs.command);
+
+		NS_DBG("switch_state: operation is unknown, try to find it\n");
+
+		if (find_operation(ns, 0) != 0)
+			return;
+
+		if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) {
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+			return;
+		}
+	}
+
+	/* For 16x devices column means the page offset in words */
+	if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) {
+		NS_DBG("switch_state: double the column number for 16x device\n");
+		ns->regs.column <<= 1;
+	}
+
+	if (NS_STATE(ns->nxstate) == STATE_READY) {
+		/*
+		 * The current state is the last. Return to STATE_READY
+		 */
+
+		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) {
+			NS_WARN("switch_state: not all bytes were processed, %d left\n",
+					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;
+
+		NS_DBG("switch_state: the next state is data I/O, switch, "
+			"state: %s, nxstate: %s\n",
+			get_state_name(ns->state), get_state_name(ns->nxstate));
+
+		/*
+		 * Set the internal register to the count of bytes which
+		 * are expected to be input or output
+		 */
+		switch (NS_STATE(ns->state)) {
+			case STATE_DATAIN:
+			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");
+		}
+
+	} else if (ns->nxstate & STATE_ADDR_MASK) {
+		/*
+		 * If the next state is address input, set the internal
+		 * register to the number of expected address bytes
+		 */
+
+		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;
+
+			default:
+				NS_ERR("switch_state: BUG! unknown address state\n");
+		}
+	} else {
+		/* 
+		 * Just reset internal counters.
+		 */
+
+		ns->regs.num = 0;
+		ns->regs.count = 0;
+	}
+}
+
+static void
+ns_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+	struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
+
+	switch (cmd) {
+
+	/* set CLE line high */
+	case NAND_CTL_SETCLE:
+		NS_DBG("ns_hwcontrol: start command latch cycles\n");
+		ns->lines.cle  = 1;
+		break;
+
+	/* set CLE line low */
+	case NAND_CTL_CLRCLE:
+		NS_DBG("ns_hwcontrol: stop command latch cycles\n");
+		ns->lines.cle  = 0;
+		break;
+
+	/* set ALE line high */
+	case NAND_CTL_SETALE:
+		NS_DBG("ns_hwcontrol: start address latch cycles\n");
+		ns->lines.ale   = 1;
+		break;
+
+	/* set ALE line low */
+	case NAND_CTL_CLRALE:
+		NS_DBG("ns_hwcontrol: stop address latch cycles\n");
+		ns->lines.ale  = 0;
+		break;
+
+	/* set WP line high */
+	case NAND_CTL_SETWP:
+		NS_DBG("ns_hwcontrol: enable write protection\n");
+		ns->lines.wp = 1;
+		break;
+
+	/* set WP line low */
+	case NAND_CTL_CLRWP:
+		NS_DBG("ns_hwcontrol: disable write protection\n");
+		ns->lines.wp = 0;
+		break;
+
+	/* set CE line low */
+	case NAND_CTL_SETNCE:
+		NS_DBG("ns_hwcontrol: enable chip\n");
+		ns->lines.ce = 1;
+		break;
+
+	/* set CE line high */
+	case NAND_CTL_CLRNCE:
+		NS_DBG("ns_hwcontrol: disable chip\n");
+		ns->lines.ce = 0;
+		break;
+
+	default:
+		NS_ERR("hwcontrol: unknown command\n");
+        }
+
+	return;
+}
+
+static u_char
+ns_nand_read_byte(struct mtd_info *mtd)
+{
+        struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
+	u_char outb = 0x00;
+
+	/* Sanity and correctness checks */
+	if (!ns->lines.ce) {
+		NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb);
+		return outb;
+	}
+	if (ns->lines.ale || ns->lines.cle) {
+		NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb);
+		return outb;
+	}
+	if (!(ns->state & STATE_DATAOUT_MASK)) {
+		NS_WARN("read_byte: unexpected data output cycle, state is %s "
+			"return %#x\n", get_state_name(ns->state), (uint)outb);
+		return outb;
+	}
+
+	/* Status register may be read as many times as it is wanted */
+	if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) {
+		NS_DBG("read_byte: return %#x status\n", ns->regs.status);
+		return ns->regs.status;
+	}
+
+	/* Check if there is any data in the internal buffer which may be read */
+	if (ns->regs.count == ns->regs.num) {
+		NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb);
+		return outb;
+	}
+
+	switch (NS_STATE(ns->state)) {
+		case STATE_DATAOUT:
+			if (ns->busw == 8) {
+				outb = ns->buf.byte[ns->regs.count];
+				ns->regs.count += 1;
+			} else {
+				outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]);
+				ns->regs.count += 2;
+			}
+			break;
+		case STATE_DATAOUT_ID:
+			NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num);
+			outb = ns->ids[ns->regs.count];
+			ns->regs.count += 1;
+			break;
+		default:
+			BUG();
+	}
+	
+	if (ns->regs.count == ns->regs.num) {
+		NS_DBG("read_byte: all bytes were read\n");
+
+		/*
+		 * The OPT_AUTOINCR allows to read next conseqitive pages without
+		 * new read operation cycle.
+		 */
+		if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) {
+			ns->regs.count = 0;
+			if (ns->regs.row + 1 < ns->geom.pgnum)
+				ns->regs.row += 1;
+			NS_DBG("read_byte: switch to the next page (%#x)\n", ns->regs.row);
+			do_state_action(ns, ACTION_CPY);
+		}
+		else if (NS_STATE(ns->nxstate) == STATE_READY)
+			switch_state(ns);
+		
+	}
+	
+	return outb;
+}
+
+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");
+		return;
+	}
+	if (ns->lines.ale && ns->lines.cle) {
+		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.
+		 */
+
+		if (byte == NAND_CMD_RESET) {
+			NS_LOG("reset chip\n");
+			switch_to_ready_state(ns, NS_STATUS_OK(ns));
+			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.
+		 */
+		if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
+			|| NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M
+			|| ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT))
+			switch_state(ns);
+
+		/* Check if chip is expecting command */
+		if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) {
+			/*
+			 * We are in situation when something else (not command)
+			 * was expected but command was input. In this case ignore
+			 * previous command(s)/state(s) and accept the last one.
+			 */
+			NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, "
+				"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;
+		switch_state(ns);
+
+	} else if (ns->lines.ale == 1) {
+		/*
+		 * The byte written is an address.
+		 */
+
+		if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) {
+
+			NS_DBG("write_byte: operation isn't known yet, identify it\n");
+
+			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:
+					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;
+				default:
+					BUG();
+			}
+		}
+
+		/* Check that chip is expecting address */
+		if (!(ns->nxstate & STATE_ADDR_MASK)) {
+			NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, "
+				"switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate));
+			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");
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+			return;
+		}
+
+		accept_addr_byte(ns, byte);
+
+		ns->regs.count += 1;
+
+		NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n",
+				(uint)byte, ns->regs.count, ns->regs.num);
+
+		if (ns->regs.count == ns->regs.num) {
+			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, "
+				"switch to %s\n", (uint)byte,
+				get_state_name(ns->state), get_state_name(STATE_READY));
+			switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+			return;
+		}
+
+		/* Check if this is expected byte */
+		if (ns->regs.count == ns->regs.num) {
+			NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n",
+					ns->regs.num);
+			return;
+		}
+
+		if (ns->busw == 8) {
+			ns->buf.byte[ns->regs.count] = byte;
+			ns->regs.count += 1;
+		} else {
+			ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte);
+			ns->regs.count += 2;
+		}
+	}
+
+	return;
+}
+
+static int
+ns_device_ready(struct mtd_info *mtd)
+{
+	NS_DBG("device_ready\n");
+	return 1;
+}
+
+static uint16_t
+ns_nand_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = (struct nand_chip *)mtd->priv;
+
+	NS_DBG("read_word\n");
+	
+	return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
+}
+
+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 
+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;
+
+	/* Check that chip is expecting data input */
+	if (!(ns->state & STATE_DATAIN_MASK)) {
+		NS_ERR("write_buf: data input isn't expected, state is %s, "
+			"switch to STATE_READY\n", get_state_name(ns->state));
+		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+		return;
+	}
+
+	/* Check if these are expected bytes */
+	if (ns->regs.count + len > ns->regs.num) {
+		NS_ERR("write_buf: too many input bytes\n");
+		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+		return;
+	}
+
+	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 
+ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+        struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
+
+	/* Sanity and correctness checks */
+	if (!ns->lines.ce) {
+		NS_ERR("read_buf: chip is disabled\n");
+		return;
+	}
+	if (ns->lines.ale || ns->lines.cle) {
+		NS_ERR("read_buf: ALE or CLE pin is high\n");
+		return;
+	}
+	if (!(ns->state & STATE_DATAOUT_MASK)) {
+		NS_WARN("read_buf: unexpected data output cycle, current state is %s\n",
+			get_state_name(ns->state));
+		return;
+	}
+
+	if (NS_STATE(ns->state) != STATE_DATAOUT) {
+		int i;
+
+		for (i = 0; i < len; i++)
+			buf[i] = ((struct nand_chip *)mtd->priv)->read_byte(mtd);
+
+		return;
+	}
+
+	/* Check if these are expected bytes */
+	if (ns->regs.count + len > ns->regs.num) {
+		NS_ERR("read_buf: too many bytes to read\n");
+		switch_to_ready_state(ns, NS_STATUS_FAILED(ns));
+		return;
+	}
+
+	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;
+			if (ns->regs.row + 1 < ns->geom.pgnum)
+				ns->regs.row += 1;
+			NS_DBG("read_buf: switch to the next page (%#x)\n", ns->regs.row);
+			do_state_action(ns, ACTION_CPY);
+		}
+		else if (NS_STATE(ns->nxstate) == STATE_READY)
+			switch_state(ns);
+	}
+	
+	return;
+}
+
+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);
+
+	if (!memcmp(buf, &ns_verify_buf[0], len)) {
+		NS_DBG("verify_buf: the buffer is OK\n");
+		return 0;
+	} else {
+		NS_DBG("verify_buf: the buffer is wrong\n");
+		return -EFAULT;
+	}
+}
+
+/*
+ * Having only NAND chip IDs we call nand_scan which detects NAND flash
+ * parameters and then calls scan_bbt in order to scan/find/build the
+ * NAND flash bad block table. But since at that moment the NAND flash
+ * image isn't allocated in the simulator, errors arise. To avoid this
+ * we redefine the scan_bbt callback and initialize the nandsim structure
+ * before the flash media scanning.
+ */
+int ns_scan_bbt(struct mtd_info *mtd)
+{ 
+	struct nand_chip *chip = (struct nand_chip *)mtd->priv;
+	struct nandsim   *ns   = (struct nandsim *)(chip->priv);
+	int retval;
+
+	if (!NS_IS_INITIALIZED(ns))
+		if ((retval = init_nandsim(mtd)) != 0) {
+			NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
+			return retval;
+		}
+	if ((retval = nand_default_bbt(mtd)) != 0) {
+		free_nandsim(ns);
+		return retval;
+	}
+
+	return 0;
+}
+
+/*
+ * Module initialization function
+ */
+int __init ns_init_module(void)
+{
+	struct nand_chip *chip;
+	struct nandsim *nand;
+	int retval = -ENOMEM;
+
+	if (bus_width != 8 && bus_width != 16) {
+		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);
+	if (!nsmtd) {
+		NS_ERR("unable to allocate core structures.\n");
+		return -ENOMEM;
+	}
+	memset(nsmtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip) +
+			sizeof(struct nandsim));
+	chip        = (struct nand_chip *)(nsmtd + 1);
+        nsmtd->priv = (void *)chip;
+	nand        = (struct nandsim *)(chip + 1);
+	chip->priv  = (void *)nand;	
+
+	/*
+	 * Register simulator's callbacks.
+	 */
+	chip->hwcontrol  = ns_hwcontrol;
+	chip->read_byte  = ns_nand_read_byte;
+	chip->dev_ready  = ns_device_ready;
+	chip->scan_bbt   = ns_scan_bbt;
+	chip->write_byte = ns_nand_write_byte;
+	chip->write_buf  = ns_nand_write_buf;
+	chip->read_buf   = ns_nand_read_buf;
+	chip->verify_buf = ns_nand_verify_buf;
+	chip->write_word = ns_nand_write_word;
+	chip->read_word  = ns_nand_read_word;
+	chip->eccmode    = NAND_ECC_SOFT;
+
+	/* 
+	 * Perform minimum nandsim structure initialization to handle
+	 * the initial ID read command correctly 
+	 */
+	if (third_id_byte != 0xFF || fourth_id_byte != 0xFF)
+		nand->geom.idbytes = 4;
+	else
+		nand->geom.idbytes = 2;
+	nand->regs.status = NS_STATUS_OK(nand);
+	nand->nxstate = STATE_UNKNOWN;
+	nand->options |= OPT_PAGE256; /* temporary value */
+	nand->ids[0] = first_id_byte;
+	nand->ids[1] = second_id_byte;
+	nand->ids[2] = third_id_byte;
+	nand->ids[3] = fourth_id_byte;
+	if (bus_width == 16) {
+		nand->busw = 16;
+		chip->options |= NAND_BUSWIDTH_16;
+	}
+
+	if ((retval = nand_scan(nsmtd, 1)) != 0) {
+		NS_ERR("can't register NAND Simulator\n");
+		if (retval > 0)
+			retval = -ENXIO;
+		goto error;
+	}
+
+	/* Register NAND as one big partition */
+	add_mtd_partitions(nsmtd, &nand->part, 1);
+
+        return 0;
+
+error:
+	kfree(nsmtd);
+
+	return retval;
+}
+
+module_init(ns_init_module);
+
+/*
+ * Module clean-up function
+ */
+static void __exit ns_cleanup_module(void)
+{
+	struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv);
+
+	free_nandsim(ns);    /* Free nandsim private resources */
+	nand_release(nsmtd); /* Unregisterd drived */
+	kfree(nsmtd);        /* Free other structures */
+}
+
+module_exit(ns_cleanup_module);
+
+MODULE_LICENSE ("GPL");
+MODULE_AUTHOR ("Artem B. Bityuckiy");
+MODULE_DESCRIPTION ("The NAND flash simulator");
+
diff -Nru a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
--- a/drivers/mtd/nand/s3c2410.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/nand/s3c2410.c	2004-12-12 17:44:47 -08:00
@@ -11,7 +11,7 @@
  *	28-Sep-2004  BJD  Fixed ECC placement for Hardware mode
  *	12-Oct-2004  BJD  Fixed errors in use of platform data
  *
- * $Id: s3c2410.c,v 1.5 2004/10/12 10:10:15 bjd Exp $
+ * $Id: s3c2410.c,v 1.6 2004/11/24 12:25:48 bjd Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -167,7 +167,7 @@
 	if (plat != NULL) {
 		tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8);
 		twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
-		twrph1 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
+		twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
 	} else {
 		/* default timings */
 		tacls = 8;
diff -Nru a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/mtd/nand/sharpsl.c	2004-12-12 17:44:47 -08:00
@@ -0,0 +1,273 @@
+/*
+ * drivers/mtd/nand/sharpsl.c
+ *
+ *  Copyright (C) 2004 Richard Purdie
+ *
+ *  $Id: sharpsl.c,v 1.2 2004/11/24 20:38:07 rpurdie Exp $
+ *
+ *  Based on Sharp's NAND driver sharp_sl.c
+ *
+ * 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/genhd.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+static void __iomem *sharpsl_io_base;
+static int sharpsl_phys_base = 0x0C000000;
+
+/* register offset */
+#define ECCLPLB	 	sharpsl_io_base+0x00	/* line parity 7 - 0 bit */
+#define ECCLPUB	 	sharpsl_io_base+0x04	/* line parity 15 - 8 bit */
+#define ECCCP	   	sharpsl_io_base+0x08	/* column parity 5 - 0 bit */
+#define ECCCNTR	 	sharpsl_io_base+0x0C	/* ECC byte counter */
+#define ECCCLRR	 	sharpsl_io_base+0x10	/* cleare ECC */
+#define FLASHIO	 	sharpsl_io_base+0x14	/* Flash I/O */
+#define FLASHCTL	sharpsl_io_base+0x18	/* Flash Control */
+
+/* Flash control bit */
+#define FLRYBY		(1 << 5)
+#define FLCE1		(1 << 4)
+#define FLWP		(1 << 3)
+#define FLALE		(1 << 2)
+#define FLCLE		(1 << 1)
+#define FLCE0		(1 << 0)
+
+
+/*
+ * MTD structure for SharpSL
+ */
+static struct mtd_info *sharpsl_mtd = NULL;
+
+/*
+ * Define partitions for flash device
+ */
+#define DEFAULT_NUM_PARTITIONS 3
+
+#if defined CONFIG_MACH_POODLE
+#define SHARPSL_ROOTFS_SIZE 22
+#define SHARPSL_FLASH_SIZE 64
+#elif defined CONFIG_MACH_CORGI 
+#define SHARPSL_ROOTFS_SIZE 25
+#define SHARPSL_FLASH_SIZE 32
+#elif defined CONFIG_MACH_SHEPHERD
+#define SHARPSL_ROOTFS_SIZE 25
+#define SHARPSL_FLASH_SIZE 64
+#elif defined CONFIG_MACH_HUSKY
+#define SHARPSL_ROOTFS_SIZE 53
+#define SHARPSL_FLASH_SIZE 128
+#elif defined CONFIG_MACH_TOSA
+#define SHARPSL_ROOTFS_SIZE 28
+#define SHARPSL_FLASH_SIZE 64
+#else
+#define SHARPSL_ROOTFS_SIZE 30
+#define SHARPSL_FLASH_SIZE 64
+#endif
+
+static int nr_partitions;
+static struct mtd_partition sharpsl_nand_default_partition_info[] = {
+	{
+	.name = "NAND flash partition 0",
+	.offset = 0,
+	.size = 7 * 1024 * 1024,
+	},
+	
+	{
+	.name = "NAND flash partition 1",
+	.offset = 7 * 1024 * 1024,
+	.size = SHARPSL_ROOTFS_SIZE * 1024 * 1024,
+	},
+	{
+	.name = "NAND flash partition 2",
+	.offset = (SHARPSL_ROOTFS_SIZE+7) * 1024 * 1024,
+	.size = (SHARPSL_FLASH_SIZE - SHARPSL_ROOTFS_SIZE - 7) * 1024 * 1024,
+	},
+};
+
+/* 
+ *	hardware specific access to control-lines
+ */
+static void
+sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
+{
+	switch (cmd) {
+	case NAND_CTL_SETCLE: 
+		writeb(readb(FLASHCTL) | FLCLE, FLASHCTL);
+		break;
+	case NAND_CTL_CLRCLE:
+		writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL);
+		break;
+
+	case NAND_CTL_SETALE:
+		writeb(readb(FLASHCTL) | FLALE, FLASHCTL);
+		break;
+	case NAND_CTL_CLRALE:
+		writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL);
+		break;
+
+	case NAND_CTL_SETNCE: 
+		writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL);
+		break;
+	case NAND_CTL_CLRNCE: 
+		writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL);
+		break;
+	}
+}
+
+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
+
+static struct nand_bbt_descr sharpsl_bbt = {
+	.options = 0,
+	.offs = 4,
+	.len = 2,
+	.pattern = scan_ff_pattern
+};
+
+static int
+sharpsl_nand_dev_ready(struct mtd_info* mtd)
+{
+	return !((readb(FLASHCTL) & FLRYBY) == 0);
+}
+
+static void
+sharpsl_nand_enable_hwecc(struct mtd_info* mtd, int mode)
+{
+	writeb(0 ,ECCCLRR);
+}
+
+static int
+sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat,
+				u_char* ecc_code)
+{
+	ecc_code[0] = ~readb(ECCLPUB);
+	ecc_code[1] = ~readb(ECCLPLB);
+	ecc_code[2] = (~readb(ECCCP) << 2) | 0x03;
+	return readb(ECCCNTR) != 0;
+}
+
+
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+
+/*
+ * Main initialization routine
+ */
+int __init
+sharpsl_nand_init(void)
+{
+	struct nand_chip *this;
+	struct mtd_partition* sharpsl_partition_info;
+	int err = 0;
+
+	/* Allocate memory for MTD device structure and private data */
+	sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
+				GFP_KERNEL);
+	if (!sharpsl_mtd) {
+		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){
+		printk("ioremap to access Sharp SL NAND chip failed\n");
+		kfree(sharpsl_mtd);
+		return -EIO;
+	}
+	
+	/* Get pointer to private data */
+	this = (struct nand_chip *) (&sharpsl_mtd[1]);
+
+	/* Initialize structures */
+	memset((char *) sharpsl_mtd, 0, sizeof(struct mtd_info));
+	memset((char *) this, 0, sizeof(struct nand_chip));
+
+	/* Link the private data with the MTD structure */
+	sharpsl_mtd->priv = this;
+
+	/*
+	 * PXA initialize
+	 */
+	writeb(readb(FLASHCTL) | FLWP, FLASHCTL);
+
+	/* Set address of NAND IO lines */
+	this->IO_ADDR_R = FLASHIO;
+	this->IO_ADDR_W = FLASHIO;
+	/* Set address of hardware control function */
+	this->hwcontrol = sharpsl_nand_hwcontrol;
+	this->dev_ready = sharpsl_nand_dev_ready;
+	/* 15 us command delay time */
+	this->chip_delay = 15;
+	/* set eccmode using hardware ECC */
+	this->eccmode = NAND_ECC_HW3_256;
+	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);
+	if (err) {
+		iounmap(sharpsl_io_base);
+		kfree(sharpsl_mtd);
+		return err;
+	}
+
+	/* Register the partitions */
+	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;
+	}
+
+#ifdef CONFIG_MACH_HUSKY
+	/* Need to use small eraseblock size for backward compatibility */
+	sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS;
+#endif
+
+	add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions);
+
+	/* Return happy */
+	return 0;
+}
+module_init(sharpsl_nand_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit sharpsl_nand_cleanup(void)
+{
+	struct nand_chip *this = (struct nand_chip *) &sharpsl_mtd[1];
+
+	/* Release resources, unregister device */
+	nand_release(sharpsl_mtd);
+
+	iounmap(sharpsl_io_base);
+
+	/* Free the MTD device structure */
+	kfree(sharpsl_mtd);
+}
+module_exit(sharpsl_nand_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");
diff -Nru a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
--- a/drivers/mtd/nftlmount.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/nftlmount.c	2004-12-12 17:44:47 -08:00
@@ -4,7 +4,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.39 2004/11/05 22:51:41 kalev Exp $
+ * $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev 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.39 $";
+char nftlmountrev[]="$Revision: 1.40 $";
 
 /* 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
@@ -302,8 +302,6 @@
 	struct nftl_uci1 uci;
 	struct erase_info *instr = &nftl->instr;
 
-	instr->mtd = nftl->mbd.mtd;
-
 	/* Read the Unit Control Information #1 for Wear-Leveling */
 	if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
 			8, &retlen, (char *)&uci) < 0)
@@ -320,6 +318,7 @@
 	memset(instr, 0, sizeof(struct erase_info));
 
 	/* XXX: use async erase interface, XXX: test return code */
+	instr->mtd = nftl->mbd.mtd;
 	instr->addr = block * nftl->EraseSize;
 	instr->len = nftl->EraseSize;
 	MTD_ERASE(nftl->mbd.mtd, instr);
diff -Nru a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
--- a/drivers/mtd/redboot.c	2004-12-12 17:44:47 -08:00
+++ b/drivers/mtd/redboot.c	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 /*
- * $Id: redboot.c,v 1.15 2004/08/10 07:55:16 dwmw2 Exp $
+ * $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $
  *
  * Parse RedBoot-style Flash Image System (FIS) tables and
  * produce a Linux partition array to match.
@@ -30,6 +30,9 @@
 	struct fis_list *next;
 };
 
+static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
+module_param(directory, int, 0);
+
 static inline int redboot_checksum(struct fis_image_desc *img)
 {
 	/* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
@@ -50,6 +53,8 @@
 	char *nullname;
 	int namelen = 0;
 	int nulllen = 0;
+	int numslots;
+	unsigned long offset;
 #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
 	static char nullstring[] = "unallocated";
 #endif
@@ -59,8 +64,15 @@
 	if (!buf)
 		return -ENOMEM;
 
-	/* Read the start of the last erase block */
-	ret = master->read(master, master->size - master->erasesize,
+	if ( directory < 0 )
+		offset = master->size + directory*master->erasesize;
+	else
+		offset = directory*master->erasesize;
+
+	printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
+	       master->name, offset);
+
+	ret = master->read(master, offset,
 			   master->erasesize, &retlen, (void *)buf);
 
 	if (ret)
@@ -71,12 +83,16 @@
 		goto out;
 	}
 
-	/* RedBoot image could appear in any of the first three slots */
-	for (i = 0; i < 3; i++) {
-		if (!memcmp(buf[i].name, "RedBoot", 8))
+	numslots = (master->erasesize / sizeof(struct fis_image_desc));
+	for (i = 0; i < numslots; i++) {
+		if (buf[i].name[0] == 0xff) {
+			i = numslots;
+			break;
+		}
+		if (!memcmp(buf[i].name, "FIS directory", 14))
 			break;
 	}
-	if (i == 3) {
+	if (i == numslots) {
 		/* Didn't find it */
 		printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
 		       master->name);
@@ -84,7 +100,7 @@
 		goto out;
 	}
 
-	for (i = 0; i < master->erasesize / sizeof(struct fis_image_desc); i++) {
+	for (i = 0; i < numslots; i++) {
 		struct fis_list *new_fl, **prev;
 
 		if (buf[i].name[0] == 0xff)
diff -Nru a/fs/Kconfig b/fs/Kconfig
--- a/fs/Kconfig	2004-12-12 17:44:47 -08:00
+++ b/fs/Kconfig	2004-12-12 17:44:47 -08:00
@@ -1179,6 +1179,15 @@
 
 	  Say 'N' unless you have NAND flash.
 
+config JFFS2_FS_NOR_ECC
+        bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)"
+        depends on JFFS2_FS && EXPERIMENTAL
+        default n
+        help
+          This enables the experimental support for NOR flash with transparent
+          ECC for JFFS2. This type of flash chip is not common, however it is
+          available from ST Microelectronics.
+
 config JFFS2_COMPRESSION_OPTIONS
 	bool "Advanced compression options for JFFS2"
 	depends on JFFS2_FS
diff -Nru a/fs/jffs2/Makefile b/fs/jffs2/Makefile
--- a/fs/jffs2/Makefile	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/Makefile	2004-12-12 17:44:47 -08:00
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux Journalling Flash File System v2 (JFFS2)
 #
-# $Id: Makefile.common,v 1.6 2004/07/16 15:17:57 dwmw2 Exp $
+# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $
 #
 
 obj-$(CONFIG_JFFS2_FS) += jffs2.o
@@ -12,6 +12,7 @@
 jffs2-y	+= super.o
 
 jffs2-$(CONFIG_JFFS2_FS_NAND)	+= wbuf.o
+jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
 jffs2-$(CONFIG_JFFS2_RUBIN)	+= compr_rubin.o
 jffs2-$(CONFIG_JFFS2_RTIME)	+= compr_rtime.o
 jffs2-$(CONFIG_JFFS2_ZLIB)	+= compr_zlib.o
diff -Nru a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking
--- a/fs/jffs2/README.Locking	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/README.Locking	2004-12-12 17:44:47 -08:00
@@ -1,4 +1,4 @@
-	$Id: README.Locking,v 1.4 2002/03/08 16:20:06 dwmw2 Exp $
+	$Id: README.Locking,v 1.9 2004/11/20 10:35:40 dwmw2 Exp $
 
 	JFFS2 LOCKING DOCUMENTATION
 	---------------------------
@@ -80,10 +80,10 @@
 (NB) the per-inode list of physical nodes. The latter is a special
 case - see below.
 
-As the MTD API permits erase-completion callback functions to be
-called from bottom-half (timer) context, and these functions access
-the data structures protected by this lock, it must be locked with
-spin_lock_bh().
+As the MTD API no longer permits erase-completion callback functions
+to be called from bottom-half (timer) context (on the basis that nobody
+ever actually implemented such a thing), it's now sufficient to use
+a simple spin_lock() rather than spin_lock_bh().
 
 Note that the per-inode list of physical nodes (f->nodes) is a special
 case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in
@@ -99,8 +99,27 @@
 GC thread locks it, sends the signal, then unlocks it - while the GC
 thread itself locks it, zeroes c->gc_task, then unlocks on the exit path.
 
-	node_free_sem
-	-------------
+
+	inocache_lock spinlock
+	----------------------
+
+This spinlock protects the hashed list (c->inocache_list) of the
+in-core jffs2_inode_cache objects (each inode in JFFS2 has the
+correspondent jffs2_inode_cache object). So, the inocache_lock
+has to be locked while walking the c->inocache_list hash buckets.
+
+Note, the f->sem guarantees that the correspondent jffs2_inode_cache
+will not be removed. So, it is allowed to access it without locking
+the inocache_lock spinlock. 
+
+Ordering constraints: 
+
+	If both erase_completion_lock and inocache_lock are needed, the
+	c->erase_completion has to be acquired first.
+
+
+	erase_free_sem
+	--------------
 
 This semaphore is only used by the erase code which frees obsolete
 node references and the jffs2_garbage_collect_deletion_dirent()
@@ -114,3 +133,16 @@
 collection code is looking at them.
 
 Suggestions for alternative solutions to this problem would be welcomed.
+
+
+	wbuf_sem
+	--------
+
+This read/write semaphore protects against concurrent access to the
+write-behind buffer ('wbuf') used for flash chips where we must write
+in blocks. It protects both the contents of the wbuf and the metadata
+which indicates which flash region (if any) is currently covered by 
+the buffer.
+
+Ordering constraints:
+	Lock wbuf_sem last, after the alloc_sem or and f->sem.
diff -Nru a/fs/jffs2/background.c b/fs/jffs2/background.c
--- a/fs/jffs2/background.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/background.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: background.c,v 1.49 2004/07/13 08:56:40 dwmw2 Exp $
+ * $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/build.c b/fs/jffs2/build.c
--- a/fs/jffs2/build.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/build.c	2004-12-12 17:44:47 -08:00
@@ -3,17 +3,19 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $
+ * $Id: build.c,v 1.68 2004/11/27 13:38:10 gleixner Exp $
  *
  */
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
+#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 **);
@@ -62,6 +64,7 @@
 		if (!child_ic) {
 			printk(KERN_NOTICE "Eep. 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;
 		}
 
@@ -88,6 +91,7 @@
 	int ret;
 	int i;
 	struct jffs2_inode_cache *ic;
+	struct jffs2_full_dirent *fd;
 	struct jffs2_full_dirent *dead_fds = NULL;
 
 	/* First, scan the medium and build all the inode caches with
@@ -95,13 +99,11 @@
 
 	c->flags |= JFFS2_SB_FLAG_MOUNTING;
 	ret = jffs2_scan_medium(c);
-	c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
-
 	if (ret)
-		return ret;
+		goto exit;
 
 	D1(printk(KERN_DEBUG "Scanned flash completely\n"));
-	D1(jffs2_dump_block_lists(c));
+	D2(jffs2_dump_block_lists(c));
 
 	/* Now scan the directory tree, increasing nlink according to every dirent found. */
 	for_each_inode(i, c, ic) {
@@ -114,6 +116,8 @@
 			cond_resched();
 		}
 	}
+	c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
+
 	D1(printk(KERN_DEBUG "Pass 1 complete\n"));
 
 	/* Next, scan for inodes with nlink == 0 and remove them. If
@@ -135,9 +139,7 @@
 	D1(printk(KERN_DEBUG "Pass 2a starting\n"));
 
 	while (dead_fds) {
-		struct jffs2_inode_cache *ic;
-		struct jffs2_full_dirent *fd = dead_fds;
-
+		fd = dead_fds;
 		dead_fds = fd->next;
 
 		ic = jffs2_get_ino_cache(c, fd->ino);
@@ -152,7 +154,6 @@
 	
 	/* Finally, we can scan again and free the dirent structs */
 	for_each_inode(i, c, ic) {
-		struct jffs2_full_dirent *fd;
 		D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
 
 		while(ic->scan_dents) {
@@ -164,11 +165,24 @@
 		cond_resched();
 	}
 	D1(printk(KERN_DEBUG "Pass 3 complete\n"));
-	D1(jffs2_dump_block_lists(c));
+	D2(jffs2_dump_block_lists(c));
 
 	/* Rotate the lists by some number to ensure wear levelling */
 	jffs2_rotate_lists(c);
 
+	ret = 0;
+
+exit:
+	if (ret) {
+		for_each_inode(i, c, ic) {
+			while(ic->scan_dents) {
+				fd = ic->scan_dents;
+				ic->scan_dents = fd->next;
+				jffs2_free_full_dirent(fd);
+			}
+		}
+	}
+
 	return ret;
 }
 
@@ -179,9 +193,12 @@
 
 	D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
 	
-	for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_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)));
 		jffs2_mark_node_obsolete(c, raw);
+		raw = next;
 	}
 
 	if (ic->scan_dents) {
@@ -297,7 +314,10 @@
 
 	c->free_size = c->flash_size;
 	c->nr_blocks = c->flash_size / c->sector_size;
-	c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
+ 	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
+		c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks);
+	else
+		c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
 	if (!c->blocks)
 		return -ENOMEM;
 	for (i=0; i<c->nr_blocks; i++) {
@@ -310,6 +330,7 @@
 		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_MUTEX(&c->alloc_sem);
diff -Nru a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
--- a/fs/jffs2/compr_zlib.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/compr_zlib.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.28 2004/06/23 16:34:40 havasi Exp $
+ * $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/dir.c b/fs/jffs2/dir.c
--- a/fs/jffs2/dir.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/dir.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: dir.c,v 1.83 2004/10/19 07:48:44 havasi Exp $
+ * $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/erase.c b/fs/jffs2/erase.c
--- a/fs/jffs2/erase.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/erase.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.61 2004/10/20 23:59:49 dwmw2 Exp $
+ * $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
@@ -43,6 +43,7 @@
                jffs2_erase_succeeded(c, jeb);
                return;
        }
+       bad_offset = jeb->offset;
 #else /* Linux */
 	struct erase_info *instr;
 
@@ -386,6 +387,7 @@
 		jeb->dirty_size = 0;
 		jeb->wasted_size = 0;
 	} else {
+		struct kvec vecs[1];
 		struct jffs2_unknown_node marker = {
 			.magic =	cpu_to_je16(JFFS2_MAGIC_BITMASK),
 			.nodetype =	cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
@@ -394,8 +396,10 @@
 
 		marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
 
-		/* We only write the header; the rest was noise or padding anyway */
-		ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
+		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) {
 			printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
 			       jeb->offset, ret);
diff -Nru a/fs/jffs2/file.c b/fs/jffs2/file.c
--- a/fs/jffs2/file.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/file.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: file.c,v 1.98 2004/03/19 16:41:09 dwmw2 Exp $
+ * $Id: file.c,v 1.99 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/fs.c b/fs/jffs2/fs.c
--- a/fs/jffs2/fs.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/fs.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs.c,v 1.46 2004/07/13 08:56:54 dwmw2 Exp $
+ * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $
  *
  */
 
@@ -20,6 +20,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/vfs.h>
 #include <linux/crc32.h>
 #include "nodelist.h"
@@ -202,7 +203,7 @@
 
 	buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
 
-	D1(jffs2_dump_block_lists(c));
+	D2(jffs2_dump_block_lists(c));
 
 	spin_unlock(&c->erase_completion_lock);
 
@@ -463,11 +464,13 @@
 	 */
 	c->sector_size = c->mtd->erasesize; 
 	blocks = c->flash_size / c->sector_size;
-	while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
-		blocks >>= 1;
-		c->sector_size <<= 1;
-	}	
-	
+	if (!(c->mtd->flags & MTD_NO_VIRTBLOCKS)) {
+		while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
+			blocks >>= 1;
+			c->sector_size <<= 1;
+		}	
+	}
+
 	/*
 	 * Size alignment check
 	 */
@@ -533,7 +536,10 @@
  out_nodes:
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
-	kfree(c->blocks);
+	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
+		vfree(c->blocks);
+	else
+		kfree(c->blocks);
  out_inohash:
 	kfree(c->inocache_list);
  out_wbuf:
@@ -649,6 +655,11 @@
 	}
 
 	/* add setups for other bizarre flashes here... */
+	if (jffs2_nor_ecc(c)) {
+		ret = jffs2_nor_ecc_flash_setup(c);
+		if (ret)
+			return ret;
+	}
 	return ret;
 }
 
@@ -659,4 +670,7 @@
 	}
 
 	/* add cleanups for other bizarre flashes here... */
+	if (jffs2_nor_ecc(c)) {
+		jffs2_nor_ecc_flash_cleanup(c);
+	}
 }
diff -Nru a/fs/jffs2/gc.c b/fs/jffs2/gc.c
--- a/fs/jffs2/gc.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/gc.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.140 2004/11/13 10:59:22 dedekind Exp $
+ * $Id: gc.c,v 1.143 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
@@ -103,7 +103,7 @@
 		ret->wasted_size = 0;
 	}
 
-	D1(jffs2_dump_block_lists(c));
+	D2(jffs2_dump_block_lists(c));
 	return ret;
 }
 
@@ -134,7 +134,7 @@
 		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);
-			D1(jffs2_dump_block_lists(c));
+			D2(jffs2_dump_block_lists(c));
 			spin_unlock(&c->erase_completion_lock);
 			BUG();
 		}
diff -Nru a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c
--- a/fs/jffs2/ioctl.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/ioctl.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: ioctl.c,v 1.8 2003/10/28 16:16:28 dwmw2 Exp $
+ * $Id: ioctl.c,v 1.9 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
--- a/fs/jffs2/malloc.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/malloc.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: malloc.c,v 1.27 2003/10/28 17:14:58 dwmw2 Exp $
+ * $Id: malloc.c,v 1.28 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
--- a/fs/jffs2/nodelist.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/nodelist.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.c,v 1.87 2004/11/14 17:07:07 dedekind Exp $
+ * $Id: nodelist.c,v 1.89 2004/11/28 12:20:35 dedekind Exp $
  *
  */
 
@@ -182,7 +182,6 @@
 				err = -ENOMEM;
 				goto free_out;
 			}
-			memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1);
 			fd->raw = ref;
 			fd->version = je32_to_cpu(node.d.version);
 			fd->ino = je32_to_cpu(node.d.ino);
@@ -220,6 +219,7 @@
 			}
 			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 
 				*/
diff -Nru a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
--- a/fs/jffs2/nodelist.h	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/nodelist.h	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.121 2004/11/14 17:07:07 dedekind Exp $
+ * $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $
  *
  */
 
@@ -107,16 +107,6 @@
 #define ref_obsolete(ref)	(((ref)->flash_offset & 3) == REF_OBSOLETE)
 #define mark_ref_normal(ref)    do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
 
-/* 
-   Used for keeping track of deletion nodes &c, which can only be marked
-   as obsolete when the node which they mark as deleted has actually been 
-   removed from the flash.
-*/
-struct jffs2_raw_node_ref_list {
-	struct jffs2_raw_node_ref *rew;
-	struct jffs2_raw_node_ref_list *next;
-};
-
 /* 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
@@ -148,13 +138,6 @@
 
 #define INOCACHE_HASHSIZE 128
 
-struct jffs2_scan_info {
-	struct jffs2_full_dirent *dents;
-	struct jffs2_tmp_dnode_info *tmpnodes;
-	/* Latest i_size info */
-	uint32_t version;
-	uint32_t isize;
-};
 /*
   Larger representation of a raw node, kept in-core only when the 
   struct inode for this particular ino is instantiated.
@@ -163,12 +146,11 @@
 struct jffs2_full_dnode
 {
 	struct jffs2_raw_node_ref *raw;
-	uint32_t ofs; /* Don't really need this, but optimisation */
+	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, 
-			the node is obsolete.
-		     */
+			the node is obsolete.  */
 };
 
 /* 
@@ -193,6 +175,7 @@
 	unsigned char type;
 	unsigned char name[0];
 };
+
 /*
   Fragments - used to build a map of which raw node to obtain 
   data from for each part of the ino
@@ -202,7 +185,7 @@
 	struct rb_node rb;
 	struct jffs2_full_dnode *node; /* NULL for holes */
 	uint32_t size;
-	uint32_t ofs; /* Don't really need this, but optimisation */
+	uint32_t ofs; /* The offset to which this fragment belongs */
 };
 
 struct jffs2_eraseblock
@@ -221,14 +204,6 @@
 	struct jffs2_raw_node_ref *last_node;
 
 	struct jffs2_raw_node_ref *gc_node;	/* Next node to be garbage collected */
-
-	/* For deletia. When a dirent node in this eraseblock is
-	   deleted by a node elsewhere, that other node can only 
-	   be marked as obsolete when this block is actually erased.
-	   So we keep a list of the nodes to mark as obsolete when
-	   the erase is completed.
-	*/
-	// MAYBE	struct jffs2_raw_node_ref_list *deletia;
 };
 
 #define ACCT_SANITY_CHECK(c, jeb) do { \
@@ -396,7 +371,7 @@
 #define frag_erase(frag, list) rb_erase(&frag->rb, list);
 
 /* nodelist.c */
-D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
+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 jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
diff -Nru a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
--- a/fs/jffs2/nodemgmt.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/nodemgmt.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodemgmt.c,v 1.109 2004/10/07 15:08:47 havasi Exp $
+ * $Id: nodemgmt.c,v 1.115 2004/11/22 11:07:21 dwmw2 Exp $
  *
  */
 
@@ -399,6 +399,17 @@
 	}
 	jeb = &c->blocks[blocknr];
 
+	if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) &&
+	    !(c->flags & JFFS2_SB_FLAG_MOUNTING)) {
+		/* 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
+		   jffs2_raw_node_ref without the erase_completion_lock. */
+		down(&c->erase_free_sem);
+	}
+
 	spin_lock(&c->erase_completion_lock);
 
 	if (ref_flags(ref) == REF_UNCHECKED) {
@@ -463,6 +474,7 @@
 		   marked obsolete on the flash at the time they _became_
 		   obsolete, there was probably a reason for that. */
 		spin_unlock(&c->erase_completion_lock);
+		/* We didn't lock the erase_free_sem */
 		return;
 	}
 
@@ -515,61 +527,87 @@
 
 	spin_unlock(&c->erase_completion_lock);
 
-	if (!jffs2_can_mark_obsolete(c))
-		return;
-	if (jffs2_is_readonly(c))
+	if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) {
+		/* We didn't lock the erase_free_sem */
 		return;
+	}
+
+	/* The erase_free_sem is locked, and has been since before we marked the node obsolete
+	   and potentially put its eraseblock onto the erase_pending_list. Thus, we know that
+	   the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet
+	   by jffs2_free_all_node_refs() in erase.c. Which is nice. */
 
 	D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref)));
 	ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
 	if (ret) {
 		printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
-		return;
+		goto out_erase_sem;
 	}
 	if (retlen != sizeof(n)) {
 		printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
-		return;
+		goto out_erase_sem;
 	}
 	if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) {
 		printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref));
-		return;
+		goto out_erase_sem;
 	}
 	if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
 		D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
-		return;
+		goto out_erase_sem;
 	}
 	/* XXX FIXME: This is ugly now */
 	n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE);
 	ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
 	if (ret) {
 		printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
-		return;
+		goto out_erase_sem;
 	}
 	if (retlen != sizeof(n)) {
 		printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
-		return;
+		goto out_erase_sem;
 	}
 
 	/* Nodes which have been marked obsolete no longer need to be
-	   associated with any inode. Remove them from the per-inode list */
+	   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 
+	   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 
+	   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. */
 	if (ref->next_in_ino) {
 		struct jffs2_inode_cache *ic;
 		struct jffs2_raw_node_ref **p;
 
+		spin_lock(&c->erase_completion_lock);
+
 		ic = jffs2_raw_ref_to_ic(ref);
 		for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino))
 			;
 
 		*p = ref->next_in_ino;
 		ref->next_in_ino = NULL;
+
+		if (ic->nodes == (void *)ic) {
+			D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
+			jffs2_del_ino_cache(c, ic);
+			jffs2_free_inode_cache(ic);
+		}
+
+		spin_unlock(&c->erase_completion_lock);
 	}
 
 
 	/* Merge with the next node in the physical list, if there is one
-	   and if it's also obsolete. */
-	if (ref->next_phys && ref_obsolete(ref->next_phys) ) {
+	   and if it's also obsolete and if it doesn't belong to any inode */
+	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;
 		ref->next_phys = n->next_phys;
                 if (jeb->last_node == n) jeb->last_node = ref;
@@ -577,7 +615,8 @@
 			/* gc will be happy continuing gc on this node */
 			jeb->gc_node=ref;
 		}
-		BUG_ON(n->next_in_ino);
+		spin_unlock(&c->erase_completion_lock);
+
 		jffs2_free_raw_node_ref(n);
 	}
 	
@@ -585,11 +624,13 @@
 	   and that one is obsolete */
 	if (ref != jeb->first_node ) {
 		struct jffs2_raw_node_ref *p = jeb->first_node;
-		
+
+		spin_lock(&c->erase_completion_lock);
+
 		while (p->next_phys != ref)
 			p = p->next_phys;
 		
-		if (ref_obsolete(p) ) {
+		if (ref_obsolete(p) && !ref->next_in_ino) {
 			p->__totlen += ref->__totlen;
 			if (jeb->last_node == ref) {
 				jeb->last_node = p;
@@ -601,10 +642,13 @@
 			p->next_phys = ref->next_phys;
 			jffs2_free_raw_node_ref(ref);
 		}
+		spin_unlock(&c->erase_completion_lock);
 	}
+ out_erase_sem:
+	up(&c->erase_free_sem);
 }
 
-#if CONFIG_JFFS2_FS_DEBUG > 0
+#if CONFIG_JFFS2_FS_DEBUG >= 2
 void jffs2_dump_block_lists(struct jffs2_sb_info *c)
 {
 
diff -Nru a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
--- a/fs/jffs2/os-linux.h	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/os-linux.h	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2002-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-linux.h,v 1.47 2004/07/14 13:20:23 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
@@ -99,7 +99,7 @@
 
 #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
 
-#ifndef CONFIG_JFFS2_FS_NAND
+#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
 #define jffs2_can_mark_obsolete(c) (1)
 #define jffs2_cleanmarker_oob(c) (0)
 #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
@@ -115,10 +115,13 @@
 #define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e)
 #define jffs2_wbuf_timeout NULL
 #define jffs2_wbuf_process NULL
+#define jffs2_nor_ecc(c) (0)
+#define jffs2_nor_ecc_flash_setup(c) (0)
+#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
 
-#else /* NAND support present */
+#else /* NAND and/or ECC'd NOR support present */
 
-#define jffs2_can_mark_obsolete(c) (c->mtd->type == MTD_NORFLASH || c->mtd->type == MTD_RAM)
+#define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM)
 #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
 
 #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
@@ -135,8 +138,19 @@
 int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
 void jffs2_wbuf_timeout(unsigned long data);
 void jffs2_wbuf_process(void *data);
+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
 void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
+#ifdef CONFIG_JFFS2_FS_NOR_ECC
+#define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC))
+int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c);
+void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
+#else
+#define jffs2_nor_ecc(c) (0)
+#define jffs2_nor_ecc_flash_setup(c) (0)
+#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
+#endif /* NOR ECC */
 #endif /* NAND */
 
 /* erase.c */
diff -Nru a/fs/jffs2/pushpull.h b/fs/jffs2/pushpull.h
--- a/fs/jffs2/pushpull.h	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/pushpull.h	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: pushpull.h,v 1.9 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: pushpull.h,v 1.10 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/read.c b/fs/jffs2/read.c
--- a/fs/jffs2/read.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/read.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.36 2004/05/25 11:12:32 havasi Exp $
+ * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $
  *
  */
 
@@ -174,7 +174,7 @@
 			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);
-				D1(jffs2_print_frag_list(f));
+				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);
diff -Nru a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
--- a/fs/jffs2/readinode.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/readinode.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.114 2004/11/14 17:07:07 dedekind Exp $
+ * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $
  *
  */
 
@@ -22,7 +22,7 @@
 
 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 >= 1
+#if CONFIG_JFFS2_FS_DEBUG >= 2
 static void jffs2_print_fragtree(struct rb_root *list, int permitbug)
 {
 	struct jffs2_node_frag *this = frag_first(list);
@@ -56,7 +56,9 @@
 		printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
 	}
 }
+#endif
 
+#if CONFIG_JFFS2_FS_DEBUG >= 1
 static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f)
 {
 	struct jffs2_node_frag *frag;
@@ -225,7 +227,7 @@
 		   If so, both 'this' and the new node get marked REF_NORMAL so
 		   the GC can take a look.
 		*/
-		if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
+		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);
diff -Nru a/fs/jffs2/scan.c b/fs/jffs2/scan.c
--- a/fs/jffs2/scan.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/scan.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.112 2004/09/12 09:56:13 gleixner Exp $
+ * $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $
  *
  */
 #include <linux/kernel.h>
@@ -68,7 +68,7 @@
 static inline int min_free(struct jffs2_sb_info *c)
 {
 	uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
-#ifdef CONFIG_JFFS2_FS_NAND
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
 	if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
 		return c->wbuf_pagesize;
 #endif
@@ -160,11 +160,8 @@
 
 		case BLK_STATE_PARTDIRTY:
                         /* Some data, but not full. Dirty list. */
-                        /* Except that we want to remember the block with most free space,
-                           and stick it in the 'nextblock' position to start writing to it.
-                           Later when we do snapshots, this must be the most recent block,
-                           not the one with most free space.
-                        */
+                        /* 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 */
@@ -223,7 +220,7 @@
 		c->dirty_size -= c->nextblock->dirty_size;
 		c->nextblock->dirty_size = 0;
 	}
-#ifdef CONFIG_JFFS2_FS_NAND
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
 	if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
 		/* If we're going to start writing into a block which already 
 		   contains data, and the end of the data isn't page-aligned,
diff -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c
--- a/fs/jffs2/super.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/super.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: super.c,v 1.102 2004/11/12 02:42:17 tpoynor Exp $
+ * $Id: super.c,v 1.104 2004/11/23 15:37:31 gleixner Exp $
  *
  */
 
@@ -277,7 +277,10 @@
 	up(&c->alloc_sem);
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
-	kfree(c->blocks);
+	if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
+		vfree(c->blocks);
+	else
+		kfree(c->blocks);
 	jffs2_flash_cleanup(c);
 	kfree(c->inocache_list);
 	if (c->mtd->sync)
diff -Nru a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
--- a/fs/jffs2/symlink.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/symlink.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: symlink.c,v 1.13 2004/07/13 08:59:04 dwmw2 Exp $
+ * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
--- a/fs/jffs2/wbuf.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/wbuf.c	2004-12-12 17:44:47 -08:00
@@ -4,12 +4,12 @@
  * Copyright (C) 2001-2003 Red Hat, Inc.
  * Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de>
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: wbuf.c,v 1.72 2004/09/11 19:22:43 gleixner Exp $
+ * $Id: wbuf.c,v 1.82 2004/11/20 22:08:31 dwmw2 Exp $
  *
  */
 
@@ -130,22 +130,8 @@
 	}
 }
 
-/* Recover from failure to write wbuf. Recover the nodes up to the
- * wbuf, not the one which we were starting to try to write. */
-
-static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
+static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
-	struct jffs2_eraseblock *jeb, *new_jeb;
-	struct jffs2_raw_node_ref **first_raw, **raw;
-	size_t retlen;
-	int ret;
-	unsigned char *buf;
-	uint32_t start, end, ofs, len;
-
-	spin_lock(&c->erase_completion_lock);
-
-	jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
-
 	D1(printk("About to refile bad block at %08x\n", jeb->offset));
 
 	D2(jffs2_dump_block_lists(c));
@@ -175,6 +161,25 @@
 
 	ACCT_SANITY_CHECK(c,jeb);
 	D1(ACCT_PARANOIA_CHECK(jeb));
+}
+
+/* Recover from failure to write wbuf. Recover the nodes up to the
+ * wbuf, not the one which we were starting to try to write. */
+
+static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
+{
+	struct jffs2_eraseblock *jeb, *new_jeb;
+	struct jffs2_raw_node_ref **first_raw, **raw;
+	size_t retlen;
+	int ret;
+	unsigned char *buf;
+	uint32_t start, end, ofs, len;
+
+	spin_lock(&c->erase_completion_lock);
+
+	jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
+
+	jffs2_block_refile(c, jeb);
 
 	/* Find the first node to be recovered, by skipping over every
 	   node which ends before the wbuf starts, or which is obsolete. */
@@ -224,7 +229,11 @@
 		}
 
 		/* Do the read... */
-		ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo);
+		if (jffs2_cleanmarker_oob(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;
@@ -281,8 +290,11 @@
 			ret = -EIO;
 		} else
 #endif
+		if (jffs2_cleanmarker_oob(c))
 			ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
 						buf, NULL, c->oobinfo);
+		else
+			ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf);
 
 		if (ret || retlen != towrite) {
 			/* Argh. We tried. Really we did. */
@@ -392,6 +404,10 @@
    1: Pad, do not adjust nextblock free_size
    2: Pad, adjust nextblock free_size
 */
+#define NOPAD		0
+#define PAD_NOACCOUNT	1
+#define PAD_ACCOUNTING	2
+
 static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
 {
 	int ret;
@@ -419,6 +435,10 @@
 	*/
 	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);
@@ -426,9 +446,6 @@
 			padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
 			padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
 			padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
-		} else {
-			/* Pad with JFFS2_DIRTY_BITMASK */
-			memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
 		}
 	}
 	/* else jffs2_flash_writev has actually filled in the rest of the
@@ -444,8 +461,11 @@
 		ret = -EIO;
 	} else 
 #endif
-	ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);
-
+	
+	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
+		ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
 
 	if (ret || retlen != c->wbuf_pagesize) {
 		if (ret)
@@ -458,7 +478,7 @@
 
 		jffs2_wbuf_recover(c);
 
-		return ret; 
+		return ret;
 	}
 
 	spin_lock(&c->erase_completion_lock);
@@ -525,7 +545,9 @@
 	if (c->unchecked_size) {
 		/* GC won't make any progress for a while */
 		D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
-		ret = __jffs2_flush_wbuf(c, 2);
+		down_write(&c->wbuf_sem);
+		ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+		up_write(&c->wbuf_sem);
 	} else while (old_wbuf_len &&
 		      old_wbuf_ofs == c->wbuf_ofs) {
 
@@ -537,7 +559,9 @@
 		if (ret) {
 			/* GC failed. Flush it with padding instead */
 			down(&c->alloc_sem);
-			ret = __jffs2_flush_wbuf(c, 2);
+			down_write(&c->wbuf_sem);
+			ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+			up_write(&c->wbuf_sem);
 			break;
 		}
 		down(&c->alloc_sem);
@@ -552,9 +576,14 @@
 /* Pad write-buffer to end and write it, wasting space. */
 int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
 {
-	return __jffs2_flush_wbuf(c, 1);
-}
+	int ret;
 
+	down_write(&c->wbuf_sem);
+	ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
+	up_write(&c->wbuf_sem);
+
+	return ret;
+}
 
 #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
 #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
@@ -575,6 +604,8 @@
 	if (!c->wbuf)
 		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);
@@ -582,6 +613,17 @@
 		memset(c->wbuf,0xff,c->wbuf_pagesize);
 	}
 
+	/* Fixup the wbuf if we are moving to a new eraseblock.  The checks below
+	   fail for ECC'd NOR because cleanmarker == 16, so a block starts at
+	   xxx0010.  */
+	if (jffs2_nor_ecc(c)) {
+		if (((c->wbuf_ofs % c->sector_size) == 0) && !c->wbuf_len) {
+			c->wbuf_ofs = PAGE_DIV(to);
+			c->wbuf_len = PAGE_MOD(to);
+			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 
@@ -592,12 +634,12 @@
 		/* It's a write to a new block */
 		if (c->wbuf_len) {
 			D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
-			ret = jffs2_flush_wbuf_pad(c);
+			ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
 			if (ret) {
 				/* the underlying layer has to check wbuf_len to do the cleanup */
 				D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
 				*retlen = 0;
-				return ret;
+				goto exit;
 			}
 		}
 		/* set pointer to new block */
@@ -623,7 +665,6 @@
 	invec = 0;
 	outvec = 0;
 
-
 	/* Fill writebuffer first, if already in use */	
 	if (c->wbuf_len) {
 		uint32_t invec_ofs = 0;
@@ -658,14 +699,14 @@
 		}			
 		
 		/* write buffer is full, flush buffer */
-		ret = __jffs2_flush_wbuf(c, 0);
+		ret = __jffs2_flush_wbuf(c, NOPAD);
 		if (ret) {
 			/* the underlying layer has to check wbuf_len to do the cleanup */
 			D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
 			/* Retlen zero to make sure our caller doesn't mark the space dirty.
 			   We've already done everything that's necessary */
 			*retlen = 0;
-			return ret;
+			goto exit;
 		}
 		outvec_to += donelen;
 		c->wbuf_ofs = outvec_to;
@@ -709,19 +750,22 @@
 
 	if (splitvec != -1) {
 		uint32_t remainder;
-		int ret;
 
 		remainder = outvecs[splitvec].iov_len - split_ofs;
 		outvecs[splitvec].iov_len = split_ofs;
 
 		/* We did cross a page boundary, so we write some now */
-		ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); 
+		if (jffs2_cleanmarker_oob(c))
+			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. 
 			*/
 			*retlen = donelen;
-			return ret;
+			goto exit;
 		}
 		
 		donelen += wbuf_retlen;
@@ -760,7 +804,11 @@
 	if (c->wbuf_len && ino)
 		jffs2_wbuf_dirties_inode(c, ino);
 
-	return 0;
+	ret = 0;
+	
+exit:
+	up_write(&c->wbuf_sem);
+	return ret;
 }
 
 /*
@@ -789,7 +837,12 @@
 
 	/* Read flash */
 	if (!jffs2_can_mark_obsolete(c)) {
-		ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
+		down_read(&c->wbuf_sem);
+
+		if (jffs2_cleanmarker_oob(c))
+			ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
+		else
+			ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
 
 		if ( (ret == -EBADMSG) && (*retlen == len) ) {
 			printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
@@ -811,23 +864,23 @@
 
 	/* if no writebuffer available or write buffer empty, return */
 	if (!c->wbuf_pagesize || !c->wbuf_len)
-		return ret;
+		goto exit;
 
 	/* if we read in a different block, return */
 	if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) 
-		return ret;	
+		goto exit;
 
 	if (ofs >= c->wbuf_ofs) {
 		owbf = (ofs - c->wbuf_ofs);	/* offset in write buffer */
 		if (owbf > c->wbuf_len)		/* is read beyond write buffer ? */
-			return ret;
+			goto exit;
 		lwbf = c->wbuf_len - owbf;	/* number of bytes to copy */
 		if (lwbf > len)	
 			lwbf = len;
 	} else {	
 		orbf = (c->wbuf_ofs - ofs);	/* offset in read buffer */
 		if (orbf > len)			/* is write beyond write buffer ? */
-			return ret;
+			goto exit;
 		lwbf = len - orbf; 		/* number of bytes to copy */
 		if (lwbf > c->wbuf_len)	
 			lwbf = c->wbuf_len;
@@ -835,6 +888,8 @@
 	if (lwbf > 0)
 		memcpy(buf+orbf,c->wbuf+owbf,lwbf);
 
+exit:
+	up_read(&c->wbuf_sem);
 	return ret;
 }
 
@@ -1079,9 +1134,9 @@
 	int res;
 
 	/* Initialise write buffer */
+	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)
@@ -1105,3 +1160,25 @@
 {
 	kfree(c->wbuf);
 }
+
+#ifdef CONFIG_JFFS2_FS_NOR_ECC
+int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
+	/* Cleanmarker is actually larger on the flashes */
+	c->cleanmarker_size = 16;
+
+	/* Initialize write buffer */
+	init_rwsem(&c->wbuf_sem);
+	c->wbuf_pagesize = c->mtd->eccsize;
+	c->wbuf_ofs = 0xFFFFFFFF;
+
+	c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+	if (!c->wbuf)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) {
+	kfree(c->wbuf);
+}
+#endif
diff -Nru a/fs/jffs2/write.c b/fs/jffs2/write.c
--- a/fs/jffs2/write.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/write.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.86 2004/11/13 10:44:26 dedekind Exp $
+ * $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/writev.c b/fs/jffs2/writev.c
--- a/fs/jffs2/writev.c	2004-12-12 17:44:47 -08:00
+++ b/fs/jffs2/writev.c	2004-12-12 17:44:47 -08:00
@@ -3,11 +3,11 @@
  *
  * Copyright (C) 2001, 2002 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: writev.c,v 1.5 2004/07/13 08:58:25 dwmw2 Exp $
+ * $Id: writev.c,v 1.6 2004/11/16 20:36:12 dwmw2 Exp $
  *
  */
 
diff -Nru a/include/linux/jffs2.h b/include/linux/jffs2.h
--- a/include/linux/jffs2.h	2004-12-12 17:44:47 -08:00
+++ b/include/linux/jffs2.h	2004-12-12 17:44:47 -08:00
@@ -3,12 +3,12 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in the 
  * jffs2 directory.
  *
- * $Id: jffs2.h,v 1.33 2004/05/25 11:31:55 havasi Exp $
+ * $Id: jffs2.h,v 1.34 2004/11/16 20:36:14 dwmw2 Exp $
  *
  */
 
diff -Nru a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
--- a/include/linux/jffs2_fs_sb.h	2004-12-12 17:44:47 -08:00
+++ b/include/linux/jffs2_fs_sb.h	2004-12-12 17:44:47 -08:00
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.45 2003/10/08 11:46:27 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.48 2004/11/20 10:41:12 dwmw2 Exp $ */
 
 #ifndef _JFFS2_FS_SB
 #define _JFFS2_FS_SB
@@ -11,6 +11,7 @@
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/list.h>
+#include <linux/rwsem.h>
 
 #define JFFS2_SB_FLAG_RO 1
 #define JFFS2_SB_FLAG_MOUNTING 2
@@ -35,9 +36,7 @@
 
 	struct semaphore alloc_sem;	/* Used to protect all the following 
 					   fields, and also to protect against
-					   out-of-order writing of nodes.
-					   And GC.
-					*/
+					   out-of-order writing of nodes. And GC. */
 	uint32_t cleanmarker_size;	/* Size of an _inline_ CLEANMARKER
 					 (i.e. zero for OOB CLEANMARKER */
 
@@ -95,13 +94,15 @@
 	   to an obsoleted node. I don't like this. Alternatives welcomed. */
 	struct semaphore erase_free_sem;
 
-#ifdef CONFIG_JFFS2_FS_NAND
+#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
 	/* 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 */
 
 	/* Information about out-of-band area usage... */
 	struct nand_oobinfo *oobinfo;
diff -Nru a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
--- a/include/linux/mtd/cfi.h	2004-12-12 17:44:47 -08:00
+++ b/include/linux/mtd/cfi.h	2004-12-12 17:44:47 -08:00
@@ -1,7 +1,7 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.49 2004/11/15 20:56:32 nico Exp $
+ * $Id: cfi.h,v 1.50 2004/11/20 12:46:51 dwmw2 Exp $
  */
 
 #ifndef __MTD_CFI_H__
@@ -349,14 +349,12 @@
 
 static inline void cfi_udelay(int us)
 {
-	unsigned long t = us * HZ / 1000000;
-	if (t) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(t);
-		return;
+	if (us >= 1000) {
+		msleep((us+999)/1000);
+	} else {
+		udelay(us);
+		cond_resched();
 	}
-	udelay(us);
-	cond_resched();
 }
 
 static inline void cfi_spin_lock(spinlock_t *mutex)
diff -Nru a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h
--- a/include/linux/mtd/flashchip.h	2004-12-12 17:44:47 -08:00
+++ b/include/linux/mtd/flashchip.h	2004-12-12 17:44:47 -08:00
@@ -6,7 +6,7 @@
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.14 2004/06/15 16:44:59 nico Exp $
+ * $Id: flashchip.h,v 1.15 2004/11/05 22:41:06 nico Exp $
  *
  */
 
@@ -37,6 +37,8 @@
 	FL_LOCKING,
 	FL_UNLOCKING,
 	FL_POINT,
+	FL_XIP_WHILE_ERASING,
+	FL_XIP_WHILE_WRITING,
 	FL_UNKNOWN
 } flstate_t;
 
diff -Nru a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
--- a/include/linux/mtd/nand.h	2004-12-12 17:44:47 -08:00
+++ b/include/linux/mtd/nand.h	2004-12-12 17:44:47 -08:00
@@ -5,7 +5,7 @@
  *                     Steven J. Hill <sjhill@realitydiluted.com>
  *		       Thomas Gleixner <tglx@linutronix.de>
  *
- * $Id: nand.h,v 1.66 2004/10/02 10:07:08 gleixner Exp $
+ * $Id: nand.h,v 1.68 2004/11/12 10:40:37 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
@@ -138,6 +138,8 @@
 #define NAND_ECC_HW6_512	4
 /* Hardware ECC 8 byte ECC per 512 Byte data */
 #define NAND_ECC_HW8_512	6
+/* Hardware ECC 12 byte ECC per 2048 Byte data */
+#define NAND_ECC_HW12_2048	7
 
 /*
  * Constants for Hardware ECC
@@ -253,6 +255,7 @@
  * @scan_bbt:		[REPLACEABLE] function to scan bad block table
  * @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
  * @chip_delay:		[BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
  * @chip_lock:		[INTERN] spinlock used to protect access to this structure and the chip
@@ -277,6 +280,7 @@
  * @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 
  * @controller:		[OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
  * @priv:		[OPTIONAL] pointer to private chip date
  */
@@ -307,6 +311,7 @@
 	int		(*scan_bbt)(struct mtd_info *mtd);
 	int		eccmode;
 	int		eccsize;
+	int		eccbytes;
 	int		eccsteps;
 	int 		chip_delay;
 	spinlock_t	chip_lock;
@@ -330,6 +335,7 @@
 	uint8_t		*bbt;
 	struct nand_bbt_descr	*bbt_td;
 	struct nand_bbt_descr	*bbt_md;
+	struct nand_bbt_descr	*badblock_pattern;
 	struct nand_hw_control  *controller;
 	void		*priv;
 };
diff -Nru a/include/linux/mtd/xip.h b/include/linux/mtd/xip.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/linux/mtd/xip.h	2004-12-12 17:44:47 -08:00
@@ -0,0 +1,99 @@
+/*
+ * MTD primitives for XIP support
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 2, 2004
+ * Copyright:	(C) 2004 MontaVista Software, Inc.
+ *
+ * This XIP support for MTD has been loosely inspired
+ * by an earlier patch authored by David Woodhouse.
+ *
+ * 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.
+ *
+ * $Id: xip.h,v 1.1 2004/11/05 22:41:06 nico Exp $
+ */
+
+#ifndef __LINUX_MTD_XIP_H__
+#define __LINUX_MTD_XIP_H__
+
+#include <linux/config.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>
+
+/*
+ * Each architecture has to provide the following macros.  They must access
+ * the hardware directly and not rely on any other (XIP) functions since they
+ * won't be available when used (flash not in array mode).
+ *
+ * xip_irqpending()
+ *
+ * 	return non zero when any hardware interrupt is pending.
+ *
+ * xip_currtime()
+ *
+ * 	return a platform specific time reference to be used with
+ * 	xip_elapsed_since().
+ *
+ * xip_elapsed_since(x)
+ *
+ * 	return in usecs the elapsed timebetween now and the reference x as
+ * 	returned by xip_currtime().
+ *
+ * 	note 1: convertion to usec can be approximated, as long as the
+ * 		returned value is <= the real elapsed time.
+ * 	note 2: this should be able to cope with a few seconds without
+ * 		overflowing.
+ */
+
+#if defined(CONFIG_ARCH_SA1100) || defined(CONFIG_ARCH_PXA)
+
+#include <asm/hardware.h>
+#ifdef CONFIG_ARCH_PXA
+#include <asm/arch/pxa-regs.h>
+#endif
+
+#define xip_irqpending()	(ICIP & ICMR)
+
+/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */
+#define xip_currtime()		(OSCR)
+#define xip_elapsed_since(x)	(signed)((OSCR - (x)) / 4)
+
+#else
+#error "missing IRQ and timer primitives for XIP MTD support"
+#endif
+
+/*
+ * xip_cpu_idle() is used when waiting for a delay equal or larger than
+ * the system timer tick period.  This should put the CPU into idle mode
+ * to save power and to be woken up only when some interrupts are pending.
+ * As above, this should not rely upon standard kernel code.
+ */
+
+#if defined(CONFIG_CPU_XSCALE)
+#define xip_cpu_idle()  asm volatile ("mcr p14, 0, %0, c7, c0, 0" :: "r" (1))
+#else
+#define xip_cpu_idle()  do { } while (0)
+#endif
+
+#else
+
+#define __xipram
+
+#endif /* CONFIG_MTD_XIP */
+
+#endif /* __LINUX_MTD_XIP_H__ */
diff -Nru a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
--- a/include/mtd/mtd-abi.h	2004-12-12 17:44:47 -08:00
+++ b/include/mtd/mtd-abi.h	2004-12-12 17:44:47 -08:00
@@ -1,5 +1,5 @@
 /*
- * $Id: mtd-abi.h,v 1.6 2004/08/09 13:38:30 dwmw2 Exp $
+ * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $
  *
  * Portions of MTD ABI definition which are shared by kernel and user space 
  */
@@ -40,6 +40,7 @@
 #define MTD_XIP			32	// eXecute-In-Place possible
 #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
 
 // Some common devices / combinations of capabilities
 #define MTD_CAP_ROM		0
diff -Nru a/kernel/workqueue.c b/kernel/workqueue.c
--- a/kernel/workqueue.c	2004-12-12 17:44:47 -08:00
+++ b/kernel/workqueue.c	2004-12-12 17:44:47 -08:00
@@ -8,7 +8,7 @@
  *
  * Derived from the taskqueue/keventd code by:
  *
- *   David Woodhouse <dwmw2@redhat.com>
+ *   David Woodhouse <dwmw2@infradead.org>
  *   Andrew Morton <andrewm@uow.edu.au>
  *   Kai Petzke <wpp@marie.physik.tu-berlin.de>
  *   Theodore Ts'o <tytso@mit.edu>
diff -Nru a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
--- a/lib/reed_solomon/reed_solomon.c	2004-12-12 17:44:47 -08:00
+++ b/lib/reed_solomon/reed_solomon.c	2004-12-12 17:44:47 -08:00
@@ -9,7 +9,7 @@
  * Reed Solomon code lifted from reed solomon library written by Phil Karn
  * Copyright 2002 Phil Karn, KA9Q
  *
- * $Id: rslib.c,v 1.4 2004/10/05 22:07:53 gleixner Exp $
+ * $Id: rslib.c,v 1.5 2004/10/22 15:41:47 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
@@ -22,19 +22,19 @@
  * Each user must call init_rs to get a pointer to a rs_control
  * structure for the given rs parameters. This structure is either
  * generated or a already available matching control structure is used.
- * If a structure is generated then the polynominal arrays for
+ * 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 timecritical path.
- * Usually a module / driver should initialize the neccecary 
+ * make sure not to call this function from a time critical path.
+ * 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 syndrom 
+ * 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 + syndrom) and calls the
+ * the syndrome over the received (data + syndrome) and calls the
  * second stage, which does the decoding / error correction itself.
- * Many hw encoders provide a syndrom calculation over the received
- * data + syndrom and can call the second stage directly.
+ * Many hw encoders provide a syndrome calculation over the received
+ * data + syndrome and can call the second stage directly.
  *
  */