bk://linux-mtd.bkbits.net/mtd-2.6 linux-mtd.adm@bkbits.net|ChangeSet|20050401072541|58970 linux-mtd.adm # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/04/04 00:53:52-07:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd # # drivers/mtd/maps/pci.c # 2005/04/04 00:53:45-07:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/04/01 11:22:44-08:00 akpm@bix.(none) # Merge bk://linux-mtd.bkbits.net/mtd-2.6 into bix.(none):/usr/src/bk-mtd # # fs/Kconfig # 2005/04/01 11:22:40-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/03/31 23:25:41-08:00 linux-mtd.adm@bkbits.net # Merge bk://linux.bkbits.net/linux-2.6 # into bkbits.net:/repos/l/linux-mtd/mtd-2.6 # # fs/Kconfig # 2005/03/31 23:25:32-08:00 linux-mtd.adm@bkbits.net +0 -0 # Auto merged # # ChangeSet # 2005/03/28 22:24:39-08:00 akpm@bix.(none) # Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mtd # # fs/Kconfig # 2005/03/28 22:24:33-08:00 akpm@bix.(none) +0 -0 # Auto merged # # ChangeSet # 2005/03/24 20:21:31+01:00 tglx@tglx.tec.linutronix.de # Fix error path. Release resources # # Signed-off-by: Richard Purdie # Signed-off-by: Thomas Gleixner # # drivers/mtd/maps/sharpsl-flash.c # 2005/03/24 20:21:23+01:00 tglx@tglx.tec.linutronix.de +6 -3 # Fix error path. Release resources # # ChangeSet # 2005/03/21 06:39:55+01:00 rpurdie@infradead.org # MTD: sharpsl-flash: Fix map init, make partitions machine dependend # # Add the missing map init call. Split partition initialization for # the different sharpsl based machines # # Signed-off-by: Richard Purdie # Signed-off-by: Thomas Gleixner # # drivers/mtd/maps/sharpsl-flash.c # 2005/03/21 06:39:45+01:00 rpurdie@infradead.org +23 -7 # Make partition size machine dependend # # ChangeSet # 2005/03/20 23:17:14+01:00 dedekind@infradead.org # JFFS2: Prevent inode cache deletion for nodes with nlink > 0 # # Due to the missing nlink check it happened that the inode cache # was deleted even for the root node. # # Signed-off-by: Artem B. Bityuckiy # Signed-off-by: Thomas Gleixner # # fs/jffs2/nodemgmt.c # 2005/03/20 23:17:07+01:00 dedekind@infradead.org +2 -2 # Prevent inode cache deletion when nlink > 0 # # fs/jffs2/erase.c # 2005/03/20 23:17:07+01:00 dedekind@infradead.org +2 -2 # Prevent inode cache deletion when nlink > 0 # # ChangeSet # 2005/03/20 23:13:53+01:00 dedekind@infradead.org # JFFS2: Prevent GC Thread noop busy loop # # The garbage collect thread can run into a busy loop condition, when it is # woken up, but the only blocks to recycle (erase) are protected from erasing # by pending data in the write buffer. # Enforce flush of write buffer for this case. # # Signed-off-by: Artem B. Bityuckiy # Signed-off-by: Thomas Gleixner # # fs/jffs2/gc.c # 2005/03/20 23:13:44+01:00 dedekind@infradead.org +9 -1 # Force wbuf flush, if no other blocks are available than those # on the erasable_pending_wbuf_list # # # ChangeSet # 2005/03/19 23:29:06+01:00 tglx@tglx.tec.linutronix.de # MTD: block2mtd. Fix incompatible pointer type # # Signed-off-by: Thomas Gleixner # # drivers/mtd/devices/block2mtd.c # 2005/03/19 23:28:56+01:00 tglx@tglx.tec.linutronix.de +5 -5 # Cleanup Viro's size_t change # # ChangeSet # 2005/03/19 23:17:49+01:00 tglx@tglx.tec.linutronix.de # MTD: plat-ram.c Make it usable on non ARM platforms # # Use memset instead of ARM only memzero function # # Signed-off-by: Thomas Gleixner # # drivers/mtd/maps/plat-ram.c # 2005/03/19 23:17:42+01:00 tglx@tglx.tec.linutronix.de +1 -1 # memzero is not defined on all platforms # # ChangeSet # 2005/03/19 23:14:35+01:00 tglx@tglx.tec.linutronix.de # MTD: cfi_cmdset_0001: Fix compiler warnings # # Signed-off-by: Thomas Gleixner # # drivers/mtd/chips/cfi_cmdset_0001.c # 2005/03/19 23:14:27+01:00 tglx@tglx.tec.linutronix.de +4 -4 # Fix compiler warnings # # ChangeSet # 2005/03/18 23:02:41+01:00 tglx@infradead.org # MTD: IXP2000 Flash driver. Move port setting to platform code # # # Signed-off-by: Lennert Buytenhek # Signed-off-by: Thomas Gleixner # # drivers/mtd/maps/ixp2000.c # 2005/03/18 23:02:30+01:00 tglx@infradead.org +1 -6 # Setting the slowport to 8-bit mode is something that ought to be # done in the IXP2000 generic code, not in the MTD map driver. See # the description for ARM patch 2493/1 for an explanation. # http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=2493/1 # Now that 2493/1 has been accepted and will be upstream soon, this # doesn't need to be done in the map driver anymore. # # ChangeSet # 2005/03/18 22:59:34+01:00 tglx@infradead.org # MTD: Convert pci_module_init to pci_module_register # # Convert from pci_module_init to pci_register_driver # (from:http://kerneljanitors.org/TODO). # # Signed-off-by: Christophe Lucas # Signed-off-by: Domen Puncer # Signed-off-by: Thomas Gleixner # # # # drivers/mtd/maps/scb2_flash.c # 2005/03/18 22:59:27+01:00 tglx@infradead.org +2 -2 # Convert from pci_module_init to pci_register_driver # (from:http://kerneljanitors.org/TODO). # # drivers/mtd/maps/pci.c # 2005/03/18 22:59:27+01:00 tglx@infradead.org +2 -2 # Convert from pci_module_init to pci_register_driver # (from:http://kerneljanitors.org/TODO). # # drivers/mtd/maps/ichxrom.c # 2005/03/18 22:59:27+01:00 tglx@infradead.org +2 -2 # Convert from pci_module_init to pci_register_driver # (from:http://kerneljanitors.org/TODO). # # drivers/mtd/maps/amd76xrom.c # 2005/03/18 22:59:27+01:00 tglx@infradead.org +2 -2 # Convert from pci_module_init to pci_register_driver # (from:http://kerneljanitors.org/TODO). # # ChangeSet # 2005/03/18 22:57:56+01:00 nico@infradead.org # MTD: Add OTP (One Time Programming) support for CFI FLASH # # Add selection option to Kconfig # # Signed-off-by: Nicolas Pitre # Signed-off-by: Thomas Gleixner # # drivers/mtd/chips/Kconfig # 2005/03/18 22:57:45+01:00 nico@infradead.org +26 -1 # Add selection option # # ChangeSet # 2005/03/18 22:53:28+01:00 nico@infradead.org # MTD: Add OTP (One Time Programming) support for CFI FLASH # # This enables support for reading, writing and locking so called # "Protection Registers" present on some flash chips. # A subset of them are pre-programmed at the factory with a # unique set of values. The rest is user-programmable. # # Signed-off-by: Nicolas Pitre # Signed-off-by: Thomas Gleixner # # # include/mtd/mtd-abi.h # 2005/03/18 22:53:19+01:00 nico@infradead.org +16 -1 # User interface to Protection Registers # # This is implemented using a ioctl to switch the MTD char device into # one of the different OTP "modes", at which point read/write/seek can # operate on the selected OTP area. Also some extra ioctls to query # for size and lock protection segments or groups. Some example user # space utilities are provided. # # include/linux/mtd/mtd.h # 2005/03/18 22:53:19+01:00 nico@infradead.org +5 -5 # Support for Protection Registers on Intel flash chips # # include/linux/mtd/map.h # 2005/03/18 22:53:19+01:00 nico@infradead.org +15 -2 # Support for Protection Registers on Intel flash chips # # include/linux/mtd/flashchip.h # 2005/03/18 22:53:19+01:00 nico@infradead.org +4 -3 # Support for Protection Registers on Intel flash chips # # include/linux/mtd/cfi.h # 2005/03/18 22:53:19+01:00 nico@infradead.org +10 -2 # Support for Protection Registers on Intel flash chips # # drivers/mtd/mtdpart.c # 2005/03/18 22:53:19+01:00 nico@infradead.org +27 -1 # Support for Protection Registers on Intel flash chips # Add the necessary changes to partition code. # # drivers/mtd/mtdchar.c # 2005/03/18 22:53:19+01:00 nico@infradead.org +121 -8 # User interface to Protection Registers # # This is implemented using a ioctl to switch the MTD char device into # one of the different OTP "modes", at which point read/write/seek can # operate on the selected OTP area. Also some extra ioctls to query # for size and lock protection segments or groups. Some example user # space utilities are provided. # # drivers/mtd/chips/cfi_cmdset_0001.c # 2005/03/18 22:53:19+01:00 nico@infradead.org +292 -116 # Support for Protection Registers on Intel flash chips # # ChangeSet # 2005/03/18 22:47:37+01:00 dedekind@infradead.org # JFFS2: Use function to manipulate superblock # # Signed-Off-By: Artem B. Bityuckiy # Signed-Off-By: Thomas Gleixner # # fs/jffs2/wbuf.c # 2005/03/18 22:47:30+01:00 dedekind@infradead.org +2 -2 # Use the corresponding function to mark Superblock dirty instead of # doing it directly. # # ChangeSet # 2005/03/18 22:45:53+01:00 tglx@infradead.org # MTD: Fix bogus status check in cfi_cmdset_0001.c # # Fix the buggy status check. The change makes the code endianess # aware and replaces the bogus nested loop to or the status flags # together. # # Signed-off-by: Thomas Gleixner # # include/linux/mtd/cfi.h # 2005/03/18 22:45:46+01:00 tglx@infradead.org +63 -0 # Implement the counterpart to cfi_build_cmd() # # drivers/mtd/chips/cfi_cmdset_0001.c # 2005/03/18 22:45:46+01:00 tglx@infradead.org +3 -13 # Fix the buggy status check. The change makes the code endianess # aware and replaces the bogus nested loop to or the status flags # together. # # ChangeSet # 2005/03/18 22:40:48+01:00 tglx@infradead.org # MTD: Trivial code cosmetics # # Signed-off-by: Thomas Gleixner # # drivers/mtd/chips/jedec_probe.c # 2005/03/18 22:40:41+01:00 tglx@infradead.org +5 -3 # Let it look the same as the other entries # # # # ChangeSet # 2005/03/18 22:36:58+01:00 dedekind@infradead.org # JFFS2: Add symlink caching support. # # Signed-off-by: Artem B. Bityuckiy # Signed-off-by: Thomas Gleixner # # fs/jffs2/write.c # 2005/03/18 22:36:51+01:00 dedekind@infradead.org +19 -18 # Add symlink caching support. # # fs/jffs2/symlink.c # 2005/03/18 22:36:51+01:00 dedekind@infradead.org +30 -12 # Add symlink caching support. # # fs/jffs2/readinode.c # 2005/03/18 22:36:51+01:00 dedekind@infradead.org +48 -6 # Add symlink caching support. # # fs/jffs2/read.c # 2005/03/18 22:36:51+01:00 dedekind@infradead.org +1 -31 # Add symlink caching support. # # fs/jffs2/dir.c # 2005/03/18 22:36:51+01:00 dedekind@infradead.org +21 -7 # Add symlink caching support. # # ChangeSet # 2005/03/18 22:28:28+01:00 dwmw2@infradead.org # JFFS2: Prevent inocache removal for inodes in use # # Signed-off-by: David Woodhouse # Signed-off-by: Thomas Gleixner # # fs/jffs2/readinode.c # 2005/03/18 22:28:21+01:00 dwmw2@infradead.org +8 -2 # Don't remove inocache for inodes which are in read_inode() or # clear_inode() until they're done. # # fs/jffs2/nodemgmt.c # 2005/03/18 22:28:21+01:00 dwmw2@infradead.org +1 -4 # Don't remove inocache for inodes which are in read_inode() or # clear_inode() until they're done. # # fs/jffs2/nodelist.h # 2005/03/18 22:28:21+01:00 dwmw2@infradead.org +2 -1 # Add new inode status for in clear_inode() # # fs/jffs2/nodelist.c # 2005/03/18 22:28:21+01:00 dwmw2@infradead.org +13 -4 # Don't remove inocache for inodes which are in read_inode() or # clear_inode() until they're done. # # fs/jffs2/erase.c # 2005/03/18 22:28:20+01:00 dwmw2@infradead.org +2 -5 # Don't remove inocache for inodes which are in read_inode() or # clear_inode() until they're done. # # ChangeSet # 2005/03/18 22:17:37+01:00 dedekind@infradead.org # JFFS2: Fix deadlock during filesystem scan # # Fix NOR-specific bug # If during fs scan ic->scan_dents is not zero, so when # jffs2_mark_node_obsolete() is called it tries to # find the ic corresponding dents references # Set ic->scan_dents = 0 during scan. # # Signed-off-by: Artem B. Bityuckiy # Signed-off-by: Thomas Gleixner # # include/linux/jffs2_fs_sb.h # 2005/03/18 22:17:30+01:00 dedekind@infradead.org +2 -1 # Split mount flag into scan, build phase # # fs/jffs2/scan.c # 2005/03/18 22:17:30+01:00 dedekind@infradead.org +3 -3 # Look up the ref->next_phys field instead of ->next_in_ino to # determine if the block has more then one node. # # fs/jffs2/nodemgmt.c # 2005/03/18 22:17:30+01:00 dedekind@infradead.org +6 -5 # Prevent scanning of dents during scan and build # # fs/jffs2/build.c # 2005/03/18 22:17:30+01:00 dedekind@infradead.org +6 -3 # Split mount flag into scan, build phase # # ChangeSet # 2005/03/18 21:38:10+01:00 pavlov@infradead.org # JFFS2: Add DataFlash support. Unify all writebuffer dependend code. # # DataFlash page-sizes are not a power of two (they're multiples of 528 # bytes). There are a few places in JFFS2 code where sector_size is used # as a bitmask. A new macro (SECTOR_ADDR) was defined to calculate these # sector addresses. For non-DataFlash devices, the original (faster) # bitmask operation is still used. # # In scan.c, the EMPTY_SCAN_SIZE was a constant of 1024. # Since this could be larger than the sector size of the DataFlash, this # is now basically set to MIN(sector_size, 1024). # # Addition of a jffs2_is_writebuffered() macro to unify all FLASH # specific code which depends on the writebuffer functionality. # # Merge CONFIG_JFFS2_FS_NAND, CONFIG_JFFS2_FS_NOR_ECC, # CONFIG_JFFS2_FS_DATAFLASH into CONFIG_JFFS2_FS_WRITEBUFFER. # # Signed-off-by: Andrew Victor # Signed-off-by: Thomas Gleixner # # include/mtd/mtd-abi.h # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +1 -0 # ABI changes required to support JFFS2-on-Dataflash devices. # # include/linux/jffs2_fs_sb.h # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +1 -1 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/wbuf.c # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +59 -35 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/super.c # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +2 -2 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/scan.c # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +23 -12 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/os-linux.h # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +14 -9 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/nodelist.h # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +2 -2 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/gc.c # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +2 -3 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/fs.c # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +19 -2 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/erase.c # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +12 -4 # Core changes required to support JFFS2-on-Dataflash devices. # # fs/jffs2/Makefile # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +1 -2 # Merge CONFIG_JFFS2_FS_NAND, CONFIG_JFFS2_FS_NOR_ECC, # CONFIG_JFFS2_FS_DATAFLASH into CONFIG_JFFS2_FS_WRITEBUFFER. # # fs/Kconfig # 2005/03/18 21:38:01+01:00 pavlov@infradead.org +9 -17 # Merge CONFIG_JFFS2_FS_NAND, CONFIG_JFFS2_FS_NOR_ECC, # CONFIG_JFFS2_FS_DATAFLASH into CONFIG_JFFS2_FS_WRITEBUFFER. # # ChangeSet # 2005/03/18 21:29:18+01:00 estelle@infradead.org # JFFS2: Improve and fix failure handling for NAND Flash # # Signed-off-by: Estelle Hammache # Signed-off-by: Thomas Gleixner # # fs/jffs2/write.c # 2005/03/18 21:29:11+01:00 estelle@infradead.org +22 -1 # Correction of retry case to avoid silent failure of rmdir when # jffs2_wbuf_recover GCs the previous entry (+ corresponding # dnode case). # # fs/jffs2/wbuf.c # 2005/03/18 21:29:11+01:00 estelle@infradead.org +54 -22 # - block refiling when writing directly to flash a buffer which is # bigger than wbuf # - retry cases for flushing wbuf # - prevent deadlock when checking erased block for space allocation # during wbuf recovery. # # fs/jffs2/nodemgmt.c # 2005/03/18 21:29:11+01:00 estelle@infradead.org +6 -3 # - avoid segfault when nextblock was refiled because of a write failure # - avoid filing blocks on the clean list when they have wasted space # # ChangeSet # 2005/03/18 21:23:50+01:00 bjd@infradead.org # MTD: Platform device RAM driver (mtd-ram) # # Driver for generic RAM blocks which are exported by an platform_device # from the device driver system. # # Signed-off-by: Ben Dooks # Signed-off-by: Thomas Gleixner # # include/linux/mtd/plat-ram.h # 2005/03/18 21:23:43+01:00 bjd@infradead.org +35 -0 # # drivers/mtd/maps/plat-ram.c # 2005/03/18 21:23:43+01:00 bjd@infradead.org +278 -0 # # include/linux/mtd/plat-ram.h # 2005/03/18 21:23:43+01:00 bjd@infradead.org +0 -0 # BitKeeper file /home/tglx/work/bk/mtd/mtd-cvs/include/linux/mtd/plat-ram.h # # drivers/mtd/maps/plat-ram.c # 2005/03/18 21:23:43+01:00 bjd@infradead.org +0 -0 # BitKeeper file /home/tglx/work/bk/mtd/mtd-cvs/drivers/mtd/maps/plat-ram.c # # drivers/mtd/maps/Makefile # 2005/03/18 21:23:42+01:00 bjd@infradead.org +2 -1 # Add MTD Platform RAM Driver # # drivers/mtd/maps/Kconfig # 2005/03/18 21:23:42+01:00 bjd@infradead.org +11 -1 # Add MTD Platform RAM Driver # # ChangeSet # 2005/03/18 21:19:48+01:00 bjd@infradead.org # MTD: BAST Flash mapping driver updates # # Signed-off-by: Ben Dooks # Signed-off-by: Thomas Gleixner # # drivers/mtd/maps/bast-flash.c # 2005/03/18 21:19:41+01:00 bjd@infradead.org +8 -5 # - Ensure the whole device is added if there are no partitions found # on the device, so that at least the flash can be read/written. # # - Replace some of the constants with their SZ_xxx counterparts # # drivers/mtd/maps/Kconfig # 2005/03/18 21:19:41+01:00 bjd@infradead.org +4 -3 # Update the BAST driver config (which already supports the vr1000) to # be selected only if the vr1000 has been configured # # ChangeSet # 2005/03/18 21:16:10+01:00 dvrabel@infradead.org # MTD: Replaced all Au1x mapping drivers with a single driver. # # Replaced all the Au1x mapping drivers with a simplified single driver. # This driver does not have as many options but it's easier to maintain. # And, it turns out AMD never shipped boards with different flash # densities. # # Signed-off-by: David Vrabel # Signed-off-by: Thomas Gleixner # # drivers/mtd/maps/alchemy-flash.c # 2005/03/18 21:16:02+01:00 dvrabel@infradead.org +192 -0 # # drivers/mtd/maps/alchemy-flash.c # 2005/03/18 21:16:02+01:00 dvrabel@infradead.org +0 -0 # BitKeeper file /home/tglx/work/bk/mtd/mtd-cvs/drivers/mtd/maps/alchemy-flash.c # # drivers/mtd/maps/Makefile # 2005/03/18 21:16:02+01:00 dvrabel@infradead.org +1 -5 # Replaced all the Au1x mapping drivers with a simplified single driver. # This driver does not have as many options but it's easier to maintain. # And, it turns out AMD never shipped boards with different flash # densities. # # Remove obsolete elan-104nc entry. # # drivers/mtd/maps/Kconfig # 2005/03/18 21:16:02+01:00 dvrabel@infradead.org +4 -67 # Replaced all the Au1x mapping drivers with a simplified single driver. # This driver does not have as many options but it's easier to maintain. # And, it turns out AMD never shipped boards with different flash # densities. # # BitKeeper/deleted/.del-pb1xxx-flash.c~d9d12f6812c661ca # 2005/03/18 21:13:17+01:00 tglx@tglx.tec.linutronix.de +0 -0 # Delete: drivers/mtd/maps/pb1xxx-flash.c # # BitKeeper/deleted/.del-pb1550-flash.c~7b79c7d929dcc041 # 2005/03/18 21:13:17+01:00 tglx@tglx.tec.linutronix.de +0 -0 # Delete: drivers/mtd/maps/pb1550-flash.c # # BitKeeper/deleted/.del-db1x00-flash.c~ffded93352845f72 # 2005/03/18 21:13:16+01:00 tglx@tglx.tec.linutronix.de +0 -0 # Delete: drivers/mtd/maps/db1x00-flash.c # # BitKeeper/deleted/.del-db1550-flash.c~d0994e1fb40f96d7 # 2005/03/18 21:13:16+01:00 tglx@tglx.tec.linutronix.de +0 -0 # Delete: drivers/mtd/maps/db1550-flash.c # # ChangeSet # 2005/03/18 21:11:31+01:00 dvrabel@infradead.org # MTD: Remove unmaintained Elan-104NC driver # # Remove support for the Arcom Elan-104NC since it's no longer # being maintained. # # Signed-off-by: David Vrabel # Signed-off-by: Thomas Gleixner # # drivers/mtd/maps/Kconfig # 2005/03/18 21:11:21+01:00 dvrabel@infradead.org +0 -10 # Remove support for the Arcom Elan-104NC since it's no longer # being maintained. # # BitKeeper/deleted/.del-elan-104nc.c~e85c886b7c148471 # 2005/03/18 21:09:31+01:00 tglx@tglx.tec.linutronix.de +0 -0 # Delete: drivers/mtd/maps/elan-104nc.c # # ChangeSet # 2005/03/18 21:07:51+01:00 joern@infradead.org # MTD: block2mtd driver: Fix offset calculation. Remove copyright. # # Fix the offset calculation # Remove Gareth from the Copyrights (at his own request) # # Signed-off-by: Joern Engel # Signed-off-by: Thomas Gleixner # # drivers/mtd/devices/block2mtd.c # 2005/03/18 21:07:44+01:00 joern@infradead.org +4 -6 # - Remove Gareth from the Copyrights (at his own request) # - Fix the offset calculation # # ChangeSet # 2005/03/18 21:05:06+01:00 joern@infradead.org # MTD: phram driver, fix use after free, allow short reads # # Use after free, found by the Coverity tool # Signed-off-by: Alexander Nyberg # # Allow short reads. Accept newline at the end of input. # # Signed-off-by: Joern Engel # # Signed-off-by: Thomas Gleixner # # drivers/mtd/devices/phram.c # 2005/03/18 21:04:56+01:00 joern@infradead.org +24 -10 # - Use after free, found by the Coverity tool # - Allow short reads. Jffs2 apparently needs this. # - Accept newline at the end of input. # # ChangeSet # 2005/03/18 20:59:05+01:00 jwboyer@infradead.org # MTD: slram driver error checks and erasesize initialization # # Signed-off-by: Josh Boyer # Signed-off-by: Thomas Gleixner # # drivers/mtd/devices/slram.c # 2005/03/18 20:58:56+01:00 jwboyer@infradead.org +18 -5 # Add error checks to read/write functions and add an eraseblock size. # Makes slram a suitable device for JFFS2. # # ChangeSet # 2005/03/18 20:55:19+01:00 dedekind@infradead.org # MTD: Documentation fix # # Signed-off-by: Artem B. Bityuckiy # Signed-off-by: Thomas Gleixner # # drivers/mtd/mtdcore.c # 2005/03/18 20:55:12+01:00 dedekind@infradead.org +3 -3 # Fix unregister_mtd_user() public function documentation. # # ChangeSet # 2005/03/18 20:52:13+01:00 bjd@infradead.org # MTD: Fix device probing. Add new chip ID # # Signed-off-by: Ben Dooks # Signed-off-by: Thomas Gleixner # # drivers/mtd/chips/jedec_probe.c # 2005/03/18 20:52:06+01:00 bjd@infradead.org +27 -1 # - added SST 39VF1601 (MPF+) Chip ID # # - The change to the generic probe to look for the # smallest width of chip first is causing some problems # on boards with a single 16bit device. # The problem seems to be the jedec_match() is truncating # the device-id read from the table to match against the # one read from the hardware, causing a match against the # partial id of some chips with 16bit IDs (such as the # SST39LF160) # This fixes things for my own board, but something may # need to be done if the same problem is exhibited for # chips with an 8bit ID # # ChangeSet # 2005/03/18 20:48:37+01:00 rmk@infradead.org # MTD: Fix chip probing to avoid buswidth misdetection # # Signed-off-by: Russell King # Signed-off-by: Thomas Gleixner # # drivers/mtd/chips/gen_probe.c # 2005/03/18 20:48:30+01:00 rmk@infradead.org +2 -2 # Fix MTD device probing, trying larger numbers of chips before smaller # numbers of chips across the bus width. # # This means we'll avoid misdetecting a 2 x16 array as 1 x32 if the # high 16-bits happen to read as zeros in the QRY area. # # ChangeSet # 2005/03/18 20:45:49+01:00 jonashg@infradead.org # MTD: Remove CFI capable chip from deprecated amd driver # # Signed-off-by: Jonas Holmberg # Signed-off-by: Thomas Gleixner # # drivers/mtd/chips/amd_flash.c # 2005/03/18 20:45:40+01:00 jonashg@infradead.org +1 -13 # Removed table entry for AM29BDS643D, since device ID clashes with # AM29DL640G and both chips support CFI. # # ChangeSet # 2005/03/18 20:19:54+01:00 hvr@infradead.org # MTD: FTL bug fix. Initialize erase callback structure # # # Signed-off-by: Herbert Valerio Riedel # Signed-off-by: Thomas Gleixner # # drivers/mtd/ftl.c # 2005/03/18 20:19:46+01:00 hvr@infradead.org +3 -2 # Fixed missing pointer assignment, for the case that mtd partitions # are enabled where it would cause a 0-pointer dereferencing in # mtdpart.c:mtd_erase_callback() # # ChangeSet # 2005/03/18 20:16:17+01:00 tglx@infradead.org # MTD: Nand driver fixes and improvements # # - Remove unused variable # - Replace yield() # - Command wait timeout # - Move manufacturer ID search # - Pointer check for bad block table # - Option to skip bad block table check # # Signed-off-by: Thomas Gleixner # # drivers/mtd/nand/nand_base.c # 2005/03/18 20:16:08+01:00 tglx@infradead.org +42 -21 # - fixed unused loop variable # Signed-off-by: Ben Dooks # # - check bad block table pointer before dereferencing # Signed-off-by: Artem B. Bityuckiy # # - Move manufacturer ID search to display correct ID in case of buswidth # mismatch. # Signed-off-by: Kyungmin Park # # - Replace yield() by cond_resched. msleep(1) is not a real solution as # on machines with HZ=100 (e.g. ARM) msleep slows down the operation # by factor 10. # M.Wilcox stared at yield() and frowned # - Check timeout while we wait for the command to finish. # No worry about a false result. This prevents deadlocking # when probing an unknown number of chips and is useful # for removable media too. # - Skip bad block table scan on request # # # ChangeSet # 2005/03/18 20:07:21+01:00 dmarlin@infradead.org # MTD: AG-AND cleanups and improvements # # - Device recovery # - Bad block table rewriting # - Extra failure checks # # Signed-off-by: David A. Marlin # Signed-off-by: Thomas Gleixner # # # include/linux/mtd/nand.h # 2005/03/18 20:07:10+01:00 dmarlin@infradead.org +41 -3 # - Added extended commands for AG-AND device and added option # for BBT_AUTO_REFRESH. # - Add optional hardware specific callback routine to perform # extra error status checks on erase and write failures for # devices with hardware ECC. # - Add an option to skip bad block table scan # # drivers/mtd/nand/rtc_from4.c # 2005/03/18 20:07:10+01:00 dmarlin@infradead.org +132 -8 # - Add routine to perform device recovery (deplete) procedure. # - Clean up some compiler warnings. # - Added routine to perform extra error status checks on erase and write # failures to determine if errors are correctable. # - Added option to prevent JFFS2 from using virtual erase blocks. # - Performed minor cleanup on whitespace and comments. # # drivers/mtd/nand/nand_ids.c # 2005/03/18 20:07:10+01:00 dmarlin@infradead.org +2 -2 # Add bad block table autorefresh option for AG-AND chips # # drivers/mtd/nand/nand_base.c # 2005/03/18 20:07:10+01:00 dmarlin@infradead.org +127 -20 # - Added workaround for Renesas AG-AND chips "disturb" issue for Bad Block Table. # - Added support for the device recovery command sequence for Renesas AG-AND chips. # - Replace some literals with defined symbols. # - Add optional hardware specific callback routine to perform extra error # - status checks on erase and write failures for devices with hardware ECC. # # # ChangeSet # 2005/03/18 19:53:26+01:00 tglx@tglx.tec.linutronix.de # MTD: NAND DiskOnChip driver cleanup and fixes # # - Command delay on chip detection # - NFTL on BE machines # - Make config options for base address work # # Signed-off-by: Thomas Gleixner # # drivers/mtd/nand/diskonchip.c # 2005/03/18 19:53:17+01:00 tglx@tglx.tec.linutronix.de +9 -2 # Wait for the command to finish. Do not use the ready function here, # as it might hang for ever. The status read result will show, whether # the chip is there or not. # # drivers/mtd/nand/diskonchip.c # 2005/03/18 19:48:35+01:00 tglx@tglx.tec.linutronix.de +4 -0 # Make NFTL devices work on big endian machines. # # drivers/mtd/nand/diskonchip.c # 2005/03/18 19:45:42+01:00 tglx@tglx.tec.linutronix.de +2 -15 # Remove comment ugliness # # drivers/mtd/nand/diskonchip.c # 2005/03/18 19:44:00+01:00 tglx@tglx.tec.linutronix.de +4 -4 # Use the CONFIG_ options from KConfig instead of random symbols # # ChangeSet # 2005/03/18 19:39:56+01:00 tglx@tglx.tec.linutronix.de # MTD: NAND remove duplicated device ID # # Signed-off-by: Kyungmin Park # Signed-off-by: Thomas Gleixner # # drivers/mtd/nand/nand_ids.c # 2005/03/18 19:39:46+01:00 tglx@tglx.tec.linutronix.de +0 -2 # Remove duplicated Samsung NAND 512MiB 3,3V 8-bit device ID. # Correct device ID is defined in large page device section. # # ChangeSet # 2005/03/18 19:32:49+01:00 tglx@tglx.tec.linutronix.de # MTD: Samsung S3C2410 NAND driver sparse fixes and simplifications # # Signed-off-by: Ben Dooks # Signed-off-by: Thomas Gleixner # # drivers/mtd/nand/s3c2410.c # 2005/03/18 19:32:40+01:00 tglx@tglx.tec.linutronix.de +21 -113 # - Fix sparse errors due to lack of address-space markers # - Updated header comments # - Updated with tglx's suggestion to simplify the command invocation by # changing the address of the IO write area instead of having an extra # command function # # ChangeSet # 2005/03/18 19:12:47+01:00 tglx@tglx.tec.linutronix.de # MTD: Change mode on executable source file # # Signed-off-by: Thomas Gleixner # # drivers/mtd/nand/sharpsl.c # 2005/03/18 19:10:04+01:00 tglx@tglx.tec.linutronix.de +0 -0 # Change mode to -rw-rw-r-- # # ChangeSet # 2005/03/18 19:08:35+01:00 tglx@tglx.tec.linutronix.de # MTD: SharpSL NAND driver: update default partition size # # NAND SharpSL: Correct Poodle default partition size # # Signed-off-by: Richard Purdie # Signed-off-by: Thomas Gleixner # # drivers/mtd/nand/sharpsl.c # 2005/03/18 19:08:26+01:00 tglx@tglx.tec.linutronix.de +2 -2 # NAND SharpSL: Correct Poodle default partition size # diff -Nru a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig --- a/drivers/mtd/chips/Kconfig 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/chips/Kconfig 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ # drivers/mtd/chips/Kconfig -# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $ +# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $ menu "RAM/ROM/Flash chip drivers" depends on MTD!=n @@ -154,6 +154,31 @@ help If your flash chips are interleaved in eights - i.e. you have eight flash chips addressed by each bus cycle, then say 'Y'. + +config MTD_OTP + bool "Protection Registers aka one-time programmable (OTP) bits" + depends on MTD_CFI_ADV_OPTIONS + default n + help + This enables support for reading, writing and locking so called + "Protection Registers" present on some flash chips. + A subset of them are pre-programmed at the factory with a + unique set of values. The rest is user-programmable. + + The user-programmable Protection Registers contain one-time + programmable (OTP) bits; when programmed, register bits cannot be + erased. Each Protection Register can be accessed multiple times to + program individual bits, as long as the register remains unlocked. + + Each Protection Register has an associated Lock Register bit. When a + Lock Register bit is programmed, the associated Protection Register + can only be read; it can no longer be programmed. Additionally, + because the Lock Register bits themselves are OTP, when programmed, + Lock Register bits cannot be erased. Therefore, when a Protection + Register is locked, it cannot be unlocked. + + This feature should therefore be used with extreme care. Any mistake + in the programming of OTP bits will waste them. config MTD_CFI_INTELEXT tristate "Support for Intel/Sharp flash chips" diff -Nru a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c --- a/drivers/mtd/chips/amd_flash.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/chips/amd_flash.c 2005-05-11 20:59:08 -07:00 @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg * - * $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -67,7 +67,6 @@ #define AM29LV160DT 0x22C4 #define AM29LV160DB 0x2249 #define AM29BDS323D 0x22D1 -#define AM29BDS643D 0x227E /* Atmel */ #define AT49xV16x 0x00C0 @@ -616,17 +615,6 @@ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 }, { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 }, { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 }, - } - }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29BDS643D, - .name = "AMD AM29BDS643D", - .size = 0x00800000, - .numeraseregions = 3, - .regions = { - { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 }, - { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 }, - { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 }, } }, { .mfr_id = MANUFACTURER_ATMEL, 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 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/chips/cfi_cmdset_0001.c 2005-05-11 20:59:08 -07:00 @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.164 2004/11/16 18:29:00 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.170 2005/03/16 22:41:05 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -48,14 +48,20 @@ #define M50LPW080 0x002F static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_intelext_sync (struct mtd_info *); static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t); +static int cfi_intelext_get_fact_prot_info (struct mtd_info *, + struct otp_info *, size_t); +static int cfi_intelext_get_user_prot_info (struct mtd_info *, + struct otp_info *, size_t); static int cfi_intelext_suspend (struct mtd_info *); static void cfi_intelext_resume (struct mtd_info *); @@ -252,7 +258,8 @@ int nb_parts, i; /* Protection Register info */ - extra_size += (extp->NumProtectionFields - 1) * (4 + 6); + extra_size += (extp->NumProtectionFields - 1) * + sizeof(struct cfi_intelext_otpinfo); /* Burst Read info */ extra_size += 6; @@ -422,9 +429,13 @@ mtd->eraseregions[i].numblocks); } -#if 0 - mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; +#ifdef CONFIG_MTD_OTP mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg; + mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; + mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg; + mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg; + mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info; + mtd->get_user_prot_info = cfi_intelext_get_user_prot_info; #endif /* This function has the potential to distort the reality @@ -471,7 +482,8 @@ int offs, numregions, numparts, partshift, numvirtchips, i, j; /* Protection Register info */ - offs = (extp->NumProtectionFields - 1) * (4 + 6); + offs = (extp->NumProtectionFields - 1) * + sizeof(struct cfi_intelext_otpinfo); /* Burst Read info */ offs += 6; @@ -563,7 +575,7 @@ resettime: timeo = jiffies + HZ; retry: - if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) { + if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) { /* * OK. We have possibility for contension on the write/erase * operations which are global to the real chip and not per @@ -1176,111 +1188,11 @@ return ret; } -#if 0 -static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd, - loff_t from, size_t len, - size_t *retlen, - u_char *buf, - int base_offst, int reg_sz) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp = cfi->cmdset_priv; - struct flchip *chip; - int ofs_factor = cfi->interleave * cfi->device_type; - int count = len; - int chip_num, offst; - int ret; - - chip_num = ((unsigned int)from/reg_sz); - offst = from - (reg_sz*chip_num)+base_offst; - - while (count) { - /* Calculate which chip & protection register offset we need */ - - if (chip_num >= cfi->numchips) - goto out; - - chip = &cfi->chips[chip_num]; - - spin_lock(chip->mutex); - ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); - if (ret) { - spin_unlock(chip->mutex); - return (len-count)?:ret; - } - - xip_disable(map, chip, chip->start); - - if (chip->state != FL_JEDEC_QUERY) { - map_write(map, CMD(0x90), chip->start); - chip->state = FL_JEDEC_QUERY; - } - - while (count && ((offst-base_offst) < reg_sz)) { - *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); - buf++; - offst++; - count--; - } - - xip_enable(map, chip, chip->start); - put_chip(map, chip, chip->start); - spin_unlock(chip->mutex); - - /* Move on to the next chip */ - chip_num++; - offst = base_offst; - } - - out: - return len-count; -} - -static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp=cfi->cmdset_priv; - int base_offst,reg_sz; - - /* Check that we actually have some protection registers */ - if(!extp || !(extp->FeatureSupport&64)){ - printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); - return 0; - } - - base_offst=(1<FactProtRegSize); - reg_sz=(1<UserProtRegSize); - - return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz); -} - -static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp=cfi->cmdset_priv; - int base_offst,reg_sz; - - /* Check that we actually have some protection registers */ - if(!extp || !(extp->FeatureSupport&64)){ - printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); - return 0; - } - - base_offst=0; - reg_sz=(1<FactProtRegSize); - - return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz); -} -#endif - static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, - unsigned long adr, map_word datum) + unsigned long adr, map_word datum, int mode) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, status_OK; + map_word status, status_OK, write_cmd; unsigned long timeo; int z, ret=0; @@ -1288,9 +1200,14 @@ /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); + switch (mode) { + case FL_WRITING: write_cmd = CMD(0x40); break; + case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; + default: return -EINVAL; + } spin_lock(chip->mutex); - ret = get_chip(map, chip, adr, FL_WRITING); + ret = get_chip(map, chip, adr, mode); if (ret) { spin_unlock(chip->mutex); return ret; @@ -1299,9 +1216,9 @@ XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); ENABLE_VPP(map); xip_disable(map, chip, adr); - map_write(map, CMD(0x40), adr); + map_write(map, write_cmd, adr); map_write(map, datum, adr); - chip->state = FL_WRITING; + chip->state = mode; spin_unlock(chip->mutex); INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map)); @@ -1311,7 +1228,7 @@ timeo = jiffies + (HZ/2); z = 0; for (;;) { - if (chip->state != FL_WRITING) { + if (chip->state != mode) { /* Someone's suspended the write. Sleep */ DECLARE_WAITQUEUE(wait, current); @@ -1399,7 +1316,7 @@ datum = map_word_load_partial(map, datum, buf, gap, n); ret = do_write_oneword(map, &cfi->chips[chipnum], - bus_ofs, datum); + bus_ofs, datum, FL_WRITING); if (ret) return ret; @@ -1420,7 +1337,7 @@ map_word datum = map_word_load(map, buf); ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum); + ofs, datum, FL_WRITING); if (ret) return ret; @@ -1444,7 +1361,7 @@ datum = map_word_load_partial(map, datum, buf, 0, len); ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum); + ofs, datum, FL_WRITING); if (ret) return ret; @@ -1780,44 +1697,34 @@ /* check for lock bit */ if (map_word_bitsset(map, status, CMD(0x3a))) { - unsigned char chipstatus; + unsigned long chipstatus; /* Reset the error bits */ map_write(map, CMD(0x50), adr); map_write(map, CMD(0x70), adr); xip_enable(map, chip, adr); - chipstatus = status.x[0]; - if (!map_word_equal(map, status, CMD(chipstatus))) { - int i, w; - for (w=0; w> (cfi->device_type * 8); - } - } - printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n", - status.x[0], chipstatus); - } + chipstatus = MERGESTATUS(status); if ((chipstatus & 0x30) == 0x30) { - printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); + printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus); ret = -EIO; } else if (chipstatus & 0x02) { /* Protection bit set */ ret = -EROFS; } else if (chipstatus & 0x8) { /* Voltage */ - printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus); + printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus); ret = -EIO; } else if (chipstatus & 0x20) { if (retries--) { - printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus); + printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus); timeo = jiffies + HZ; put_chip(map, chip, adr); spin_unlock(chip->mutex); goto retry; } - printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus); + printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus); ret = -EIO; } } else { @@ -1882,6 +1789,7 @@ if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; + chip->oldstate = FL_READY; wake_up(&chip->wq); } spin_unlock(chip->mutex); @@ -2033,6 +1941,264 @@ return ret; } + +#ifdef CONFIG_MTD_OTP + +typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, + u_long data_offset, u_char *buf, u_int size, + u_long prot_offset, u_int groupno, u_int groupsize); + +static int __xipram +do_otp_read(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + struct cfi_private *cfi = map->fldrv_priv; + int ret; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + /* let's ensure we're not reading back cached data from array mode */ + if (map->inval_cache) + map->inval_cache(map, chip->start + offset, size); + + xip_disable(map, chip, chip->start); + if (chip->state != FL_JEDEC_QUERY) { + map_write(map, CMD(0x90), chip->start); + chip->state = FL_JEDEC_QUERY; + } + map_copy_from(map, buf, chip->start + offset, size); + xip_enable(map, chip, chip->start); + + /* then ensure we don't keep OTP data in the cache */ + if (map->inval_cache) + map->inval_cache(map, chip->start + offset, size); + + put_chip(map, chip, chip->start); + spin_unlock(chip->mutex); + return 0; +} + +static int +do_otp_write(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + int ret; + + while (size) { + unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1); + int gap = offset - bus_ofs; + int n = min_t(int, size, map_bankwidth(map)-gap); + map_word datum = map_word_ff(map); + + datum = map_word_load_partial(map, datum, buf, gap, n); + ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); + if (ret) + return ret; + + offset += n; + buf += n; + size -= n; + } + + return 0; +} + +static int +do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + struct cfi_private *cfi = map->fldrv_priv; + map_word datum; + + /* make sure area matches group boundaries */ + if (size != grpsz) + return -EXDEV; + + datum = map_word_ff(map); + datum = map_word_clr(map, datum, CMD(1 << grpno)); + return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE); +} + +static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, + otp_op_t action, int user_regs) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + struct cfi_pri_intelext *extp = cfi->cmdset_priv; + struct flchip *chip; + struct cfi_intelext_otpinfo *otp; + u_long devsize, reg_prot_offset, data_offset; + u_int chip_num, chip_step, field, reg_fact_size, reg_user_size; + u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups; + int ret; + + *retlen = 0; + + /* Check that we actually have some OTP registers */ + if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields) + return -ENODATA; + + /* we need real chips here not virtual ones */ + devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave; + chip_step = devsize >> cfi->chipshift; + + for (chip_num = 0; chip_num < cfi->numchips; chip_num += chip_step) { + chip = &cfi->chips[chip_num]; + otp = (struct cfi_intelext_otpinfo *)&extp->extra[0]; + + /* first OTP region */ + field = 0; + reg_prot_offset = extp->ProtRegAddr; + reg_fact_groups = 1; + reg_fact_size = 1 << extp->FactProtRegSize; + reg_user_groups = 1; + reg_user_size = 1 << extp->UserProtRegSize; + + while (len > 0) { + /* flash geometry fixup */ + data_offset = reg_prot_offset + 1; + data_offset *= cfi->interleave * cfi->device_type; + reg_prot_offset *= cfi->interleave * cfi->device_type; + reg_fact_size *= cfi->interleave; + reg_user_size *= cfi->interleave; + + if (user_regs) { + groups = reg_user_groups; + groupsize = reg_user_size; + /* skip over factory reg area */ + groupno = reg_fact_groups; + data_offset += reg_fact_groups * reg_fact_size; + } else { + groups = reg_fact_groups; + groupsize = reg_fact_size; + groupno = 0; + } + + while (len > 0 && groups > 0) { + if (!action) { + /* + * Special case: if action is NULL + * we fill buf with otp_info records. + */ + struct otp_info *otpinfo; + map_word lockword; + len -= sizeof(struct otp_info); + if (len <= 0) + return -ENOSPC; + ret = do_otp_read(map, chip, + reg_prot_offset, + (u_char *)&lockword, + map_bankwidth(map), + 0, 0, 0); + if (ret) + return ret; + otpinfo = (struct otp_info *)buf; + otpinfo->start = from; + otpinfo->length = groupsize; + otpinfo->locked = + !map_word_bitsset(map, lockword, + CMD(1 << groupno)); + from += groupsize; + buf += sizeof(*otpinfo); + *retlen += sizeof(*otpinfo); + } else if (from >= groupsize) { + from -= groupsize; + data_offset += groupsize; + } else { + int size = groupsize; + data_offset += from; + size -= from; + from = 0; + if (size > len) + size = len; + ret = action(map, chip, data_offset, + buf, size, reg_prot_offset, + groupno, groupsize); + if (ret < 0) + return ret; + buf += size; + len -= size; + *retlen += size; + data_offset += size; + } + groupno++; + groups--; + } + + /* next OTP region */ + if (++field == extp->NumProtectionFields) + break; + reg_prot_offset = otp->ProtRegAddr; + reg_fact_groups = otp->FactGroups; + reg_fact_size = 1 << otp->FactProtRegSize; + reg_user_groups = otp->UserGroups; + reg_user_size = 1 << otp->UserProtRegSize; + otp++; + } + } + + return 0; +} + +static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_read, 0); +} + +static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_read, 1); +} + +static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_write, 1); +} + +static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd, + loff_t from, size_t len) +{ + size_t retlen; + return cfi_intelext_otp_walk(mtd, from, len, &retlen, + NULL, do_otp_lock, 1); +} + +static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + size_t retlen; + int ret; + + ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0); + return ret ? : retlen; +} + +static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + size_t retlen; + int ret; + + ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1); + return ret ? : retlen; +} + +#endif static int cfi_intelext_suspend(struct mtd_info *mtd) { diff -Nru a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c --- a/drivers/mtd/chips/gen_probe.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/chips/gen_probe.c 2005-05-11 20:59:08 -07:00 @@ -2,7 +2,7 @@ * Routines common to all CFI-type probes. * (C) 2001-2003 Red Hat, Inc. * GPL'd - * $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $ + * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $ */ #include @@ -162,7 +162,7 @@ int max_chips = map_bankwidth(map); /* And minimum 1 */ int nr_chips, type; - for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) { + for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) { if (!cfi_interleave_supported(nr_chips)) continue; diff -Nru a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c --- a/drivers/mtd/chips/jedec_probe.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/chips/jedec_probe.c 2005-05-11 20:59:08 -07:00 @@ -1,7 +1,7 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $ + $Id: jedec_probe.c,v 1.65 2005/03/17 20:09:51 gleixner Exp $ See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) for the standard this probe goes back to. @@ -142,6 +142,7 @@ #define SST29LE512 0x003d #define SST39LF800 0x2781 #define SST39LF160 0x2782 +#define SST39VF1601 0x234b #define SST39LF512 0x00D4 #define SST39LF010 0x00D5 #define SST39LF020 0x00D6 @@ -1302,7 +1303,8 @@ .DevSize = SIZE_256KiB, .CmdSet = P_ID_SST_PAGE, .NumEraseRegions= 1, - .regions = {ERASEINFO(0x01000,64), + .regions = { + ERASEINFO(0x01000,64), } }, { .mfr_id = MANUFACTURER_SST, @@ -1314,7 +1316,8 @@ .DevSize = SIZE_256KiB, .CmdSet = P_ID_SST_PAGE, .NumEraseRegions= 1, - .regions = {ERASEINFO(0x01000,64), + .regions = { + ERASEINFO(0x01000,64), } }, { .mfr_id = MANUFACTURER_SST, @@ -1448,6 +1451,21 @@ ERASEINFO(0x1000,256), ERASEINFO(0x1000,256) } + }, { + .mfr_id = MANUFACTURER_SST, /* should be CFI */ + .dev_id = SST39VF1601, + .name = "SST 39VF1601", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ + [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x1000,256), + ERASEINFO(0x1000,256) + } }, { .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ @@ -1856,6 +1874,16 @@ case CFI_DEVICETYPE_X8: mfr = (__u8)finfo->mfr_id; id = (__u8)finfo->dev_id; + + /* bjd: it seems that if we do this, we can end up + * detecting 16bit flashes as an 8bit device, even though + * there aren't. + */ + if (finfo->dev_id > 0xff) { + DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n", + __func__); + goto match_done; + } break; case CFI_DEVICETYPE_X16: mfr = (__u16)finfo->mfr_id; diff -Nru a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c --- a/drivers/mtd/devices/block2mtd.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/devices/block2mtd.c 2005-05-11 20:59:08 -07:00 @@ -1,10 +1,9 @@ /* - * $Id: block2mtd.c,v 1.23 2005/01/05 17:05:46 dwmw2 Exp $ + * $Id: block2mtd.c,v 1.26 2005/03/17 19:48:19 gleixner Exp $ * * block2mtd.c - create an mtd from a block device * * Copyright (C) 2001,2002 Simon Evans - * Copyright (C) 2004 Gareth Bult * Copyright (C) 2004,2005 Jörn Engel * * Licence: GPL @@ -20,7 +19,7 @@ #include #include -#define VERSION "$Revision: 1.23 $" +#define VERSION "$Revision: 1.26 $" #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) @@ -89,7 +88,6 @@ static struct page* page_readahead(struct address_space *mapping, int index) { filler_t *filler = (filler_t*)mapping->a_ops->readpage; - //do_page_cache_readahead(mapping, index, XXX, 64); cache_readahead(mapping, index); return read_cache_page(mapping, index, filler, NULL); } @@ -157,7 +155,7 @@ struct block2mtd_dev *dev = mtd->priv; struct page *page; int index = from >> PAGE_SHIFT; - int offset = from & (PAGE_SHIFT-1); + int offset = from & (PAGE_SIZE-1); int cpylen; if (from > mtd->size) @@ -370,16 +368,16 @@ } -static int parse_num32(u32 *num32, const char *token) +static int parse_num(size_t *num, const char *token) { char *endp; - unsigned long n; + size_t n; - n = ustrtoul(token, &endp, 0); + n = (size_t) ustrtoul(token, &endp, 0); if (*endp) return -EINVAL; - *num32 = n; + *num = n; return 0; } @@ -422,7 +420,7 @@ char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */ char *token[2]; char *name; - u32 erase_size = PAGE_SIZE; + size_t erase_size = PAGE_SIZE; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) @@ -449,7 +447,7 @@ return 0; if (token[1]) { - ret = parse_num32(&erase_size, token[1]); + ret = parse_num(&erase_size, token[1]); if (ret) parse_err("illegal erase size"); } diff -Nru a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c --- a/drivers/mtd/devices/phram.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/devices/phram.c 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ /** - * $Id: phram.c,v 1.11 2005/01/05 18:05:13 dwmw2 Exp $ + * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $ * * Copyright (c) ???? Jochen Schäuble * Copyright (c) 2003-2004 Jörn Engel @@ -15,9 +15,7 @@ * * Example: * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi - * */ - #include #include #include @@ -36,7 +34,6 @@ static LIST_HEAD(phram_list); - static int phram_erase(struct mtd_info *mtd, struct erase_info *instr) { u_char *start = mtd->priv; @@ -71,7 +68,8 @@ return 0; } -static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) +static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, + size_t len) { } @@ -80,8 +78,11 @@ { u_char *start = mtd->priv; - if (from + len > mtd->size) + if (from >= mtd->size) return -EINVAL; + + if (len > mtd->size - from) + len = mtd->size - from; memcpy(buf, start + from, len); @@ -94,8 +95,11 @@ { u_char *start = mtd->priv; - if (to + len > mtd->size) + if (to >= mtd->size) return -EINVAL; + + if (len > mtd->size - to) + len = mtd->size - to; memcpy(start + to, buf, len); @@ -107,9 +111,9 @@ static void unregister_devices(void) { - struct phram_mtd_list *this; + struct phram_mtd_list *this, *safe; - list_for_each_entry(this, &phram_list, list) { + list_for_each_entry_safe(this, safe, &phram_list, list) { del_mtd_device(&this->mtd); iounmap(this->mtd.priv); kfree(this); @@ -145,7 +149,7 @@ new->mtd.write = phram_write; new->mtd.owner = THIS_MODULE; new->mtd.type = MTD_RAM; - new->mtd.erasesize = 0; + new->mtd.erasesize = PAGE_SIZE; ret = -EAGAIN; if (add_mtd_device(&new->mtd)) { @@ -214,6 +218,15 @@ return 0; } + +static inline void kill_final_newline(char *str) +{ + char *newline = strrchr(str, '\n'); + if (newline && !newline[1]) + *newline = 0; +} + + #define parse_err(fmt, args...) do { \ ERROR(fmt , ## args); \ return 0; \ @@ -232,6 +245,7 @@ parse_err("parameter too long\n"); strcpy(str, val); + kill_final_newline(str); for (i=0; i<3; i++) token[i] = strsep(&str, ","); diff -Nru a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c --- a/drivers/mtd/devices/slram.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/devices/slram.c 2005-05-11 20:59:08 -07:00 @@ -1,6 +1,6 @@ /*====================================================================== - $Id: slram.c,v 1.33 2005/01/05 18:05:13 dwmw2 Exp $ + $Id: slram.c,v 1.35 2005/03/17 19:44:27 gleixner Exp $ This driver provides a method to access memory not used by the kernel itself (i.e. if the kernel commandline mem=xxx is used). To actually @@ -50,6 +50,7 @@ #include #define SLRAM_MAX_DEVICES_PARAMS 6 /* 3 parameters / device */ +#define SLRAM_BLK_SZ 0x4000 #define T(fmt, args...) printk(KERN_DEBUG fmt, ## args) #define E(fmt, args...) printk(KERN_NOTICE fmt, ## args) @@ -108,6 +109,9 @@ { slram_priv_t *priv = mtd->priv; + if (from + len > mtd->size) + return -EINVAL; + *mtdbuf = priv->start + from; *retlen = len; return(0); @@ -121,7 +125,13 @@ size_t *retlen, u_char *buf) { slram_priv_t *priv = mtd->priv; - + + if (from > mtd->size) + return -EINVAL; + + if (from + len > mtd->size) + len = mtd->size - from; + memcpy(buf, priv->start + from, len); *retlen = len; @@ -133,6 +143,9 @@ { slram_priv_t *priv = mtd->priv; + if (to + len > mtd->size) + return -EINVAL; + memcpy(priv->start + to, buf, len); *retlen = len; @@ -188,7 +201,7 @@ (*curmtd)->mtdinfo->name = name; (*curmtd)->mtdinfo->size = length; (*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS | - MTD_WRITEB_WRITEABLE | MTD_VOLATILE; + MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM; (*curmtd)->mtdinfo->erase = slram_erase; (*curmtd)->mtdinfo->point = slram_point; (*curmtd)->mtdinfo->unpoint = slram_unpoint; @@ -196,7 +209,7 @@ (*curmtd)->mtdinfo->write = slram_write; (*curmtd)->mtdinfo->owner = THIS_MODULE; (*curmtd)->mtdinfo->type = MTD_RAM; - (*curmtd)->mtdinfo->erasesize = 0x0; + (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ; if (add_mtd_device((*curmtd)->mtdinfo)) { E("slram: Failed to register new device\n"); @@ -261,7 +274,7 @@ } T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n", devname, devstart, devlength); - if ((devstart < 0) || (devlength < 0)) { + if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) { E("slram: Illegal start / length parameter.\n"); return(-EINVAL); } diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c --- a/drivers/mtd/ftl.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/ftl.c 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $ + * $Id: ftl.c,v 1.56 2005/03/17 19:54:36 gleixner Exp $ * * Fixes: Arnaldo Carvalho de Melo * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -357,6 +357,7 @@ if (!erase) return -ENOMEM; + erase->mtd = part->mbd.mtd; erase->callback = ftl_erase_callback; erase->addr = xfer->Offset; erase->len = 1 << part->header.EraseUnitSize; @@ -1096,7 +1097,7 @@ int init_ftl(void) { - DEBUG(0, "$Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $\n"); + DEBUG(0, "$Id: ftl.c,v 1.56 2005/03/17 19:54:36 gleixner Exp $\n"); return register_mtd_blktrans(&ftl_tr); } diff -Nru a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig --- a/drivers/mtd/maps/Kconfig 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/Kconfig 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.42 2005/01/05 16:59:50 dwmw2 Exp $ +# $Id: Kconfig,v 1.49 2005/03/17 19:59:47 gleixner Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -122,16 +122,6 @@ More info at . -config MTD_ELAN_104NC - tristate "CFI Flash device mapped on Arcom ELAN-104NC" - depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS - help - This provides a driver for the on-board flash of the Arcom Control - System's ELAN-104NC development board. By default the flash - is split into 3 partitions which are accessed as separate MTD - devices. This board utilizes Intel StrataFlash. More info at - . - config MTD_LUBBOCK tristate "CFI Flash device mapped on Intel Lubbock XScale eval board" depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS @@ -213,74 +203,11 @@ help Support for flash chips on NETtel/SecureEdge/SnapGear boards. -config MTD_PB1XXX - tristate "Flash devices on Alchemy PB1xxx boards" - depends on MIPS && ( MIPS_PB1000 || MIPS_PB1100 || MIPS_PB1500 ) - help - Flash memory access on Alchemy Pb1000/Pb1100/Pb1500 boards - -config MTD_PB1XXX_BOOT - bool "PB1x00 boot flash device" - depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 ) - help - Use the first of the two 32MiB flash banks on Pb1100/Pb1500 board. - You can say 'Y' to both this and 'MTD_PB1XXX_USER' below, to use - both banks. - -config MTD_PB1XXX_USER - bool "PB1x00 user flash device" - depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 ) - default y if MTD_PB1XX_BOOT = n - help - Use the second of the two 32MiB flash banks on Pb1100/Pb1500 board. - You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use - both banks. - -config MTD_PB1550 - tristate "Flash devices on Alchemy PB1550 board" - depends on MIPS && MIPS_PB1550 - help - Flash memory access on Alchemy Pb1550 board - -config MTD_PB1550_BOOT - bool "PB1550 boot flash device" - depends on MTD_PB1550 - help - Use the first of the two 64MiB flash banks on Pb1550 board. - You can say 'Y' to both this and 'MTD_PB1550_USER' below, to use - both banks. - -config MTD_PB1550_USER - bool "PB1550 user flash device" - depends on MTD_PB1550 - default y if MTD_PB1550_BOOT = n - help - Use the second of the two 64MiB flash banks on Pb1550 board. - You can say 'Y' to both this and 'MTD_PB1550_BOOT' above, to use - both banks. - -config MTD_DB1550 - tristate "Flash devices on Alchemy DB1550 board" - depends on MIPS && MIPS_DB1550 - help - Flash memory access on Alchemy Db1550 board - -config MTD_DB1550_BOOT - bool "DB1550 boot flash device" - depends on MTD_DB1550 - help - Use the first of the two 64MiB flash banks on Db1550 board. - You can say 'Y' to both this and 'MTD_DB1550_USER' below, to use - both banks. - -config MTD_DB1550_USER - bool "DB1550 user flash device" - depends on MTD_DB1550 - default y if MTD_DB1550_BOOT = n - help - Use the second of the two 64MiB flash banks on Db1550 board. - You can say 'Y' to both this and 'MTD_DB1550_BOOT' above, to use - both banks. +config MTD_ALCHEMY + tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support' + depends on MIPS && SOC_AU1X00 + help + Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards config MTD_DILNETPC tristate "CFI Flash device mapped on DIL/Net PC" @@ -637,13 +564,14 @@ Map driver for Dy-4 SVME/DMV-182 board. config MTD_BAST - tristate "Map driver for Simtec BAST (EB2410ITX)" - depends on ARCH_BAST + tristate "Map driver for Simtec BAST (EB2410ITX) or Thorcom VR1000" + depends on ARCH_BAST || MACH_VR1000 select MTD_PARTITIONS select MTD_MAP_BANK_WIDTH_16 select MTD_JEDECPROBE help - Map driver for NOR flash on the Simtec BAST (EB2410ITX). + Map driver for NOR flash on the Simtec BAST (EB2410ITX), or the + Thorcom VR1000 Note, this driver *cannot* over-ride the WP link on the board, or currently detect the state of the link. @@ -658,6 +586,16 @@ depends on MTD && ARCH_PXA help This enables access to the flash chip on the Sharp SL Series of PDAs. + +config MTD_PLATRAM + tristate "Map driver for platform device RAM (mtd-ram)" + depends on MTD + select MTD_RAM + help + Map driver for RAM areas described via the platform device + system. + + This selection automatically selects the map_ram driver. endmenu diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile --- a/drivers/mtd/maps/Makefile 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/Makefile 2005-05-11 20:59:08 -07:00 @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.23 2005/01/05 17:06:36 dwmw2 Exp $ +# $Id: Makefile.common,v 1.28 2005/03/17 14:16:13 joern Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o -obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_L440GX) += l440gx.o @@ -44,10 +43,7 @@ obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o -obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o -obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o -obj-$(CONFIG_MTD_PB1550) += pb1550-flash.o -obj-$(CONFIG_MTD_DB1550) += db1550-flash.o +obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o obj-$(CONFIG_MTD_LASAT) += lasat.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o obj-$(CONFIG_MTD_EDB7312) += edb7312.o @@ -71,3 +67,4 @@ obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o +obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o diff -Nru a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/maps/alchemy-flash.c 2005-05-11 20:59:08 -07:00 @@ -0,0 +1,192 @@ +/* + * Flash memory access on AMD Alchemy evaluation boards + * + * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $ + * + * (C) 2003, 2004 Pete Popov + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef CONFIG_MIPS_PB1000 +#define BOARD_MAP_NAME "Pb1000 Flash" +#define BOARD_FLASH_SIZE 0x00800000 /* 8MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_PB1500 +#define BOARD_MAP_NAME "Pb1500 Flash" +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_PB1100 +#define BOARD_MAP_NAME "Pb1100 Flash" +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_PB1550 +#define BOARD_MAP_NAME "Pb1550 Flash" +#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_PB1200 +#define BOARD_MAP_NAME "Pb1200 Flash" +#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */ +#define BOARD_FLASH_WIDTH 2 /* 16-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1000 +#define BOARD_MAP_NAME "Db1000 Flash" +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1500 +#define BOARD_MAP_NAME "Db1500 Flash" +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1100 +#define BOARD_MAP_NAME "Db1100 Flash" +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1550 +#define BOARD_MAP_NAME "Db1550 Flash" +#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#endif + +#ifdef CONFIG_MIPS_DB1200 +#define BOARD_MAP_NAME "Db1200 Flash" +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 2 /* 16-bits */ +#endif + +#ifdef CONFIG_MIPS_HYDROGEN3 +#define BOARD_MAP_NAME "Hydrogen3 Flash" +#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#define USE_LOCAL_ACCESSORS /* why? */ +#endif + +#ifdef CONFIG_MIPS_BOSPORUS +#define BOARD_MAP_NAME "Bosporus Flash" +#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */ +#define BOARD_FLASH_WIDTH 2 /* 16-bits */ +#endif + +#ifdef CONFIG_MIPS_MIRAGE +#define BOARD_MAP_NAME "Mirage Flash" +#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */ +#define BOARD_FLASH_WIDTH 4 /* 32-bits */ +#define USE_LOCAL_ACCESSORS /* why? */ +#endif + +static struct map_info alchemy_map = { + .name = BOARD_MAP_NAME, +}; + +static struct mtd_partition alchemy_partitions[] = { + { + .name = "User FS", + .size = BOARD_FLASH_SIZE - 0x00400000, + .offset = 0x0000000 + },{ + .name = "YAMON", + .size = 0x0100000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw kernel", + .size = (0x300000 - 0x40000), /* last 256KB is yamon env */ + .offset = MTDPART_OFS_APPEND, + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *mymtd; + +int __init alchemy_mtd_init(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + unsigned long window_addr; + unsigned long window_size; + + /* Default flash buswidth */ + alchemy_map.bankwidth = BOARD_FLASH_WIDTH; + + window_addr = 0x20000000 - BOARD_FLASH_SIZE; + window_size = BOARD_FLASH_SIZE; +#ifdef CONFIG_MIPS_MIRAGE_WHY + /* Boot ROM flash bank only; no user bank */ + window_addr = 0x1C000000; + window_size = 0x04000000; + /* USERFS from 0x1C00 0000 to 0x1FC00000 */ + alchemy_partitions[0].size = 0x03C00000; +#endif + + /* + * Static partition definition selection + */ + parts = alchemy_partitions; + nb_parts = NB_OF(alchemy_partitions); + alchemy_map.size = window_size; + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n", + alchemy_map.bankwidth*8); + alchemy_map.virt = ioremap(window_addr, window_size); + mymtd = do_map_probe("cfi_probe", &alchemy_map); + if (!mymtd) { + iounmap(alchemy_map.virt); + return -ENXIO; + } + mymtd->owner = THIS_MODULE; + + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit alchemy_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + iounmap(alchemy_map.virt); + } +} + +module_init(alchemy_mtd_init); +module_exit(alchemy_mtd_cleanup); + +MODULE_AUTHOR("Embedded Alley Solutions, Inc"); +MODULE_DESCRIPTION(BOARD_MAP_NAME " MTD driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c --- a/drivers/mtd/maps/amd76xrom.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/amd76xrom.c 2005-05-11 20:59:08 -07:00 @@ -2,7 +2,7 @@ * amd76xrom.c * * Normal mappings of chips in physical memory - * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $ + * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $ */ #include @@ -314,7 +314,7 @@ } return -ENXIO; #if 0 - return pci_module_init(&amd76xrom_driver); + return pci_register_driver(&amd76xrom_driver); #endif } diff -Nru a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c --- a/drivers/mtd/maps/bast-flash.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/bast-flash.c 2005-05-11 20:59:08 -07:00 @@ -1,14 +1,15 @@ /* linux/drivers/mtd/maps/bast_flash.c * - * Copyright (c) 2004 Simtec Electronics - * Ben Dooks + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks * * Simtec Bast (EB2410ITX) NOR MTD Mapping driver * * Changelog: * 20-Sep-2004 BJD Initial version + * 17-Jan-2005 BJD Add whole device if no partitions found * - * $Id: bast-flash.c,v 1.1 2004/09/21 14:29:04 bjd Exp $ + * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,9 +47,9 @@ #include #ifdef CONFIG_MTD_BAST_MAXSIZE -#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * (1024*1024)) +#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M) #else -#define AREA_MAXSIZE (32*1024*1024) +#define AREA_MAXSIZE (32 * SZ_1M) #endif #define PFX "bast-flash: " @@ -189,6 +190,8 @@ err = add_mtd_partitions(info->mtd, info->partitions, err); if (err) printk(KERN_ERR PFX "cannot add/parse partitions\n"); + } else { + err = add_mtd_device(info->mtd); } if (err == 0) diff -Nru a/drivers/mtd/maps/db1550-flash.c b/drivers/mtd/maps/db1550-flash.c --- a/drivers/mtd/maps/db1550-flash.c 2005-05-11 20:59:08 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,187 +0,0 @@ -/* - * Flash memory access on Alchemy Db1550 board - * - * $Id: db1550-flash.c,v 1.7 2004/11/04 13:24:14 gleixner Exp $ - * - * (C) 2004 Embedded Edge, LLC, based on db1550-flash.c: - * (C) 2003, 2004 Pete Popov - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef DEBUG_RW -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static unsigned long window_addr; -static unsigned long window_size; - - -static struct map_info db1550_map = { - .name = "Db1550 flash", -}; - -static unsigned char flash_bankwidth = 4; - -/* - * Support only 64MB NOR Flash parts - */ - -#if defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER) -#define DB1550_BOTH_BANKS -#elif defined(CONFIG_MTD_DB1550_BOOT) && !defined(CONFIG_MTD_DB1550_USER) -#define DB1550_BOOT_ONLY -#elif !defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER) -#define DB1550_USER_ONLY -#endif - -#ifdef DB1550_BOTH_BANKS -/* both banks will be used. Combine the first bank and the first - * part of the second bank together into a single jffs/jffs2 - * partition. - */ -static struct mtd_partition db1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash - * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash - */ - { - .name = "User FS", - .size = (0x1FC00000 - 0x18000000), - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000 - 0x40000), /* last 256KB is yamon env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(DB1550_BOOT_ONLY) -static struct mtd_partition db1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash - */ - { - .name = "User FS", - .size = 0x03c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000-0x40000), /* last 256KB is yamon env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(DB1550_USER_ONLY) -static struct mtd_partition db1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash - */ - { - .name = "User FS", - .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */ - .offset = 0x0000000 - },{ - .name = "raw kernel", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; -#else -#error MTD_DB1550 define combo error /* should never happen */ -#endif - -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -static struct mtd_info *mymtd; - -/* - * Probe the flash density and setup window address and size - * based on user CONFIG options. There are times when we don't - * want the MTD driver to be probing the boot or user flash, - * so having the option to enable only one bank is important. - */ -int setup_flash_params(void) -{ -#if defined(DB1550_BOTH_BANKS) - window_addr = 0x18000000; - window_size = 0x8000000; -#elif defined(DB1550_BOOT_ONLY) - window_addr = 0x1C000000; - window_size = 0x4000000; -#else /* USER ONLY */ - window_addr = 0x18000000; - window_size = 0x4000000; -#endif - return 0; -} - -int __init db1550_mtd_init(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - - /* Default flash bankwidth */ - db1550_map.bankwidth = flash_bankwidth; - - if (setup_flash_params()) - return -ENXIO; - - /* - * Static partition definition selection - */ - parts = db1550_partitions; - nb_parts = NB_OF(db1550_partitions); - db1550_map.size = window_size; - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Db1550 flash: probing %d-bit flash bus\n", - db1550_map.bankwidth*8); - db1550_map.virt = ioremap(window_addr, window_size); - mymtd = do_map_probe("cfi_probe", &db1550_map); - if (!mymtd) return -ENXIO; - mymtd->owner = THIS_MODULE; - - add_mtd_partitions(mymtd, parts, nb_parts); - return 0; -} - -static void __exit db1550_mtd_cleanup(void) -{ - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - iounmap((void *) db1550_map.virt); - } -} - -module_init(db1550_mtd_init); -module_exit(db1550_mtd_cleanup); - -MODULE_AUTHOR("Embedded Edge, LLC"); -MODULE_DESCRIPTION("Db1550 mtd map driver"); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/db1x00-flash.c b/drivers/mtd/maps/db1x00-flash.c --- a/drivers/mtd/maps/db1x00-flash.c 2005-05-11 20:59:08 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,226 +0,0 @@ -/* - * Flash memory access on Alchemy Db1xxx boards - * - * $Id: db1x00-flash.c,v 1.6 2004/11/04 13:24:14 gleixner Exp $ - * - * (C) 2003 Pete Popov - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef DEBUG_RW -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -/* MTD CONFIG OPTIONS */ -#if defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER) -#define DB1X00_BOTH_BANKS -#elif defined(CONFIG_MTD_DB1X00_BOOT) && !defined(CONFIG_MTD_DB1X00_USER) -#define DB1X00_BOOT_ONLY -#elif !defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER) -#define DB1X00_USER_ONLY -#endif - -static unsigned long window_addr; -static unsigned long window_size; -static unsigned long flash_size; - -static unsigned short *bcsr = (unsigned short *)0xAE000000; -static unsigned char flash_bankwidth = 4; - -/* - * The Db1x boards support different flash densities. We setup - * the mtd_partition structures below for default of 64Mbit - * flash densities, and override the partitions sizes, if - * necessary, after we check the board status register. - */ - -#ifdef DB1X00_BOTH_BANKS -/* both banks will be used. Combine the first bank and the first - * part of the second bank together into a single jffs/jffs2 - * partition. - */ -static struct mtd_partition db1x00_partitions[] = { - { - .name = "User FS", - .size = 0x1c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000-0x40000), /* last 256KB is env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(DB1X00_BOOT_ONLY) -static struct mtd_partition db1x00_partitions[] = { - { - .name = "User FS", - .size = 0x00c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000-0x40000), /* last 256KB is env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(DB1X00_USER_ONLY) -static struct mtd_partition db1x00_partitions[] = { - { - .name = "User FS", - .size = 0x0e00000, - .offset = 0x0000000 - },{ - .name = "raw kernel", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; -#else -#error MTD_DB1X00 define combo error /* should never happen */ -#endif -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -#define NAME "Db1x00 Linux Flash" - -static struct map_info db1xxx_mtd_map = { - .name = NAME, -}; - -static struct mtd_partition *parsed_parts; -static struct mtd_info *db1xxx_mtd; - -/* - * Probe the flash density and setup window address and size - * based on user CONFIG options. There are times when we don't - * want the MTD driver to be probing the boot or user flash, - * so having the option to enable only one bank is important. - */ -int setup_flash_params(void) -{ - switch ((bcsr[2] >> 14) & 0x3) { - case 0: /* 64Mbit devices */ - flash_size = 0x800000; /* 8MB per part */ -#if defined(DB1X00_BOTH_BANKS) - window_addr = 0x1E000000; - window_size = 0x2000000; -#elif defined(DB1X00_BOOT_ONLY) - window_addr = 0x1F000000; - window_size = 0x1000000; -#else /* USER ONLY */ - window_addr = 0x1E000000; - window_size = 0x1000000; -#endif - break; - case 1: - /* 128 Mbit devices */ - flash_size = 0x1000000; /* 16MB per part */ -#if defined(DB1X00_BOTH_BANKS) - window_addr = 0x1C000000; - window_size = 0x4000000; - /* USERFS from 0x1C00 0000 to 0x1FC0 0000 */ - db1x00_partitions[0].size = 0x3C00000; -#elif defined(DB1X00_BOOT_ONLY) - window_addr = 0x1E000000; - window_size = 0x2000000; - /* USERFS from 0x1E00 0000 to 0x1FC0 0000 */ - db1x00_partitions[0].size = 0x1C00000; -#else /* USER ONLY */ - window_addr = 0x1C000000; - window_size = 0x2000000; - /* USERFS from 0x1C00 0000 to 0x1DE00000 */ - db1x00_partitions[0].size = 0x1DE0000; -#endif - break; - case 2: - /* 256 Mbit devices */ - flash_size = 0x4000000; /* 64MB per part */ -#if defined(DB1X00_BOTH_BANKS) - return 1; -#elif defined(DB1X00_BOOT_ONLY) - /* Boot ROM flash bank only; no user bank */ - window_addr = 0x1C000000; - window_size = 0x4000000; - /* USERFS from 0x1C00 0000 to 0x1FC00000 */ - db1x00_partitions[0].size = 0x3C00000; -#else /* USER ONLY */ - return 1; -#endif - break; - default: - return 1; - } - db1xxx_mtd_map.size = window_size; - db1xxx_mtd_map.bankwidth = flash_bankwidth; - db1xxx_mtd_map.phys = window_addr; - db1xxx_mtd_map.bankwidth = flash_bankwidth; - return 0; -} - -int __init db1x00_mtd_init(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - - if (setup_flash_params()) - return -ENXIO; - - /* - * Static partition definition selection - */ - parts = db1x00_partitions; - nb_parts = NB_OF(db1x00_partitions); - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n", - db1xxx_mtd_map.bankwidth*8); - db1xxx_mtd_map.virt = ioremap(window_addr, window_size); - db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map); - if (!db1xxx_mtd) return -ENXIO; - db1xxx_mtd->owner = THIS_MODULE; - - add_mtd_partitions(db1xxx_mtd, parts, nb_parts); - return 0; -} - -static void __exit db1x00_mtd_cleanup(void) -{ - if (db1xxx_mtd) { - del_mtd_partitions(db1xxx_mtd); - map_destroy(db1xxx_mtd); - if (parsed_parts) - kfree(parsed_parts); - } -} - -module_init(db1x00_mtd_init); -module_exit(db1x00_mtd_cleanup); - -MODULE_AUTHOR("Pete Popov"); -MODULE_DESCRIPTION("Db1x00 mtd map driver"); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c --- a/drivers/mtd/maps/elan-104nc.c 2005-05-11 20:59:08 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,228 +0,0 @@ -/* elan-104nc.c -- MTD map driver for Arcom Control Systems ELAN-104NC - - Copyright (C) 2000 Arcom Control System Ltd - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - - $Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $ - -The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 -mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. - -The flash is accessed as follows: - - 32 kbyte memory window at 0xb0000-0xb7fff - - 16 bit I/O port (0x22) for some sort of paging. - -The single flash device is divided into 3 partition which appear as separate -MTD devices. - -Linux thinks that the I/O port is used by the PIC and hence check_region() will -always fail. So we don't do it. I just hope it doesn't break anything. -*/ -#include -#include -#include -#include -#include - -#include -#include -#include - -#define WINDOW_START 0xb0000 -/* Number of bits in offset. */ -#define WINDOW_SHIFT 15 -#define WINDOW_LENGTH (1 << WINDOW_SHIFT) -/* The bits for the offset into the window. */ -#define WINDOW_MASK (WINDOW_LENGTH-1) -#define PAGE_IO 0x22 -#define PAGE_IO_SIZE 2 - -static volatile int page_in_window = -1; // Current page in window. -static void __iomem *iomapadr; -static DEFINE_SPINLOCK(elan_104nc_spin); - -/* partition_info gives details on the logical partitions that the split the - * single flash device into. If the size if zero we use up to the end of the - * device. */ -static struct mtd_partition partition_info[]={ - { .name = "ELAN-104NC flash boot partition", - .offset = 0, - .size = 640*1024 }, - { .name = "ELAN-104NC flash partition 1", - .offset = 640*1024, - .size = 896*1024 }, - { .name = "ELAN-104NC flash partition 2", - .offset = (640+896)*1024 } -}; -#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) - -/* - * If no idea what is going on here. This is taken from the FlashFX stuff. - */ -#define ROMCS 1 - -static inline void elan_104nc_setup(void) -{ - u16 t; - - outw( 0x0023 + ROMCS*2, PAGE_IO ); - t=inb( PAGE_IO+1 ); - - t=(t & 0xf9) | 0x04; - - outw( ((0x0023 + ROMCS*2) | (t << 8)), PAGE_IO ); -} - -static inline void elan_104nc_page(struct map_info *map, unsigned long ofs) -{ - unsigned long page = ofs >> WINDOW_SHIFT; - - if( page!=page_in_window ) { - int cmd1; - int cmd2; - - cmd1=(page & 0x700) + 0x0833 + ROMCS*0x4000; - cmd2=((page & 0xff) << 8) + 0x0032; - - outw( cmd1, PAGE_IO ); - outw( cmd2, PAGE_IO ); - - page_in_window = page; - } -} - - -static map_word elan_104nc_read16(struct map_info *map, unsigned long ofs) -{ - map_word ret; - spin_lock(&elan_104nc_spin); - elan_104nc_page(map, ofs); - ret.x[0] = readw(iomapadr + (ofs & WINDOW_MASK)); - spin_unlock(&elan_104nc_spin); - return ret; -} - -static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - while (len) { - unsigned long thislen = len; - if (len > (WINDOW_LENGTH - (from & WINDOW_MASK))) - thislen = WINDOW_LENGTH-(from & WINDOW_MASK); - - spin_lock(&elan_104nc_spin); - elan_104nc_page(map, from); - memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen); - spin_unlock(&elan_104nc_spin); - to += thislen; - from += thislen; - len -= thislen; - } -} - -static void elan_104nc_write16(struct map_info *map, map_word d, unsigned long adr) -{ - spin_lock(&elan_104nc_spin); - elan_104nc_page(map, adr); - writew(d.x[0], iomapadr + (adr & WINDOW_MASK)); - spin_unlock(&elan_104nc_spin); -} - -static void elan_104nc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - while(len) { - unsigned long thislen = len; - if (len > (WINDOW_LENGTH - (to & WINDOW_MASK))) - thislen = WINDOW_LENGTH-(to & WINDOW_MASK); - - spin_lock(&elan_104nc_spin); - elan_104nc_page(map, to); - memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen); - spin_unlock(&elan_104nc_spin); - to += thislen; - from += thislen; - len -= thislen; - } -} - -static struct map_info elan_104nc_map = { - .name = "ELAN-104NC flash", - .phys = NO_XIP, - .size = 8*1024*1024, /* this must be set to a maximum possible amount - of flash so the cfi probe routines find all - the chips */ - .bankwidth = 2, - .read = elan_104nc_read16, - .copy_from = elan_104nc_copy_from, - .write = elan_104nc_write16, - .copy_to = elan_104nc_copy_to -}; - -/* MTD device for all of the flash. */ -static struct mtd_info *all_mtd; - -static void cleanup_elan_104nc(void) -{ - if( all_mtd ) { - del_mtd_partitions( all_mtd ); - map_destroy( all_mtd ); - } - - iounmap(iomapadr); -} - -static int __init init_elan_104nc(void) -{ - /* Urg! We use I/O port 0x22 without request_region()ing it, - because it's already allocated to the PIC. */ - - iomapadr = ioremap(WINDOW_START, WINDOW_LENGTH); - if (!iomapadr) { - printk( KERN_ERR"%s: failed to ioremap memory region\n", - elan_104nc_map.name ); - return -EIO; - } - - printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", - elan_104nc_map.name, - PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, - WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 ); - - elan_104nc_setup(); - - /* Probe for chip. */ - all_mtd = do_map_probe("cfi_probe", &elan_104nc_map ); - if( !all_mtd ) { - cleanup_elan_104nc(); - return -ENXIO; - } - - all_mtd->owner = THIS_MODULE; - - /* Create MTD devices for each partition. */ - add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS ); - - return 0; -} - -module_init(init_elan_104nc); -module_exit(cleanup_elan_104nc); - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Arcom Control Systems Ltd."); -MODULE_DESCRIPTION("MTD map driver for Arcom Control Systems ELAN-104NC"); diff -Nru a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c --- a/drivers/mtd/maps/ichxrom.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/ichxrom.c 2005-05-11 20:59:08 -07:00 @@ -2,7 +2,7 @@ * ichxrom.c * * Normal mappings of chips in physical memory - * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $ + * $Id: ichxrom.c,v 1.17 2005/03/18 14:04:35 gleixner Exp $ */ #include @@ -366,7 +366,7 @@ } return -ENXIO; #if 0 - return pci_module_init(&ichxrom_driver); + return pci_register_driver(&ichxrom_driver); #endif } diff -Nru a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c --- a/drivers/mtd/maps/ixp2000.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/ixp2000.c 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ /* - * $Id: ixp2000.c,v 1.5 2004/11/16 17:15:48 dsaxena Exp $ + * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $ * * drivers/mtd/maps/ixp2000.c * @@ -215,11 +215,6 @@ err = -EIO; goto Error; } - - /* - * Setup read mode for FLASH - */ - *IXP2000_SLOWPORT_FRM = 1; #if defined(__ARMEB__) /* diff -Nru a/drivers/mtd/maps/pb1550-flash.c b/drivers/mtd/maps/pb1550-flash.c --- a/drivers/mtd/maps/pb1550-flash.c 2005-05-11 20:59:08 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,203 +0,0 @@ -/* - * Flash memory access on Alchemy Pb1550 board - * - * $Id: pb1550-flash.c,v 1.6 2004/11/04 13:24:15 gleixner Exp $ - * - * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c: - * (C) 2003 Pete Popov - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#ifdef DEBUG_RW -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -static unsigned long window_addr; -static unsigned long window_size; - - -static struct map_info pb1550_map = { - .name = "Pb1550 flash", -}; - -static unsigned char flash_bankwidth = 4; - -/* - * Support only 64MB NOR Flash parts - */ - -#ifdef PB1550_BOTH_BANKS -/* both banks will be used. Combine the first bank and the first - * part of the second bank together into a single jffs/jffs2 - * partition. - */ -static struct mtd_partition pb1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash - * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash - */ - { - .name = "User FS", - .size = (0x1FC00000 - 0x18000000), - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000 - 0x40000), /* last 256KB is yamon env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(PB1550_BOOT_ONLY) -static struct mtd_partition pb1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash - */ - { - .name = "User FS", - .size = 0x03c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = MTDPART_OFS_APPEND, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = (0x300000-0x40000), /* last 256KB is yamon env */ - .offset = MTDPART_OFS_APPEND, - } -}; -#elif defined(PB1550_USER_ONLY) -static struct mtd_partition pb1550_partitions[] = { - /* assume boot[2:0]:swap is '0000' or '1000', which translates to: - * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash - */ - { - .name = "User FS", - .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */ - .offset = 0x0000000 - },{ - .name = "raw kernel", - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, - } -}; -#else -#error MTD_PB1550 define combo error /* should never happen */ -#endif - -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -static struct mtd_info *mymtd; - -/* - * Probe the flash density and setup window address and size - * based on user CONFIG options. There are times when we don't - * want the MTD driver to be probing the boot or user flash, - * so having the option to enable only one bank is important. - */ -int setup_flash_params(void) -{ - u16 boot_swapboot; - boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | - ((bcsr->status >> 6) & 0x1); - printk("Pb1550 MTD: boot:swap %d\n", boot_swapboot); - - switch (boot_swapboot) { - case 0: /* 512Mbit devices, both enabled */ - case 1: - case 8: - case 9: -#if defined(PB1550_BOTH_BANKS) - window_addr = 0x18000000; - window_size = 0x8000000; -#elif defined(PB1550_BOOT_ONLY) - window_addr = 0x1C000000; - window_size = 0x4000000; -#else /* USER ONLY */ - window_addr = 0x1E000000; - window_size = 0x4000000; -#endif - break; - case 0xC: - case 0xD: - case 0xE: - case 0xF: - /* 64 MB Boot NOR Flash is disabled */ - /* and the start address is moved to 0x0C00000 */ - window_addr = 0x0C000000; - window_size = 0x4000000; - default: - printk("Pb1550 MTD: unsupported boot:swap setting\n"); - return 1; - } - return 0; -} - -int __init pb1550_mtd_init(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - - /* Default flash bankwidth */ - pb1550_map.bankwidth = flash_bankwidth; - - if (setup_flash_params()) - return -ENXIO; - - /* - * Static partition definition selection - */ - parts = pb1550_partitions; - nb_parts = NB_OF(pb1550_partitions); - pb1550_map.size = window_size; - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", - pb1550_map.bankwidth*8); - pb1550_map.virt = ioremap(window_addr, window_size); - mymtd = do_map_probe("cfi_probe", &pb1550_map); - if (!mymtd) return -ENXIO; - mymtd->owner = THIS_MODULE; - - add_mtd_partitions(mymtd, parts, nb_parts); - return 0; -} - -static void __exit pb1550_mtd_cleanup(void) -{ - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - } -} - -module_init(pb1550_mtd_init); -module_exit(pb1550_mtd_cleanup); - -MODULE_AUTHOR("Embedded Edge, LLC"); -MODULE_DESCRIPTION("Pb1550 mtd map driver"); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c --- a/drivers/mtd/maps/pb1xxx-flash.c 2005-05-11 20:59:08 -07:00 +++ /dev/null Wed Dec 31 16:00:00 196900 @@ -1,178 +0,0 @@ -/* - * Flash memory access on Alchemy Pb1xxx boards - * - * (C) 2001 Pete Popov - * - * $Id: pb1xxx-flash.c,v 1.14 2004/11/04 13:24:15 gleixner Exp $ - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#ifdef DEBUG_RW -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -#ifdef CONFIG_MIPS_PB1000 - -#define WINDOW_ADDR 0x1F800000 -#define WINDOW_SIZE 0x800000 - -static struct mtd_partition pb1xxx_partitions[] = { - { - .name = "yamon env", - .size = 0x00020000, - .offset = 0, - .mask_flags = MTD_WRITEABLE}, - { - .name = "User FS", - .size = 0x003e0000, - .offset = 0x20000,}, - { - .name = "boot code", - .size = 0x100000, - .offset = 0x400000, - .mask_flags = MTD_WRITEABLE}, - { - .name = "raw/kernel", - .size = 0x300000, - .offset = 0x500000} -}; - -#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) - -#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) -/* both 32MB banks will be used. Combine the first 32MB bank and the - * first 28MB of the second bank together into a single jffs/jffs2 - * partition. - */ -#define WINDOW_ADDR 0x1C000000 -#define WINDOW_SIZE 0x4000000 -static struct mtd_partition pb1xxx_partitions[] = { - { - .name = "User FS", - .size = 0x3c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = 0x3c00000, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = 0x02c0000, - .offset = 0x3d00000 - } -}; -#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) -#define WINDOW_ADDR 0x1E000000 -#define WINDOW_SIZE 0x2000000 -static struct mtd_partition pb1xxx_partitions[] = { - { - .name = "User FS", - .size = 0x1c00000, - .offset = 0x0000000 - },{ - .name = "yamon", - .size = 0x0100000, - .offset = 0x1c00000, - .mask_flags = MTD_WRITEABLE - },{ - .name = "raw kernel", - .size = 0x02c0000, - .offset = 0x1d00000 - } -}; -#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) -#define WINDOW_ADDR 0x1C000000 -#define WINDOW_SIZE 0x2000000 -static struct mtd_partition pb1xxx_partitions[] = { - { - .name = "User FS", - .size = 0x1e00000, - .offset = 0x0000000 - },{ - .name = "raw kernel", - .size = 0x0200000, - .offset = 0x1e00000, - } -}; -#else -#error MTD_PB1500 define combo error /* should never happen */ -#endif -#else -#error Unsupported board -#endif - -#define NAME "Pb1x00 Linux Flash" -#define PADDR WINDOW_ADDR -#define BUSWIDTH 4 -#define SIZE WINDOW_SIZE -#define PARTITIONS 4 - -static struct map_info pb1xxx_mtd_map = { - .name = NAME, - .size = SIZE, - .bankwidth = BUSWIDTH, - .phys = PADDR, -}; - -static struct mtd_info *pb1xxx_mtd; - -int __init pb1xxx_mtd_init(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - char *part_type; - - /* - * Static partition definition selection - */ - part_type = "static"; - parts = pb1xxx_partitions; - nb_parts = ARRAY_SIZE(pb1xxx_partitions); - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", - BUSWIDTH*8); - pb1xxx_mtd_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); - - simple_map_init(&pb1xxx_mtd_map); - - pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map); - if (!pb1xxx_mtd) return -ENXIO; - pb1xxx_mtd->owner = THIS_MODULE; - - add_mtd_partitions(pb1xxx_mtd, parts, nb_parts); - return 0; -} - -static void __exit pb1xxx_mtd_cleanup(void) -{ - if (pb1xxx_mtd) { - del_mtd_partitions(pb1xxx_mtd); - map_destroy(pb1xxx_mtd); - iounmap((void *) pb1xxx_mtd_map.virt); - } -} - -module_init(pb1xxx_mtd_init); -module_exit(pb1xxx_mtd_cleanup); - -MODULE_AUTHOR("Pete Popov"); -MODULE_DESCRIPTION("Pb1xxx CFI map driver"); -MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c --- a/drivers/mtd/maps/pci.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/pci.c 2005-05-11 20:59:08 -07: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.9 2004/11/28 09:40:40 dwmw2 Exp $ + * $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $ * * Generic PCI memory map driver. We support the following boards: * - Intel IQ80310 ATU. @@ -370,7 +370,7 @@ static int __init mtd_pci_maps_init(void) { - return pci_module_init(&mtd_pci_driver); + return pci_register_driver(&mtd_pci_driver); } static void __exit mtd_pci_maps_exit(void) diff -Nru a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/drivers/mtd/maps/plat-ram.c 2005-05-11 20:59:08 -07:00 @@ -0,0 +1,278 @@ +/* drivers/mtd/maps/plat-ram.c + * + * (c) 2004-2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks + * + * Generic platfrom device based RAM map + * + * $Id: plat-ram.c,v 1.2 2005/03/14 20:33:19 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* private structure for each mtd platform ram device created */ + +struct platram_info { + struct device *dev; + struct mtd_info *mtd; + struct map_info map; + struct mtd_partition *partitions; + struct resource *area; + struct platdata_mtd_ram *pdata; +}; + +/* to_platram_info() + * + * device private data to struct platram_info conversion +*/ + +static inline struct platram_info *to_platram_info(struct device *dev) +{ + return (struct platram_info *)dev_get_drvdata(dev); +} + +/* platram_setrw + * + * call the platform device's set rw/ro control + * + * to = 0 => read-only + * = 1 => read-write +*/ + +static inline void platram_setrw(struct platram_info *info, int to) +{ + if (info->pdata == NULL) + return; + + if (info->pdata->set_rw != NULL) + (info->pdata->set_rw)(info->dev, to); +} + +/* platram_remove + * + * called to remove the device from the driver's control +*/ + +static int platram_remove(struct device *dev) +{ + struct platram_info *info = to_platram_info(dev); + + dev_set_drvdata(dev, NULL); + + dev_dbg(dev, "removing device\n"); + + if (info == NULL) + return 0; + + if (info->mtd) { +#ifdef CONFIG_MTD_PARTITIONS + if (info->partitions) { + del_mtd_partitions(info->mtd); + kfree(info->partitions); + } +#endif + del_mtd_device(info->mtd); + map_destroy(info->mtd); + } + + /* ensure ram is left read-only */ + + platram_setrw(info, PLATRAM_RO); + + /* release resources */ + + if (info->area) { + release_resource(info->area); + kfree(info->area); + } + + if (info->map.virt != NULL) + iounmap(info->map.virt); + + kfree(info); + + return 0; +} + +/* platram_probe + * + * called from device drive system when a device matching our + * driver is found. +*/ + +static int platram_probe(struct device *dev) +{ + struct platform_device *pd = to_platform_device(dev); + struct platdata_mtd_ram *pdata; + struct platram_info *info; + struct resource *res; + int err = 0; + + dev_dbg(dev, "probe entered\n"); + + if (dev->platform_data == NULL) { + dev_err(dev, "no platform data supplied\n"); + err = -ENOENT; + goto exit_error; + } + + pdata = dev->platform_data; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + dev_err(dev, "no memory for flash info\n"); + err = -ENOMEM; + goto exit_error; + } + + memset(info, 0, sizeof(*info)); + dev_set_drvdata(dev, info); + + info->dev = dev; + info->pdata = pdata; + + /* get the resource for the memory mapping */ + + res = platform_get_resource(pd, IORESOURCE_MEM, 0); + + if (res == NULL) { + dev_err(dev, "no memory resource specified\n"); + err = -ENOENT; + goto exit_free; + } + + dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start); + + /* setup map parameters */ + + info->map.phys = res->start; + info->map.size = (res->end - res->start) + 1; + info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name; + info->map.bankwidth = pdata->bankwidth; + + /* register our usage of the memory area */ + + info->area = request_mem_region(res->start, info->map.size, pd->name); + if (info->area == NULL) { + dev_err(dev, "failed to request memory region\n"); + err = -EIO; + goto exit_free; + } + + /* remap the memory area */ + + info->map.virt = ioremap(res->start, info->map.size); + dev_dbg(dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size); + + if (info->map.virt == NULL) { + dev_err(dev, "failed to ioremap() region\n"); + err = -EIO; + goto exit_free; + } + + simple_map_init(&info->map); + + dev_dbg(dev, "initialised map, probing for mtd\n"); + + /* probe for the right mtd map driver */ + + info->mtd = do_map_probe("map_ram" , &info->map); + if (info->mtd == NULL) { + dev_err(dev, "failed to probe for map_ram\n"); + err = -ENOMEM; + goto exit_free; + } + + info->mtd->owner = THIS_MODULE; + + platram_setrw(info, PLATRAM_RW); + + /* check to see if there are any available partitions, or wether + * to add this device whole */ + +#ifdef CONFIG_MTD_PARTITIONS + if (pdata->nr_partitions > 0) { + const char **probes = { NULL }; + + if (pdata->probes) + probes = (const char **)pdata->probes; + + err = parse_mtd_partitions(info->mtd, probes, + &info->partitions, 0); + if (err > 0) { + err = add_mtd_partitions(info->mtd, info->partitions, + err); + } + } +#endif /* CONFIG_MTD_PARTITIONS */ + + if (add_mtd_device(info->mtd)) { + dev_err(dev, "add_mtd_device() failed\n"); + err = -ENOMEM; + } + + dev_info(dev, "registered mtd device\n"); + return err; + + exit_free: + platram_remove(dev); + exit_error: + return err; +} + +/* device driver info */ + +static struct device_driver platram_driver = { + .name = "mtd-ram", + .bus = &platform_bus_type, + .probe = platram_probe, + .remove = platram_remove, +}; + +/* module init/exit */ + +static int __init platram_init(void) +{ + printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n"); + return driver_register(&platram_driver); +} + +static void __exit platram_exit(void) +{ + driver_unregister(&platram_driver); +} + +module_init(platram_init); +module_exit(platram_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("MTD platform RAM map driver"); diff -Nru a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c --- a/drivers/mtd/maps/scb2_flash.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/scb2_flash.c 2005-05-11 20:59:08 -07:00 @@ -1,6 +1,6 @@ /* * MTD map driver for BIOS Flash on Intel SCB2 boards - * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $ + * $Id: scb2_flash.c,v 1.12 2005/03/18 14:04:35 gleixner Exp $ * Copyright (C) 2002 Sun Microsystems, Inc. * Tim Hockin * @@ -238,7 +238,7 @@ static int __init scb2_flash_init(void) { - return pci_module_init(&scb2_flash_driver); + return pci_register_driver(&scb2_flash_driver); } static void __exit diff -Nru a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c --- a/drivers/mtd/maps/sharpsl-flash.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/maps/sharpsl-flash.c 2005-05-11 20:59:08 -07:00 @@ -4,7 +4,7 @@ * Copyright (C) 2001 Lineo Japan, Inc. * Copyright (C) 2002 SHARP * - * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $ + * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $ * * based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp * Handle mapping of the flash on the RPX Lite and CLLF boards @@ -24,13 +24,14 @@ #include #include #include -#include #include #include #include +#include +#include #define WINDOW_ADDR 0x00000000 -#define WINDOW_SIZE 0x01000000 +#define WINDOW_SIZE 0x00800000 #define BANK_WIDTH 2 static struct mtd_info *mymtd; @@ -44,9 +45,7 @@ static struct mtd_partition sharpsl_partitions[1] = { { - name: "Filesystem", - size: 0x006d0000, - offset: 0x00120000 + name: "Boot PROM Filesystem", } }; @@ -58,12 +57,16 @@ int nb_parts = 0; char *part_type = "static"; - printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); + printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", + WINDOW_SIZE, WINDOW_ADDR); sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!sharpsl_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + + simple_map_init(&sharpsl_map); + mymtd = do_map_probe("map_rom", &sharpsl_map); if (!mymtd) { iounmap(sharpsl_map.virt); @@ -72,6 +75,22 @@ mymtd->owner = THIS_MODULE; + if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky() + || machine_is_poodle()) { + sharpsl_partitions[0].size=0x006d0000; + sharpsl_partitions[0].offset=0x00120000; + } else if (machine_is_tosa()) { + sharpsl_partitions[0].size=0x006a0000; + sharpsl_partitions[0].offset=0x00160000; + } else if (machine_is_spitz()) { + sharpsl_partitions[0].size=0x006b0000; + sharpsl_partitions[0].offset=0x00140000; + } else { + map_destroy(mymtd); + iounmap(sharpsl_map.virt); + return -ENODEV; + } + parts = sharpsl_partitions; nb_parts = NB_OF(sharpsl_partitions); diff -Nru a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c --- a/drivers/mtd/mtdchar.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/mtdchar.c 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ /* - * $Id: mtdchar.c,v 1.66 2005/01/05 18:05:11 dwmw2 Exp $ + * $Id: mtdchar.c,v 1.69 2005/03/17 19:56:08 gleixner Exp $ * * Character-device access to raw MTD devices. * @@ -59,9 +59,25 @@ #define mtdchar_devfs_exit() do { } while(0) #endif +/* + * We use file->private_data to store a pointer to the MTDdevice. + * Since alighment is at least 32 bits, we have 2 bits free for OTP + * modes as well. + */ + +#define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L) + +#define MTD_MODE_OTP_FACT 1 +#define MTD_MODE_OTP_USER 2 +#define MTD_MODE(file) ((long)((file)->private_data) & 3) + +#define SET_MTD_MODE(file, mode) \ + do { long __p = (long)((file)->private_data); \ + (file)->private_data = (void *)((__p & ~3L) | mode); } while (0) + static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) { - struct mtd_info *mtd = file->private_data; + struct mtd_info *mtd = TO_MTD(file); switch (orig) { case 0: @@ -134,7 +150,7 @@ DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); - mtd = file->private_data; + mtd = TO_MTD(file); if (mtd->sync) mtd->sync(mtd); @@ -151,7 +167,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos) { - struct mtd_info *mtd = file->private_data; + struct mtd_info *mtd = TO_MTD(file); size_t retlen=0; size_t total_retlen=0; int ret=0; @@ -178,7 +194,16 @@ if (!kbuf) return -ENOMEM; - ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); + switch (MTD_MODE(file)) { + case MTD_MODE_OTP_FACT: + ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); + break; + case MTD_MODE_OTP_USER: + ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); + break; + default: + ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); + } /* Nand returns -EBADMSG on ecc errors, but it returns * the data. For our userspace tools it is important * to dump areas with ecc errors ! @@ -196,6 +221,8 @@ count -= retlen; buf += retlen; + if (retlen == 0) + count = 0; } else { kfree(kbuf); @@ -210,7 +237,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos) { - struct mtd_info *mtd = file->private_data; + struct mtd_info *mtd = TO_MTD(file); char *kbuf; size_t retlen; size_t total_retlen=0; @@ -245,7 +272,20 @@ return -EFAULT; } - ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); + switch (MTD_MODE(file)) { + case MTD_MODE_OTP_FACT: + ret = -EROFS; + break; + case MTD_MODE_OTP_USER: + if (!mtd->write_user_prot_reg) { + ret = -EOPNOTSUPP; + break; + } + ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); + break; + default: + ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); + } if (!ret) { *ppos += retlen; total_retlen += retlen; @@ -276,7 +316,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { - struct mtd_info *mtd = file->private_data; + struct mtd_info *mtd = TO_MTD(file); void __user *argp = (void __user *)arg; int ret = 0; u_long size; @@ -517,6 +557,79 @@ return mtd->block_markbad(mtd, offs); break; } + +#ifdef CONFIG_MTD_OTP + case OTPSELECT: + { + int mode; + if (copy_from_user(&mode, argp, sizeof(int))) + return -EFAULT; + SET_MTD_MODE(file, 0); + switch (mode) { + case MTD_OTP_FACTORY: + if (!mtd->read_fact_prot_reg) + ret = -EOPNOTSUPP; + else + SET_MTD_MODE(file, MTD_MODE_OTP_FACT); + break; + case MTD_OTP_USER: + if (!mtd->read_fact_prot_reg) + ret = -EOPNOTSUPP; + else + SET_MTD_MODE(file, MTD_MODE_OTP_USER); + break; + default: + ret = -EINVAL; + case MTD_OTP_OFF: + break; + } + break; + } + + case OTPGETREGIONCOUNT: + case OTPGETREGIONINFO: + { + struct otp_info *buf = kmalloc(4096, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = -EOPNOTSUPP; + switch (MTD_MODE(file)) { + case MTD_MODE_OTP_FACT: + if (mtd->get_fact_prot_info) + ret = mtd->get_fact_prot_info(mtd, buf, 4096); + break; + case MTD_MODE_OTP_USER: + if (mtd->get_user_prot_info) + ret = mtd->get_user_prot_info(mtd, buf, 4096); + break; + } + if (ret >= 0) { + if (cmd == OTPGETREGIONCOUNT) { + int nbr = ret / sizeof(struct otp_info); + ret = copy_to_user(argp, &nbr, sizeof(int)); + } else + ret = copy_to_user(argp, buf, ret); + if (ret) + ret = -EFAULT; + } + kfree(buf); + break; + } + + case OTPLOCK: + { + struct otp_info info; + + if (MTD_MODE(file) != MTD_MODE_OTP_USER) + return -EINVAL; + if (copy_from_user(&info, argp, sizeof(info))) + return -EFAULT; + if (!mtd->lock_user_prot_reg) + return -EOPNOTSUPP; + ret = mtd->lock_user_prot_reg(mtd, info.start, info.length); + break; + } +#endif default: ret = -ENOTTY; diff -Nru a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c --- a/drivers/mtd/mtdcore.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/mtdcore.c 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.44 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -149,8 +149,8 @@ } /** - * register_mtd_user - unregister a 'user' of MTD devices. - * @new: pointer to notifier info structure + * unregister_mtd_user - unregister a 'user' of MTD devices. + * @old: pointer to notifier info structure * * Removes a callback function pair from the list of 'users' to be * notified upon addition or removal of MTD devices. Causes the diff -Nru a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c --- a/drivers/mtd/mtdpart.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/mtdpart.c 2005-05-11 20:59:08 -07:00 @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $ * * 02-21-2002 Thomas Gleixner * added support for read_oob, write_oob @@ -116,6 +116,13 @@ len, retlen, buf); } +static int part_get_user_prot_info (struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->get_user_prot_info (part->master, buf, len); +} + static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -124,6 +131,13 @@ len, retlen, buf); } +static int part_get_fact_prot_info (struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->get_fact_prot_info (part->master, buf, len); +} + static int part_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { @@ -182,6 +196,12 @@ len, retlen, buf); } +static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->lock_user_prot_reg (part->master, from, len); +} + static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen) { @@ -409,6 +429,12 @@ slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; if(master->write_user_prot_reg) slave->mtd.write_user_prot_reg = part_write_user_prot_reg; + if(master->lock_user_prot_reg) + slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; + if(master->get_user_prot_info) + slave->mtd.get_user_prot_info = part_get_user_prot_info; + if(master->get_fact_prot_info) + slave->mtd.get_fact_prot_info = part_get_fact_prot_info; if (master->sync) slave->mtd.sync = part_sync; if (!i && master->suspend && master->resume) { diff -Nru a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c --- a/drivers/mtd/nand/diskonchip.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/nand/diskonchip.c 2005-05-11 20:59:08 -07:00 @@ -16,7 +16,7 @@ * * Interface to generic NAND code for M-Systems DiskOnChip devices * - * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $ + * $Id: diskonchip.c,v 1.49 2005/02/22 21:48:21 gleixner Exp $ */ #include @@ -35,13 +35,13 @@ #include /* Where to look for the devices? */ -#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS -#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0 +#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS +#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0 #endif static unsigned long __initdata doc_locations[] = { #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) -#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH +#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, @@ -123,7 +123,7 @@ #endif module_param(inftl_bbt_write, int, 0); -static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS; +static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS; module_param(doc_config_location, ulong, 0); MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); @@ -410,7 +410,12 @@ doc200x_hwcontrol(mtd, NAND_CTL_SETALE); this->write_byte(mtd, 0); doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); - + + /* We cant' use dev_ready here, but at least we wait for the + * command to complete + */ + udelay(50); + ret = this->read_byte(mtd) << 8; ret |= this->read_byte(mtd); @@ -429,6 +434,8 @@ doc2000_write_byte(mtd, 0); doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); + udelay(50); + ident.dword = readl(docptr + DoC_2k_CDSN_IO); if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n"); @@ -1122,8 +1129,10 @@ if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; mh = (struct NFTLMediaHeader *) buf; -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) + mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits); + mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN); + mh->FormattedSize = le32_to_cpu(mh->FormattedSize); + printk(KERN_INFO " DataOrgID = %s\n" " NumEraseUnits = %d\n" " FirstPhysicalEUN = %d\n" @@ -1132,7 +1141,6 @@ mh->DataOrgID, mh->NumEraseUnits, mh->FirstPhysicalEUN, mh->FormattedSize, mh->UnitSizeFactor); -//#endif blocks = mtd->size >> this->phys_erase_shift; maxblocks = min(32768U, mtd->erasesize - psize); @@ -1175,10 +1183,6 @@ offs <<= this->page_shift; offs += mtd->erasesize; - //parts[0].name = " DiskOnChip Boot / Media Header partition"; - //parts[0].offset = 0; - //parts[0].size = offs; - parts[0].name = " DiskOnChip BDTL partition"; parts[0].offset = offs; parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; @@ -1233,8 +1237,6 @@ mh->FormatFlags = le32_to_cpu(mh->FormatFlags); mh->PercentUsed = le32_to_cpu(mh->PercentUsed); -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) printk(KERN_INFO " bootRecordID = %s\n" " NoOfBootImageBlocks = %d\n" " NoOfBinaryPartitions = %d\n" @@ -1252,7 +1254,6 @@ ((unsigned char *) &mh->OsakVersion)[2] & 0xf, ((unsigned char *) &mh->OsakVersion)[3] & 0xf, mh->PercentUsed); -//#endif vshift = this->phys_erase_shift + mh->BlockMultiplierBits; @@ -1278,8 +1279,6 @@ ip->spareUnits = le32_to_cpu(ip->spareUnits); ip->Reserved0 = le32_to_cpu(ip->Reserved0); -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) printk(KERN_INFO " PARTITION[%d] ->\n" " virtualUnits = %d\n" " firstUnit = %d\n" @@ -1289,16 +1288,15 @@ i, ip->virtualUnits, ip->firstUnit, ip->lastUnit, ip->flags, ip->spareUnits); -//#endif -/* +#if 0 if ((i == 0) && (ip->firstUnit > 0)) { parts[0].name = " DiskOnChip IPL / Media Header partition"; parts[0].offset = 0; parts[0].size = mtd->erasesize * ip->firstUnit; numparts = 1; } -*/ +#endif if (ip->flags & INFTL_BINARY) parts[numparts].name = " DiskOnChip BDK partition"; diff -Nru a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c --- a/drivers/mtd/nand/nand_base.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/nand/nand_base.c 2005-05-11 20:59:08 -07:00 @@ -28,6 +28,24 @@ * among multiple independend devices. Suggestions and initial patch * from Ben Dooks * + * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue. + * Basically, any block not rewritten may lose data when surrounding blocks + * are rewritten many times. JFFS2 ensures this doesn't happen for blocks + * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they + * do not lose data, force them to be rewritten when some of the surrounding + * blocks are erased. Rather than tracking a specific nearby block (which + * could itself go bad), use a page address 'mask' to select several blocks + * in the same area, and rewrite the BBT when any of them are erased. + * + * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas + * AG-AND chips. If there was a sudden loss of power during an erase operation, + * a "device recovery" operation must be performed when power is restored + * to ensure correct operation. + * + * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to + * perform extra error status checks on erase and write failures. This required + * adding a wrapper function for nand_read_ecc. + * * Credits: * David Woodhouse for adding multichip support * @@ -41,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $ + * $Id: nand_base.c,v 1.136 2005/03/14 18:30:44 bjd Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -443,7 +461,8 @@ /* Get block number */ block = ((int) ofs) >> this->bbt_erase_shift; - this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + if (this->bbt) + this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) @@ -466,7 +485,7 @@ struct nand_chip *this = mtd->priv; /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - return (this->read_byte(mtd) & 0x80) ? 0 : 1; + return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; } /** @@ -490,6 +509,22 @@ return nand_isbad_bbt (mtd, ofs, allowbbt); } +/* + * Wait for the ready pin, after a command + * The timeout is catched later. + */ +static void nand_wait_ready(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + unsigned long timeo = jiffies + 2; + + /* wait until command is processed or timeout occures */ + do { + if (this->dev_ready(mtd)) + return; + } while (time_before(jiffies, timeo)); +} + /** * nand_command - [DEFAULT] Send command to NAND device * @mtd: MTD device structure @@ -571,7 +606,7 @@ this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & 0x40)); + while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); return; /* This applies to read commands */ @@ -585,12 +620,11 @@ return; } } - /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); - /* wait until command is processed */ - while (!this->dev_ready(mtd)); + + nand_wait_ready(mtd); } /** @@ -619,7 +653,7 @@ /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the command to the device. */ - this->write_byte(mtd, command); + this->write_byte(mtd, (command & 0xff)); /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); @@ -647,8 +681,8 @@ /* * program and erase have their own busy handlers - * status and sequential in needs no delay - */ + * status, sequential in, and deplete1 need no delay + */ switch (command) { case NAND_CMD_CACHEDPROG: @@ -657,8 +691,19 @@ case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: return; + /* + * read error status commands require only a short delay + */ + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + case NAND_CMD_STATUS_ERROR1: + case NAND_CMD_STATUS_ERROR2: + case NAND_CMD_STATUS_ERROR3: + udelay(this->chip_delay); + return; case NAND_CMD_RESET: if (this->dev_ready) @@ -667,7 +712,7 @@ this->hwcontrol(mtd, NAND_CTL_SETCLE); this->write_byte(mtd, NAND_CMD_STATUS); this->hwcontrol(mtd, NAND_CTL_CLRCLE); - while ( !(this->read_byte(mtd) & 0x40)); + while ( !(this->read_byte(mtd) & NAND_STATUS_READY)); return; case NAND_CMD_READ0: @@ -690,12 +735,12 @@ return; } } - + /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); - /* wait until command is processed */ - while (!this->dev_ready(mtd)); + + nand_wait_ready(mtd); } /** @@ -785,7 +830,7 @@ if (this->read_byte(mtd) & NAND_STATUS_READY) break; } - yield (); + cond_resched(); } status = (int) this->read_byte(mtd); return status; @@ -871,8 +916,14 @@ if (!cached) { /* call wait ready function */ status = this->waitfunc (mtd, this, FL_WRITING); + + /* See if operation failed and additional status checks are available */ + if ((status & NAND_STATUS_FAIL) && (this->errstat)) { + status = this->errstat(mtd, this, FL_WRITING, status, page); + } + /* See if device thinks it succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); return -EIO; } @@ -975,7 +1026,7 @@ if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + nand_wait_ready(mtd); /* All done, return happy */ if (!numpages) @@ -997,23 +1048,24 @@ #endif /** - * nand_read - [MTD Interface] MTD compability function for nand_read_ecc + * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read * @retlen: pointer to variable to store the number of read bytes * @buf: the databuffer to put data * - * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL -*/ + * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL + * and flags = 0xff + */ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { - return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); + return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff); } /** - * nand_read_ecc - [MTD Interface] Read data with ECC + * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read @@ -1022,11 +1074,35 @@ * @oob_buf: filesystem supplied oob data buffer * @oobsel: oob selection structure * - * NAND read with ECC + * This function simply calls nand_do_read_ecc with flags = 0xff */ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) { + return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); +} + + +/** + * nand_do_read_ecc - [MTD Interface] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data + * @oob_buf: filesystem supplied oob data buffer + * @oobsel: oob selection structure + * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed + * and how many corrected error bits are acceptable: + * bits 0..7 - number of tolerable errors + * bit 8 - 0 == do not get/release chip, 1 == get/release chip + * + * NAND read with ECC + */ +int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags) +{ int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; @@ -1051,7 +1127,8 @@ } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd ,FL_READING); + if (flags & NAND_GET_DEVICE) + nand_get_device (this, mtd, FL_READING); /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) @@ -1155,7 +1232,8 @@ /* We calc error correction directly, it checks the hw * generator for an error, reads back the syndrome and * does the error correction on the fly */ - if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { + ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); + if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; @@ -1194,7 +1272,7 @@ p[i] = ecc_status; } - if (ecc_status == -1) { + if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } @@ -1239,7 +1317,7 @@ if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + nand_wait_ready(mtd); if (read == len) break; @@ -1264,7 +1342,8 @@ } /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + if (flags & NAND_GET_DEVICE) + nand_release_device(mtd); /* * Return success, if no ECC failures, else -EBADMSG @@ -1337,7 +1416,7 @@ if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + nand_wait_ready(mtd); /* Read more ? */ if (i < len) { @@ -1417,7 +1496,7 @@ if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + nand_wait_ready(mtd); /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) @@ -1733,7 +1812,7 @@ status = this->waitfunc (mtd, this, FL_WRITING); /* See if device thinks it succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); ret = -EIO; goto out; @@ -1987,6 +2066,7 @@ return nand_erase_nand (mtd, instr, 0); } +#define BBT_PAGE_MASK 0xffffff3f /** * nand_erase_intern - [NAND Interface] erase block(s) * @mtd: MTD device structure @@ -1999,6 +2079,10 @@ { int page, len, status, pages_per_block, ret, chipnr; struct nand_chip *this = mtd->priv; + int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */ + unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */ + /* It is used to see if the current page is in the same */ + /* 256 block group and the same bank as the bbt. */ DEBUG (MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); @@ -2044,6 +2128,13 @@ goto erase_exit; } + /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */ + if (this->options & BBT_AUTO_REFRESH) { + bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; + } else { + bbt_masked_page = 0xffffffff; /* should not match anything */ + } + /* Loop through the pages */ len = instr->len; @@ -2066,13 +2157,26 @@ status = this->waitfunc (mtd, this, FL_ERASING); + /* See if operation failed and additional status checks are available */ + if ((status & NAND_STATUS_FAIL) && (this->errstat)) { + status = this->errstat(mtd, this, FL_ERASING, status, page); + } + /* See if block erase succeeded */ - if (status & 0x01) { + if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; instr->fail_addr = (page << this->page_shift); goto erase_exit; } + + /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */ + if (this->options & BBT_AUTO_REFRESH) { + if (((page & BBT_PAGE_MASK) == bbt_masked_page) && + (page != this->bbt_td->pages[chipnr])) { + rewrite_bbt[chipnr] = (page << this->page_shift); + } + } /* Increment page address and decrement length */ len -= (1 << this->phys_erase_shift); @@ -2083,6 +2187,13 @@ chipnr++; this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); + + /* if BBT requires refresh and BBT-PERCHIP, + * set the BBT page mask to see if this BBT should be rewritten */ + if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) { + bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK; + } + } } instr->state = MTD_ERASE_DONE; @@ -2097,6 +2208,18 @@ /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); + /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */ + if ((this->options & BBT_AUTO_REFRESH) && (!ret)) { + for (chipnr = 0; chipnr < this->numchips; chipnr++) { + if (rewrite_bbt[chipnr]) { + /* update the BBT for chip */ + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n", + chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]); + nand_update_bbt (mtd, rewrite_bbt[chipnr]); + } + } + } + /* Return more or less happy */ return ret; } @@ -2168,7 +2291,7 @@ */ int nand_scan (struct mtd_info *mtd, int maxchips) { - int i, j, nand_maf_id, nand_dev_id, busw; + int i, nand_maf_id, nand_dev_id, busw, maf_id; struct nand_chip *this = mtd->priv; /* Get buswidth to select the correct functions*/ @@ -2256,12 +2379,18 @@ busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16; } + /* Try to identify manufacturer */ + for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) { + if (nand_manuf_ids[maf_id].id == nand_maf_id) + break; + } + /* Check, if buswidth is correct. Hardware drivers should set * this correct ! */ if (busw != (this->options & NAND_BUSWIDTH_16)) { printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, - nand_manuf_ids[i].name , mtd->name); + nand_manuf_ids[maf_id].name , mtd->name); printk (KERN_WARNING "NAND bus width %d instead %d bit\n", (this->options & NAND_BUSWIDTH_16) ? 16 : 8, @@ -2300,14 +2429,9 @@ if (mtd->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp; - /* Try to identify manufacturer */ - for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { - if (nand_manuf_ids[j].id == nand_maf_id) - break; - } printk (KERN_INFO "NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, - nand_manuf_ids[j].name , nand_flash_ids[i].name); + nand_manuf_ids[maf_id].name , nand_flash_ids[i].name); break; } @@ -2524,6 +2648,10 @@ memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); mtd->owner = THIS_MODULE; + + /* Check, if we should skip the bad block table scan */ + if (this->options & NAND_SKIP_BBTSCAN) + return 0; /* Build bad block table */ return this->scan_bbt (mtd); diff -Nru a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c --- a/drivers/mtd/nand/nand_ids.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/nand/nand_ids.c 2005-05-11 20:59:08 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) * - * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $ + * $Id: nand_ids.c,v 1.12 2005/02/16 09:33:27 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -62,8 +62,6 @@ {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, - {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0}, - /* These are the new chips with large page size. The pagesize * and the erasesize is determined from the extended id bytes */ @@ -103,7 +101,7 @@ * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go * There are more speed improvements for reads and writes possible, but not implemented now */ - {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY}, + {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, {NULL,} }; diff -Nru a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c --- a/drivers/mtd/nand/rtc_from4.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/nand/rtc_from4.c 2005-05-11 20:59:08 -07:00 @@ -6,7 +6,7 @@ * Derived from drivers/mtd/nand/spia.c * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $ + * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -83,13 +83,18 @@ #define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070) #define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7) +#define ERR_STAT_ECC_AVAILABLE 0x20 + /* Undefine for software ECC */ #define RTC_FROM4_HWECC 1 +/* Define as 1 for no virtual erase blocks (in JFFS2) */ +#define RTC_FROM4_NO_VIRTBLOCKS 0 + /* * Module stuff */ -static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE); +static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE); const static struct mtd_partition partition_info[] = { { @@ -267,7 +272,6 @@ } - /* * rtc_from4_nand_device_ready - hardware specific ready/busy check * @mtd: MTD device structure @@ -286,6 +290,40 @@ } + +/* + * deplete - code to perform device recovery in case there was a power loss + * @mtd: MTD device structure + * @chip: Chip to select (0 == slot 3, 1 == slot 4) + * + * If there was a sudden loss of power during an erase operation, a + * "device recovery" operation must be performed when power is restored + * to ensure correct operation. This routine performs the required steps + * for the requested chip. + * + * See page 86 of the data sheet for details. + * + */ +static void deplete(struct mtd_info *mtd, int chip) +{ + struct nand_chip *this = mtd->priv; + + /* wait until device is ready */ + while (!this->dev_ready(mtd)); + + this->select_chip(mtd, chip); + + /* Send the commands for device recovery, phase 1 */ + this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000); + this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); + + /* Send the commands for device recovery, phase 2 */ + this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004); + this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1); + +} + + #ifdef RTC_FROM4_HWECC /* * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function @@ -329,6 +367,7 @@ } + /* * rtc_from4_calculate_ecc - hardware specific code to read ECC code * @mtd: MTD device structure @@ -356,6 +395,7 @@ ecc_code[7] |= 0x0f; /* set the last four bits (not used) */ } + /* * rtc_from4_correct_data - hardware specific code to correct data using ECC code * @mtd: MTD device structure @@ -365,16 +405,14 @@ * * The FPGA tells us fast, if there's an error or not. If no, we go back happy * else we read the ecc results from the fpga and call the rs library to decode - * and hopefully correct the error + * and hopefully correct the error. * - * For now I use the code, which we read from the FLASH to use the RS lib, - * as the syndrom conversion has a unresolved issue. */ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2) { int i, j, res; unsigned short status; - uint16_t par[6], syn[6], tmp; + uint16_t par[6], syn[6]; uint8_t ecc[8]; volatile unsigned short *rs_ecc; @@ -416,15 +454,86 @@ } /* Let the library code do its magic.*/ - res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL); + res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL); if (res > 0) { DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); } return res; } + + +/** + * rtc_from4_errstat - perform additional error status checks + * @mtd: MTD device structure + * @this: NAND chip structure + * @state: state or the operation + * @status: status code returned from read status + * @page: startpage inside the chip, must be called with (page & this->pagemask) + * + * Perform additional error status checks on erase and write failures + * to determine if errors are correctable. For this device, correctable + * 1-bit errors on erase and write are considered acceptable. + * + * note: see pages 34..37 of data sheet for details. + * + */ +static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page) +{ + int er_stat=0; + int rtn, retlen; + size_t len; + uint8_t *buf; + int i; + + this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1); + + if (state == FL_ERASING) { + for (i=0; i<4; i++) { + if (status & 1<<(i+1)) { + this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1); + rtn = this->read_byte(mtd); + this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); + if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { + er_stat |= 1<<(i+1); /* err_ecc_not_avail */ + } + } + } + } else if (state == FL_WRITING) { + /* single bank write logic */ + this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1); + rtn = this->read_byte(mtd); + this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1); + if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { + er_stat |= 1<<1; /* err_ecc_not_avail */ + } else { + len = mtd->oobblock; + buf = kmalloc (len, GFP_KERNEL); + if (!buf) { + printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n"); + er_stat = 1; /* if we can't check, assume failed */ + } else { + /* recovery read */ + /* page read */ + rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1); + if (rtn) { /* if read failed or > 1-bit error corrected */ + er_stat |= 1<<1; /* ECC read failed */ + } + kfree(buf); + } + } + } + + rtn = status; + if (er_stat == 0) { /* if ECC is available */ + rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */ + } + + return rtn; +} #endif + /* * Main initialization routine */ @@ -432,6 +541,7 @@ { struct nand_chip *this; unsigned short bcr1, bcr2, wcr2; + int i; /* Allocate memory for MTD device structure and private data */ rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip), @@ -483,6 +593,8 @@ this->eccmode = NAND_ECC_HW8_512; this->options |= NAND_HWECC_SYNDROME; + /* return the status of extra status and ECC checks */ + this->errstat = rtc_from4_errstat; /* set the nand_oobinfo to support FPGA H/W error detection */ this->autooob = &rtc_from4_nand_oobinfo; this->enable_hwecc = rtc_from4_enable_hwecc; @@ -503,6 +615,18 @@ kfree(rtc_from4_mtd); return -ENXIO; } + + /* Perform 'device recovery' for each chip in case there was a power loss. */ + for (i=0; i < this->numchips; i++) { + deplete(rtc_from4_mtd, i); + } + +#if RTC_FROM4_NO_VIRTBLOCKS + /* use a smaller erase block to minimize wasted space when a block is bad */ + /* note: this uses eight times as much RAM as using the default and makes */ + /* mounts take four times as long. */ + rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS; +#endif /* Register the partitions */ add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS); diff -Nru a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c --- a/drivers/mtd/nand/s3c2410.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/nand/s3c2410.c 2005-05-11 20:59:08 -07:00 @@ -1,7 +1,8 @@ /* linux/drivers/mtd/nand/s3c2410.c * * Copyright (c) 2004 Simtec Electronics - * Ben Dooks + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks * * Samsung S3C2410 NAND driver * @@ -10,8 +11,10 @@ * 23-Sep-2004 BJD Mulitple device support * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode * 12-Oct-2004 BJD Fixed errors in use of platform data + * 18-Feb-2005 BJD Fix sparse errors + * 14-Mar-2005 BJD Applied tglx's code reduction patch * - * $Id: s3c2410.c,v 1.7 2005/01/05 18:05:14 dwmw2 Exp $ + * $Id: s3c2410.c,v 1.12 2005/03/17 11:31:26 bjd Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -69,10 +72,10 @@ */ static struct nand_oobinfo nand_hw_eccoob = { - .useecc = MTD_NANDECC_AUTOPLACE, - .eccbytes = 3, - .eccpos = {0, 1, 2 }, - .oobfree = { {8, 8} } + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 3, + .eccpos = {0, 1, 2 }, + .oobfree = { {8, 8} } }; /* controller and mtd information */ @@ -99,7 +102,7 @@ struct device *device; struct resource *area; struct clk *clk; - void *regs; + void __iomem *regs; int mtd_count; }; @@ -234,6 +237,7 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + struct nand_chip *chip = mtd->priv; unsigned long cur; switch (cmd) { @@ -249,117 +253,22 @@ writel(cur, info->regs + S3C2410_NFCONF); break; - /* we don't need to implement these */ case NAND_CTL_SETCLE: - case NAND_CTL_CLRCLE: - case NAND_CTL_SETALE: - case NAND_CTL_CLRALE: - pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd); + chip->IO_ADDR_W = info->regs + S3C2410_NFCMD; break; - } -} - -/* s3c2410_nand_command - * - * This function implements sending commands and the relevant address - * information to the chip, via the hardware controller. Since the - * S3C2410 generates the correct ALE/CLE signaling automatically, we - * do not need to use hwcontrol. -*/ - -static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command, - int column, int page_addr) -{ - register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - register struct nand_chip *this = mtd->priv; - - /* - * Write out the command to the device. - */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->oobblock) { - /* OOB area */ - column -= mtd->oobblock; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - - writeb(readcmd, info->regs + S3C2410_NFCMD); - } - writeb(command, info->regs + S3C2410_NFCMD); - - /* Set ALE and clear CLE to start address cycle */ - if (column != -1 || page_addr != -1) { - - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (this->options & NAND_BUSWIDTH_16) - column >>= 1; - writeb(column, info->regs + S3C2410_NFADDR); - } - if (page_addr != -1) { - writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR); - writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR); - /* One more address cycle for higher density devices */ - if (this->chipsize & 0x0c000000) - writeb((unsigned char) ((page_addr >> 16) & 0x0f), - info->regs + S3C2410_NFADDR); - } - /* Latch in address */ - } - - /* - * program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (this->dev_ready) - break; - - udelay(this->chip_delay); - writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD); - - while ( !(this->read_byte(mtd) & 0x40)); - return; + case NAND_CTL_SETALE: + chip->IO_ADDR_W = info->regs + S3C2410_NFADDR; + break; - /* This applies to read commands */ + /* NAND_CTL_CLRCLE: */ + /* NAND_CTL_CLRALE: */ default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!this->dev_ready) { - udelay (this->chip_delay); - return; - } + chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; + break; } - - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay (100); - /* wait until command is processed */ - while (!this->dev_ready(mtd)); } - /* s3c2410_nand_devready() * * returns 0 if the nand is busy, 1 if it is ready @@ -523,11 +432,10 @@ { struct nand_chip *chip = &nmtd->chip; - chip->IO_ADDR_R = (char *)info->regs + S3C2410_NFDATA; - chip->IO_ADDR_W = (char *)info->regs + S3C2410_NFDATA; + chip->IO_ADDR_R = info->regs + S3C2410_NFDATA; + chip->IO_ADDR_W = info->regs + S3C2410_NFDATA; chip->hwcontrol = s3c2410_nand_hwcontrol; chip->dev_ready = s3c2410_nand_devready; - chip->cmdfunc = s3c2410_nand_command; chip->write_buf = s3c2410_nand_write_buf; chip->read_buf = s3c2410_nand_read_buf; chip->select_chip = s3c2410_nand_select_chip; diff -Nru a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c --- a/drivers/mtd/nand/sharpsl.c 2005-05-11 20:59:08 -07:00 +++ b/drivers/mtd/nand/sharpsl.c 2005-05-11 20:59:08 -07:00 @@ -3,7 +3,7 @@ * * Copyright (C) 2004 Richard Purdie * - * $Id: sharpsl.c,v 1.3 2005/01/03 14:53:50 rpurdie Exp $ + * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $ * * Based on Sharp's NAND driver sharp_sl.c * @@ -216,7 +216,7 @@ nr_partitions = DEFAULT_NUM_PARTITIONS; sharpsl_partition_info = sharpsl_nand_default_partition_info; if (machine_is_poodle()) { - sharpsl_partition_info[1].size=22 * 1024 * 1024; + sharpsl_partition_info[1].size=30 * 1024 * 1024; } else if (machine_is_corgi() || machine_is_shepherd()) { sharpsl_partition_info[1].size=25 * 1024 * 1024; } else if (machine_is_husky()) { diff -Nru a/fs/Kconfig b/fs/Kconfig --- a/fs/Kconfig 2005-05-11 20:59:08 -07:00 +++ b/fs/Kconfig 2005-05-11 20:59:08 -07:00 @@ -1063,26 +1063,18 @@ If reporting bugs, please try to have available a full dump of the messages at debug level 1 while the misbehaviour was occurring. -config JFFS2_FS_NAND - bool "JFFS2 support for NAND flash" +config JFFS2_FS_WRITEBUFFER + bool "JFFS2 write-buffering support" depends on JFFS2_FS - default n + default y help - This enables the support for NAND flash in JFFS2. NAND is a newer - type of flash chip design than the traditional NOR flash, with - higher density but a handful of characteristics which make it more - interesting for the file system to use. + This enables the write-buffering support in JFFS2. - Say 'N' unless you have NAND flash. - -config JFFS2_FS_NOR_ECC - bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)" - depends on JFFS2_FS && EXPERIMENTAL - default n - help - This enables the experimental support for NOR flash with transparent - ECC for JFFS2. This type of flash chip is not common, however it is - available from ST Microelectronics. + This functionality is required to support JFFS2 on the following + types of flash devices: + - NAND flash including DiskOnChip + - NOR flash with transparent ECC + - DataFlash config JFFS2_COMPRESSION_OPTIONS bool "Advanced compression options for JFFS2" diff -Nru a/fs/jffs2/Makefile b/fs/jffs2/Makefile --- a/fs/jffs2/Makefile 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/Makefile 2005-05-11 20:59:08 -07:00 @@ -11,8 +11,7 @@ jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o jffs2-y += super.o -jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o -jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o +jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o diff -Nru a/fs/jffs2/build.c b/fs/jffs2/build.c --- a/fs/jffs2/build.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/build.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $ + * $Id: build.c,v 1.70 2005/02/28 08:21:05 dedekind Exp $ * */ @@ -97,14 +97,16 @@ /* First, scan the medium and build all the inode caches with lists of physical nodes */ - c->flags |= JFFS2_SB_FLAG_MOUNTING; + c->flags |= JFFS2_SB_FLAG_SCANNING; ret = jffs2_scan_medium(c); + c->flags &= ~JFFS2_SB_FLAG_SCANNING; if (ret) goto exit; D1(printk(KERN_DEBUG "Scanned flash completely\n")); D2(jffs2_dump_block_lists(c)); + c->flags |= JFFS2_SB_FLAG_BUILDING; /* Now scan the directory tree, increasing nlink according to every dirent found. */ for_each_inode(i, c, ic) { D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); @@ -116,7 +118,6 @@ cond_resched(); } } - c->flags &= ~JFFS2_SB_FLAG_MOUNTING; D1(printk(KERN_DEBUG "Pass 1 complete\n")); @@ -164,6 +165,8 @@ ic->scan_dents = NULL; cond_resched(); } + c->flags &= ~JFFS2_SB_FLAG_BUILDING; + D1(printk(KERN_DEBUG "Pass 3 complete\n")); D2(jffs2_dump_block_lists(c)); diff -Nru a/fs/jffs2/dir.c b/fs/jffs2/dir.c --- a/fs/jffs2/dir.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/dir.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: dir.c,v 1.85 2005/03/01 10:34:03 dedekind Exp $ * */ @@ -296,11 +296,11 @@ struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen, phys_ofs; - int ret; + int ret, targetlen = strlen(target); /* FIXME: If you care. We'd need to use frags for the target if it grows much more than this */ - if (strlen(target) > 254) + if (targetlen > 254) return -EINVAL; ri = jffs2_alloc_raw_inode(); @@ -314,7 +314,7 @@ * Just the node will do for now, though */ namelen = dentry->d_name.len; - ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); @@ -333,16 +333,16 @@ f = JFFS2_INODE_INFO(inode); - inode->i_size = strlen(target); + inode->i_size = targetlen; ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; - ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); + ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); + fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -353,6 +353,20 @@ jffs2_clear_inode(inode); return PTR_ERR(fn); } + + /* We use f->dents field to store the target path. */ + f->dents = kmalloc(targetlen + 1, GFP_KERNEL); + if (!f->dents) { + printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); + up(&f->sem); + jffs2_complete_reservation(c); + jffs2_clear_inode(inode); + return -ENOMEM; + } + + memcpy(f->dents, target, targetlen + 1); + D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents)); + /* No data here. Only a metadata node, which will be obsoleted by the first data write */ diff -Nru a/fs/jffs2/erase.c b/fs/jffs2/erase.c --- a/fs/jffs2/erase.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/erase.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: erase.c,v 1.74 2005/03/20 17:46:20 dedekind Exp $ * */ @@ -48,6 +48,7 @@ #else /* Linux */ struct erase_info *instr; + D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size)); instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); if (!instr) { printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); @@ -233,7 +234,7 @@ continue; } - if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) { + if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) { /* It's in the block we're erasing */ struct jffs2_raw_node_ref *this; @@ -277,11 +278,8 @@ printk("\n"); }); - if (ic->nodes == (void *)ic) { - D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino)); + if (ic->nodes == (void *)ic && ic->nlink == 0) jffs2_del_ino_cache(c, ic); - jffs2_free_inode_cache(ic); - } } static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) @@ -310,7 +308,7 @@ int ret; uint32_t bad_offset; - if (!jffs2_cleanmarker_oob(c)) { + if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) { marker_ref = jffs2_alloc_raw_node_ref(); if (!marker_ref) { printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); @@ -351,7 +349,7 @@ bad_offset += i; printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); bad: - if (!jffs2_cleanmarker_oob(c)) + if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) jffs2_free_raw_node_ref(marker_ref); kfree(ebuf); bad2: @@ -381,6 +379,13 @@ if (jffs2_write_nand_cleanmarker(c, jeb)) goto bad2; + jeb->first_node = jeb->last_node = NULL; + + jeb->free_size = c->sector_size; + jeb->used_size = 0; + jeb->dirty_size = 0; + jeb->wasted_size = 0; + } else if (c->cleanmarker_size == 0) { jeb->first_node = jeb->last_node = NULL; jeb->free_size = c->sector_size; diff -Nru a/fs/jffs2/fs.c b/fs/jffs2/fs.c --- a/fs/jffs2/fs.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/fs.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $ + * $Id: fs.c,v 1.53 2005/02/09 09:23:53 pavlov Exp $ * */ @@ -450,11 +450,15 @@ c = JFFS2_SB_INFO(sb); -#ifndef CONFIG_JFFS2_FS_NAND +#ifndef CONFIG_JFFS2_FS_WRITEBUFFER if (c->mtd->type == MTD_NANDFLASH) { printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n"); return -EINVAL; } + if (c->mtd->type == MTD_DATAFLASH) { + printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n"); + return -EINVAL; + } #endif c->flash_size = c->mtd->size; @@ -661,6 +665,14 @@ if (ret) return ret; } + + /* and Dataflash */ + if (jffs2_dataflash(c)) { + ret = jffs2_dataflash_setup(c); + if (ret) + return ret; + } + return ret; } @@ -673,5 +685,10 @@ /* add cleanups for other bizarre flashes here... */ if (jffs2_nor_ecc(c)) { jffs2_nor_ecc_flash_cleanup(c); + } + + /* and DataFlash */ + if (jffs2_dataflash(c)) { + jffs2_dataflash_cleanup(c); } } diff -Nru a/fs/jffs2/gc.c b/fs/jffs2/gc.c --- a/fs/jffs2/gc.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/gc.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $ + * $Id: gc.c,v 1.147 2005/03/20 21:43:22 dedekind Exp $ * */ @@ -50,6 +50,7 @@ put the clever wear-levelling algorithms. Eventually. */ /* We possibly want to favour the dirtier blocks more when the number of free blocks is low. */ +again: if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); nextlist = &c->bad_used_list; @@ -79,6 +80,13 @@ D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n")); nextlist = &c->erasable_list; + } else if (!list_empty(&c->erasable_pending_wbuf_list)) { + /* There are blocks are wating for the wbuf sync */ + D1(printk(KERN_DEBUG "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n")); + spin_unlock(&c->erase_completion_lock); + jffs2_flush_wbuf_pad(c); + spin_lock(&c->erase_completion_lock); + goto again; } else { /* Eep. All were empty */ D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n")); @@ -816,8 +824,7 @@ /* Doesn't matter if there's one in the same erase block. We're going to delete it too at the same time. */ - if ((raw->flash_offset & ~(c->sector_size-1)) == - (fd->raw->flash_offset & ~(c->sector_size-1))) + if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) continue; D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw))); diff -Nru a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c --- a/fs/jffs2/nodelist.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/nodelist.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.90 2004/12/08 17:59:20 dwmw2 Exp $ + * $Id: nodelist.c,v 1.93 2005/02/27 23:01:32 dwmw2 Exp $ * */ @@ -127,7 +127,7 @@ valid_ref = jffs2_first_valid_node(f->inocache->nodes); - if (!valid_ref) + if (!valid_ref && (f->inocache->ino != 1)) printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); while (valid_ref) { @@ -490,6 +490,8 @@ { struct jffs2_inode_cache **prev; D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); + BUG_ON(!new->ino); + spin_lock(&c->inocache_lock); prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; @@ -506,7 +508,7 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) { struct jffs2_inode_cache **prev; - D2(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); + D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); spin_lock(&c->inocache_lock); prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; @@ -518,6 +520,14 @@ *prev = old->next; } + /* Free it now unless it's in READING or CLEARING state, which + are the transitions upon read_inode() and clear_inode(). The + rest of the time we know nobody else is looking at it, and + if it's held by read_inode() or clear_inode() they'll free it + for themselves. */ + if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) + jffs2_free_inode_cache(old); + spin_unlock(&c->inocache_lock); } @@ -530,7 +540,6 @@ this = c->inocache_list[i]; while (this) { next = this->next; - D2(printk(KERN_DEBUG "jffs2_free_ino_caches: Freeing ino #%u at %p\n", this->ino, this)); jffs2_free_inode_cache(this); this = next; } diff -Nru a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h --- a/fs/jffs2/nodelist.h 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/nodelist.h 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $ + * $Id: nodelist.h,v 1.128 2005/02/27 23:01:32 dwmw2 Exp $ * */ @@ -135,6 +135,7 @@ #define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */ #define INO_STATE_GC 4 /* GCing a 'pristine' node */ #define INO_STATE_READING 5 /* In read_inode() */ +#define INO_STATE_CLEARING 6 /* In clear_inode() */ #define INOCACHE_HASHSIZE 128 @@ -462,7 +463,7 @@ /* erase.c */ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count); -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER /* wbuf.c */ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino); int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); diff -Nru a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c --- a/fs/jffs2/nodemgmt.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/nodemgmt.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.115 2004/11/22 11:07:21 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.120 2005/03/20 17:46:20 dedekind Exp $ * */ @@ -308,7 +308,10 @@ D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); #if 1 - if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) { + /* we could get some obsolete nodes after nextblock was refiled + in wbuf.c */ + if ((c->nextblock || !ref_obsolete(new)) + &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) { printk(KERN_WARNING "argh. node added in wrong place\n"); jffs2_free_raw_node_ref(new); return -EINVAL; @@ -332,7 +335,7 @@ c->used_size += len; } - if (!jeb->free_size && !jeb->dirty_size) { + if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); @@ -400,7 +403,7 @@ jeb = &c->blocks[blocknr]; if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && - !(c->flags & JFFS2_SB_FLAG_MOUNTING)) { + !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { /* Hm. This may confuse static lock analysis. If any of the above three conditions is false, we're going to return from this function without actually obliterating any nodes or freeing @@ -467,8 +470,8 @@ D1(ACCT_PARANOIA_CHECK(jeb)); - if (c->flags & JFFS2_SB_FLAG_MOUNTING) { - /* Mount in progress. Don't muck about with the block + if (c->flags & JFFS2_SB_FLAG_SCANNING) { + /* Flash scanning is in progress. Don't muck about with the block lists because they're not ready yet, and don't actually obliterate nodes that look obsolete. If they weren't marked obsolete on the flash at the time they _became_ @@ -527,7 +530,8 @@ spin_unlock(&c->erase_completion_lock); - if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) { + if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) || + (c->flags & JFFS2_SB_FLAG_BUILDING)) { /* We didn't lock the erase_free_sem */ return; } @@ -590,11 +594,8 @@ *p = ref->next_in_ino; ref->next_in_ino = NULL; - if (ic->nodes == (void *)ic) { - D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino)); + if (ic->nodes == (void *)ic && ic->nlink == 0) jffs2_del_ino_cache(c, ic); - jffs2_free_inode_cache(ic); - } spin_unlock(&c->erase_completion_lock); } diff -Nru a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h --- a/fs/jffs2/os-linux.h 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/os-linux.h 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: os-linux.h,v 1.55 2005/03/17 20:23:06 gleixner Exp $ * */ @@ -97,9 +97,12 @@ #endif } + #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) +#define jffs2_is_writebuffered(c) (c->wbuf != NULL) -#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) +#ifndef CONFIG_JFFS2_FS_WRITEBUFFER +#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) #define jffs2_can_mark_obsolete(c) (1) #define jffs2_cleanmarker_oob(c) (0) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) @@ -116,11 +119,13 @@ #define jffs2_wbuf_timeout NULL #define jffs2_wbuf_process NULL #define jffs2_nor_ecc(c) (0) +#define jffs2_dataflash(c) (0) #define jffs2_nor_ecc_flash_setup(c) (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) #else /* NAND and/or ECC'd NOR support present */ +#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM) #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) @@ -142,16 +147,16 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); int jffs2_nand_flash_setup(struct jffs2_sb_info *c); void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c); -#ifdef CONFIG_JFFS2_FS_NOR_ECC + #define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC)) int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c); void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); -#else -#define jffs2_nor_ecc(c) (0) -#define jffs2_nor_ecc_flash_setup(c) (0) -#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) -#endif /* NOR ECC */ -#endif /* NAND */ + +#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH) +int jffs2_dataflash_setup(struct jffs2_sb_info *c); +void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); + +#endif /* WRITEBUFFER */ /* erase.c */ static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) diff -Nru a/fs/jffs2/read.c b/fs/jffs2/read.c --- a/fs/jffs2/read.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/read.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $ + * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $ * */ @@ -214,33 +214,3 @@ return 0; } -/* Core function to read symlink target. */ -char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f) -{ - char *buf; - int ret; - - down(&f->sem); - - if (!f->metadata) { - printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino); - up(&f->sem); - return ERR_PTR(-EINVAL); - } - buf = kmalloc(f->metadata->size+1, GFP_USER); - if (!buf) { - up(&f->sem); - return ERR_PTR(-ENOMEM); - } - buf[f->metadata->size]=0; - - ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size); - - up(&f->sem); - - if (ret) { - kfree(buf); - return ERR_PTR(ret); - } - return buf; -} diff -Nru a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c --- a/fs/jffs2/readinode.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/readinode.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $ + * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $ * */ @@ -623,6 +623,40 @@ case. */ if (!je32_to_cpu(latest_node->isize)) latest_node->isize = latest_node->dsize; + + if (f->inocache->state != INO_STATE_CHECKING) { + /* Symlink's inode data is the target path. Read it and + * keep in RAM to facilitate quick follow symlink operation. + * We use f->dents field to store the target path, which + * is somewhat ugly. */ + f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); + if (!f->dents) { + printk(KERN_WARNING "Can't allocate %d bytes of memory " + "for the symlink target path cache\n", + je32_to_cpu(latest_node->csize)); + up(&f->sem); + jffs2_do_clear_inode(c, f); + return -ENOMEM; + } + + ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), + je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); + + if (ret || retlen != je32_to_cpu(latest_node->csize)) { + if (retlen != je32_to_cpu(latest_node->csize)) + ret = -EIO; + kfree(f->dents); + f->dents = NULL; + up(&f->sem); + jffs2_do_clear_inode(c, f); + return -ret; + } + + ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; + D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", + (char *)f->dents)); + } + /* fall through... */ case S_IFBLK: @@ -672,6 +706,9 @@ down(&f->sem); deleted = f->inocache && !f->inocache->nlink; + if (f->inocache && f->inocache->state != INO_STATE_CHECKING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); + if (f->metadata) { if (deleted) jffs2_mark_node_obsolete(c, f->metadata->raw); @@ -680,16 +717,27 @@ jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); - fds = f->dents; + /* For symlink inodes we us f->dents to store the target path name */ + if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { + if (f->dents) { + kfree(f->dents); + f->dents = NULL; + } + } else { + fds = f->dents; - while(fds) { - fd = fds; - fds = fd->next; - jffs2_free_full_dirent(fd); + while(fds) { + fd = fds; + fds = fd->next; + jffs2_free_full_dirent(fd); + } } - if (f->inocache && f->inocache->state != INO_STATE_CHECKING) + if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); + if (f->inocache->nodes == (void *)f->inocache) + jffs2_del_ino_cache(c, f->inocache); + } up(&f->sem); } diff -Nru a/fs/jffs2/scan.c b/fs/jffs2/scan.c --- a/fs/jffs2/scan.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/scan.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $ + * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $ * */ #include @@ -19,7 +19,7 @@ #include #include "nodelist.h" -#define EMPTY_SCAN_SIZE 1024 +#define DEFAULT_EMPTY_SCAN_SIZE 1024 #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ c->free_size -= _x; c->dirty_size += _x; \ @@ -68,13 +68,21 @@ static inline int min_free(struct jffs2_sb_info *c) { uint32_t min = 2 * sizeof(struct jffs2_raw_inode); -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) return c->wbuf_pagesize; #endif return min; } + +static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { + if (sector_size < DEFAULT_EMPTY_SCAN_SIZE) + return sector_size; + else + return DEFAULT_EMPTY_SCAN_SIZE; +} + int jffs2_scan_medium(struct jffs2_sb_info *c) { int i, ret; @@ -220,7 +228,7 @@ c->dirty_size -= c->nextblock->dirty_size; c->nextblock->dirty_size = 0; } -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { /* If we're going to start writing into a block which already contains data, and the end of the data isn't page-aligned, @@ -286,7 +294,7 @@ uint32_t hdr_crc, buf_ofs, buf_len; int err; int noise = 0; -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER int cleanmarkerfound = 0; #endif @@ -295,7 +303,7 @@ D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs)); -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (jffs2_cleanmarker_oob(c)) { int ret = jffs2_check_nand_cleanmarker(c, jeb); D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret)); @@ -316,7 +324,7 @@ if (!buf_size) { buf_len = c->sector_size; } else { - buf_len = EMPTY_SCAN_SIZE; + buf_len = EMPTY_SCAN_SIZE(c->sector_size); err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); if (err) return err; @@ -326,11 +334,11 @@ ofs = 0; /* Scan only 4KiB of 0xFF before declaring it's empty */ - while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) + while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) ofs += 4; - if (ofs == EMPTY_SCAN_SIZE) { -#ifdef CONFIG_JFFS2_FS_NAND + if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) { +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (jffs2_cleanmarker_oob(c)) { /* scan oob, take care of cleanmarker */ int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound); @@ -343,7 +351,10 @@ } #endif D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); - return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ + if (c->cleanmarker_size == 0) + return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */ + else + return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ } if (ofs) { D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, @@ -422,8 +433,8 @@ /* If we're only checking the beginning of a block with a cleanmarker, bail now */ if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && - c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) { - D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE)); + c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) { + D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); return BLK_STATE_CLEANMARKER; } @@ -618,7 +629,7 @@ } if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size - && (!jeb->first_node || !jeb->first_node->next_in_ino) ) + && (!jeb->first_node || !jeb->first_node->next_phys) ) return BLK_STATE_CLEANMARKER; /* move blocks with max 4 byte dirty space to cleanlist */ diff -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c --- a/fs/jffs2/super.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/super.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.104 2004/11/23 15:37:31 gleixner Exp $ + * $Id: super.c,v 1.105 2005/02/09 09:23:54 pavlov Exp $ * */ @@ -309,7 +309,7 @@ int ret; printk(KERN_INFO "JFFS2 version 2.2." -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER " (NAND)" #endif " (C) 2001-2003 Red Hat, Inc.\n"); diff -Nru a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c --- a/fs/jffs2/symlink.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/symlink.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $ + * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $ * */ @@ -19,27 +19,45 @@ #include "nodelist.h" static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); -static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd); struct inode_operations jffs2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jffs2_follow_link, - .put_link = jffs2_put_link, .setattr = jffs2_setattr }; static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { - unsigned char *buf; - buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); - nd_set_link(nd, buf); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); + + /* + * We don't acquire the f->sem mutex here since the only data we + * use is f->dents which in case of the symlink inode points to the + * symlink's target path. + * + * 1. If we are here the inode has already built and f->dents has + * to point to the target path. + * 2. Nobody uses f->dents (if the inode is symlink's inode). The + * exception is inode freeing function which frees f->dents. But + * it can't be called while we are here and before VFS has + * stopped using our f->dents string which we provide by means of + * nd_set_link() call. + */ + + if (!f->dents) { + printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); + return -EIO; + } + D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); + + nd_set_link(nd, (char *)f->dents); + + /* + * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe + * since the only way that may cause f->dents to be changed is iput() operation. + * But VFS will not use f->dents after iput() has been called. + */ return 0; } -static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd) -{ - char *s = nd_get_link(nd); - if (!IS_ERR(s)) - kfree(s); -} diff -Nru a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c --- a/fs/jffs2/wbuf.c 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/wbuf.c 2005-05-11 20:59:08 -07:00 @@ -9,7 +9,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.82 2004/11/20 22:08:31 dwmw2 Exp $ + * $Id: wbuf.c,v 1.91 2005/03/18 09:58:06 dedekind Exp $ * */ @@ -83,7 +83,7 @@ struct jffs2_inodirty *new; /* Mark the superblock dirty so that kupdated will flush... */ - OFNI_BS_2SFFJ(c)->s_dirt = 1; + jffs2_erase_pending_trigger(c); if (jffs2_wbuf_pending_for_ino(c, ino)) return; @@ -130,7 +130,10 @@ } } -static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +#define REFILE_NOTEMPTY 0 +#define REFILE_ANYWAY 1 + +static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty) { D1(printk("About to refile bad block at %08x\n", jeb->offset)); @@ -144,7 +147,7 @@ D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset)); list_add(&jeb->list, &c->bad_used_list); } else { - BUG(); + BUG_ON(allow_empty == REFILE_NOTEMPTY); /* It has to have had some nodes or we couldn't be here */ D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset)); list_add(&jeb->list, &c->erase_pending_list); @@ -179,7 +182,7 @@ jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; - jffs2_block_refile(c, jeb); + jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); /* Find the first node to be recovered, by skipping over every node which ends before the wbuf starts, or which is obsolete. */ @@ -264,17 +267,16 @@ ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); if (ret) { printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); - if (buf) - kfree(buf); + kfree(buf); return; } if (end-start >= c->wbuf_pagesize) { - /* Need to do another write immediately. This, btw, - means that we'll be writing from 'buf' and not from - the wbuf. Since if we're writing from the wbuf there - won't be more than a wbuf full of data, now will - there? :) */ - + /* Need to do another write immediately, but it's possible + that this is just because the wbuf itself is completely + full, and there's nothing earlier read back from the + flash. Hence 'buf' isn't necessarily what we're writing + from. */ + unsigned char *rewrite_buf = buf?:c->wbuf; uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", @@ -292,9 +294,9 @@ #endif if (jffs2_cleanmarker_oob(c)) ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, - buf, NULL, c->oobinfo); + rewrite_buf, NULL, c->oobinfo); else - ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf); + ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); if (ret || retlen != towrite) { /* Argh. We tried. Really we did. */ @@ -321,10 +323,10 @@ c->wbuf_len = (end - start) - towrite; c->wbuf_ofs = ofs + towrite; - memcpy(c->wbuf, buf + towrite, c->wbuf_len); + memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ - - kfree(buf); + if (buf) + kfree(buf); } else { /* OK, now we're left with the dregs in whichever buffer we're using */ if (buf) { @@ -413,9 +415,9 @@ int ret; size_t retlen; - /* Nothing to do if not NAND flash. In particular, we shouldn't + /* Nothing to do if not write-buffering the flash. In particular, we shouldn't del_timer() the timer we never initialised. */ - if (jffs2_can_mark_obsolete(c)) + if (!jffs2_is_writebuffered(c)) return 0; if (!down_trylock(&c->alloc_sem)) { @@ -424,7 +426,7 @@ BUG(); } - if(!c->wbuf || !c->wbuf_len) + if (!c->wbuf_len) /* already checked c->wbuf above */ return 0; /* claim remaining space on the page @@ -433,7 +435,7 @@ if we have a switch to next page, we will not have enough remaining space for this. */ - if (pad) { + if (pad && !jffs2_dataflash(c)) { c->wbuf_len = PAD(c->wbuf_len); /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR @@ -484,7 +486,7 @@ spin_lock(&c->erase_completion_lock); /* Adjust free size of the block if we padded. */ - if (pad) { + if (pad && !jffs2_dataflash(c)) { struct jffs2_eraseblock *jeb; jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; @@ -532,6 +534,9 @@ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino)); + if (!c->wbuf) + return 0; + down(&c->alloc_sem); if (!jffs2_wbuf_pending_for_ino(c, ino)) { D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); @@ -547,6 +552,10 @@ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n")); down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); + /* retry flushing wbuf in case jffs2_wbuf_recover + left some data in the wbuf */ + if (ret) + ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); up_write(&c->wbuf_sem); } else while (old_wbuf_len && old_wbuf_ofs == c->wbuf_ofs) { @@ -561,6 +570,10 @@ down(&c->alloc_sem); down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); + /* retry flushing wbuf in case jffs2_wbuf_recover + left some data in the wbuf */ + if (ret) + ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); up_write(&c->wbuf_sem); break; } @@ -578,15 +591,27 @@ { int ret; + if (!c->wbuf) + return 0; + down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); + /* retry - maybe wbuf recover left some data in wbuf. */ + if (ret) + ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); up_write(&c->wbuf_sem); return ret; } +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER +#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) +#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) +#else #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) +#endif + int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) { struct kvec outvecs[3]; @@ -601,7 +626,7 @@ uint32_t outvec_to = to; /* If not NAND flash, don't bother */ - if (!c->wbuf) + if (!jffs2_is_writebuffered(c)) return jffs2_flash_direct_writev(c, invecs, count, to, retlen); down_write(&c->wbuf_sem); @@ -630,7 +655,7 @@ erase block. Anything else, and you die. New block starts at xxx000c (0-b = block header) */ - if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) { + if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { /* It's a write to a new block */ if (c->wbuf_len) { D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); @@ -762,9 +787,18 @@ if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { /* At this point we have no problem, - c->wbuf is empty. + c->wbuf is empty. However refile nextblock to avoid + writing again to same address. */ - *retlen = donelen; + struct jffs2_eraseblock *jeb; + + spin_lock(&c->erase_completion_lock); + + jeb = &c->blocks[outvec_to / c->sector_size]; + jffs2_block_refile(c, jeb, REFILE_ANYWAY); + + *retlen = 0; + spin_unlock(&c->erase_completion_lock); goto exit; } @@ -819,7 +853,7 @@ { struct kvec vecs[1]; - if (jffs2_can_mark_obsolete(c)) + if (!jffs2_is_writebuffered(c)) return c->mtd->write(c->mtd, ofs, len, retlen, buf); vecs[0].iov_base = (unsigned char *) buf; @@ -835,40 +869,43 @@ loff_t orbf = 0, owbf = 0, lwbf = 0; int ret; - /* Read flash */ - if (!jffs2_can_mark_obsolete(c)) { - down_read(&c->wbuf_sem); + if (!jffs2_is_writebuffered(c)) + return c->mtd->read(c->mtd, ofs, len, retlen, buf); - 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); + /* Read flash */ + if (jffs2_cleanmarker_oob(c)) + ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); + else + ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); - if ( (ret == -EBADMSG) && (*retlen == len) ) { - printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", - len, ofs); - /* - * We have the raw data without ECC correction in the buffer, maybe - * we are lucky and all data or parts are correct. We check the node. - * If data are corrupted node check will sort it out. - * We keep this block, it will fail on write or erase and the we - * mark it bad. Or should we do that now? But we should give him a chance. - * Maybe we had a system crash or power loss before the ecc write or - * a erase was completed. - * So we return success. :) - */ - ret = 0; - } - } else - return c->mtd->read(c->mtd, ofs, len, retlen, buf); + if ( (ret == -EBADMSG) && (*retlen == len) ) { + printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", + len, ofs); + /* + * We have the raw data without ECC correction in the buffer, maybe + * we are lucky and all data or parts are correct. We check the node. + * If data are corrupted node check will sort it out. + * We keep this block, it will fail on write or erase and the we + * mark it bad. Or should we do that now? But we should give him a chance. + * Maybe we had a system crash or power loss before the ecc write or + * a erase was completed. + * So we return success. :) + */ + ret = 0; + } /* if no writebuffer available or write buffer empty, return */ if (!c->wbuf_pagesize || !c->wbuf_len) - goto exit; + return ret;; /* if we read in a different block, return */ - if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) - goto exit; + if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs)) + return ret; + + /* Lock only if we have reason to believe wbuf contains relevant data, + so that checking an erased block during wbuf recovery space allocation + does not deadlock. */ + down_read(&c->wbuf_sem); if (ofs >= c->wbuf_ofs) { owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ @@ -1161,7 +1198,27 @@ kfree(c->wbuf); } -#ifdef CONFIG_JFFS2_FS_NOR_ECC +int jffs2_dataflash_setup(struct jffs2_sb_info *c) { + c->cleanmarker_size = 0; /* No cleanmarkers needed */ + + /* Initialize write buffer */ + init_rwsem(&c->wbuf_sem); + c->wbuf_pagesize = c->sector_size; + c->wbuf_ofs = 0xFFFFFFFF; + + c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); + if (!c->wbuf) + return -ENOMEM; + + printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize); + + return 0; +} + +void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { + kfree(c->wbuf); +} + int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { /* Cleanmarker is actually larger on the flashes */ c->cleanmarker_size = 16; @@ -1181,4 +1238,3 @@ 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 2005-05-11 20:59:08 -07:00 +++ b/fs/jffs2/write.c 2005-05-11 20:59:08 -07:00 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $ + * $Id: write.c,v 1.91 2005/03/01 10:34:03 dedekind Exp $ * */ @@ -136,6 +136,15 @@ raw->__totlen = PAD(sizeof(*ri)+datalen); raw->next_phys = NULL; + if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) { + BUG_ON(!retried); + D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, " + "highest version %d -> updating dnode\n", + je32_to_cpu(ri->version), f->highest_version)); + ri->version = cpu_to_je32(++f->highest_version); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + } + ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen, (alloc_mode==ALLOC_GC)?0:f->inocache->ino); @@ -280,6 +289,16 @@ raw->__totlen = PAD(sizeof(*rd)+namelen); raw->next_phys = NULL; + if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) { + BUG_ON(!retried); + D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, " + "highest version %d -> updating dirent\n", + je32_to_cpu(rd->version), f->highest_version)); + rd->version = cpu_to_je32(++f->highest_version); + fd->version = je32_to_cpu(rd->version); + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + } + ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); if (ret || (retlen != sizeof(*rd) + namelen)) { @@ -625,20 +644,23 @@ down(&dead_f->sem); - while (dead_f->dents) { - /* There can be only deleted ones */ - fd = dead_f->dents; - - dead_f->dents = fd->next; - - if (fd->ino) { - printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", - dead_f->inocache->ino, fd->name, fd->ino); - } else { - D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino)); + if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { + while (dead_f->dents) { + /* There can be only deleted ones */ + fd = dead_f->dents; + + dead_f->dents = fd->next; + + if (fd->ino) { + printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", + dead_f->inocache->ino, fd->name, fd->ino); + } else { + D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", + fd->name, dead_f->inocache->ino)); + } + jffs2_mark_node_obsolete(c, fd->raw); + jffs2_free_full_dirent(fd); } - jffs2_mark_node_obsolete(c, fd->raw); - jffs2_free_full_dirent(fd); } dead_f->inocache->nlink--; diff -Nru a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h --- a/include/linux/jffs2_fs_sb.h 2005-05-11 20:59:08 -07:00 +++ b/include/linux/jffs2_fs_sb.h 2005-05-11 20:59:08 -07:00 @@ -14,7 +14,8 @@ #include #define JFFS2_SB_FLAG_RO 1 -#define JFFS2_SB_FLAG_MOUNTING 2 +#define JFFS2_SB_FLAG_SCANNING 2 /* Flash scanning is in progress */ +#define JFFS2_SB_FLAG_BUILDING 4 /* File system building is in progress */ struct jffs2_inodirty; @@ -94,7 +95,7 @@ to an obsoleted node. I don't like this. Alternatives welcomed. */ struct semaphore erase_free_sem; -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER /* Write-behind buffer for NAND flash */ unsigned char *wbuf; uint32_t wbuf_ofs; diff -Nru a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h --- a/include/linux/mtd/cfi.h 2005-05-11 20:59:08 -07:00 +++ b/include/linux/mtd/cfi.h 2005-05-11 20:59:08 -07:00 @@ -1,7 +1,7 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.50 2004/11/20 12:46:51 dwmw2 Exp $ + * $Id: cfi.h,v 1.53 2005/03/15 19:03:13 gleixner Exp $ */ #ifndef __MTD_CFI_H__ @@ -148,6 +148,14 @@ uint8_t extra[0]; } __attribute__((packed)); +struct cfi_intelext_otpinfo { + uint32_t ProtRegAddr; + uint16_t FactGroups; + uint8_t FactProtRegSize; + uint16_t UserGroups; + uint8_t UserProtRegSize; +} __attribute__((packed)); + struct cfi_intelext_blockinfo { uint16_t NumIdentBlocks; uint16_t BlockSize; @@ -244,7 +252,7 @@ * It looks too long to be inline, but in the common case it should almost all * get optimised away. */ -static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi) +static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi) { map_word val = { {0} }; int wordwidth, words_per_bus, chip_mode, chips_per_word; @@ -306,6 +314,69 @@ return val; } #define CMD(x) cfi_build_cmd((x), map, cfi) + + +static inline unsigned char cfi_merge_status(map_word val, struct map_info *map, + struct cfi_private *cfi) +{ + int wordwidth, words_per_bus, chip_mode, chips_per_word; + unsigned long onestat, res = 0; + int i; + + /* We do it this way to give the compiler a fighting chance + of optimising away all the crap for 'bankwidth' larger than + an unsigned long, in the common case where that support is + disabled */ + if (map_bankwidth_is_large(map)) { + wordwidth = sizeof(unsigned long); + words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1 + } else { + wordwidth = map_bankwidth(map); + words_per_bus = 1; + } + + chip_mode = map_bankwidth(map) / cfi_interleave(cfi); + chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); + + onestat = val.x[0]; + /* Or all status words together */ + for (i=1; i < words_per_bus; i++) { + onestat |= val.x[i]; + } + + res = onestat; + switch(chips_per_word) { + default: BUG(); +#if BITS_PER_LONG >= 64 + case 8: + res |= (onestat >> (chip_mode * 32)); +#endif + case 4: + res |= (onestat >> (chip_mode * 16)); + case 2: + res |= (onestat >> (chip_mode * 8)); + case 1: + ; + } + + /* Last, determine what the bit-pattern should be for a single + device, according to chip mode and endianness... */ + switch (chip_mode) { + case 1: + break; + case 2: + res = cfi16_to_cpu(res); + break; + case 4: + res = cfi32_to_cpu(res); + break; + default: BUG(); + } + return res; +} + +#define MERGESTATUS(x) cfi_merge_status((x), map, cfi) + /* * Sends a CFI command to a bank of flash for the given geometry. diff -Nru a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h --- a/include/linux/mtd/flashchip.h 2005-05-11 20:59:08 -07:00 +++ b/include/linux/mtd/flashchip.h 2005-05-11 20:59:08 -07:00 @@ -6,7 +6,7 @@ * * (C) 2000 Red Hat. GPLd. * - * $Id: flashchip.h,v 1.15 2004/11/05 22:41:06 nico Exp $ + * $Id: flashchip.h,v 1.17 2005/03/14 18:27:15 bjd Exp $ * */ @@ -29,6 +29,7 @@ FL_ERASE_SUSPENDED, FL_WRITING, FL_WRITING_TO_BUFFER, + FL_OTP_WRITE, FL_WRITE_SUSPENDING, FL_WRITE_SUSPENDED, FL_PM_SUSPENDED, @@ -62,8 +63,8 @@ flstate_t state; flstate_t oldstate; - int write_suspended:1; - int erase_suspended:1; + unsigned int write_suspended:1; + unsigned int erase_suspended:1; unsigned long in_progress_block_addr; spinlock_t *mutex; diff -Nru a/include/linux/mtd/map.h b/include/linux/mtd/map.h --- a/include/linux/mtd/map.h 2005-05-11 20:59:08 -07:00 +++ b/include/linux/mtd/map.h 2005-05-11 20:59:08 -07:00 @@ -1,6 +1,6 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.46 2005/01/05 17:09:44 dwmw2 Exp $ */ +/* $Id: map.h,v 1.48 2005/02/16 15:54:59 nico Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ @@ -263,6 +263,17 @@ return r; } +static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2) +{ + map_word r; + int i; + + for (i=0; ibankwidth)) -#define map_is_linear(map) (1) +#define map_is_linear(map) ({ (void)(map); 1; }) #endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ diff -Nru a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h --- a/include/linux/mtd/mtd.h 2005-05-11 20:59:08 -07:00 +++ b/include/linux/mtd/mtd.h 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ /* - * $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $ + * $Id: mtd.h,v 1.57 2005/02/08 17:11:15 nico Exp $ * * Copyright (C) 1999-2003 David Woodhouse et al. * @@ -113,12 +113,12 @@ * flash devices. The user data is one time programmable but the * factory data is read only. */ - int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - + int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - - /* This function is not yet implemented */ + int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); + int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); /* kvec-based read/write methods. We need these especially for NAND flash, with its limited number of write cycles per erase. diff -Nru a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h --- a/include/linux/mtd/nand.h 2005-05-11 20:59:08 -07:00 +++ b/include/linux/mtd/nand.h 2005-05-11 20:59:08 -07:00 @@ -5,7 +5,7 @@ * Steven J. Hill * Thomas Gleixner * - * $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $ + * $Id: nand.h,v 1.71 2005/02/09 12:12:59 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -48,6 +48,10 @@ * 02-08-2004 tglx added option field to nand structure for chip anomalities * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id * update of nand_chip structure description + * 01-17-2005 dmarlin added extended commands for AG-AND device and added option + * for BBT_AUTO_REFRESH. + * 01-20-2005 dmarlin added optional pointer to hardware specific callback for + * extra error status checks. */ #ifndef __LINUX_MTD_NAND_H #define __LINUX_MTD_NAND_H @@ -115,6 +119,25 @@ #define NAND_CMD_READSTART 0x30 #define NAND_CMD_CACHEDPROG 0x15 +/* Extended commands for AG-AND device */ +/* + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but + * there is no way to distinguish that from NAND_CMD_READ0 + * until the remaining sequence of commands has been completed + * so add a high order bit and mask it off in the command. + */ +#define NAND_CMD_DEPLETE1 0x100 +#define NAND_CMD_DEPLETE2 0x38 +#define NAND_CMD_STATUS_MULTI 0x71 +#define NAND_CMD_STATUS_ERROR 0x72 +/* multi-bank error status (banks 0-3) */ +#define NAND_CMD_STATUS_ERROR0 0x73 +#define NAND_CMD_STATUS_ERROR1 0x74 +#define NAND_CMD_STATUS_ERROR2 0x75 +#define NAND_CMD_STATUS_ERROR3 0x76 +#define NAND_CMD_STATUS_RESET 0x7f +#define NAND_CMD_STATUS_CLEAR 0xff + /* Status bits */ #define NAND_STATUS_FAIL 0x01 #define NAND_STATUS_FAIL_N1 0x02 @@ -143,7 +166,7 @@ /* * Constants for Hardware ECC -*/ + */ /* Reset Hardware ECC for read */ #define NAND_ECC_READ 0 /* Reset Hardware ECC for write */ @@ -151,6 +174,10 @@ /* Enable Hardware ECC before syndrom is read back from flash */ #define NAND_ECC_READSYN 2 +/* Bit mask for flags passed to do_nand_read_ecc */ +#define NAND_GET_DEVICE 0x80 + + /* Option constants for bizarre disfunctionality and real * features */ @@ -170,6 +197,10 @@ /* Chip has a array of 4 pages which can be read without * additional ready /busy waits */ #define NAND_4PAGE_ARRAY 0x00000040 +/* Chip requires that BBT is periodically rewritten to prevent + * bits from adjacent blocks from 'leaking' in altering data. + * This happens with the Renesas AG-AND chips, possibly others. */ +#define BBT_AUTO_REFRESH 0x00000080 /* Options valid for Samsung large page devices */ #define NAND_SAMSUNG_LP_OPTIONS \ @@ -192,7 +223,8 @@ * This can only work if we have the ecc bytes directly behind the * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ #define NAND_HWECC_SYNDROME 0x00020000 - +/* This option skips the bbt scan during initialization. */ +#define NAND_SKIP_BBTSCAN 0x00040000 /* Options set by nand scan */ /* Nand scan has allocated oob_buf */ @@ -283,6 +315,8 @@ * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices * @priv: [OPTIONAL] pointer to private chip date + * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks + * (determine if errors are correctable) */ struct nand_chip { @@ -338,6 +372,7 @@ struct nand_bbt_descr *badblock_pattern; struct nand_hw_control *controller; void *priv; + int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); }; /* @@ -459,6 +494,9 @@ extern int nand_default_bbt (struct mtd_info *mtd); extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); +extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags); /* * Constants for oob configuration diff -Nru a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h --- /dev/null Wed Dec 31 16:00:00 196900 +++ b/include/linux/mtd/plat-ram.h 2005-05-11 20:59:08 -07:00 @@ -0,0 +1,35 @@ +/* linux/include/mtd/plat-ram.h + * + * (c) 2004 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks + * + * Generic platform device based RAM map + * + * $Id: plat-ram.h,v 1.2 2005/01/24 00:37:40 bjd Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __LINUX_MTD_PLATRAM_H +#define __LINUX_MTD_PLATRAM_H __FILE__ + +#define PLATRAM_RO (0) +#define PLATRAM_RW (1) + +struct platdata_mtd_ram { + char *mapname; + char **probes; + struct mtd_partition *partitions; + int nr_partitions; + int bankwidth; + + /* control callbacks */ + + void (*set_rw)(struct device *dev, int to); +}; + +#endif /* __LINUX_MTD_PLATRAM_H */ diff -Nru a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h --- a/include/mtd/mtd-abi.h 2005-05-11 20:59:08 -07:00 +++ b/include/mtd/mtd-abi.h 2005-05-11 20:59:08 -07:00 @@ -1,5 +1,5 @@ /* - * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $ + * $Id: mtd-abi.h,v 1.10 2005/02/09 09:17:42 pavlov Exp $ * * Portions of MTD ABI definition which are shared by kernel and user space */ @@ -29,6 +29,7 @@ #define MTD_NORFLASH 3 #define MTD_NANDFLASH 4 #define MTD_PEROM 5 +#define MTD_DATAFLASH 6 #define MTD_OTHER 14 #define MTD_UNKNOWN 15 @@ -61,6 +62,11 @@ #define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme #define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read) +/* OTP mode selection */ +#define MTD_OTP_OFF 0 +#define MTD_OTP_FACTORY 1 +#define MTD_OTP_USER 2 + struct mtd_info_user { uint8_t type; uint32_t flags; @@ -80,6 +86,12 @@ uint32_t regionindex; }; +struct otp_info { + uint32_t start; + uint32_t length; + uint32_t locked; +}; + #define MEMGETINFO _IOR('M', 1, struct mtd_info_user) #define MEMERASE _IOW('M', 2, struct erase_info_user) #define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) @@ -92,6 +104,10 @@ #define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) #define MEMGETBADBLOCK _IOW('M', 11, loff_t) #define MEMSETBADBLOCK _IOW('M', 12, loff_t) +#define OTPSELECT _IOR('M', 13, int) +#define OTPGETREGIONCOUNT _IOW('M', 14, int) +#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) +#define OTPLOCK _IOR('M', 16, struct otp_info) struct nand_oobinfo { uint32_t useecc;