bk://linux-mtd.bkbits.net/mtd-2.6
dwmw2@shinybook.infradead.org|ChangeSet|20041120125346|41956 dwmw2

# This is a BitKeeper generated diff -Nru style patch.
#
# 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-11-21 19:53:31 -08:00
+++ b/CREDITS	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/MAINTAINERS	2004-11-21 19:53:31 -08:00
@@ -1433,7 +1433,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-11-21 19:53:31 -08:00
+++ b/drivers/char/applicom.c	2004-11-21 19:53:32 -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/chips/Kconfig b/drivers/mtd/chips/Kconfig
--- a/drivers/mtd/chips/Kconfig	2004-11-21 19:53:31 -08:00
+++ b/drivers/mtd/chips/Kconfig	2004-11-21 19:53:31 -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.10 2004/11/05 22:41:04 nico Exp $
 
 menu "RAM/ROM/Flash chip drivers"
 	depends on MTD!=n
@@ -271,6 +271,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-11-21 19:53:31 -08:00
+++ b/drivers/mtd/chips/amd_flash.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/drivers/mtd/chips/cfi_cmdset_0020.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/drivers/mtd/chips/cfi_probe.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/drivers/mtd/chips/cfi_util.c	2004-11-21 19:53:31 -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-11-21 19:53:32 -08:00
+++ b/drivers/mtd/chips/jedec_probe.c	2004-11-21 19:53:32 -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/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
--- a/drivers/mtd/nand/nand_base.c	2004-11-21 19:53:32 -08:00
+++ b/drivers/mtd/nand/nand_base.c	2004-11-21 19:53:32 -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-11-21 19:53:31 -08:00
+++ b/drivers/mtd/nand/nand_bbt.c	2004-11-21 19:53:31 -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/fs/Kconfig b/fs/Kconfig
--- a/fs/Kconfig	2004-11-21 19:53:31 -08:00
+++ b/fs/Kconfig	2004-11-21 19:53:31 -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-11-21 19:53:32 -08:00
+++ b/fs/jffs2/Makefile	2004-11-21 19:53:32 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/README.Locking	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/background.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/build.c	2004-11-21 19:53:31 -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: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $
+ * $Id: build.c,v 1.64 2004/11/20 10:44:07 dwmw2 Exp $
  *
  */
 
@@ -62,6 +62,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 +89,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 +97,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 +114,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 +137,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 +152,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,10 +163,23 @@
 		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;
 }
diff -Nru a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
--- a/fs/jffs2/compr_zlib.c	2004-11-21 19:53:32 -08:00
+++ b/fs/jffs2/compr_zlib.c	2004-11-21 19:53:32 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/dir.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/erase.c	2004-11-21 19:53:31 -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-11-21 19:53:32 -08:00
+++ b/fs/jffs2/file.c	2004-11-21 19:53:32 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/fs.c	2004-11-21 19:53:31 -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.49 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
@@ -202,7 +202,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);
 
@@ -649,6 +649,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 +664,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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/gc.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/ioctl.c	2004-11-21 19:53:31 -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-11-21 19:53:32 -08:00
+++ b/fs/jffs2/malloc.c	2004-11-21 19:53:32 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/nodelist.c	2004-11-21 19:53:31 -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.88 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
--- a/fs/jffs2/nodelist.h	2004-11-21 19:53:32 -08:00
+++ b/fs/jffs2/nodelist.h	2004-11-21 19:53:32 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/nodemgmt.c	2004-11-21 19:53:31 -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.111 2004/11/16 20:36:11 dwmw2 Exp $
  *
  */
 
@@ -604,7 +604,7 @@
 	}
 }
 
-#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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/os-linux.h	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/pushpull.h	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/read.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/readinode.c	2004-11-21 19:53:31 -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.116 2004/11/16 20:36:12 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;
diff -Nru a/fs/jffs2/scan.c b/fs/jffs2/scan.c
--- a/fs/jffs2/scan.c	2004-11-21 19:53:31 -08:00
+++ b/fs/jffs2/scan.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/super.c	2004-11-21 19:53:31 -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.103 2004/11/16 20:36:12 dwmw2 Exp $
  *
  */
 
diff -Nru a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
--- a/fs/jffs2/symlink.c	2004-11-21 19:53:31 -08:00
+++ b/fs/jffs2/symlink.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/wbuf.c	2004-11-21 19:53:31 -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.81 2004/11/20 10:44:07 dwmw2 Exp $
  *
  */
 
@@ -224,7 +224,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 +285,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 +399,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 +430,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 +441,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 +456,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 +473,7 @@
 
 		jffs2_wbuf_recover(c);
 
-		return ret; 
+		return ret;
 	}
 
 	spin_lock(&c->erase_completion_lock);
@@ -525,7 +540,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 +554,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 +571,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 +599,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 +608,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 +629,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 +660,6 @@
 	invec = 0;
 	outvec = 0;
 
-
 	/* Fill writebuffer first, if already in use */	
 	if (c->wbuf_len) {
 		uint32_t invec_ofs = 0;
@@ -658,14 +694,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 +745,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 +799,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 +832,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 +859,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 +883,8 @@
 	if (lwbf > 0)
 		memcpy(buf+orbf,c->wbuf+owbf,lwbf);
 
+exit:
+	up_read(&c->wbuf_sem);
 	return ret;
 }
 
@@ -1079,9 +1129,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 +1155,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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/write.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/fs/jffs2/writev.c	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/include/linux/jffs2.h	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/include/linux/jffs2_fs_sb.h	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/include/linux/mtd/cfi.h	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/include/linux/mtd/flashchip.h	2004-11-21 19:53:31 -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-11-21 19:53:31 -08:00
+++ b/include/linux/mtd/nand.h	2004-11-21 19:53:31 -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-11-21 19:53:32 -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/kernel/workqueue.c b/kernel/workqueue.c
--- a/kernel/workqueue.c	2004-11-21 19:53:32 -08:00
+++ b/kernel/workqueue.c	2004-11-21 19:53:32 -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>