bk://linux-mtd.bkbits.net/mtd-2.6 dedekind@infradead.org|ChangeSet|20041129225833|54013 dedekind # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2004/11/29 20:22:56-08:00 akpm@bix.(none) # Merge bk://linux-mtd.bkbits.net/mtd-2.6 into bix.(none):/usr/src/bk-mtd # # MAINTAINERS # 2004/11/29 20:22:53-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/29 20:20:14-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd # # MAINTAINERS # 2004/11/29 20:20:10-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/29 22:58:33+00:00 dedekind@infradead.org # JFFS2: jffs2_get_inode_nodes(): Remove gratuitous memset on new nodes. # # We're about to set every field in the node structure. No need to spend # time filling it with zeroes. This is a fairly hot path. # # Signed-off-by: Artem Bityuckiy # Signed-off-by: David Woodhouse # # fs/jffs2/nodelist.c # 2004/11/29 22:58:12+00:00 dedekind@infradead.org +2 -2 # Remove unneeded memset # # ChangeSet # 2004/11/29 22:55:00+00:00 dedekind@infradead.org # JFFS2: Include vmalloc.h to fix compile warning. # # The previous fixes to use vmalloc for the eraseblock array missed it. # # Signed-off-by: Artem Bityuckiy # Signed-off-by: David Woodhouse # # fs/jffs2/fs.c # 2004/11/29 22:54:38+00:00 dedekind@infradead.org +2 -1 # Include vmalloc.h header to prevent warning. # # ChangeSet # 2004/11/29 22:43:46+00:00 bunk@stusta.de # MTD: Use select in Kconfig where appropriate. # # Signed-off-by: Adrian Bunk # Signed-off-by: David Woodhouse # # drivers/mtd/nand/Kconfig # 2004/11/29 22:43:24+00:00 bunk@stusta.de +2 -3 # The patch below switches options to use select where appropriate. # Signed-off-by: Adrian Bunk # # drivers/mtd/devices/Kconfig # 2004/11/29 22:43:24+00:00 bunk@stusta.de +8 -9 # The patch below switches options to use select where appropriate. # Signed-off-by: Adrian Bunk # # drivers/mtd/chips/Kconfig # 2004/11/29 22:43:24+00:00 bunk@stusta.de +6 -5 # The patch below switches options to use select where appropriate. # Signed-off-by: Adrian Bunk # # ChangeSet # 2004/11/29 22:34:26+00:00 dwmw2@shinybook.infradead.org # Merge linux-mtd@bkbits.net:mtd-2.6 # into shinybook.infradead.org:/home/dwmw2/bk/mtd-2.6 # # MAINTAINERS # 2004/11/29 22:34:18+00:00 dwmw2@shinybook.infradead.org +0 -0 # Auto merged # # ChangeSet # 2004/11/28 22:06:36-08:00 akpm@bix.(none) # Merge bk://linux-mtd.bkbits.net/mtd-2.6 into bix.(none):/usr/src/bk-mtd # # MAINTAINERS # 2004/11/28 22:06:32-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/28 19:18:16+00:00 dwmw2@dwmw2.baythorne.internal # Merge dwmw2.baythorne.internal:/inst/bk/linus-2.6 # into dwmw2.baythorne.internal:/inst/bk/mtd-2.6 # # drivers/mtd/maps/ts5500_flash.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -4 # Auto merged # # drivers/mtd/maps/scx200_docflash.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -2 # Auto merged # # drivers/mtd/maps/scb2_flash.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -2 # Auto merged # # drivers/mtd/maps/sc520cdp.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -6 # Auto merged # # drivers/mtd/maps/sbc_gxx.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -2 # Auto merged # # drivers/mtd/maps/physmap.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3 # Auto merged # # drivers/mtd/maps/pci.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3 # Auto merged # # drivers/mtd/maps/nettel.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -2 # Auto merged # # drivers/mtd/maps/netsc520.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3 # Auto merged # # drivers/mtd/maps/l440gx.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3 # Auto merged # # drivers/mtd/maps/ichxrom.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3 # Auto merged # # drivers/mtd/maps/elan-104nc.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -1 # Auto merged # # drivers/mtd/maps/ebony.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -6 # Auto merged # # drivers/mtd/maps/dilnetpc.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3 # Auto merged # # drivers/mtd/maps/amd76xrom.c # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -3 # Auto merged # # MAINTAINERS # 2004/11/28 19:18:10+00:00 dwmw2@dwmw2.baythorne.internal +0 -0 # Auto merged # # ChangeSet # 2004/11/28 19:16:07+00:00 dwmw2@dwmw2.baythorne.internal # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # # Signed-off-by: Al Viro # Signed-off-by: David Woodhouse # # drivers/mtd/maps/ts5500_flash.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +5 -5 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/scx200_docflash.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +3 -3 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/scb2_flash.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +3 -3 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/sc520cdp.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +7 -7 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/sbc_gxx.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +3 -3 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/physmap.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/pci.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/nettel.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +3 -3 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/netsc520.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/l440gx.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/ichxrom.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/elan-104nc.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +2 -2 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/ebony.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +7 -8 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/dilnetpc.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # drivers/mtd/maps/amd76xrom.c # 2004/11/28 09:52:32+00:00 dwmw2@dwmw2.baythorne.internal +4 -4 # NULL noise removal, missing __iomem in a couple of declarations, # removal of bogus cast to void * in iounmap() calls. # Signed-off-by: Al Viro # # ChangeSet # 2004/11/28 00:40:38+00:00 dwmw2@shinybook.infradead.org # Merge shinybook.infradead.org:/home/dwmw2/bk/linus-2.6 # into shinybook.infradead.org:/home/dwmw2/bk/mtd-2.6 # # MAINTAINERS # 2004/11/28 00:40:30+00:00 dwmw2@shinybook.infradead.org +0 -0 # Auto merged # # ChangeSet # 2004/11/28 00:33:43+00:00 dwmw2@shinybook.infradead.org # rslib: Spelling fixes. # # Some of the fixes from Joe Perches got missed out # of the last update. # # Signed-off-by: Thomas Gleixner # Signed-off-by: David Woodhouse # # lib/reed_solomon/reed_solomon.c # 2004/11/28 00:33:19+00:00 dwmw2@shinybook.infradead.org +8 -8 # revision 1.5 # date: 2004/10/22 15:41:47; author: gleixner; state: Exp; lines: +8 -8 # Joe Perches provided the spelling and # grammar fixes for Documentation. # I'm happy if somebody takes care of my language related # nescience. :) # # ChangeSet # 2004/11/28 00:19:24+00:00 dwmw2@shinybook.infradead.org # JFFS2: Allow NAND driver to disable virtual eraseblocks. # # In order to keep the RAM usage down with large devices and smaller # erase block sizes, we were using blocks in JFFS2 larger than the # physical erase size. This means that bad blocks lose a lot more space # though; allow it to be disabled. # # Signed-off-by: Thomas Gleixner # Signed-off-by: David Woodhouse # # include/mtd/mtd-abi.h # 2004/11/28 00:19:02+00:00 dwmw2@shinybook.infradead.org +2 -1 # revision 1.7 # date: 2004/11/23 15:37:32; author: gleixner; state: Exp; lines: +2 -1 # Disable virtual eraseblocks on request (MTD_NO_VIRTBLOCKS) is set. Be careful this can eat up a lot of memory # # fs/jffs2/super.c # 2004/11/28 00:19:01+00:00 dwmw2@shinybook.infradead.org +5 -2 # revision 1.104 # date: 2004/11/23 15:37:31; author: gleixner; state: Exp; lines: +5 -2 # Disable virtual eraseblocks on request (MTD_NO_VIRTBLOCKS) is set. Be careful this can eat up a lot of memory # # fs/jffs2/fs.c # 2004/11/28 00:19:01+00:00 dwmw2@shinybook.infradead.org +12 -7 # revision 1.50 # date: 2004/11/23 15:37:31; author: gleixner; state: Exp; lines: +12 -7 # Disable virtual eraseblocks on request (MTD_NO_VIRTBLOCKS) is set. Be careful this can eat up a lot of memory # # fs/jffs2/build.c # 2004/11/28 00:19:01+00:00 dwmw2@shinybook.infradead.org +7 -2 # revision 1.68 # date: 2004/11/27 13:38:10; author: gleixner; state: Exp; lines: +3 -1 # include headers to make it build # ---------------------------- # revision 1.67 # date: 2004/11/23 15:37:31; author: gleixner; state: Exp; lines: +5 -2 # Disable virtual eraseblocks on request (MTD_NO_VIRTBLOCKS) is set. Be careful this can eat up a lot of memory # # ChangeSet # 2004/11/28 00:15:04+00:00 dwmw2@shinybook.infradead.org # JFFS2: Split eraseblock refiling into separate function # # ...in preparation for further cleanups from Estelle Hammache which # will need to call it from elsewhere. # # Signed-off-by: David Woodhouse # # fs/jffs2/wbuf.c # 2004/11/28 00:14:42+00:00 dwmw2@shinybook.infradead.org +21 -16 # revision 1.82 # date: 2004/11/20 22:08:31; author: dwmw2; state: Exp; lines: +21 -16 # separate out block refiling # # ChangeSet # 2004/11/28 00:11:59+00:00 dwmw2@shinybook.infradead.org # JFFS2: Initialise bad_count for each eraseblock correctly. # # Patch from Estelle Hammache # Signed-off-by: David Woodhouse # # fs/jffs2/build.c # 2004/11/28 00:11:36+00:00 dwmw2@shinybook.infradead.org +2 -1 # revision 1.66 # date: 2004/11/20 19:18:07; author: dwmw2; state: Exp; lines: +2 -1 # Patch from Estelle Hammache: initialise bad_count. # # ChangeSet # 2004/11/28 00:07:08+00:00 dwmw2@shinybook.infradead.org # JFFS2: Various fixes for recent RAM use reduction. # # We recently started trying to merge the jffs2_raw_node_ref structures # for adjacent obsolete nodes. Fix a bunch of problems in that: # - Free inode cache structure for a dead inode which is now completely gone. # - Fix races vs. erase code which also walks the same lists. # - Fix BUG() when trying to merge with a node which still belongs to an inode. # # Signed-off-by: David Woodhouse # # fs/jffs2/nodemgmt.c # 2004/11/28 00:06:46+00:00 dwmw2@shinybook.infradead.org +60 -16 # revision 1.115 # date: 2004/11/22 11:07:21; author: dwmw2; state: Exp; lines: +5 -5 # Fix another bug in the merging of obsolete nodes # ---------------------------- # revision 1.114 # date: 2004/11/20 16:39:59; author: dwmw2; state: Exp; lines: +6 -2 # Add another reason why we can't currently merge obsolete node refs on # NAND. # ---------------------------- # revision 1.113 # date: 2004/11/20 16:25:19; author: dwmw2; state: Exp; lines: +7 -1 # Free inocache if it's all gone. # ---------------------------- # revision 1.112 # date: 2004/11/20 14:25:05; author: dwmw2; state: Exp; lines: +46 -12 # Fix race in jffs2_mark_node_obsolete(). There was nothing preventing the # block from being erased and 'ref' from being freed before we even got # around to marking it obsolete and then trying to merge nodes. # # fs/jffs2/build.c # 2004/11/28 00:06:46+00:00 dwmw2@shinybook.infradead.org +5 -2 # revision 1.65 # date: 2004/11/20 16:19:38; author: dwmw2; state: Exp; lines: +5 -2 # Fix freeing of refs belonging to unlinked inode # # ChangeSet # 2004/11/27 23:58:00+00:00 dwmw2@shinybook.infradead.org # JFFS2: Fix oops in read_inode. # # If the node with lowest version in a file was in the range # 0xfffff000 onwards, we oopsed because our rounding was bogus. # # Signed-off-by: David Woodhouse # # fs/jffs2/readinode.c # 2004/11/27 23:57:39+00:00 dwmw2@shinybook.infradead.org +2 -2 # revision 1.117 # date: 2004/11/20 18:06:54; author: dwmw2; state: Exp; lines: +2 -2 # Fix oops if we happen to have a node in the range 0xfffff000 onwards as the # lowest versioned node in the inode. # # ChangeSet # 2004/11/27 23:36:47+00:00 dwmw2@shinybook.infradead.org # MTD: NAND flash simulator # # We want to contribute the NAND flash simulator which we successfully use # when developing JFFS2. It is very useful tool which helps to develop # without real flash. # # It supports several options which allow to select which flash type to # emulate (just flash IDs which are in nand_ids.c file). See modinfo for # other options. # # Signed-off-by: Artem B. Bityuckiy # Signed-off-by: David Woodhouse # # drivers/mtd/nand/nandsim.c # 2004/11/27 23:36:22+00:00 dwmw2@shinybook.infradead.org +1619 -0 # # drivers/mtd/nand/nandsim.c # 2004/11/27 23:36:22+00:00 dwmw2@shinybook.infradead.org +0 -0 # BitKeeper file /home/dwmw2/bk/mtd-2.6/drivers/mtd/nand/nandsim.c # # drivers/mtd/nand/Makefile # 2004/11/27 23:36:22+00:00 dwmw2@shinybook.infradead.org +2 -1 # revision 1.15 # date: 2004/11/26 12:28:22; author: dedekind; state: Exp; lines: +2 -1 # Add the NAND simulator's records # # drivers/mtd/nand/Kconfig # 2004/11/27 23:36:22+00:00 dwmw2@shinybook.infradead.org +9 -1 # revision 1.24 # date: 2004/11/26 12:28:22; author: dedekind; state: Exp; lines: +9 -1 # Add the NAND simulator's records # # ChangeSet # 2004/11/27 23:18:34+00:00 dwmw2@shinybook.infradead.org # MTD: Support NOR and NAND flash on Sharp SL Series PDAs. # # Signed-off-by: Richard Purdie # Signed-off-by: David Woodhouse # # drivers/mtd/nand/sharpsl.c # 2004/11/27 23:18:12+00:00 dwmw2@shinybook.infradead.org +273 -0 # # drivers/mtd/nand/sharpsl.c # 2004/11/27 23:18:12+00:00 dwmw2@shinybook.infradead.org +0 -0 # BitKeeper file /home/dwmw2/bk/mtd-2.6/drivers/mtd/nand/sharpsl.c # # drivers/mtd/maps/sharpsl-flash.c # 2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +101 -0 # # drivers/mtd/nand/Makefile # 2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +2 -1 # revision 1.14 # date: 2004/11/24 19:33:56; author: rpurdie; state: Exp; lines: +2 -1 # Add the sharpsl nand driver. This supports the NAND chip on the Sharp SL Series # of PDAs. # # drivers/mtd/nand/Kconfig # 2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +6 -1 # revision 1.23 # date: 2004/11/24 19:33:56; author: rpurdie; state: Exp; lines: +6 -1 # Add the sharpsl nand driver. This supports the NAND chip on the Sharp SL Series # of PDAs. # # drivers/mtd/maps/sharpsl-flash.c # 2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +0 -0 # BitKeeper file /home/dwmw2/bk/mtd-2.6/drivers/mtd/maps/sharpsl-flash.c # # drivers/mtd/maps/Makefile # 2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +2 -1 # revision 1.20 # date: 2004/11/24 19:42:51; author: rpurdie; state: Exp; lines: +2 -1 # Add mapping for the flash chip on Sharp SL Series PDAs. # # drivers/mtd/maps/Kconfig # 2004/11/27 23:18:10+00:00 dwmw2@shinybook.infradead.org +7 -1 # revision 1.38 # date: 2004/11/24 19:42:51; author: rpurdie; state: Exp; lines: +7 -1 # Add mapping for the flash chip on Sharp SL Series PDAs. # # ChangeSet # 2004/11/27 23:02:48+00:00 dwmw2@shinybook.infradead.org # MTD: Fix timing setup for NAND flash on Samsung S3C2410. # # Spotted by Shannon Holland. # # Signed-off-by: Ben Dooks # Signed-off-by: David Woodhouse # # drivers/mtd/nand/s3c2410.c # 2004/11/27 23:02:28+00:00 dwmw2@shinybook.infradead.org +2 -2 # revision 1.6 # date: 2004/11/24 12:25:48; author: bjd; state: Exp; lines: +2 -2 # correct timing setup to use plat->twrph1 instead of # plat->twrph0 for timing setup for the NAND controllers # twrph1 configuration # # Thanks to Shannon Holland for pointing this out # # ChangeSet # 2004/11/27 22:59:41+00:00 dwmw2@shinybook.infradead.org # MTD: Fix oops on erase in NFTL/INFTL (again). # # Only this time, set the field we were dereferencing _after_ we zero it not before. # # Signed-off-by: Kalev Lember # Signed-off-by: David Woodhouse # # drivers/mtd/nftlmount.c # 2004/11/27 22:59:16+00:00 dwmw2@shinybook.infradead.org +3 -4 # revision 1.40 # date: 2004/11/22 14:38:29; author: kalev; state: Exp; lines: +3 -4 # fix oops # # drivers/mtd/inftlmount.c # 2004/11/27 22:59:16+00:00 dwmw2@shinybook.infradead.org +3 -4 # revision 1.16 # date: 2004/11/22 13:50:53; author: kalev; state: Exp; lines: +3 -4 # fix oops # (the instr was zeroed _after_ setting instr->mtd) # # ChangeSet # 2004/11/27 22:53:43+00:00 dwmw2@shinybook.infradead.org # MTD: Make phram work again # # o Add simple usage example. # o Fix up unit handling (k, M. G). # o Use correct size limit for setup string. # o Remove pointless printk message. # o Fix mtdblock to not allocate a read-modify-write buffer for CAP_RAM # devices (and fail to do so, returning an error). # # Signed-off-by: Jörn Engel # Signed-off-by: David Woodhouse # # drivers/mtd/mtdblock.c # 2004/11/27 22:53:20+00:00 dwmw2@shinybook.infradead.org +2 -2 # revision 1.66 # date: 2004/11/25 13:52:52; author: joern; state: Exp; lines: +2 -2 # Fix up slram and phram. # # drivers/mtd/devices/phram.c # 2004/11/27 22:53:20+00:00 dwmw2@shinybook.infradead.org +10 -6 # revision 1.6 # date: 2004/11/25 16:51:09; author: joern; state: Exp; lines: +2 -2 # Brown Paperbag category. Patch should be self-explaining to anyone who # knows how to deal with multi-dimensional arrays in c (i.e. not me). # ---------------------------- # revision 1.5 # date: 2004/11/25 13:54:09; author: joern; state: Exp; lines: +6 -4 # Make dwmw2 happy and add an i to [kMG]. # ---------------------------- # revision 1.4 # date: 2004/11/25 13:52:53; author: joern; state: Exp; lines: +7 -5 # Fix up slram and phram. # # ChangeSet # 2004/11/27 22:47:33+00:00 dwmw2@shinybook.infradead.org # MTD: mtdpart_setup() is used from platform code. Remove 'static'. # # Signed-off-by: Jarkko Lavinen # Signed-off-by: David Woodhouse # # drivers/mtd/cmdlinepart.c # 2004/11/27 22:47:11+00:00 dwmw2@shinybook.infradead.org +4 -2 # revision 1.17 # date: 2004/11/26 11:18:47; author: lavinen; state: Exp; lines: +4 -2 # Changed mtdpart_setup() back to public, # # ChangeSet # 2004/11/27 22:42:45+00:00 dwmw2@shinybook.infradead.org # MTD: Fix RedBoot FIS table detection. # # The redboot partitioning code currently searches for a FIS table entry # named "RedBoot" (including the trailing \0) in one of the first three # entries to try and verify that the sector it is looking at really is a # FIS partition table. # # Firstly it fails when RedBoot is stored in some other Flash chip such as # a boot PROM, in this case there is no "RedBoot" entry in the partition # table. However there will always be a "FIS directory" entry in any valid # FIS directory. # # Secondly it can fail since the RedBoot entry is not always in the first # 3 slots -- this can happen for example on an x86 based platform where # the processor expects the boot device to be at the top of memory rather # than the bottom and so RedBoot is at the end of the flash device. # Equally when using "FIS directory" as the entry to search for it very # likely is not in the first three since the directory is typically at the # end of the flash. # # Signed-off-by: Ian Campbell # Signed-off-by: David Woodhouse # # drivers/mtd/redboot.c # 2004/11/27 22:42:22+00:00 dwmw2@shinybook.infradead.org +24 -8 # revision 1.17 # date: 2004/11/22 11:33:56; author: ijc; state: Exp; lines: +14 -3 # RedBoot has a compile time configuration option called # CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK. Add a similar option # to the redboot parsing code. # ---------------------------- # revision 1.16 # date: 2004/11/22 11:32:13; author: ijc; state: Exp; lines: +11 -6 # Search for a directory entry named "FIS directory" rather the "RedBoot" # since RedBoot can potentially be in another device but there should # always be a FIS directory present (or we wouldn't be looking for it...). # # Also search all blocks not just the first 3 since the directory is often at # the end of flash rather than the beginning. # # drivers/mtd/Kconfig # 2004/11/27 22:42:22+00:00 dwmw2@shinybook.infradead.org +20 -3 # revision 1.7 # date: 2004/11/22 11:33:56; author: ijc; state: Exp; lines: +20 -3 # RedBoot has a compile time configuration option called # CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK. Add a similar option # to the redboot parsing code. # # ChangeSet # 2004/11/27 13:26:24-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd # # MAINTAINERS # 2004/11/27 13:26:19-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2004/11/20 12:53:46+00:00 dwmw2@shinybook.infradead.org # MTD: Use msleep() in cfi_udelay() helper function. # # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: Maximilian Attems # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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 # # 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 # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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ä ) # - Allow board drivers to provide pattern for bad block scanning # # Signed-off-by: Thomas Gleixner # Signed-off-by: David Woodhouse # # 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 ) # # 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 # ---------------------------- # 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 ) # # 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 # Signed-off-by: David Woodhouse # # 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 # Signed-off-by: David Woodhouse # # 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 # # 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 # # 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 # ---------------------------- # # 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 # # 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 # # 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 # # 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 # # 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 # # 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-29 21:35:09 -08:00 +++ b/CREDITS 2004-11-29 21:35:09 -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-29 21:35:09 -08:00 +++ b/MAINTAINERS 2004-11-29 21:35:09 -08:00 @@ -1439,7 +1439,7 @@ MEMORY TECHNOLOGY DEVICES P: David Woodhouse -M: dwmw2@redhat.com +M: dwmw2@infradead.org W: http://www.linux-mtd.infradead.org/ L: linux-mtd@lists.infradead.org S: Maintained diff -Nru a/drivers/char/applicom.c b/drivers/char/applicom.c --- a/drivers/char/applicom.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/char/applicom.c 2004-11-29 21:35:09 -08:00 @@ -1,6 +1,6 @@ /* Derived from Applicom driver ac.c for SCO Unix */ /* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */ -/* dwmw2@redhat.com 30/8/98 */ +/* dwmw2@infradead.org 30/8/98 */ /* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $ */ /* This module is for Linux 2.1 and 2.2 series kernels. */ /*****************************************************************************/ diff -Nru a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig --- a/drivers/mtd/Kconfig 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/Kconfig 2004-11-29 21:35:09 -08:00 @@ -1,4 +1,4 @@ -# $Id: Kconfig,v 1.6 2004/08/09 13:19:42 dwmw2 Exp $ +# $Id: Kconfig,v 1.7 2004/11/22 11:33:56 ijc Exp $ menu "Memory Technology Devices (MTD)" @@ -54,8 +54,8 @@ depends on MTD_PARTITIONS ---help--- RedBoot is a ROM monitor and bootloader which deals with multiple - 'images' in flash devices by putting a table in the last erase - block of the device, similar to a partition table, which gives + 'images' in flash devices by putting a table one of the erase + blocks on the device, similar to a partition table, which gives the offsets, lengths and names of all the images stored in the flash. @@ -68,6 +68,23 @@ SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. +config MTD_REDBOOT_DIRECTORY_BLOCK + int "Location of RedBoot partition table" + depends on MTD_REDBOOT_PARTS + default "-1" + ---help--- + This option is the Linux counterpart to the + CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time + option. + + The option specifies which Flash sectors holds the RedBoot + partition table. A zero or positive value gives an absolete + erase block number. A negative value specifies a number of + sectors before the end of the device. + + For example "2" means block number 2, "-1" means the last + block and "-2" means the penultimate block. + config MTD_REDBOOT_PARTS_UNALLOCATED bool " Include unallocated flash regions" depends on MTD_REDBOOT_PARTS diff -Nru a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig --- a/drivers/mtd/chips/Kconfig 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/chips/Kconfig 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ # drivers/mtd/chips/Kconfig -# $Id: Kconfig,v 1.9 2004/07/16 15:32:14 dwmw2 Exp $ +# $Id: Kconfig,v 1.11 2004/11/29 22:40:44 dwmw2 Exp $ menu "RAM/ROM/Flash chip drivers" depends on MTD!=n @@ -7,6 +7,7 @@ config MTD_CFI tristate "Detect flash chips by Common Flash Interface (CFI) probe" depends on MTD + select MTD_GEN_PROBE help The Common Flash Interface specification was developed by Intel, AMD and other flash manufactures that provides a universal method @@ -18,6 +19,7 @@ config MTD_JEDECPROBE tristate "Detect non-CFI AMD/JEDEC-compatible flash chips" depends on MTD + select MTD_GEN_PROBE help This option enables JEDEC-style probing of flash chips which are not compatible with the Common Flash Interface, but will use the common @@ -29,8 +31,6 @@ config MTD_GEN_PROBE tristate - default m if MTD_CFI!=y && !MTD_INTELPROBE && MTD_JEDECPROBE!=y && (MTD_CFI=m || MTD_JEDECPROBE=m) - default y if MTD_CFI=y || MTD_INTELPROBE || MTD_JEDECPROBE=y config MTD_CFI_ADV_OPTIONS bool "Flash chip driver advanced configuration options" @@ -158,6 +158,7 @@ config MTD_CFI_INTELEXT tristate "Support for Intel/Sharp flash chips" depends on MTD_GEN_PROBE + select MTD_CFI_UTIL help The Common Flash Interface defines a number of different command sets which a CFI-compliant chip may claim to implement. This code @@ -167,6 +168,7 @@ config MTD_CFI_AMDSTD tristate "Support for AMD/Fujitsu flash chips" depends on MTD_GEN_PROBE + select MTD_CFI_UTIL help The Common Flash Interface defines a number of different command sets which a CFI-compliant chip may claim to implement. This code @@ -197,6 +199,7 @@ config MTD_CFI_STAA tristate "Support for ST (Advanced Architecture) flash chips" depends on MTD_GEN_PROBE + select MTD_CFI_UTIL help The Common Flash Interface defines a number of different command sets which a CFI-compliant chip may claim to implement. This code @@ -204,8 +207,6 @@ config MTD_CFI_UTIL tristate - default y if MTD_CFI_INTELEXT=y || MTD_CFI_AMDSTD=y || MTD_CFI_STAA=y - default m if MTD_CFI_INTELEXT=m || MTD_CFI_AMDSTD=m || MTD_CFI_STAA=m config MTD_RAM tristate "Support for RAM chips in bus mapping" @@ -271,6 +272,15 @@ only called JEDEC because the JEDEC association 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-29 21:35:09 -08:00 +++ b/drivers/mtd/chips/amd_flash.c 2004-11-29 21:35:09 -08:00 @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $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-29 21:35:09 -08:00 +++ b/drivers/mtd/chips/cfi_cmdset_0001.c 2004-11-29 21:35:09 -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 * - completely revamped method functions so they are aware and @@ -30,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -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-29 21:35:09 -08:00 +++ b/drivers/mtd/chips/cfi_cmdset_0002.c 2004-11-29 21:35:09 -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-29 21:35:09 -08:00 +++ b/drivers/mtd/chips/cfi_cmdset_0020.c 2004-11-29 21:35:09 -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 * - 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-29 21:35:09 -08:00 +++ b/drivers/mtd/chips/cfi_probe.c 2004-11-29 21:35:09 -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 @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -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-29 21:35:09 -08:00 +++ b/drivers/mtd/chips/cfi_util.c 2004-11-29 21:35:09 -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 #include #include +#include #include #include #include #include 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; idevice_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-29 21:35:09 -08:00 +++ b/drivers/mtd/chips/jedec_probe.c 2004-11-29 21:35:09 -08:00 @@ -1,7 +1,7 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.58 2004/11/16 18:29:00 dwmw2 Exp $ + $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $ See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) for the standard this probe goes back to. @@ -227,6 +227,11 @@ [MTD_UADDR_DONT_CARE] = { .addr1 = 0x0000, /* Doesn't matter which address */ .addr2 = 0x0000 /* is used - must be last entry */ + }, + + [MTD_UADDR_UNNECESSARY] = { + .addr1 = 0x0000, + .addr2 = 0x0000 } }; @@ -514,15 +519,20 @@ ERASEINFO(0x10000,8), } }, { - mfr_id: MANUFACTURER_AMD, - dev_id: AM29F002T, - name: "AMD AM29F002T", - DevSize: SIZE_256KiB, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,3), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F002T, + .name = "AMD AM29F002T", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,3), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1), } }, { .mfr_id = MANUFACTURER_ATMEL, @@ -770,15 +780,20 @@ ERASEINFO(0x04000,1) } }, { - mfr_id: MANUFACTURER_HYUNDAI, - dev_id: HY29F002T, - name: "Hyundai HY29F002T", - DevSize: SIZE_256KiB, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,3), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) + .mfr_id = MANUFACTURER_HYUNDAI, + .dev_id = HY29F002T, + .name = "Hyundai HY29F002T", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,3), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1), } }, { .mfr_id = MANUFACTURER_INTEL, @@ -1177,15 +1192,20 @@ ERASEINFO(0x10000,7), } }, { - mfr_id: MANUFACTURER_MACRONIX, - dev_id: MX29F002T, - name: "Macronix MX29F002T", - DevSize: SIZE_256KiB, - NumEraseRegions: 4, - regions: {ERASEINFO(0x10000,3), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29F002T, + .name = "Macronix MX29F002T", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,3), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1), } }, { .mfr_id = MANUFACTURER_PMC, @@ -1780,7 +1800,6 @@ return 0; } - /* Mask out address bits which are smaller than the device type */ p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1; p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2; @@ -1923,7 +1942,6 @@ if (MTD_UADDR_UNNECESSARY == uaddr_idx) return 0; - /* Mask out address bits which are smaller than the device type */ cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1; cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2; } diff -Nru a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c --- a/drivers/mtd/cmdlinepart.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/cmdlinepart.c 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ /* - * $Id: cmdlinepart.c,v 1.16 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $ * * Read flash partition table from command line * @@ -338,8 +338,10 @@ * This is the handler for our kernel parameter, called from * main.c::checksetup(). Note that we can not yet kmalloc() anything, * so we only save the commandline for later processing. + * + * This function needs to be visible for bootloaders. */ -static int mtdpart_setup(char *s) +int mtdpart_setup(char *s) { cmdline = s; return 1; diff -Nru a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig --- a/drivers/mtd/devices/Kconfig 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/devices/Kconfig 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.13 2004/10/01 21:47:13 gleixner Exp $ +# $Id: Kconfig,v 1.14 2004/11/29 22:40:45 dwmw2 Exp $ menu "Self-contained MTD device drivers" depends on MTD!=n @@ -130,6 +130,8 @@ config MTD_DOC2000 tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)" depends on MTD + select MTD_DOCPROBE + select MTD_NAND_IDS ---help--- This provides an MTD device driver for the M-Systems DiskOnChip 2000 and Millennium devices. Originally designed for the DiskOnChip @@ -151,6 +153,8 @@ config MTD_DOC2001 tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)" depends on MTD + select MTD_DOCPROBE + select MTD_NAND_IDS ---help--- This provides an alternative MTD device driver for the M-Systems DiskOnChip Millennium devices. Use this if you have problems with @@ -171,6 +175,8 @@ config MTD_DOC2001PLUS tristate "M-Systems Disk-On-Chip Millennium Plus" depends on MTD + select MTD_DOCPROBE + select MTD_NAND_IDS ---help--- This provides an MTD device driver for the M-Systems DiskOnChip Millennium Plus devices. @@ -186,17 +192,10 @@ config MTD_DOCPROBE tristate - default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MTD_DOC2001PLUS=m) - default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y - help - This isn't a real config option; it's derived. + select MTD_DOCECC config MTD_DOCECC tristate - default m if MTD_DOCPROBE=m - default y if MTD_DOCPROBE=y - help - This isn't a real config option; it's derived. config MTD_DOCPROBE_ADVANCED bool "Advanced detection options for DiskOnChip" diff -Nru a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c --- a/drivers/mtd/devices/phram.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/devices/phram.c 2004-11-29 21:35:09 -08:00 @@ -1,6 +1,6 @@ /** * - * $Id: phram.c,v 1.3 2004/11/16 18:29:01 dwmw2 Exp $ + * $Id: phram.c,v 1.6 2004/11/25 16:51:09 joern Exp $ * * Copyright (c) Jochen Schaeuble * 07/2003 rewritten by Joern Engel @@ -15,9 +15,12 @@ * phram=,, * may be up to 63 characters. * and can be octal, decimal or hexadecimal. If followed - * by "k", "M" or "G", the numbers will be interpreted as kilo, mega or + * by "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or * gigabytes. * + * Example: + * phram=swap,896Mi,110Mi phram=test,1006Mi,1Mi + * */ #include @@ -184,7 +187,9 @@ result *= 1024; case 'k': result *= 1024; - endp++; + /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */ + if ((*endp)[1] == 'i') + (*endp) += 2; } return result; } @@ -235,7 +240,7 @@ uint32_t len; int i, ret; - if (strnlen(val, sizeof(str)) >= sizeof(str)) + if (strnlen(val, sizeof(buf)) >= sizeof(buf)) parse_err("parameter too long\n"); strcpy(str, val); @@ -283,7 +288,7 @@ if (!val || !val[0]) parse_err("no arguments to \"slram=\"\n"); - if (strnlen(val, sizeof(str)) >= sizeof(str)) + if (strnlen(val, sizeof(buf)) >= sizeof(buf)) parse_err("parameter too long\n"); strcpy(str, val); @@ -342,7 +347,6 @@ static int __init init_phram(void) { - printk(KERN_ERR "phram loaded\n"); return 0; } diff -Nru a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c --- a/drivers/mtd/inftlmount.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/inftlmount.c 2004-11-29 21:35:09 -08:00 @@ -8,7 +8,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: inftlmount.c,v 1.15 2004/11/05 21:55:55 kalev Exp $ + * $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,7 +41,7 @@ #include #include -char inftlmountrev[]="$Revision: 1.15 $"; +char inftlmountrev[]="$Revision: 1.16 $"; /* * find_boot_record: Find the INFTL Media Header and its Spare copy which @@ -389,8 +389,6 @@ struct erase_info *instr = &inftl->instr; int physblock; - instr->mtd = inftl->mbd.mtd; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p," "block=%d)\n", inftl, block); @@ -400,6 +398,7 @@ _first_? */ /* Use async erase interface, test return code */ + instr->mtd = inftl->mbd.mtd; instr->addr = block * inftl->EraseSize; instr->len = inftl->mbd.mtd->erasesize; /* Erase one physical eraseblock at a time, even though the NAND api diff -Nru a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig --- a/drivers/mtd/maps/Kconfig 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/Kconfig 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.37 2004/10/20 22:57:18 dwmw2 Exp $ +# $Id: Kconfig,v 1.38 2004/11/24 19:42:51 rpurdie Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -644,6 +644,12 @@ int "Maximum size for BAST flash area (MiB)" depends on MTD_BAST default "4" + +config MTD_SHARP_SL + bool "ROM maped on Sharp SL Series" + depends on MTD && ARCH_PXA + help + This enables access to the flash chip on the Sharp SL Series of PDAs. endmenu diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile --- a/drivers/mtd/maps/Makefile 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/Makefile 2004-11-29 21:35:09 -08:00 @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.19 2004/09/21 14:27:16 bjd Exp $ +# $Id: Makefile.common,v 1.20 2004/11/24 19:42:51 rpurdie Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -69,3 +69,4 @@ obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o +obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o diff -Nru a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c --- a/drivers/mtd/maps/amd76xrom.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/amd76xrom.c 2004-11-29 21:35:09 -08:00 @@ -2,7 +2,7 @@ * amd76xrom.c * * Normal mappings of chips in physical memory - * $Id: amd76xrom.c,v 1.18 2004/11/16 18:29:02 dwmw2 Exp $ + * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $ */ #include diff -Nru a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c --- a/drivers/mtd/maps/dilnetpc.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/dilnetpc.c 2004-11-29 21:35:09 -08:00 @@ -14,7 +14,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: dilnetpc.c,v 1.16 2004/11/04 13:24:14 gleixner Exp $ + * $Id: dilnetpc.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $ * * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems * featuring the AMD Elan SC410 processor. There are two variants of this diff -Nru a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c --- a/drivers/mtd/maps/ebony.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/ebony.c 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ /* - * $Id: ebony.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $ + * $Id: ebony.c,v 1.14 2004/11/28 09:40:39 dwmw2 Exp $ * * Mapping for Ebony user flash * diff -Nru a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c --- a/drivers/mtd/maps/elan-104nc.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/elan-104nc.c 2004-11-29 21:35:09 -08:00 @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: elan-104nc.c,v 1.24 2004/11/16 18:29:02 dwmw2 Exp $ + $Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $ The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. diff -Nru a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c --- a/drivers/mtd/maps/ichxrom.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/ichxrom.c 2004-11-29 21:35:09 -08:00 @@ -2,7 +2,7 @@ * ichxrom.c * * Normal mappings of chips in physical memory - * $Id: ichxrom.c,v 1.15 2004/11/16 18:29:02 dwmw2 Exp $ + * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $ */ #include diff -Nru a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c --- a/drivers/mtd/maps/l440gx.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/l440gx.c 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ /* - * $Id: l440gx.c,v 1.16 2004/11/16 18:29:02 dwmw2 Exp $ + * $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $ * * BIOS Flash chip on Intel 440GX board. * diff -Nru a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c --- a/drivers/mtd/maps/netsc520.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/netsc520.c 2004-11-29 21:35:09 -08:00 @@ -3,7 +3,7 @@ * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH * - * $Id: netsc520.c,v 1.12 2004/11/04 13:24:15 gleixner Exp $ + * $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff -Nru a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c --- a/drivers/mtd/maps/nettel.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/nettel.c 2004-11-29 21:35:09 -08:00 @@ -6,7 +6,7 @@ * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) * - * $Id: nettel.c,v 1.8 2004/11/04 13:24:15 gleixner Exp $ + * $Id: nettel.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $ */ /****************************************************************************/ diff -Nru a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c --- a/drivers/mtd/maps/pci.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/pci.c 2004-11-29 21:35:09 -08:00 @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * $Id: pci.c,v 1.8 2004/07/12 22:38:29 dwmw2 Exp $ + * $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $ * * Generic PCI memory map driver. We support the following boards: * - Intel IQ80310 ATU. diff -Nru a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c --- a/drivers/mtd/maps/physmap.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/physmap.c 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ /* - * $Id: physmap.c,v 1.36 2004/11/04 13:24:15 gleixner Exp $ + * $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $ * * Normal mappings of chips in physical memory * diff -Nru a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c --- a/drivers/mtd/maps/sbc_gxx.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/sbc_gxx.c 2004-11-29 21:35:09 -08:00 @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: sbc_gxx.c,v 1.32 2004/11/16 18:29:02 dwmw2 Exp $ + $Id: sbc_gxx.c,v 1.33 2004/11/28 09:40:40 dwmw2 Exp $ The SBC-MediaGX / SBC-GXx has up to 16 MiB of Intel StrataFlash (28F320/28F640) in x8 mode. diff -Nru a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c --- a/drivers/mtd/maps/sc520cdp.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/sc520cdp.c 2004-11-29 21:35:09 -08:00 @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: sc520cdp.c,v 1.18 2004/11/04 13:24:15 gleixner Exp $ + * $Id: sc520cdp.c,v 1.19 2004/11/28 09:40:40 dwmw2 Exp $ * * * The SC520CDP is an evaluation board for the Elan SC520 processor available diff -Nru a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c --- a/drivers/mtd/maps/scb2_flash.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/scb2_flash.c 2004-11-29 21:35:09 -08:00 @@ -1,6 +1,6 @@ /* * MTD map driver for BIOS Flash on Intel SCB2 boards - * $Id: scb2_flash.c,v 1.10 2004/11/16 18:29:02 dwmw2 Exp $ + * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $ * Copyright (C) 2002 Sun Microsystems, Inc. * Tim Hockin * diff -Nru a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c --- a/drivers/mtd/maps/scx200_docflash.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/scx200_docflash.c 2004-11-29 21:35:09 -08:00 @@ -2,7 +2,7 @@ Copyright (c) 2001,2002 Christer Weinigel - $Id: scx200_docflash.c,v 1.9 2004/11/16 18:29:02 dwmw2 Exp $ + $Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $ National Semiconductor SCx200 flash mapped with DOCCS */ diff -Nru a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/maps/sharpsl-flash.c 2004-11-29 21:35:09 -08:00 @@ -0,0 +1,101 @@ +/* + * sharpsl-flash.c + * + * Copyright (C) 2001 Lineo Japan, Inc. + * Copyright (C) 2002 SHARP + * + * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $ + * + * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp + * Handle mapping of the flash on the RPX Lite and CLLF boards + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define WINDOW_ADDR 0x00000000 +#define WINDOW_SIZE 0x01000000 +#define BANK_WIDTH 2 + +static struct mtd_info *mymtd; + +struct map_info sharpsl_map = { + .name = "sharpsl-flash", + .size = WINDOW_SIZE, + .bankwidth = BANK_WIDTH, + .phys = WINDOW_ADDR +}; + +static struct mtd_partition sharpsl_partitions[1] = { + { + name: "Filesystem", + size: 0x006d0000, + offset: 0x00120000 + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +int __init init_sharpsl(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + char *part_type = "static"; + + printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); + sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); + if (!sharpsl_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + mymtd = do_map_probe("map_rom", &sharpsl_map); + if (!mymtd) { + iounmap(sharpsl_map.virt); + return -ENXIO; + } + + mymtd->owner = THIS_MODULE; + + parts = sharpsl_partitions; + nb_parts = NB_OF(sharpsl_partitions); + + printk(KERN_NOTICE "Using %s partision definition\n", part_type); + add_mtd_partitions(mymtd, parts, nb_parts); + + return 0; +} + +static void __exit cleanup_sharpsl(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (sharpsl_map.virt) { + iounmap(sharpsl_map.virt); + sharpsl_map.virt = 0; + } +} + +module_init(init_sharpsl); +module_exit(cleanup_sharpsl); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("SHARP (Original: Arnold Christensen )"); +MODULE_DESCRIPTION("MTD map driver for SHARP SL series"); diff -Nru a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c --- a/drivers/mtd/maps/ts5500_flash.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/maps/ts5500_flash.c 2004-11-29 21:35:09 -08:00 @@ -25,7 +25,7 @@ * - If you have created your own jffs file system and the bios overwrites * it during boot, try disabling Drive A: and B: in the boot order. * - * $Id: ts5500_flash.c,v 1.1 2004/09/20 15:33:26 sean Exp $ + * $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $ */ #include diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c --- a/drivers/mtd/mtdblock.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/mtdblock.c 2004-11-29 21:35:09 -08:00 @@ -1,7 +1,7 @@ /* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.65 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $ * * (C) 2000-2003 Nicolas Pitre * (C) 1999-2003 David Woodhouse @@ -248,7 +248,7 @@ unsigned long block, char *buf) { struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; - if (unlikely(!mtdblk->cache_data)) { + if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) { mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize); if (!mtdblk->cache_data) return -EINTR; diff -Nru a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig --- a/drivers/mtd/nand/Kconfig 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/nand/Kconfig 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ # drivers/mtd/nand/Kconfig -# $Id: Kconfig,v 1.22 2004/10/05 22:11:46 gleixner Exp $ +# $Id: Kconfig,v 1.25 2004/11/29 22:40:45 dwmw2 Exp $ menu "NAND Flash Device Drivers" depends on MTD!=n @@ -7,6 +7,7 @@ config MTD_NAND tristate "NAND Device Support" depends on MTD + select MTD_NAND_IDS help This enables support for accessing all type of NAND flash devices. For further information see @@ -56,8 +57,6 @@ config MTD_NAND_IDS tristate - default y if MTD_NAND = y || MTD_DOC2000 = y || MTD_DOC2001 = y || MTD_DOC2001PLUS = y - default m if MTD_NAND = m || MTD_DOC2000 = m || MTD_DOC2001 = m || MTD_DOC2001PLUS = m config MTD_NAND_TX4925NDFMC tristate "SmartMedia Card on Toshiba RBTX4925 reference board" @@ -192,4 +191,17 @@ Even if you leave this disabled, you can enable BBT writes at module load time (assuming you build diskonchip as a module) with the module parameter "inftl_bbt_write=1". + + config MTD_NAND_SHARPSL + bool "Support for NAND Flash on Sharp SL Series (C7xx + others)" + depends on MTD_NAND && ARCH_PXA + + config MTD_NAND_NANDSIM + bool "Support for NAND Flash Simulator" + depends on MTD_NAND + + help + The simulator may simulate verious NAND flash chips for the + MTD nand layer. + endmenu diff -Nru a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile --- a/drivers/mtd/nand/Makefile 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/nand/Makefile 2004-11-29 21:35:09 -08:00 @@ -1,7 +1,7 @@ # # linux/drivers/nand/Makefile # -# $Id: Makefile.common,v 1.13 2004/09/28 22:04:23 bjd Exp $ +# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o @@ -18,5 +18,7 @@ obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o obj-$(CONFIG_MTD_NAND_H1900) += h1910.o obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o +obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o +obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o nand-objs = nand_base.o nand_bbt.o diff -Nru a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c --- a/drivers/mtd/nand/nand_base.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/nand/nand_base.c 2004-11-29 21:35:09 -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-29 21:35:09 -08:00 +++ b/drivers/mtd/nand/nand_bbt.c 2004-11-29 21:35:09 -08:00 @@ -6,7 +6,7 @@ * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_bbt.c,v 1.26 2004/10/05 13:50:20 gleixner Exp $ + * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -1001,25 +1001,27 @@ return nand_scan_bbt (mtd, &agand_flashbased); } + /* Is a flash based bad block table requested ? */ if (this->options & NAND_USE_FLASH_BBT) { /* Use the default pattern descriptors */ if (!this->bbt_td) { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; - } - if (mtd->oobblock > 512) - return nand_scan_bbt (mtd, &largepage_flashbased); - else - return nand_scan_bbt (mtd, &smallpage_flashbased); + } + if (!this->badblock_pattern) { + this->badblock_pattern = (mtd->oobblock > 512) ? + &largepage_flashbased : &smallpage_flashbased; + } } else { this->bbt_td = NULL; this->bbt_md = NULL; - if (mtd->oobblock > 512) - return nand_scan_bbt (mtd, &largepage_memorybased); - else - return nand_scan_bbt (mtd, &smallpage_memorybased); + if (!this->badblock_pattern) { + this->badblock_pattern = (mtd->oobblock > 512) ? + &largepage_memorybased : &smallpage_memorybased; + } } + return nand_scan_bbt (mtd, this->badblock_pattern); } /** diff -Nru a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/nand/nandsim.c 2004-11-29 21:35:09 -08:00 @@ -0,0 +1,1619 @@ +/* + * NAND flash simulator. + * + * Author: Artem B. Bityuckiy , + * + * Copyright (C) 2004 Nokia Corporation + * + * Note: NS means "NAND Simulator". + * Note: Input means input TO flash chip, output means output FROM chip. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA + * + * $Id: nandsim.c,v 1.3 2004/11/26 13:00:24 dedekind Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_NS_ABS_POS +#include +#endif + + +/* Default simulator parameters values */ +#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ + !defined(CONFIG_NANDSIM_SECOND_ID_BYTE) || \ + !defined(CONFIG_NANDSIM_THIRD_ID_BYTE) || \ + !defined(CONFIG_NANDSIM_FOURTH_ID_BYTE) +#define CONFIG_NANDSIM_FIRST_ID_BYTE 0x98 +#define CONFIG_NANDSIM_SECOND_ID_BYTE 0x36 +#define CONFIG_NANDSIM_THIRD_ID_BYTE 0xFF /* No byte */ +#define CONFIG_NANDSIM_FOURTH_ID_BYTE 0xFF /* No byte */ +#endif + +#ifndef CONFIG_NANDSIM_ACCESS_DELAY +#define CONFIG_NANDSIM_ACCESS_DELAY 25 +#endif +#ifndef CONFIG_NANDSIM_PROGRAMM_DELAY +#define CONFIG_NANDSIM_PROGRAMM_DELAY 200 +#endif +#ifndef CONFIG_NANDSIM_ERASE_DELAY +#define CONFIG_NANDSIM_ERASE_DELAY 2 +#endif +#ifndef CONFIG_NANDSIM_OUTPUT_CYCLE +#define CONFIG_NANDSIM_OUTPUT_CYCLE 40 +#endif +#ifndef CONFIG_NANDSIM_INPUT_CYCLE +#define CONFIG_NANDSIM_INPUT_CYCLE 50 +#endif +#ifndef CONFIG_NANDSIM_BUS_WIDTH +#define CONFIG_NANDSIM_BUS_WIDTH 8 +#endif +#ifndef CONFIG_NANDSIM_DO_DELAYS +#define CONFIG_NANDSIM_DO_DELAYS 0 +#endif +#ifndef CONFIG_NANDSIM_LOG +#define CONFIG_NANDSIM_LOG 0 +#endif +#ifndef CONFIG_NANDSIM_DBG +#define CONFIG_NANDSIM_DBG 0 +#endif + +static uint first_id_byte = CONFIG_NANDSIM_FIRST_ID_BYTE; +static uint second_id_byte = CONFIG_NANDSIM_SECOND_ID_BYTE; +static uint third_id_byte = CONFIG_NANDSIM_THIRD_ID_BYTE; +static uint fourth_id_byte = CONFIG_NANDSIM_FOURTH_ID_BYTE; +static uint access_delay = CONFIG_NANDSIM_ACCESS_DELAY; +static uint programm_delay = CONFIG_NANDSIM_PROGRAMM_DELAY; +static uint erase_delay = CONFIG_NANDSIM_ERASE_DELAY; +static uint output_cycle = CONFIG_NANDSIM_OUTPUT_CYCLE; +static uint input_cycle = CONFIG_NANDSIM_INPUT_CYCLE; +static uint bus_width = CONFIG_NANDSIM_BUS_WIDTH; +static uint do_delays = CONFIG_NANDSIM_DO_DELAYS; +static uint log = CONFIG_NANDSIM_LOG; +static uint dbg = CONFIG_NANDSIM_DBG; + +module_param(first_id_byte, uint, 0400); +module_param(second_id_byte, uint, 0400); +module_param(third_id_byte, uint, 0400); +module_param(fourth_id_byte, uint, 0400); +module_param(access_delay, uint, 0400); +module_param(programm_delay, uint, 0400); +module_param(erase_delay, uint, 0400); +module_param(output_cycle, uint, 0400); +module_param(input_cycle, uint, 0400); +module_param(bus_width, uint, 0400); +module_param(do_delays, uint, 0400); +module_param(log, uint, 0400); +module_param(dbg, uint, 0400); + +MODULE_PARM_DESC(first_id_byte, "The fist byte returned by NAND Flash 'read ID' command (manufaturer ID)"); +MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); +MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); +MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); +MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); +MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); +MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); +MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); +MODULE_PARM_DESC(input_cycle, "Word input (to flash) time (nanodeconds)"); +MODULE_PARM_DESC(bus_width, "Chip's bus width (8- or 16-bit)"); +MODULE_PARM_DESC(do_delays, "Simulate NAND delays using busy-waits if not zero"); +MODULE_PARM_DESC(log, "Perform logging if not zero"); +MODULE_PARM_DESC(dbg, "Output debug information if not zero"); + +/* + * There is no macro for 0x30 command which is used in "large page" + * devices in standard mtd header, define it here. + */ +#define NAND_CMD_READ2LP 0x30 + +/* The largest possible page size */ +#define NS_LARGEST_PAGE_SIZE 2048 + +/* The prefix for simulator output */ +#define NS_OUTPUT_PREFIX "[nandsim]" + +/* Simulator's output macros (logging, debugging, warning, error) */ +#define NS_LOG(args...) \ + do { if (log) printk(KERN_INFO NS_OUTPUT_PREFIX " log: " args); } while(0) +#define NS_DBG(args...) \ + do { if (dbg) printk(KERN_INFO NS_OUTPUT_PREFIX " debug: " args); } while(0) +#define NS_WARN(args...) \ + do { printk(KERN_INFO NS_OUTPUT_PREFIX " warnig: " args); } while(0) +#define NS_ERR(args...) \ + do { printk(KERN_INFO NS_OUTPUT_PREFIX " errorr: " args); } while(0) + +/* Busy-wait delay macros (microseconds, milliseconds) */ +#define NS_UDELAY(us) \ + do { if (do_delays) udelay(us); } while(0) +#define NS_MDELAY(us) \ + do { if (do_delays) mdelay(us); } while(0) + +/* Is the nandsim structure initialized ? */ +#define NS_IS_INITIALIZED(ns) ((ns)->geom.totsz != 0) + +/* Good operation completion status */ +#define NS_STATUS_OK(ns) (NAND_STATUS_READY | (NAND_STATUS_WP * ((ns)->lines.wp == 0))) + +/* Operation failed completion status */ +#define NS_STATUS_FAILED(ns) (NAND_STATUS_FAIL | NS_STATUS_OK(ns)) + +/* Calculate the page offset in flash RAM image by (row, column) address */ +#define NS_RAW_OFFSET(ns) \ + (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column) + +/* Calculate the OOB offset in flash RAM image by (row, column) address */ +#define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz) + +/* After a command is input, the simulator goes to one of the following states */ +#define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */ +#define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */ +#define STATE_CMD_READ2LP 0x00000003 /* read data second command (large page devices) */ +#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */ +#define STATE_CMD_READOOB 0x00000005 /* read OOB area */ +#define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */ +#define STATE_CMD_STATUS 0x00000007 /* read status */ +#define STATE_CMD_STATUS_M 0x00000008 /* read multi-plane status (isn't implemented) */ +#define STATE_CMD_SEQIN 0x00000009 /* sequential data imput */ +#define STATE_CMD_READID 0x0000000A /* read ID */ +#define STATE_CMD_ERASE2 0x0000000B /* sector erase second command */ +#define STATE_CMD_RESET 0x0000000C /* reset */ +#define STATE_CMD_MASK 0x0000000F /* command states mask */ + +/* After an addres is input, the simulator goes to one of these states */ +#define STATE_ADDR_PAGE 0x00000010 /* full (row, column) address is accepted */ +#define STATE_ADDR_SEC 0x00000020 /* sector address was accepted */ +#define STATE_ADDR_ZERO 0x00000030 /* one byte zero address was accepted */ +#define STATE_ADDR_MASK 0x00000030 /* address states mask */ + +/* Durind data input/output the simulator is in these states */ +#define STATE_DATAIN 0x00000100 /* waiting for data input */ +#define STATE_DATAIN_MASK 0x00000100 /* data input states mask */ + +#define STATE_DATAOUT 0x00001000 /* waiting for page data output */ +#define STATE_DATAOUT_ID 0x00002000 /* waiting for ID bytes output */ +#define STATE_DATAOUT_STATUS 0x00003000 /* waiting for status output */ +#define STATE_DATAOUT_STATUS_M 0x00004000 /* waiting for multi-plane status output */ +#define STATE_DATAOUT_MASK 0x00007000 /* data output states mask */ + +/* Previous operation is done, ready to accept new requests */ +#define STATE_READY 0x00000000 + +/* This state is used to mark that the next state isn't known yet */ +#define STATE_UNKNOWN 0x10000000 + +/* Simulator's actions bit masks */ +#define ACTION_CPY 0x00100000 /* copy page/OOB to the internal buffer */ +#define ACTION_PRGPAGE 0x00200000 /* programm the internal buffer to flash */ +#define ACTION_SECERASE 0x00300000 /* erase sector */ +#define ACTION_ZEROOFF 0x00400000 /* don't add any offset to address */ +#define ACTION_HALFOFF 0x00500000 /* add to address half of page */ +#define ACTION_OOBOFF 0x00600000 /* add to address OOB offset */ +#define ACTION_MASK 0x00700000 /* action mask */ + +#define NS_OPER_NUM 12 /* Number of operations supported by the simulator */ +#define NS_OPER_STATES 6 /* Maximum number of states in operation */ + +#define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */ +#define OPT_PAGE256 0x00000001 /* 256-byte page chips */ +#define OPT_PAGE512 0x00000002 /* 512-byte page chips */ +#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */ +#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */ +#define OPT_AUTOINCR 0x00000020 /* page number auto inctimentation is possible */ +#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */ +#define OPT_LARGEPAGE (OPT_PAGE2048) /* 2048-byte page chips */ +#define OPT_SMALLPAGE (OPT_PAGE256 | OPT_PAGE512) /* 256 and 512-byte page chips */ + +/* Remove action bits ftom state */ +#define NS_STATE(x) ((x) & ~ACTION_MASK) + +/* + * Maximum previous states which need to be saved. Currently saving is + * only needed for page programm operation with preceeded read command + * (which is only valid for 512-byte pages). + */ +#define NS_MAX_PREVSTATES 1 + +/* + * The structure which describes all the internal simulator data. + */ +struct nandsim { + struct mtd_partition part; + + uint busw; /* flash chip bus width (8 or 16) */ + u_char ids[4]; /* chip's ID bytes */ + uint32_t options; /* chip's characteristic bits */ + uint32_t state; /* current chip state */ + uint32_t nxstate; /* next expected state */ + + uint32_t *op; /* current operation, NULL operations isn't known yet */ + uint32_t pstates[NS_MAX_PREVSTATES]; /* previous states */ + uint16_t npstates; /* number of previous states saved */ + uint16_t stateidx; /* current state index */ + + /* The simulated NAND flash image */ + union flash_media { + u_char *byte; + uint16_t *word; + } mem; + + /* Internal buffer of page + OOB size bytes */ + union internal_buffer { + u_char *byte; /* for byte access */ + uint16_t *word; /* for 16-bit word access */ + } buf; + + /* NAND flash "geometry" */ + struct nandsin_geometry { + uint32_t totsz; /* total flash size, bytes */ + uint32_t secsz; /* flash sector (erase block) size, bytes */ + uint pgsz; /* NAND flash page size, bytes */ + uint oobsz; /* page OOB area size, bytes */ + uint32_t totszoob; /* total flash size including OOB, bytes */ + uint pgszoob; /* page size including OOB , bytes*/ + uint secszoob; /* sector size including OOB, bytes */ + uint pgnum; /* total number of pages */ + uint pgsec; /* number of pages per sector */ + uint secshift; /* bits number in sector size */ + uint pgshift; /* bits number in page size */ + uint oobshift; /* bits number in OOB size */ + uint pgaddrbytes; /* bytes per page address */ + uint secaddrbytes; /* bytes per sector address */ + uint idbytes; /* the number ID bytes that this chip outputs */ + } geom; + + /* NAND flash internal registers */ + struct nandsim_regs { + unsigned command; /* the command register */ + u_char status; /* the status register */ + uint row; /* the page number */ + uint column; /* the offset within page */ + uint count; /* internal counter */ + uint num; /* number of bytes which must be processed */ + uint off; /* fixed page offset */ + } regs; + + /* NAND flash lines state */ + struct ns_lines_status { + int ce; /* chip Enable */ + int cle; /* command Latch Enable */ + int ale; /* address Latch Enable */ + int wp; /* write Protect */ + } lines; +}; + +/* + * Operations array. To perform any operation the simulator must pass + * through the correspondent states chain. + */ +static struct nandsim_operations { + uint32_t reqopts; /* options which are required to perform the operation */ + uint32_t states[NS_OPER_STATES]; /* operation's states */ +} ops[NS_OPER_NUM] = { + /* Read page + OOB from the beginning */ + {OPT_SMALLPAGE, {STATE_CMD_READ0 | ACTION_ZEROOFF, STATE_ADDR_PAGE | ACTION_CPY, + STATE_DATAOUT, STATE_READY}}, + /* Read page + OOB from the second half */ + {OPT_PAGE512_8BIT, {STATE_CMD_READ1 | ACTION_HALFOFF, STATE_ADDR_PAGE | ACTION_CPY, + STATE_DATAOUT, STATE_READY}}, + /* Read OOB */ + {OPT_SMALLPAGE, {STATE_CMD_READOOB | ACTION_OOBOFF, STATE_ADDR_PAGE | ACTION_CPY, + STATE_DATAOUT, STATE_READY}}, + /* Programm page starting from the beginning */ + {OPT_ANY, {STATE_CMD_SEQIN, STATE_ADDR_PAGE, STATE_DATAIN, + STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, + /* Programm page starting from the beginning */ + {OPT_SMALLPAGE, {STATE_CMD_READ0, STATE_CMD_SEQIN | ACTION_ZEROOFF, STATE_ADDR_PAGE, + STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, + /* Programm page starting from the second half */ + {OPT_PAGE512, {STATE_CMD_READ1, STATE_CMD_SEQIN | ACTION_HALFOFF, STATE_ADDR_PAGE, + STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, + /* Programm OOB */ + {OPT_SMALLPAGE, {STATE_CMD_READOOB, STATE_CMD_SEQIN | ACTION_OOBOFF, STATE_ADDR_PAGE, + STATE_DATAIN, STATE_CMD_PAGEPROG | ACTION_PRGPAGE, STATE_READY}}, + /* Erase sector */ + {OPT_ANY, {STATE_CMD_ERASE1, STATE_ADDR_SEC, STATE_CMD_ERASE2 | ACTION_SECERASE, STATE_READY}}, + /* Read status */ + {OPT_ANY, {STATE_CMD_STATUS, STATE_DATAOUT_STATUS, STATE_READY}}, + /* Read multi-plane status */ + {OPT_SMARTMEDIA, {STATE_CMD_STATUS_M, STATE_DATAOUT_STATUS_M, STATE_READY}}, + /* Read ID */ + {OPT_ANY, {STATE_CMD_READID, STATE_ADDR_ZERO, STATE_DATAOUT_ID, STATE_READY}}, + /* Large page devices read page */ + {OPT_LARGEPAGE, {STATE_CMD_READ0, STATE_ADDR_PAGE, STATE_CMD_READ2LP | ACTION_CPY, + STATE_DATAOUT, STATE_READY}} +}; + +/* MTD structure for NAND controller */ +static struct mtd_info *nsmtd; + +static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; + +/* + * Initialize the nandsim structure. + * + * RETURNS: 0 if success, -ERRNO if failure. + */ +static int +init_nandsim(struct mtd_info *mtd) +{ + struct nand_chip *chip = (struct nand_chip *)mtd->priv; + struct nandsim *ns = (struct nandsim *)(chip->priv); + int i; + + if (NS_IS_INITIALIZED(ns)) { + NS_ERR("init_nandsim: nandsim is already initialized\n"); + return -EIO; + } + + /* Force mtd to not do delays */ + chip->chip_delay = 0; + + /* Initialize the NAND flash parameters */ + ns->busw = chip->options & NAND_BUSWIDTH_16 ? 16 : 8; + ns->geom.totsz = mtd->size; + ns->geom.pgsz = mtd->oobblock; + ns->geom.oobsz = mtd->oobsize; + ns->geom.secsz = mtd->erasesize; + ns->geom.pgszoob = ns->geom.pgsz + ns->geom.oobsz; + ns->geom.pgnum = ns->geom.totsz / ns->geom.pgsz; + ns->geom.totszoob = ns->geom.totsz + ns->geom.pgnum * ns->geom.oobsz; + ns->geom.secshift = ffs(ns->geom.secsz) - 1; + ns->geom.pgshift = chip->page_shift; + ns->geom.oobshift = ffs(ns->geom.oobsz) - 1; + ns->geom.pgsec = ns->geom.secsz / ns->geom.pgsz; + ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec; + ns->options = 0; + + if (ns->geom.pgsz == 256) { + ns->options |= OPT_PAGE256; + } + else if (ns->geom.pgsz == 512) { + ns->options |= (OPT_PAGE512 | OPT_AUTOINCR); + if (ns->busw == 8) + ns->options |= OPT_PAGE512_8BIT; + } else if (ns->geom.pgsz == 2048) { + ns->options |= OPT_PAGE2048; + } else { + NS_ERR("init_nandsim: unknown page size %u\n", ns->geom.pgsz); + return -EIO; + } + + if (ns->options & OPT_SMALLPAGE) { + if (ns->geom.totsz < (64 << 20)) { + ns->geom.pgaddrbytes = 3; + ns->geom.secaddrbytes = 2; + } else { + ns->geom.pgaddrbytes = 4; + ns->geom.secaddrbytes = 3; + } + } else { + if (ns->geom.totsz <= (128 << 20)) { + ns->geom.pgaddrbytes = 5; + ns->geom.secaddrbytes = 2; + } else { + ns->geom.pgaddrbytes = 5; + ns->geom.secaddrbytes = 3; + } + } + + /* Detect how many ID bytes the NAND chip outputs */ + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (second_id_byte != nand_flash_ids[i].id) + continue; + if (!(nand_flash_ids[i].options & NAND_NO_AUTOINCR)) + ns->options |= OPT_AUTOINCR; + } + + if (ns->busw == 16) + NS_WARN("16-bit flashes support wasn't tested\n"); + + printk("flash size: %u MiB\n", ns->geom.totsz >> 20); + printk("page size: %u bytes\n", ns->geom.pgsz); + printk("OOB area size: %u bytes\n", ns->geom.oobsz); + printk("sector size: %u KiB\n", ns->geom.secsz >> 10); + printk("pages number: %u\n", ns->geom.pgnum); + printk("pages per sector: %u\n", ns->geom.pgsec); + printk("bus width: %u\n", ns->busw); + printk("bits in sector size: %u\n", ns->geom.secshift); + printk("bits in page size: %u\n", ns->geom.pgshift); + printk("bits in OOB size: %u\n", ns->geom.oobshift); + printk("flash size with OOB: %u KiB\n", ns->geom.totszoob >> 10); + printk("page address bytes: %u\n", ns->geom.pgaddrbytes); + printk("sector address bytes: %u\n", ns->geom.secaddrbytes); + printk("options: %#x\n", ns->options); + + /* Map / allocate and initialize the flash image */ +#ifdef CONFIG_NS_ABS_POS + ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob); + if (!ns->mem.byte) { + NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n", + (void *)CONFIG_NS_ABS_POS); + return -ENOMEM; + } +#else + ns->mem.byte = vmalloc(ns->geom.totszoob); + if (!ns->mem.byte) { + NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n", + ns->geom.totszoob); + return -ENOMEM; + } + memset(ns->mem.byte, 0xFF, ns->geom.totszoob); +#endif + + /* Allocate / initialize the internal buffer */ + ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); + if (!ns->buf.byte) { + NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", + ns->geom.pgszoob); + goto error; + } + memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); + + /* Fill the partition_info structure */ + ns->part.name = "NAND simulator partition"; + ns->part.offset = 0; + ns->part.size = ns->geom.totsz; + + return 0; + +error: +#ifdef CONFIG_NS_ABS_POS + iounmap(ns->mem.byte); +#else + vfree(ns->mem.byte); +#endif + + return -ENOMEM; +} + +/* + * Free the nandsim structure. + */ +static void +free_nandsim(struct nandsim *ns) +{ + kfree(ns->buf.byte); + +#ifdef CONFIG_NS_ABS_POS + iounmap(ns->mem.byte); +#else + vfree(ns->mem.byte); +#endif + + return; +} + +/* + * Returns the string representation of 'state' state. + */ +static char * +get_state_name(uint32_t state) +{ + switch (NS_STATE(state)) { + case STATE_CMD_READ0: + return "STATE_CMD_READ0"; + case STATE_CMD_READ1: + return "STATE_CMD_READ1"; + case STATE_CMD_PAGEPROG: + return "STATE_CMD_PAGEPROG"; + case STATE_CMD_READOOB: + return "STATE_CMD_READOOB"; + case STATE_CMD_READ2LP: + return "STATE_CMD_READ2LP"; + case STATE_CMD_ERASE1: + return "STATE_CMD_ERASE1"; + case STATE_CMD_STATUS: + return "STATE_CMD_STATUS"; + case STATE_CMD_STATUS_M: + return "STATE_CMD_STATUS_M"; + case STATE_CMD_SEQIN: + return "STATE_CMD_SEQIN"; + case STATE_CMD_READID: + return "STATE_CMD_READID"; + case STATE_CMD_ERASE2: + return "STATE_CMD_ERASE2"; + case STATE_CMD_RESET: + return "STATE_CMD_RESET"; + case STATE_ADDR_PAGE: + return "STATE_ADDR_PAGE"; + case STATE_ADDR_SEC: + return "STATE_ADDR_SEC"; + case STATE_ADDR_ZERO: + return "STATE_ADDR_ZERO"; + case STATE_DATAIN: + return "STATE_DATAIN"; + case STATE_DATAOUT: + return "STATE_DATAOUT"; + case STATE_DATAOUT_ID: + return "STATE_DATAOUT_ID"; + case STATE_DATAOUT_STATUS: + return "STATE_DATAOUT_STATUS"; + case STATE_DATAOUT_STATUS_M: + return "STATE_DATAOUT_STATUS_M"; + case STATE_READY: + return "STATE_READY"; + case STATE_UNKNOWN: + return "STATE_UNKNOWN"; + } + + NS_ERR("get_state_name: unknown state, BUG\n"); + return NULL; +} + +/* + * Check if command is valid. + * + * RETURNS: 1 if wrong command, 0 if right. + */ +static int +check_command(int cmd) +{ + switch (cmd) { + + case NAND_CMD_READ0: + case NAND_CMD_READ2LP: + case NAND_CMD_PAGEPROG: + case NAND_CMD_READOOB: + case NAND_CMD_ERASE1: + case NAND_CMD_STATUS: + case NAND_CMD_SEQIN: + case NAND_CMD_READID: + case NAND_CMD_ERASE2: + case NAND_CMD_RESET: + case NAND_CMD_READ1: + return 0; + + case NAND_CMD_STATUS_MULTI: + default: + return 1; + } +} + +/* + * Returns state after command is accepted by command number. + */ +static uint32_t +get_state_by_command(unsigned command) +{ + switch (command) { + case NAND_CMD_READ0: + return STATE_CMD_READ0; + case NAND_CMD_READ1: + return STATE_CMD_READ1; + case NAND_CMD_PAGEPROG: + return STATE_CMD_PAGEPROG; + case NAND_CMD_READ2LP: + return STATE_CMD_READ2LP; + case NAND_CMD_READOOB: + return STATE_CMD_READOOB; + case NAND_CMD_ERASE1: + return STATE_CMD_ERASE1; + case NAND_CMD_STATUS: + return STATE_CMD_STATUS; + case NAND_CMD_STATUS_MULTI: + return STATE_CMD_STATUS_M; + case NAND_CMD_SEQIN: + return STATE_CMD_SEQIN; + case NAND_CMD_READID: + return STATE_CMD_READID; + case NAND_CMD_ERASE2: + return STATE_CMD_ERASE2; + case NAND_CMD_RESET: + return STATE_CMD_RESET; + } + + NS_ERR("get_state_by_command: unknown command, BUG\n"); + return 0; +} + +/* + * Move an address byte to the correspondent internal register. + */ +static inline void +accept_addr_byte(struct nandsim *ns, u_char bt) +{ + uint byte = (uint)bt; + + if (ns->regs.count < (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) + ns->regs.column |= (byte << 8 * ns->regs.count); + else { + ns->regs.row |= (byte << 8 * (ns->regs.count - + ns->geom.pgaddrbytes + + ns->geom.secaddrbytes)); + } + + return; +} + +/* + * Switch to STATE_READY state. + */ +static inline void +switch_to_ready_state(struct nandsim *ns, u_char status) +{ + NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY)); + + ns->state = STATE_READY; + ns->nxstate = STATE_UNKNOWN; + ns->op = NULL; + ns->npstates = 0; + ns->stateidx = 0; + ns->regs.num = 0; + ns->regs.count = 0; + ns->regs.off = 0; + ns->regs.row = 0; + ns->regs.column = 0; + ns->regs.status = status; +} + +/* + * If the operation isn't known yet, try to find it in the global array + * of supported operations. + * + * Operation can be unknown because of the following. + * 1. New command was accepted and this is the firs call to find the + * correspondent states chain. In this case ns->npstates = 0; + * 2. There is several operations which begin with the same command(s) + * (for example program from the second half and read from the + * second half operations both begin with the READ1 command). In this + * case the ns->pstates[] array contains previous states. + * + * Thus, the function tries to find operation containing the following + * states (if the 'flag' parameter is 0): + * ns->pstates[0], ... ns->pstates[ns->npstates], ns->state + * + * If (one and only one) matching operation is found, it is accepted ( + * ns->ops, ns->state, ns->nxstate are initialized, ns->npstate is + * zeroed). + * + * If there are several maches, the current state is pushed to the + * ns->pstates. + * + * The operation can be unknown only while commands are input to the chip. + * As soon as address command is accepted, the operation must be known. + * In such situation the function is called with 'flag' != 0, and the + * operation is searched using the following pattern: + * ns->pstates[0], ... ns->pstates[ns->npstates],
+ * + * It is supposed that this pattern must either match one operation on + * none. There can't be ambiguity in that case. + * + * If no matches found, the functions does the following: + * 1. if there are saved states present, try to ignore them and search + * again only using the last command. If nothing was found, switch + * to the STATE_READY state. + * 2. if there are no saved states, switch to the STATE_READY state. + * + * RETURNS: -2 - no matched operations found. + * -1 - several matches. + * 0 - operation is found. + */ +static int +find_operation(struct nandsim *ns, uint32_t flag) +{ + int opsfound = 0; + int i, j, idx = 0; + + for (i = 0; i < NS_OPER_NUM; i++) { + + int found = 1; + + if (!(ns->options & ops[i].reqopts)) + /* Ignore operations we can't perform */ + continue; + + if (flag) { + if (!(ops[i].states[ns->npstates] & STATE_ADDR_MASK)) + continue; + } else { + if (NS_STATE(ns->state) != NS_STATE(ops[i].states[ns->npstates])) + continue; + } + + for (j = 0; j < ns->npstates; j++) + if (NS_STATE(ops[i].states[j]) != NS_STATE(ns->pstates[j]) + && (ns->options & ops[idx].reqopts)) { + found = 0; + break; + } + + if (found) { + idx = i; + opsfound += 1; + } + } + + if (opsfound == 1) { + /* Exact match */ + ns->op = &ops[idx].states[0]; + if (flag) { + /* + * In this case the find_operation function was + * called when address has just began input. But it isn't + * yet fully input and the current state must + * not be one of STATE_ADDR_*, but the STATE_ADDR_* + * state must be the next state (ns->nxstate). + */ + ns->stateidx = ns->npstates - 1; + } else { + ns->stateidx = ns->npstates; + } + ns->npstates = 0; + ns->state = ns->op[ns->stateidx]; + ns->nxstate = ns->op[ns->stateidx + 1]; + NS_DBG("find_operation: operation found, index: %d, state: %s, nxstate %s\n", + idx, get_state_name(ns->state), get_state_name(ns->nxstate)); + return 0; + } + + if (opsfound == 0) { + /* Nothing was found. Try to ignore previous commands (if any) and search again */ + if (ns->npstates != 0) { + NS_DBG("find_operation: no operation found, try again with state %s\n", + get_state_name(ns->state)); + ns->npstates = 0; + return find_operation(ns, 0); + + } + NS_DBG("find_operation: no operations found\n"); + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return -2; + } + + if (flag) { + /* This shouldn't happen */ + NS_DBG("find_operation: BUG, operation must be known if address is input\n"); + return -2; + } + + NS_DBG("find_operation: there is still ambiguity\n"); + + ns->pstates[ns->npstates++] = ns->state; + + return -1; +} + +/* + * If state has any action bit, perform this action. + * + * RETURNS: 0 if success, -1 if error. + */ +static int +do_state_action(struct nandsim *ns, uint32_t action) +{ + int i, num; + int busdiv = ns->busw == 8 ? 1 : 2; + + action &= ACTION_MASK; + + /* Check that page address input is correct */ + if (action != ACTION_SECERASE && ns->regs.row >= ns->geom.pgnum) { + NS_WARN("do_state_action: wrong page number (%#x)\n", ns->regs.row); + return -1; + } + + switch (action) { + + case ACTION_CPY: + /* + * Copy page data to the internal buffer. + */ + + /* Column shouldn't be very large */ + if (ns->regs.column >= (ns->geom.pgszoob - ns->regs.off)) { + NS_ERR("do_state_action: column number is too large\n"); + break; + } + num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; + memcpy(ns->buf.byte, ns->mem.byte + NS_RAW_OFFSET(ns) + ns->regs.off, num); + + NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n", + num, NS_RAW_OFFSET(ns) + ns->regs.off); + + if (ns->regs.off == 0) + NS_LOG("read page %d\n", ns->regs.row); + else if (ns->regs.off < ns->geom.pgsz) + NS_LOG("read page %d (second half)\n", ns->regs.row); + else + NS_LOG("read OOB of page %d\n", ns->regs.row); + + NS_UDELAY(access_delay); + NS_UDELAY(input_cycle * ns->geom.pgsz / 1000 / busdiv); + + break; + + case ACTION_SECERASE: + /* + * Erase sector. + */ + + if (ns->lines.wp) { + NS_ERR("do_state_action: device is write-protected, ignore sector erase\n"); + return -1; + } + + if (ns->regs.row >= ns->geom.pgnum - ns->geom.pgsec + || (ns->regs.row & ~(ns->geom.secsz - 1))) { + NS_ERR("do_state_action: wrong sector address (%#x)\n", ns->regs.row); + return -1; + } + + ns->regs.row = (ns->regs.row << + 8 * (ns->geom.pgaddrbytes - ns->geom.secaddrbytes)) | ns->regs.column; + ns->regs.column = 0; + + NS_DBG("do_state_action: erase sector at address %#x, off = %d\n", + ns->regs.row, NS_RAW_OFFSET(ns)); + NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift)); + + memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob); + + NS_MDELAY(erase_delay); + + break; + + case ACTION_PRGPAGE: + /* + * Programm page - move internal buffer data to the page. + */ + + if (ns->lines.wp) { + NS_WARN("do_state_action: device is write-protected, programm\n"); + return -1; + } + + num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; + if (num != ns->regs.count) { + NS_ERR("do_state_action: too few bytes were input (%d instead of %d)\n", + ns->regs.count, num); + return -1; + } + + for (i = 0; i < num; i++) + ns->mem.byte[NS_RAW_OFFSET(ns) + ns->regs.off + i] &= ns->buf.byte[i]; + + NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n", + num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off); + NS_LOG("programm page %d\n", ns->regs.row); + + NS_UDELAY(programm_delay); + NS_UDELAY(output_cycle * ns->geom.pgsz / 1000 / busdiv); + + break; + + case ACTION_ZEROOFF: + NS_DBG("do_state_action: set internal offset to 0\n"); + ns->regs.off = 0; + break; + + case ACTION_HALFOFF: + if (!(ns->options & OPT_PAGE512_8BIT)) { + NS_ERR("do_state_action: BUG! can't skip half of page for non-512" + "byte page size 8x chips\n"); + return -1; + } + NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz/2); + ns->regs.off = ns->geom.pgsz/2; + break; + + case ACTION_OOBOFF: + NS_DBG("do_state_action: set internal offset to %d\n", ns->geom.pgsz); + ns->regs.off = ns->geom.pgsz; + break; + + default: + NS_DBG("do_state_action: BUG! unknown action\n"); + } + + return 0; +} + +/* + * Switch simulator's state. + */ +static void +switch_state(struct nandsim *ns) +{ + if (ns->op) { + /* + * The current operation have already been identified. + * Just follow the states chain. + */ + + ns->stateidx += 1; + ns->state = ns->nxstate; + ns->nxstate = ns->op[ns->stateidx + 1]; + + NS_DBG("switch_state: operation is known, switch to the next state, " + "state: %s, nxstate: %s\n", + get_state_name(ns->state), get_state_name(ns->nxstate)); + + /* See, whether we need to do some action */ + if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + + } else { + /* + * We don't yet know which operation we perform. + * Try to identify it. + */ + + /* + * The only event causing the switch_state function to + * be called with yet unknown operation is new command. + */ + ns->state = get_state_by_command(ns->regs.command); + + NS_DBG("switch_state: operation is unknown, try to find it\n"); + + if (find_operation(ns, 0) != 0) + return; + + if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + } + + /* For 16x devices column means the page offset in words */ + if ((ns->nxstate & STATE_ADDR_MASK) && ns->busw == 16) { + NS_DBG("switch_state: double the column number for 16x device\n"); + ns->regs.column <<= 1; + } + + if (NS_STATE(ns->nxstate) == STATE_READY) { + /* + * The current state is the last. Return to STATE_READY + */ + + u_char status = NS_STATUS_OK(ns); + + /* In case of data states, see if all bytes were input/output */ + if ((ns->state & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) + && ns->regs.count != ns->regs.num) { + NS_WARN("switch_state: not all bytes were processed, %d left\n", + ns->regs.num - ns->regs.count); + status = NS_STATUS_FAILED(ns); + } + + NS_DBG("switch_state: operation complete, switch to STATE_READY state\n"); + + switch_to_ready_state(ns, status); + + return; + } else if (ns->nxstate & (STATE_DATAIN_MASK | STATE_DATAOUT_MASK)) { + /* + * If the next state is data input/output, switch to it now + */ + + ns->state = ns->nxstate; + ns->nxstate = ns->op[++ns->stateidx + 1]; + ns->regs.num = ns->regs.count = 0; + + NS_DBG("switch_state: the next state is data I/O, switch, " + "state: %s, nxstate: %s\n", + get_state_name(ns->state), get_state_name(ns->nxstate)); + + /* + * Set the internal register to the count of bytes which + * are expected to be input or output + */ + switch (NS_STATE(ns->state)) { + case STATE_DATAIN: + case STATE_DATAOUT: + ns->regs.num = ns->geom.pgszoob - ns->regs.off - ns->regs.column; + break; + + case STATE_DATAOUT_ID: + ns->regs.num = ns->geom.idbytes; + break; + + case STATE_DATAOUT_STATUS: + case STATE_DATAOUT_STATUS_M: + ns->regs.count = ns->regs.num = 0; + break; + + default: + NS_ERR("switch_state: BUG! unknown data state\n"); + } + + } else if (ns->nxstate & STATE_ADDR_MASK) { + /* + * If the next state is address input, set the internal + * register to the number of expected address bytes + */ + + ns->regs.count = 0; + + switch (NS_STATE(ns->nxstate)) { + case STATE_ADDR_PAGE: + ns->regs.num = ns->geom.pgaddrbytes; + + break; + case STATE_ADDR_SEC: + ns->regs.num = ns->geom.secaddrbytes; + break; + + case STATE_ADDR_ZERO: + ns->regs.num = 1; + break; + + default: + NS_ERR("switch_state: BUG! unknown address state\n"); + } + } else { + /* + * Just reset internal counters. + */ + + ns->regs.num = 0; + ns->regs.count = 0; + } +} + +static void +ns_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; + + switch (cmd) { + + /* set CLE line high */ + case NAND_CTL_SETCLE: + NS_DBG("ns_hwcontrol: start command latch cycles\n"); + ns->lines.cle = 1; + break; + + /* set CLE line low */ + case NAND_CTL_CLRCLE: + NS_DBG("ns_hwcontrol: stop command latch cycles\n"); + ns->lines.cle = 0; + break; + + /* set ALE line high */ + case NAND_CTL_SETALE: + NS_DBG("ns_hwcontrol: start address latch cycles\n"); + ns->lines.ale = 1; + break; + + /* set ALE line low */ + case NAND_CTL_CLRALE: + NS_DBG("ns_hwcontrol: stop address latch cycles\n"); + ns->lines.ale = 0; + break; + + /* set WP line high */ + case NAND_CTL_SETWP: + NS_DBG("ns_hwcontrol: enable write protection\n"); + ns->lines.wp = 1; + break; + + /* set WP line low */ + case NAND_CTL_CLRWP: + NS_DBG("ns_hwcontrol: disable write protection\n"); + ns->lines.wp = 0; + break; + + /* set CE line low */ + case NAND_CTL_SETNCE: + NS_DBG("ns_hwcontrol: enable chip\n"); + ns->lines.ce = 1; + break; + + /* set CE line high */ + case NAND_CTL_CLRNCE: + NS_DBG("ns_hwcontrol: disable chip\n"); + ns->lines.ce = 0; + break; + + default: + NS_ERR("hwcontrol: unknown command\n"); + } + + return; +} + +static u_char +ns_nand_read_byte(struct mtd_info *mtd) +{ + struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; + u_char outb = 0x00; + + /* Sanity and correctness checks */ + if (!ns->lines.ce) { + NS_ERR("read_byte: chip is disabled, return %#x\n", (uint)outb); + return outb; + } + if (ns->lines.ale || ns->lines.cle) { + NS_ERR("read_byte: ALE or CLE pin is high, return %#x\n", (uint)outb); + return outb; + } + if (!(ns->state & STATE_DATAOUT_MASK)) { + NS_WARN("read_byte: unexpected data output cycle, state is %s " + "return %#x\n", get_state_name(ns->state), (uint)outb); + return outb; + } + + /* Status register may be read as many times as it is wanted */ + if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS) { + NS_DBG("read_byte: return %#x status\n", ns->regs.status); + return ns->regs.status; + } + + /* Check if there is any data in the internal buffer which may be read */ + if (ns->regs.count == ns->regs.num) { + NS_WARN("read_byte: no more data to output, return %#x\n", (uint)outb); + return outb; + } + + switch (NS_STATE(ns->state)) { + case STATE_DATAOUT: + if (ns->busw == 8) { + outb = ns->buf.byte[ns->regs.count]; + ns->regs.count += 1; + } else { + outb = (u_char)cpu_to_le16(ns->buf.word[ns->regs.count >> 1]); + ns->regs.count += 2; + } + break; + case STATE_DATAOUT_ID: + NS_DBG("read_byte: read ID byte %d, total = %d\n", ns->regs.count, ns->regs.num); + outb = ns->ids[ns->regs.count]; + ns->regs.count += 1; + break; + default: + BUG(); + } + + if (ns->regs.count == ns->regs.num) { + NS_DBG("read_byte: all bytes were read\n"); + + /* + * The OPT_AUTOINCR allows to read next conseqitive pages without + * new read operation cycle. + */ + if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { + ns->regs.count = 0; + if (ns->regs.row + 1 < ns->geom.pgnum) + ns->regs.row += 1; + NS_DBG("read_byte: switch to the next page (%#x)\n", ns->regs.row); + do_state_action(ns, ACTION_CPY); + } + else if (NS_STATE(ns->nxstate) == STATE_READY) + switch_state(ns); + + } + + return outb; +} + +static void +ns_nand_write_byte(struct mtd_info *mtd, u_char byte) +{ + struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; + + /* Sanity and correctness checks */ + if (!ns->lines.ce) { + NS_ERR("write_byte: chip is disabled, ignore write\n"); + return; + } + if (ns->lines.ale && ns->lines.cle) { + NS_ERR("write_byte: ALE and CLE pins are high simultaneously, ignore write\n"); + return; + } + + if (ns->lines.cle == 1) { + /* + * The byte written is a command. + */ + + if (byte == NAND_CMD_RESET) { + NS_LOG("reset chip\n"); + switch_to_ready_state(ns, NS_STATUS_OK(ns)); + return; + } + + /* + * Chip might still be in STATE_DATAOUT + * (if OPT_AUTOINCR feature is supported), STATE_DATAOUT_STATUS or + * STATE_DATAOUT_STATUS_M state. If so, switch state. + */ + if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS + || NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M + || ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT)) + switch_state(ns); + + /* Check if chip is expecting command */ + if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { + /* + * We are in situation when something else (not command) + * was expected but command was input. In this case ignore + * previous command(s)/state(s) and accept the last one. + */ + NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " + "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + } + + /* Check that the command byte is correct */ + if (check_command(byte)) { + NS_ERR("write_byte: unknown command %#x\n", (uint)byte); + return; + } + + NS_DBG("command byte corresponding to %s state accepted\n", + get_state_name(get_state_by_command(byte))); + ns->regs.command = byte; + switch_state(ns); + + } else if (ns->lines.ale == 1) { + /* + * The byte written is an address. + */ + + if (NS_STATE(ns->nxstate) == STATE_UNKNOWN) { + + NS_DBG("write_byte: operation isn't known yet, identify it\n"); + + if (find_operation(ns, 1) < 0) + return; + + if ((ns->state & ACTION_MASK) && do_state_action(ns, ns->state) < 0) { + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + + ns->regs.count = 0; + switch (NS_STATE(ns->nxstate)) { + case STATE_ADDR_PAGE: + ns->regs.num = ns->geom.pgaddrbytes; + break; + case STATE_ADDR_SEC: + ns->regs.num = ns->geom.secaddrbytes; + break; + case STATE_ADDR_ZERO: + ns->regs.num = 1; + break; + default: + BUG(); + } + } + + /* Check that chip is expecting address */ + if (!(ns->nxstate & STATE_ADDR_MASK)) { + NS_ERR("write_byte: address (%#x) isn't expected, expected state is %s, " + "switch to STATE_READY\n", (uint)byte, get_state_name(ns->nxstate)); + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + + /* Check if this is expected byte */ + if (ns->regs.count == ns->regs.num) { + NS_ERR("write_byte: no more address bytes expected\n"); + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + + accept_addr_byte(ns, byte); + + ns->regs.count += 1; + + NS_DBG("write_byte: address byte %#x was accepted (%d bytes input, %d expected)\n", + (uint)byte, ns->regs.count, ns->regs.num); + + if (ns->regs.count == ns->regs.num) { + NS_DBG("address (%#x, %#x) is accepted\n", ns->regs.row, ns->regs.column); + switch_state(ns); + } + + } else { + /* + * The byte written is an input data. + */ + + /* Check that chip is expecting data input */ + if (!(ns->state & STATE_DATAIN_MASK)) { + NS_ERR("write_byte: data input (%#x) isn't expected, state is %s, " + "switch to %s\n", (uint)byte, + get_state_name(ns->state), get_state_name(STATE_READY)); + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + + /* Check if this is expected byte */ + if (ns->regs.count == ns->regs.num) { + NS_WARN("write_byte: %u input bytes has already been accepted, ignore write\n", + ns->regs.num); + return; + } + + if (ns->busw == 8) { + ns->buf.byte[ns->regs.count] = byte; + ns->regs.count += 1; + } else { + ns->buf.word[ns->regs.count >> 1] = cpu_to_le16((uint16_t)byte); + ns->regs.count += 2; + } + } + + return; +} + +static int +ns_device_ready(struct mtd_info *mtd) +{ + NS_DBG("device_ready\n"); + return 1; +} + +static uint16_t +ns_nand_read_word(struct mtd_info *mtd) +{ + struct nand_chip *chip = (struct nand_chip *)mtd->priv; + + NS_DBG("read_word\n"); + + return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8); +} + +static void +ns_nand_write_word(struct mtd_info *mtd, uint16_t word) +{ + struct nand_chip *chip = (struct nand_chip *)mtd->priv; + + NS_DBG("write_word\n"); + + chip->write_byte(mtd, word & 0xFF); + chip->write_byte(mtd, word >> 8); +} + +static void +ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; + + /* Check that chip is expecting data input */ + if (!(ns->state & STATE_DATAIN_MASK)) { + NS_ERR("write_buf: data input isn't expected, state is %s, " + "switch to STATE_READY\n", get_state_name(ns->state)); + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + + /* Check if these are expected bytes */ + if (ns->regs.count + len > ns->regs.num) { + NS_ERR("write_buf: too many input bytes\n"); + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + + memcpy(ns->buf.byte + ns->regs.count, buf, len); + ns->regs.count += len; + + if (ns->regs.count == ns->regs.num) { + NS_DBG("write_buf: %d bytes were written\n", ns->regs.count); + } +} + +static void +ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv; + + /* Sanity and correctness checks */ + if (!ns->lines.ce) { + NS_ERR("read_buf: chip is disabled\n"); + return; + } + if (ns->lines.ale || ns->lines.cle) { + NS_ERR("read_buf: ALE or CLE pin is high\n"); + return; + } + if (!(ns->state & STATE_DATAOUT_MASK)) { + NS_WARN("read_buf: unexpected data output cycle, current state is %s\n", + get_state_name(ns->state)); + return; + } + + if (NS_STATE(ns->state) != STATE_DATAOUT) { + int i; + + for (i = 0; i < len; i++) + buf[i] = ((struct nand_chip *)mtd->priv)->read_byte(mtd); + + return; + } + + /* Check if these are expected bytes */ + if (ns->regs.count + len > ns->regs.num) { + NS_ERR("read_buf: too many bytes to read\n"); + switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); + return; + } + + memcpy(buf, ns->buf.byte + ns->regs.count, len); + ns->regs.count += len; + + if (ns->regs.count == ns->regs.num) { + if ((ns->options & OPT_AUTOINCR) && NS_STATE(ns->state) == STATE_DATAOUT) { + ns->regs.count = 0; + if (ns->regs.row + 1 < ns->geom.pgnum) + ns->regs.row += 1; + NS_DBG("read_buf: switch to the next page (%#x)\n", ns->regs.row); + do_state_action(ns, ACTION_CPY); + } + else if (NS_STATE(ns->nxstate) == STATE_READY) + switch_state(ns); + } + + return; +} + +static int +ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) +{ + ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len); + + if (!memcmp(buf, &ns_verify_buf[0], len)) { + NS_DBG("verify_buf: the buffer is OK\n"); + return 0; + } else { + NS_DBG("verify_buf: the buffer is wrong\n"); + return -EFAULT; + } +} + +/* + * Having only NAND chip IDs we call nand_scan which detects NAND flash + * parameters and then calls scan_bbt in order to scan/find/build the + * NAND flash bad block table. But since at that moment the NAND flash + * image isn't allocated in the simulator, errors arise. To avoid this + * we redefine the scan_bbt callback and initialize the nandsim structure + * before the flash media scanning. + */ +int ns_scan_bbt(struct mtd_info *mtd) +{ + struct nand_chip *chip = (struct nand_chip *)mtd->priv; + struct nandsim *ns = (struct nandsim *)(chip->priv); + int retval; + + if (!NS_IS_INITIALIZED(ns)) + if ((retval = init_nandsim(mtd)) != 0) { + NS_ERR("scan_bbt: can't initialize the nandsim structure\n"); + return retval; + } + if ((retval = nand_default_bbt(mtd)) != 0) { + free_nandsim(ns); + return retval; + } + + return 0; +} + +/* + * Module initialization function + */ +int __init ns_init_module(void) +{ + struct nand_chip *chip; + struct nandsim *nand; + int retval = -ENOMEM; + + if (bus_width != 8 && bus_width != 16) { + NS_ERR("wrong bus width (%d), use only 8 or 16\n", bus_width); + return -EINVAL; + } + + /* Allocate and initialize mtd_info, nand_chip and nandsim structures */ + nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) + + sizeof(struct nandsim), GFP_KERNEL); + if (!nsmtd) { + NS_ERR("unable to allocate core structures.\n"); + return -ENOMEM; + } + memset(nsmtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip) + + sizeof(struct nandsim)); + chip = (struct nand_chip *)(nsmtd + 1); + nsmtd->priv = (void *)chip; + nand = (struct nandsim *)(chip + 1); + chip->priv = (void *)nand; + + /* + * Register simulator's callbacks. + */ + chip->hwcontrol = ns_hwcontrol; + chip->read_byte = ns_nand_read_byte; + chip->dev_ready = ns_device_ready; + chip->scan_bbt = ns_scan_bbt; + chip->write_byte = ns_nand_write_byte; + chip->write_buf = ns_nand_write_buf; + chip->read_buf = ns_nand_read_buf; + chip->verify_buf = ns_nand_verify_buf; + chip->write_word = ns_nand_write_word; + chip->read_word = ns_nand_read_word; + chip->eccmode = NAND_ECC_SOFT; + + /* + * Perform minimum nandsim structure initialization to handle + * the initial ID read command correctly + */ + if (third_id_byte != 0xFF || fourth_id_byte != 0xFF) + nand->geom.idbytes = 4; + else + nand->geom.idbytes = 2; + nand->regs.status = NS_STATUS_OK(nand); + nand->nxstate = STATE_UNKNOWN; + nand->options |= OPT_PAGE256; /* temporary value */ + nand->ids[0] = first_id_byte; + nand->ids[1] = second_id_byte; + nand->ids[2] = third_id_byte; + nand->ids[3] = fourth_id_byte; + if (bus_width == 16) { + nand->busw = 16; + chip->options |= NAND_BUSWIDTH_16; + } + + if ((retval = nand_scan(nsmtd, 1)) != 0) { + NS_ERR("can't register NAND Simulator\n"); + if (retval > 0) + retval = -ENXIO; + goto error; + } + + /* Register NAND as one big partition */ + add_mtd_partitions(nsmtd, &nand->part, 1); + + return 0; + +error: + kfree(nsmtd); + + return retval; +} + +module_init(ns_init_module); + +/* + * Module clean-up function + */ +static void __exit ns_cleanup_module(void) +{ + struct nandsim *ns = (struct nandsim *)(((struct nand_chip *)nsmtd->priv)->priv); + + free_nandsim(ns); /* Free nandsim private resources */ + nand_release(nsmtd); /* Unregisterd drived */ + kfree(nsmtd); /* Free other structures */ +} + +module_exit(ns_cleanup_module); + +MODULE_LICENSE ("GPL"); +MODULE_AUTHOR ("Artem B. Bityuckiy"); +MODULE_DESCRIPTION ("The NAND flash simulator"); + diff -Nru a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c --- a/drivers/mtd/nand/s3c2410.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/nand/s3c2410.c 2004-11-29 21:35:09 -08:00 @@ -11,7 +11,7 @@ * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode * 12-Oct-2004 BJD Fixed errors in use of platform data * - * $Id: s3c2410.c,v 1.5 2004/10/12 10:10:15 bjd Exp $ + * $Id: s3c2410.c,v 1.6 2004/11/24 12:25:48 bjd Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -167,7 +167,7 @@ if (plat != NULL) { tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8); twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); - twrph1 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8); + twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8); } else { /* default timings */ tacls = 8; diff -Nru a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/nand/sharpsl.c 2004-11-29 21:35:09 -08:00 @@ -0,0 +1,273 @@ +/* + * drivers/mtd/nand/sharpsl.c + * + * Copyright (C) 2004 Richard Purdie + * + * $Id: sharpsl.c,v 1.2 2004/11/24 20:38:07 rpurdie Exp $ + * + * Based on Sharp's NAND driver sharp_sl.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __iomem *sharpsl_io_base; +static int sharpsl_phys_base = 0x0C000000; + +/* register offset */ +#define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */ +#define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */ +#define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */ +#define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */ +#define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */ +#define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */ +#define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */ + +/* Flash control bit */ +#define FLRYBY (1 << 5) +#define FLCE1 (1 << 4) +#define FLWP (1 << 3) +#define FLALE (1 << 2) +#define FLCLE (1 << 1) +#define FLCE0 (1 << 0) + + +/* + * MTD structure for SharpSL + */ +static struct mtd_info *sharpsl_mtd = NULL; + +/* + * Define partitions for flash device + */ +#define DEFAULT_NUM_PARTITIONS 3 + +#if defined CONFIG_MACH_POODLE +#define SHARPSL_ROOTFS_SIZE 22 +#define SHARPSL_FLASH_SIZE 64 +#elif defined CONFIG_MACH_CORGI +#define SHARPSL_ROOTFS_SIZE 25 +#define SHARPSL_FLASH_SIZE 32 +#elif defined CONFIG_MACH_SHEPHERD +#define SHARPSL_ROOTFS_SIZE 25 +#define SHARPSL_FLASH_SIZE 64 +#elif defined CONFIG_MACH_HUSKY +#define SHARPSL_ROOTFS_SIZE 53 +#define SHARPSL_FLASH_SIZE 128 +#elif defined CONFIG_MACH_TOSA +#define SHARPSL_ROOTFS_SIZE 28 +#define SHARPSL_FLASH_SIZE 64 +#else +#define SHARPSL_ROOTFS_SIZE 30 +#define SHARPSL_FLASH_SIZE 64 +#endif + +static int nr_partitions; +static struct mtd_partition sharpsl_nand_default_partition_info[] = { + { + .name = "NAND flash partition 0", + .offset = 0, + .size = 7 * 1024 * 1024, + }, + + { + .name = "NAND flash partition 1", + .offset = 7 * 1024 * 1024, + .size = SHARPSL_ROOTFS_SIZE * 1024 * 1024, + }, + { + .name = "NAND flash partition 2", + .offset = (SHARPSL_ROOTFS_SIZE+7) * 1024 * 1024, + .size = (SHARPSL_FLASH_SIZE - SHARPSL_ROOTFS_SIZE - 7) * 1024 * 1024, + }, +}; + +/* + * hardware specific access to control-lines + */ +static void +sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd) +{ + switch (cmd) { + case NAND_CTL_SETCLE: + writeb(readb(FLASHCTL) | FLCLE, FLASHCTL); + break; + case NAND_CTL_CLRCLE: + writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL); + break; + + case NAND_CTL_SETALE: + writeb(readb(FLASHCTL) | FLALE, FLASHCTL); + break; + case NAND_CTL_CLRALE: + writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL); + break; + + case NAND_CTL_SETNCE: + writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL); + break; + case NAND_CTL_CLRNCE: + writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL); + break; + } +} + +static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; + +static struct nand_bbt_descr sharpsl_bbt = { + .options = 0, + .offs = 4, + .len = 2, + .pattern = scan_ff_pattern +}; + +static int +sharpsl_nand_dev_ready(struct mtd_info* mtd) +{ + return !((readb(FLASHCTL) & FLRYBY) == 0); +} + +static void +sharpsl_nand_enable_hwecc(struct mtd_info* mtd, int mode) +{ + writeb(0 ,ECCCLRR); +} + +static int +sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat, + u_char* ecc_code) +{ + ecc_code[0] = ~readb(ECCLPUB); + ecc_code[1] = ~readb(ECCLPLB); + ecc_code[2] = (~readb(ECCCP) << 2) | 0x03; + return readb(ECCCNTR) != 0; +} + + +#ifdef CONFIG_MTD_PARTITIONS +const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + + +/* + * Main initialization routine + */ +int __init +sharpsl_nand_init(void) +{ + struct nand_chip *this; + struct mtd_partition* sharpsl_partition_info; + int err = 0; + + /* Allocate memory for MTD device structure and private data */ + sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), + GFP_KERNEL); + if (!sharpsl_mtd) { + printk ("Unable to allocate SharpSL NAND MTD device structure.\n"); + return -ENOMEM; + } + + /* map physical adress */ + sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); + if(!sharpsl_io_base){ + printk("ioremap to access Sharp SL NAND chip failed\n"); + kfree(sharpsl_mtd); + return -EIO; + } + + /* Get pointer to private data */ + this = (struct nand_chip *) (&sharpsl_mtd[1]); + + /* Initialize structures */ + memset((char *) sharpsl_mtd, 0, sizeof(struct mtd_info)); + memset((char *) this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + sharpsl_mtd->priv = this; + + /* + * PXA initialize + */ + writeb(readb(FLASHCTL) | FLWP, FLASHCTL); + + /* Set address of NAND IO lines */ + this->IO_ADDR_R = FLASHIO; + this->IO_ADDR_W = FLASHIO; + /* Set address of hardware control function */ + this->hwcontrol = sharpsl_nand_hwcontrol; + this->dev_ready = sharpsl_nand_dev_ready; + /* 15 us command delay time */ + this->chip_delay = 15; + /* set eccmode using hardware ECC */ + this->eccmode = NAND_ECC_HW3_256; + this->enable_hwecc = sharpsl_nand_enable_hwecc; + this->calculate_ecc = sharpsl_nand_calculate_ecc; + this->correct_data = nand_correct_data; + this->badblock_pattern = &sharpsl_bbt; + + /* Scan to find existence of the device */ + err=nand_scan(sharpsl_mtd,1); + if (err) { + iounmap(sharpsl_io_base); + kfree(sharpsl_mtd); + return err; + } + + /* Register the partitions */ + sharpsl_mtd->name = "sharpsl-nand"; + nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, + &sharpsl_partition_info, 0); + + if (nr_partitions <= 0) { + nr_partitions = DEFAULT_NUM_PARTITIONS; + sharpsl_partition_info = sharpsl_nand_default_partition_info; + } + +#ifdef CONFIG_MACH_HUSKY + /* Need to use small eraseblock size for backward compatibility */ + sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; +#endif + + add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions); + + /* Return happy */ + return 0; +} +module_init(sharpsl_nand_init); + +/* + * Clean up routine + */ +#ifdef MODULE +static void __exit sharpsl_nand_cleanup(void) +{ + struct nand_chip *this = (struct nand_chip *) &sharpsl_mtd[1]; + + /* Release resources, unregister device */ + nand_release(sharpsl_mtd); + + iounmap(sharpsl_io_base); + + /* Free the MTD device structure */ + kfree(sharpsl_mtd); +} +module_exit(sharpsl_nand_cleanup); +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Richard Purdie "); +MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series"); diff -Nru a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c --- a/drivers/mtd/nftlmount.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/nftlmount.c 2004-11-29 21:35:09 -08:00 @@ -4,7 +4,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: nftlmount.c,v 1.39 2004/11/05 22:51:41 kalev Exp $ + * $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ #define SECTORSIZE 512 -char nftlmountrev[]="$Revision: 1.39 $"; +char nftlmountrev[]="$Revision: 1.40 $"; /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update @@ -302,8 +302,6 @@ struct nftl_uci1 uci; struct erase_info *instr = &nftl->instr; - instr->mtd = nftl->mbd.mtd; - /* Read the Unit Control Information #1 for Wear-Leveling */ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&uci) < 0) @@ -320,6 +318,7 @@ memset(instr, 0, sizeof(struct erase_info)); /* XXX: use async erase interface, XXX: test return code */ + instr->mtd = nftl->mbd.mtd; instr->addr = block * nftl->EraseSize; instr->len = nftl->EraseSize; MTD_ERASE(nftl->mbd.mtd, instr); diff -Nru a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c --- a/drivers/mtd/redboot.c 2004-11-29 21:35:09 -08:00 +++ b/drivers/mtd/redboot.c 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ /* - * $Id: redboot.c,v 1.15 2004/08/10 07:55:16 dwmw2 Exp $ + * $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $ * * Parse RedBoot-style Flash Image System (FIS) tables and * produce a Linux partition array to match. @@ -30,6 +30,9 @@ struct fis_list *next; }; +static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK; +module_param(directory, int, 0); + static inline int redboot_checksum(struct fis_image_desc *img) { /* RedBoot doesn't actually write the desc_cksum field yet AFAICT */ @@ -50,6 +53,8 @@ char *nullname; int namelen = 0; int nulllen = 0; + int numslots; + unsigned long offset; #ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED static char nullstring[] = "unallocated"; #endif @@ -59,8 +64,15 @@ if (!buf) return -ENOMEM; - /* Read the start of the last erase block */ - ret = master->read(master, master->size - master->erasesize, + if ( directory < 0 ) + offset = master->size + directory*master->erasesize; + else + offset = directory*master->erasesize; + + printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n", + master->name, offset); + + ret = master->read(master, offset, master->erasesize, &retlen, (void *)buf); if (ret) @@ -71,12 +83,16 @@ goto out; } - /* RedBoot image could appear in any of the first three slots */ - for (i = 0; i < 3; i++) { - if (!memcmp(buf[i].name, "RedBoot", 8)) + numslots = (master->erasesize / sizeof(struct fis_image_desc)); + for (i = 0; i < numslots; i++) { + if (buf[i].name[0] == 0xff) { + i = numslots; + break; + } + if (!memcmp(buf[i].name, "FIS directory", 14)) break; } - if (i == 3) { + if (i == numslots) { /* Didn't find it */ printk(KERN_NOTICE "No RedBoot partition table detected in %s\n", master->name); @@ -84,7 +100,7 @@ goto out; } - for (i = 0; i < master->erasesize / sizeof(struct fis_image_desc); i++) { + for (i = 0; i < numslots; i++) { struct fis_list *new_fl, **prev; if (buf[i].name[0] == 0xff) diff -Nru a/fs/Kconfig b/fs/Kconfig --- a/fs/Kconfig 2004-11-29 21:35:09 -08:00 +++ b/fs/Kconfig 2004-11-29 21:35:09 -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-29 21:35:09 -08:00 +++ b/fs/jffs2/Makefile 2004-11-29 21:35:09 -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-29 21:35:09 -08:00 +++ b/fs/jffs2/README.Locking 2004-11-29 21:35:09 -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-29 21:35:09 -08:00 +++ b/fs/jffs2/background.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/build.c 2004-11-29 21:35:09 -08:00 @@ -3,17 +3,19 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $ + * $Id: build.c,v 1.68 2004/11/27 13:38:10 gleixner Exp $ * */ #include #include #include +#include +#include #include "nodelist.h" static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **); @@ -62,6 +64,7 @@ if (!child_ic) { printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", fd->name, fd->ino, ic->ino); + jffs2_mark_node_obsolete(c, fd->raw); continue; } @@ -88,6 +91,7 @@ int ret; int i; struct jffs2_inode_cache *ic; + struct jffs2_full_dirent *fd; struct jffs2_full_dirent *dead_fds = NULL; /* First, scan the medium and build all the inode caches with @@ -95,13 +99,11 @@ c->flags |= JFFS2_SB_FLAG_MOUNTING; ret = jffs2_scan_medium(c); - c->flags &= ~JFFS2_SB_FLAG_MOUNTING; - if (ret) - return ret; + goto exit; D1(printk(KERN_DEBUG "Scanned flash completely\n")); - D1(jffs2_dump_block_lists(c)); + D2(jffs2_dump_block_lists(c)); /* Now scan the directory tree, increasing nlink according to every dirent found. */ for_each_inode(i, c, ic) { @@ -114,6 +116,8 @@ cond_resched(); } } + c->flags &= ~JFFS2_SB_FLAG_MOUNTING; + D1(printk(KERN_DEBUG "Pass 1 complete\n")); /* Next, scan for inodes with nlink == 0 and remove them. If @@ -135,9 +139,7 @@ D1(printk(KERN_DEBUG "Pass 2a starting\n")); while (dead_fds) { - struct jffs2_inode_cache *ic; - struct jffs2_full_dirent *fd = dead_fds; - + fd = dead_fds; dead_fds = fd->next; ic = jffs2_get_ino_cache(c, fd->ino); @@ -152,7 +154,6 @@ /* Finally, we can scan again and free the dirent structs */ for_each_inode(i, c, ic) { - struct jffs2_full_dirent *fd; D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes)); while(ic->scan_dents) { @@ -164,11 +165,24 @@ cond_resched(); } D1(printk(KERN_DEBUG "Pass 3 complete\n")); - D1(jffs2_dump_block_lists(c)); + D2(jffs2_dump_block_lists(c)); /* Rotate the lists by some number to ensure wear levelling */ jffs2_rotate_lists(c); + ret = 0; + +exit: + if (ret) { + for_each_inode(i, c, ic) { + while(ic->scan_dents) { + fd = ic->scan_dents; + ic->scan_dents = fd->next; + jffs2_free_full_dirent(fd); + } + } + } + return ret; } @@ -179,9 +193,12 @@ D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino)); - for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) { + raw = ic->nodes; + while (raw != (void *)ic) { + struct jffs2_raw_node_ref *next = raw->next_in_ino; D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw))); jffs2_mark_node_obsolete(c, raw); + raw = next; } if (ic->scan_dents) { @@ -297,7 +314,10 @@ c->free_size = c->flash_size; c->nr_blocks = c->flash_size / c->sector_size; - c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL); + if (c->mtd->flags & MTD_NO_VIRTBLOCKS) + c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks); + else + c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL); if (!c->blocks) return -ENOMEM; for (i=0; inr_blocks; i++) { @@ -310,6 +330,7 @@ c->blocks[i].used_size = 0; c->blocks[i].first_node = NULL; c->blocks[i].last_node = NULL; + c->blocks[i].bad_count = 0; } init_MUTEX(&c->alloc_sem); diff -Nru a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c --- a/fs/jffs2/compr_zlib.c 2004-11-29 21:35:09 -08:00 +++ b/fs/jffs2/compr_zlib.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/dir.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/erase.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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 *) ▮ + 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-29 21:35:09 -08:00 +++ b/fs/jffs2/file.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/fs.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.46 2004/07/13 08:56:54 dwmw2 Exp $ + * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $ * */ @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include "nodelist.h" @@ -202,7 +203,7 @@ buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; - D1(jffs2_dump_block_lists(c)); + D2(jffs2_dump_block_lists(c)); spin_unlock(&c->erase_completion_lock); @@ -463,11 +464,13 @@ */ c->sector_size = c->mtd->erasesize; blocks = c->flash_size / c->sector_size; - while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) { - blocks >>= 1; - c->sector_size <<= 1; - } - + if (!(c->mtd->flags & MTD_NO_VIRTBLOCKS)) { + while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) { + blocks >>= 1; + c->sector_size <<= 1; + } + } + /* * Size alignment check */ @@ -533,7 +536,10 @@ out_nodes: jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); - kfree(c->blocks); + if (c->mtd->flags & MTD_NO_VIRTBLOCKS) + vfree(c->blocks); + else + kfree(c->blocks); out_inohash: kfree(c->inocache_list); out_wbuf: @@ -649,6 +655,11 @@ } /* add setups for other bizarre flashes here... */ + if (jffs2_nor_ecc(c)) { + ret = jffs2_nor_ecc_flash_setup(c); + if (ret) + return ret; + } return ret; } @@ -659,4 +670,7 @@ } /* add cleanups for other bizarre flashes here... */ + if (jffs2_nor_ecc(c)) { + jffs2_nor_ecc_flash_cleanup(c); + } } diff -Nru a/fs/jffs2/gc.c b/fs/jffs2/gc.c --- a/fs/jffs2/gc.c 2004-11-29 21:35:09 -08:00 +++ b/fs/jffs2/gc.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/ioctl.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/malloc.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/nodelist.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.87 2004/11/14 17:07:07 dedekind Exp $ + * $Id: nodelist.c,v 1.89 2004/11/28 12:20:35 dedekind Exp $ * */ @@ -182,7 +182,6 @@ err = -ENOMEM; goto free_out; } - memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1); fd->raw = ref; fd->version = je32_to_cpu(node.d.version); fd->ino = je32_to_cpu(node.d.ino); @@ -220,6 +219,7 @@ } fd->nhash = full_name_hash(fd->name, node.d.nsize); fd->next = NULL; + fd->name[node.d.nsize] = '\0'; /* Wheee. We now have a complete jffs2_full_dirent structure, with the name in it and everything. Link it into the list */ diff -Nru a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h --- a/fs/jffs2/nodelist.h 2004-11-29 21:35:09 -08:00 +++ b/fs/jffs2/nodelist.h 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/nodemgmt.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.109 2004/10/07 15:08:47 havasi Exp $ + * $Id: nodemgmt.c,v 1.115 2004/11/22 11:07:21 dwmw2 Exp $ * */ @@ -399,6 +399,17 @@ } jeb = &c->blocks[blocknr]; + if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && + !(c->flags & JFFS2_SB_FLAG_MOUNTING)) { + /* Hm. This may confuse static lock analysis. If any of the above + three conditions is false, we're going to return from this + function without actually obliterating any nodes or freeing + any jffs2_raw_node_refs. So we don't need to stop erases from + happening, or protect against people holding an obsolete + jffs2_raw_node_ref without the erase_completion_lock. */ + down(&c->erase_free_sem); + } + spin_lock(&c->erase_completion_lock); if (ref_flags(ref) == REF_UNCHECKED) { @@ -463,6 +474,7 @@ marked obsolete on the flash at the time they _became_ obsolete, there was probably a reason for that. */ spin_unlock(&c->erase_completion_lock); + /* We didn't lock the erase_free_sem */ return; } @@ -515,61 +527,87 @@ spin_unlock(&c->erase_completion_lock); - if (!jffs2_can_mark_obsolete(c)) - return; - if (jffs2_is_readonly(c)) + if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) { + /* We didn't lock the erase_free_sem */ return; + } + + /* The erase_free_sem is locked, and has been since before we marked the node obsolete + and potentially put its eraseblock onto the erase_pending_list. Thus, we know that + the block hasn't _already_ been erased, and that 'ref' itself hasn't been freed yet + by jffs2_free_all_node_refs() in erase.c. Which is nice. */ D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref))); ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); if (ret) { printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); - return; + goto out_erase_sem; } if (retlen != sizeof(n)) { printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); - return; + goto out_erase_sem; } if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) { printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref)); - return; + goto out_erase_sem; } if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) { D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype))); - return; + goto out_erase_sem; } /* XXX FIXME: This is ugly now */ n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE); ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); if (ret) { printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); - return; + goto out_erase_sem; } if (retlen != sizeof(n)) { printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); - return; + goto out_erase_sem; } /* Nodes which have been marked obsolete no longer need to be - associated with any inode. Remove them from the per-inode list */ + associated with any inode. Remove them from the per-inode list. + + Note we can't do this for NAND at the moment because we need + obsolete dirent nodes to stay on the lists, because of the + horridness in jffs2_garbage_collect_deletion_dirent(). Also + because we delete the inocache, and on NAND we need that to + stay around until all the nodes are actually erased, in order + to stop us from giving the same inode number to another newly + created inode. */ if (ref->next_in_ino) { struct jffs2_inode_cache *ic; struct jffs2_raw_node_ref **p; + spin_lock(&c->erase_completion_lock); + ic = jffs2_raw_ref_to_ic(ref); for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino)) ; *p = ref->next_in_ino; ref->next_in_ino = NULL; + + if (ic->nodes == (void *)ic) { + D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino)); + jffs2_del_ino_cache(c, ic); + jffs2_free_inode_cache(ic); + } + + spin_unlock(&c->erase_completion_lock); } /* Merge with the next node in the physical list, if there is one - and if it's also obsolete. */ - if (ref->next_phys && ref_obsolete(ref->next_phys) ) { + and if it's also obsolete and if it doesn't belong to any inode */ + if (ref->next_phys && ref_obsolete(ref->next_phys) && + !ref->next_phys->next_in_ino) { struct jffs2_raw_node_ref *n = ref->next_phys; + spin_lock(&c->erase_completion_lock); + ref->__totlen += n->__totlen; ref->next_phys = n->next_phys; if (jeb->last_node == n) jeb->last_node = ref; @@ -577,7 +615,8 @@ /* gc will be happy continuing gc on this node */ jeb->gc_node=ref; } - BUG_ON(n->next_in_ino); + spin_unlock(&c->erase_completion_lock); + jffs2_free_raw_node_ref(n); } @@ -585,11 +624,13 @@ and that one is obsolete */ if (ref != jeb->first_node ) { struct jffs2_raw_node_ref *p = jeb->first_node; - + + spin_lock(&c->erase_completion_lock); + while (p->next_phys != ref) p = p->next_phys; - if (ref_obsolete(p) ) { + if (ref_obsolete(p) && !ref->next_in_ino) { p->__totlen += ref->__totlen; if (jeb->last_node == ref) { jeb->last_node = p; @@ -601,10 +642,13 @@ p->next_phys = ref->next_phys; jffs2_free_raw_node_ref(ref); } + spin_unlock(&c->erase_completion_lock); } + out_erase_sem: + up(&c->erase_free_sem); } -#if CONFIG_JFFS2_FS_DEBUG > 0 +#if CONFIG_JFFS2_FS_DEBUG >= 2 void jffs2_dump_block_lists(struct jffs2_sb_info *c) { diff -Nru a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h --- a/fs/jffs2/os-linux.h 2004-11-29 21:35:09 -08:00 +++ b/fs/jffs2/os-linux.h 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2002-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/pushpull.h 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001, 2002 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/read.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/readinode.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.114 2004/11/14 17:07:07 dedekind Exp $ + * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $ * */ @@ -22,7 +22,7 @@ static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); -#if CONFIG_JFFS2_FS_DEBUG >= 1 +#if CONFIG_JFFS2_FS_DEBUG >= 2 static void jffs2_print_fragtree(struct rb_root *list, int permitbug) { struct jffs2_node_frag *this = frag_first(list); @@ -56,7 +56,9 @@ printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); } } +#endif +#if CONFIG_JFFS2_FS_DEBUG >= 1 static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f) { struct jffs2_node_frag *frag; @@ -225,7 +227,7 @@ If so, both 'this' and the new node get marked REF_NORMAL so the GC can take a look. */ - if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { + if (lastend && (lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { if (this->node) mark_ref_normal(this->node->raw); mark_ref_normal(newfrag->node->raw); diff -Nru a/fs/jffs2/scan.c b/fs/jffs2/scan.c --- a/fs/jffs2/scan.c 2004-11-29 21:35:09 -08:00 +++ b/fs/jffs2/scan.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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 @@ -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-29 21:35:09 -08:00 +++ b/fs/jffs2/super.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.102 2004/11/12 02:42:17 tpoynor Exp $ + * $Id: super.c,v 1.104 2004/11/23 15:37:31 gleixner Exp $ * */ @@ -277,7 +277,10 @@ up(&c->alloc_sem); jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); - kfree(c->blocks); + if (c->mtd->flags & MTD_NO_VIRTBLOCKS) + vfree(c->blocks); + else + kfree(c->blocks); jffs2_flash_cleanup(c); kfree(c->inocache_list); if (c->mtd->sync) diff -Nru a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c --- a/fs/jffs2/symlink.c 2004-11-29 21:35:09 -08:00 +++ b/fs/jffs2/symlink.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001, 2002 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/wbuf.c 2004-11-29 21:35:09 -08:00 @@ -4,12 +4,12 @@ * Copyright (C) 2001-2003 Red Hat, Inc. * Copyright (C) 2004 Thomas Gleixner * - * Created by David Woodhouse + * Created by David Woodhouse * Modified debugged and enhanced by Thomas Gleixner * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.72 2004/09/11 19:22:43 gleixner Exp $ + * $Id: wbuf.c,v 1.82 2004/11/20 22:08:31 dwmw2 Exp $ * */ @@ -130,22 +130,8 @@ } } -/* Recover from failure to write wbuf. Recover the nodes up to the - * wbuf, not the one which we were starting to try to write. */ - -static void jffs2_wbuf_recover(struct jffs2_sb_info *c) +static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { - struct jffs2_eraseblock *jeb, *new_jeb; - struct jffs2_raw_node_ref **first_raw, **raw; - size_t retlen; - int ret; - unsigned char *buf; - uint32_t start, end, ofs, len; - - spin_lock(&c->erase_completion_lock); - - jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; - D1(printk("About to refile bad block at %08x\n", jeb->offset)); D2(jffs2_dump_block_lists(c)); @@ -175,6 +161,25 @@ ACCT_SANITY_CHECK(c,jeb); D1(ACCT_PARANOIA_CHECK(jeb)); +} + +/* Recover from failure to write wbuf. Recover the nodes up to the + * wbuf, not the one which we were starting to try to write. */ + +static void jffs2_wbuf_recover(struct jffs2_sb_info *c) +{ + struct jffs2_eraseblock *jeb, *new_jeb; + struct jffs2_raw_node_ref **first_raw, **raw; + size_t retlen; + int ret; + unsigned char *buf; + uint32_t start, end, ofs, len; + + spin_lock(&c->erase_completion_lock); + + jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; + + jffs2_block_refile(c, jeb); /* Find the first node to be recovered, by skipping over every node which ends before the wbuf starts, or which is obsolete. */ @@ -224,7 +229,11 @@ } /* Do the read... */ - ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); + if (jffs2_cleanmarker_oob(c)) + ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); + else + ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); + if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { /* ECC recovered */ ret = 0; @@ -281,8 +290,11 @@ ret = -EIO; } else #endif + if (jffs2_cleanmarker_oob(c)) ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, buf, NULL, c->oobinfo); + else + ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf); if (ret || retlen != towrite) { /* Argh. We tried. Really we did. */ @@ -392,6 +404,10 @@ 1: Pad, do not adjust nextblock free_size 2: Pad, adjust nextblock free_size */ +#define NOPAD 0 +#define PAD_NOACCOUNT 1 +#define PAD_ACCOUNTING 2 + static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) { int ret; @@ -419,6 +435,10 @@ */ if (pad) { c->wbuf_len = PAD(c->wbuf_len); + + /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR + with 8 byte page size */ + memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); @@ -426,9 +446,6 @@ padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING); padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len); padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4)); - } else { - /* Pad with JFFS2_DIRTY_BITMASK */ - memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); } } /* else jffs2_flash_writev has actually filled in the rest of the @@ -444,8 +461,11 @@ ret = -EIO; } else #endif - ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); - + + if (jffs2_cleanmarker_oob(c)) + ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); + else + ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); if (ret || retlen != c->wbuf_pagesize) { if (ret) @@ -458,7 +478,7 @@ jffs2_wbuf_recover(c); - return ret; + return ret; } spin_lock(&c->erase_completion_lock); @@ -525,7 +545,9 @@ if (c->unchecked_size) { /* GC won't make any progress for a while */ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n")); - ret = __jffs2_flush_wbuf(c, 2); + down_write(&c->wbuf_sem); + ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); + up_write(&c->wbuf_sem); } else while (old_wbuf_len && old_wbuf_ofs == c->wbuf_ofs) { @@ -537,7 +559,9 @@ if (ret) { /* GC failed. Flush it with padding instead */ down(&c->alloc_sem); - ret = __jffs2_flush_wbuf(c, 2); + down_write(&c->wbuf_sem); + ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); + up_write(&c->wbuf_sem); break; } down(&c->alloc_sem); @@ -552,9 +576,14 @@ /* Pad write-buffer to end and write it, wasting space. */ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) { - return __jffs2_flush_wbuf(c, 1); -} + int ret; + down_write(&c->wbuf_sem); + ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); + up_write(&c->wbuf_sem); + + return ret; +} #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) @@ -575,6 +604,8 @@ if (!c->wbuf) return jffs2_flash_direct_writev(c, invecs, count, to, retlen); + down_write(&c->wbuf_sem); + /* If wbuf_ofs is not initialized, set it to target address */ if (c->wbuf_ofs == 0xFFFFFFFF) { c->wbuf_ofs = PAGE_DIV(to); @@ -582,6 +613,17 @@ memset(c->wbuf,0xff,c->wbuf_pagesize); } + /* Fixup the wbuf if we are moving to a new eraseblock. The checks below + fail for ECC'd NOR because cleanmarker == 16, so a block starts at + xxx0010. */ + if (jffs2_nor_ecc(c)) { + if (((c->wbuf_ofs % c->sector_size) == 0) && !c->wbuf_len) { + c->wbuf_ofs = PAGE_DIV(to); + c->wbuf_len = PAGE_MOD(to); + memset(c->wbuf,0xff,c->wbuf_pagesize); + } + } + /* Sanity checks on target address. It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to write at the beginning of a new @@ -592,12 +634,12 @@ /* It's a write to a new block */ if (c->wbuf_len) { D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); - ret = jffs2_flush_wbuf_pad(c); + ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); if (ret) { /* the underlying layer has to check wbuf_len to do the cleanup */ D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret)); *retlen = 0; - return ret; + goto exit; } } /* set pointer to new block */ @@ -623,7 +665,6 @@ invec = 0; outvec = 0; - /* Fill writebuffer first, if already in use */ if (c->wbuf_len) { uint32_t invec_ofs = 0; @@ -658,14 +699,14 @@ } /* write buffer is full, flush buffer */ - ret = __jffs2_flush_wbuf(c, 0); + ret = __jffs2_flush_wbuf(c, NOPAD); if (ret) { /* the underlying layer has to check wbuf_len to do the cleanup */ D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret)); /* Retlen zero to make sure our caller doesn't mark the space dirty. We've already done everything that's necessary */ *retlen = 0; - return ret; + goto exit; } outvec_to += donelen; c->wbuf_ofs = outvec_to; @@ -709,19 +750,22 @@ if (splitvec != -1) { uint32_t remainder; - int ret; remainder = outvecs[splitvec].iov_len - split_ofs; outvecs[splitvec].iov_len = split_ofs; /* We did cross a page boundary, so we write some now */ - ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); + if (jffs2_cleanmarker_oob(c)) + ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); + else + ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); + if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { /* At this point we have no problem, c->wbuf is empty. */ *retlen = donelen; - return ret; + goto exit; } donelen += wbuf_retlen; @@ -760,7 +804,11 @@ if (c->wbuf_len && ino) jffs2_wbuf_dirties_inode(c, ino); - return 0; + ret = 0; + +exit: + up_write(&c->wbuf_sem); + return ret; } /* @@ -789,7 +837,12 @@ /* Read flash */ if (!jffs2_can_mark_obsolete(c)) { - ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); + down_read(&c->wbuf_sem); + + if (jffs2_cleanmarker_oob(c)) + ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); + else + ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); if ( (ret == -EBADMSG) && (*retlen == len) ) { printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", @@ -811,23 +864,23 @@ /* if no writebuffer available or write buffer empty, return */ if (!c->wbuf_pagesize || !c->wbuf_len) - return ret; + goto exit; /* if we read in a different block, return */ if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) - return ret; + goto exit; if (ofs >= c->wbuf_ofs) { owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ - return ret; + goto exit; lwbf = c->wbuf_len - owbf; /* number of bytes to copy */ if (lwbf > len) lwbf = len; } else { orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ if (orbf > len) /* is write beyond write buffer ? */ - return ret; + goto exit; lwbf = len - orbf; /* number of bytes to copy */ if (lwbf > c->wbuf_len) lwbf = c->wbuf_len; @@ -835,6 +888,8 @@ if (lwbf > 0) memcpy(buf+orbf,c->wbuf+owbf,lwbf); +exit: + up_read(&c->wbuf_sem); return ret; } @@ -1079,9 +1134,9 @@ int res; /* Initialise write buffer */ + init_rwsem(&c->wbuf_sem); c->wbuf_pagesize = c->mtd->oobblock; c->wbuf_ofs = 0xFFFFFFFF; - c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) @@ -1105,3 +1160,25 @@ { kfree(c->wbuf); } + +#ifdef CONFIG_JFFS2_FS_NOR_ECC +int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { + /* Cleanmarker is actually larger on the flashes */ + c->cleanmarker_size = 16; + + /* Initialize write buffer */ + init_rwsem(&c->wbuf_sem); + c->wbuf_pagesize = c->mtd->eccsize; + c->wbuf_ofs = 0xFFFFFFFF; + + c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); + if (!c->wbuf) + return -ENOMEM; + + return 0; +} + +void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { + kfree(c->wbuf); +} +#endif diff -Nru a/fs/jffs2/write.c b/fs/jffs2/write.c --- a/fs/jffs2/write.c 2004-11-29 21:35:09 -08:00 +++ b/fs/jffs2/write.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/fs/jffs2/writev.c 2004-11-29 21:35:09 -08:00 @@ -3,11 +3,11 @@ * * Copyright (C) 2001, 2002 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/include/linux/jffs2.h 2004-11-29 21:35:09 -08:00 @@ -3,12 +3,12 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * 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-29 21:35:09 -08:00 +++ b/include/linux/jffs2_fs_sb.h 2004-11-29 21:35:09 -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 #include #include +#include #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-29 21:35:09 -08:00 +++ b/include/linux/mtd/cfi.h 2004-11-29 21:35:09 -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-29 21:35:09 -08:00 +++ b/include/linux/mtd/flashchip.h 2004-11-29 21:35:09 -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-29 21:35:09 -08:00 +++ b/include/linux/mtd/nand.h 2004-11-29 21:35:09 -08:00 @@ -5,7 +5,7 @@ * Steven J. Hill * Thomas Gleixner * - * $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-29 21:35:09 -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 + +#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 + +/* + * 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 +#ifdef CONFIG_ARCH_PXA +#include +#endif + +#define xip_irqpending() (ICIP & ICMR) + +/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */ +#define xip_currtime() (OSCR) +#define xip_elapsed_since(x) (signed)((OSCR - (x)) / 4) + +#else +#error "missing IRQ and timer primitives for XIP MTD support" +#endif + +/* + * xip_cpu_idle() is used when waiting for a delay equal or larger than + * the system timer tick period. This should put the CPU into idle mode + * to save power and to be woken up only when some interrupts are pending. + * As above, this should not rely upon standard kernel code. + */ + +#if defined(CONFIG_CPU_XSCALE) +#define xip_cpu_idle() asm volatile ("mcr p14, 0, %0, c7, c0, 0" :: "r" (1)) +#else +#define xip_cpu_idle() do { } while (0) +#endif + +#else + +#define __xipram + +#endif /* CONFIG_MTD_XIP */ + +#endif /* __LINUX_MTD_XIP_H__ */ diff -Nru a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h --- a/include/mtd/mtd-abi.h 2004-11-29 21:35:09 -08:00 +++ b/include/mtd/mtd-abi.h 2004-11-29 21:35:09 -08:00 @@ -1,5 +1,5 @@ /* - * $Id: mtd-abi.h,v 1.6 2004/08/09 13:38:30 dwmw2 Exp $ + * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $ * * Portions of MTD ABI definition which are shared by kernel and user space */ @@ -40,6 +40,7 @@ #define MTD_XIP 32 // eXecute-In-Place possible #define MTD_OOB 64 // Out-of-band data (NAND flash) #define MTD_ECC 128 // Device capable of automatic ECC +#define MTD_NO_VIRTBLOCKS 256 // Virtual blocks not allowed // Some common devices / combinations of capabilities #define MTD_CAP_ROM 0 diff -Nru a/kernel/workqueue.c b/kernel/workqueue.c --- a/kernel/workqueue.c 2004-11-29 21:35:09 -08:00 +++ b/kernel/workqueue.c 2004-11-29 21:35:09 -08:00 @@ -8,7 +8,7 @@ * * Derived from the taskqueue/keventd code by: * - * David Woodhouse + * David Woodhouse * Andrew Morton * Kai Petzke * Theodore Ts'o diff -Nru a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c --- a/lib/reed_solomon/reed_solomon.c 2004-11-29 21:35:09 -08:00 +++ b/lib/reed_solomon/reed_solomon.c 2004-11-29 21:35:09 -08:00 @@ -9,7 +9,7 @@ * Reed Solomon code lifted from reed solomon library written by Phil Karn * Copyright 2002 Phil Karn, KA9Q * - * $Id: rslib.c,v 1.4 2004/10/05 22:07:53 gleixner Exp $ + * $Id: rslib.c,v 1.5 2004/10/22 15:41:47 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -22,19 +22,19 @@ * Each user must call init_rs to get a pointer to a rs_control * structure for the given rs parameters. This structure is either * generated or a already available matching control structure is used. - * If a structure is generated then the polynominal arrays for + * If a structure is generated then the polynomial arrays for * fast encoding / decoding are built. This can take some time so - * make sure not to call this function from a timecritical path. - * Usually a module / driver should initialize the neccecary + * make sure not to call this function from a time critical path. + * Usually a module / driver should initialize the necessary * rs_control structure on module / driver init and release it * on exit. - * The encoding puts the calculated syndrome into a given syndrom + * The encoding puts the calculated syndrome into a given syndrome * buffer. * The decoding is a two step process. The first step calculates - * the syndrome over the received (data + syndrom) and calls the + * the syndrome over the received (data + syndrome) and calls the * second stage, which does the decoding / error correction itself. - * Many hw encoders provide a syndrom calculation over the received - * data + syndrom and can call the second stage directly. + * Many hw encoders provide a syndrome calculation over the received + * data + syndrome and can call the second stage directly. * */