Fedora Core 2 - 1.494
authorMarc Fiuczynski <mef@cs.princeton.edu>
Wed, 15 Sep 2004 17:11:56 +0000 (17:11 +0000)
committerMarc Fiuczynski <mef@cs.princeton.edu>
Wed, 15 Sep 2004 17:11:56 +0000 (17:11 +0000)
173 files changed:
CREDITS
arch/alpha/kernel/entry.S
arch/alpha/kernel/process.c
arch/alpha/kernel/signal.c
arch/ppc/Kconfig
arch/ppc/boot/common/misc-common.c
arch/ppc/boot/simple/Makefile
arch/ppc/boot/simple/head.S
arch/ppc/boot/simple/misc-ev64260.S
arch/ppc/boot/simple/misc.c
arch/ppc/configs/ev64260_defconfig
arch/ppc/platforms/85xx/sbc8560.c
arch/ppc/platforms/85xx/sbc8560.h
arch/ppc/platforms/85xx/sbc85xx.c
arch/ppc/platforms/Makefile
arch/ppc/platforms/ev64260.h
arch/ppc/syslib/Makefile
arch/ppc/syslib/gt64260_pic.c
arch/ppc/syslib/open_pic.c
configs/kernel-2.6.7-i586-smp.config
configs/kernel-2.6.7-i586.config
configs/kernel-2.6.7-i686-smp.config
configs/kernel-2.6.7-i686.config
drivers/mtd/Kconfig
drivers/mtd/Makefile
drivers/mtd/afs.c
drivers/mtd/chips/Kconfig
drivers/mtd/chips/Makefile
drivers/mtd/chips/amd_flash.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/chips/cfi_probe.c
drivers/mtd/chips/chipreg.c
drivers/mtd/chips/gen_probe.c
drivers/mtd/chips/jedec.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/chips/map_ram.c
drivers/mtd/chips/map_rom.c
drivers/mtd/chips/sharp.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/Makefile
drivers/mtd/devices/blkmtd.c
drivers/mtd/devices/doc2000.c
drivers/mtd/devices/doc2001.c
drivers/mtd/devices/doc2001plus.c
drivers/mtd/devices/docprobe.c
drivers/mtd/devices/lart.c
drivers/mtd/devices/ms02-nv.c
drivers/mtd/devices/ms02-nv.h
drivers/mtd/devices/pmc551.c
drivers/mtd/ftl.c
drivers/mtd/inftlcore.c
drivers/mtd/inftlmount.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/amd76xrom.c
drivers/mtd/maps/arctic-mtd.c
drivers/mtd/maps/autcpu12-nvram.c
drivers/mtd/maps/beech-mtd.c
drivers/mtd/maps/cdb89712.c
drivers/mtd/maps/ceiva.c
drivers/mtd/maps/cfi_flagadm.c
drivers/mtd/maps/cstm_mips_ixx.c
drivers/mtd/maps/dbox2-flash.c
drivers/mtd/maps/dc21285.c
drivers/mtd/maps/dilnetpc.c
drivers/mtd/maps/ebony.c
drivers/mtd/maps/edb7312.c
drivers/mtd/maps/elan-104nc.c
drivers/mtd/maps/epxa10db-flash.c
drivers/mtd/maps/fortunet.c
drivers/mtd/maps/h720x-flash.c
drivers/mtd/maps/impa7.c
drivers/mtd/maps/integrator-flash.c
drivers/mtd/maps/iq80310.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/l440gx.c
drivers/mtd/maps/lasat.c
drivers/mtd/maps/lubbock-flash.c
drivers/mtd/maps/map_funcs.c
drivers/mtd/maps/mbx860.c
drivers/mtd/maps/netsc520.c
drivers/mtd/maps/nettel.c
drivers/mtd/maps/ocelot.c
drivers/mtd/maps/octagon-5066.c
drivers/mtd/maps/pb1xxx-flash.c
drivers/mtd/maps/pci.c
drivers/mtd/maps/pcmciamtd.c
drivers/mtd/maps/physmap.c
drivers/mtd/maps/pnc2000.c
drivers/mtd/maps/redwood.c
drivers/mtd/maps/rpxlite.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/maps/sbc_gxx.c
drivers/mtd/maps/sc520cdp.c
drivers/mtd/maps/scb2_flash.c
drivers/mtd/maps/scx200_docflash.c
drivers/mtd/maps/solutionengine.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/maps/tqm8xxl.c
drivers/mtd/maps/tsunami_flash.c
drivers/mtd/maps/uclinux.c
drivers/mtd/maps/vmax301.c
drivers/mtd/maps/wr_sbc82xx_flash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdblock.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdconcat.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/autcpu12.c
drivers/mtd/nand/edb7312.c
drivers/mtd/nand/nand_ecc.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/spia.c
drivers/mtd/nftlcore.c
drivers/mtd/nftlmount.c
drivers/mtd/redboot.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/serial/Kconfig
drivers/serial/Makefile
fs/Kconfig
fs/jffs2/Makefile
fs/jffs2/background.c
fs/jffs2/build.c
fs/jffs2/compr.c
fs/jffs2/compr_rtime.c
fs/jffs2/compr_rubin.c
fs/jffs2/compr_zlib.c
fs/jffs2/erase.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/gc.c
fs/jffs2/ioctl.c
fs/jffs2/malloc.c
fs/jffs2/nodelist.c
fs/jffs2/nodelist.h
fs/jffs2/nodemgmt.c
fs/jffs2/os-linux.h
fs/jffs2/read.c
fs/jffs2/readinode.c
fs/jffs2/scan.c
fs/jffs2/super.c
fs/jffs2/symlink.c
fs/jffs2/wbuf.c
fs/jffs2/write.c
fs/jffs2/writev.c
include/asm-ppc/ocp_ids.h
include/asm-ppc/serial.h
include/linux/cpumask.h
include/linux/jffs2.h
include/linux/jffs2_fs_i.h
include/linux/libata.h
include/linux/mtd/cfi.h
include/linux/mtd/doc2000.h
include/linux/mtd/flashchip.h
include/linux/mtd/ftl.h
include/linux/mtd/gen_probe.h
include/linux/mtd/inftl.h
include/linux/mtd/map.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/nand_ecc.h
include/linux/mtd/nftl.h
include/linux/mtd/partitions.h
include/linux/serialP.h
include/linux/serial_core.h
mm/shmem.c

diff --git a/CREDITS b/CREDITS
index 518c5bd..cc0cffd 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1090,6 +1090,10 @@ E: jbglaw@lug-owl.de
 D: SRM environment driver (for Alpha systems)
 P: 1024D/8399E1BB 250D 3BCF 7127 0D8C A444  A961 1DBD 5E75 8399 E1BB
 
+N: Thomas Gleixner
+E: tglx@linutronix.de
+D: NAND flash hardware support, JFFS2 on NAND flash
+
 N: Richard E. Gooch
 E: rgooch@atnf.csiro.au
 D: parent process death signal to children
index be17311..f0927ee 100644 (file)
@@ -924,6 +924,24 @@ sys_ptrace:
        jmp     $31, do_sys_ptrace
 .end sys_ptrace
 
+       .align  4
+       .globl  sys_execve
+       .ent    sys_execve
+sys_execve:
+       .prologue 0
+       mov     $sp, $19
+       jmp     $31, do_sys_execve
+.end sys_execve
+
+       .align  4
+       .globl  osf_sigprocmask
+       .ent    osf_sigprocmask
+osf_sigprocmask:
+       .prologue 0
+       mov     $sp, $18
+       jmp     $31, do_osf_sigprocmask
+.end osf_sigprocmask
+
        .align  4
        .globl  alpha_ni_syscall
        .ent    alpha_ni_syscall
index 06646a2..6fd8546 100644 (file)
@@ -456,19 +456,10 @@ dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task)
 
 /*
  * sys_execve() executes a new program.
- *
- * This works due to the alpha calling sequence: the first 6 args
- * are gotten from registers, while the rest is on the stack, so
- * we get a0-a5 for free, and then magically find "struct pt_regs"
- * on the stack for us..
- *
- * Don't do this at home.
  */
 asmlinkage int
-sys_execve(char __user *ufilename, char __user * __user *argv,
-          char __user * __user *envp,
-          unsigned long a3, unsigned long a4, unsigned long a5,
-          struct pt_regs regs)
+do_sys_execve(char __user *ufilename, char __user * __user *argv,
+             char __user * __user *envp, struct pt_regs *regs)
 {
        int error;
        char *filename;
@@ -477,7 +468,7 @@ sys_execve(char __user *ufilename, char __user * __user *argv,
        error = PTR_ERR(filename);
        if (IS_ERR(filename))
                goto out;
-       error = do_execve(filename, argv, envp, &regs);
+       error = do_execve(filename, argv, envp, regs);
        putname(filename);
 out:
        return error;
index 0797b46..dd1d919 100644 (file)
@@ -53,8 +53,7 @@ static int do_signal(sigset_t *, struct pt_regs *, struct switch_stack *,
  * operation, as all of this is local to this thread.
  */
 asmlinkage unsigned long
-osf_sigprocmask(int how, unsigned long newmask, long a2, long a3,
-               long a4, long a5, struct pt_regs regs)
+do_osf_sigprocmask(int how, unsigned long newmask, struct pt_regs *regs)
 {
        unsigned long oldmask = -EINVAL;
 
@@ -78,7 +77,7 @@ osf_sigprocmask(int how, unsigned long newmask, long a2, long a3,
                recalc_sigpending();
                spin_unlock_irq(&current->sighand->siglock);
 
-               (&regs)->r0 = 0;                /* special no error return */
+               regs->r0 = 0;           /* special no error return */
        }
        return oldmask;
 }
index 8ce1cca..4502dc4 100644 (file)
@@ -507,6 +507,12 @@ config APUS
          More information is available at:
          <http://linux-apus.sourceforge.net/>.
 
+config KATANA
+       bool "Artesyn-Katana"
+
+config DMV182
+       bool "Dy-4 SVME/DMV-182"
+
 config WILLOW
        bool "Cogent-Willow"
 
@@ -517,7 +523,10 @@ config POWERPMC250
        bool "Force-PowerPMC250"
 
 config EV64260
-       bool "Galileo-EV-64260-BP"
+       bool "Marvell-EV64260BP"
+       help
+         Select EV64260 if configuring of a Marvell (formerly Galileo)
+         EV64260BP Evaluation platofm.
 
 config SPRUCE
        bool "IBM-Spruce"
@@ -671,9 +680,29 @@ config PPC_OF
        depends on PPC_PMAC || PPC_CHRP
        default y
 
+menu "Set bridge options"
+       depends on MV64X60
+
+config MV64X60_BASE
+       hex "Set bridge base used by firmware"
+       default "0xf1000000"
+       help
+         A firmware can leave the base address of the bridge's registers at
+         a non-standard location.  If so, set this value to reflect the
+         address of that non-standard location.
+
+config MV64X60_NEW_BASE
+       hex "Set bridge base used by kernel"
+       default "0xf1000000"
+       help
+         If the current base address of the bridge's registers is not where
+         you want it, set this value to the address that you want it moved to.
+
+endmenu
+
 config PPC_GEN550
        bool
-       depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || PRPMC750 || K2 || PRPMC800
+       depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS || PCORE || PRPMC750 || K2 || PRPMC800 || (EV64260 && !MV64X60_MPSC) || DMV182
        default y
 
 config FORCE
@@ -686,6 +715,16 @@ config GT64260
        depends on EV64260
        default y
 
+config MV64360
+       bool
+       depends on KATANA || DMV182
+       default y
+
+config MV64X60
+       bool
+       depends on (GT64260 || MV64360)
+       default y
+
 config NONMONARCH_SUPPORT
        bool "Enable Non-Monarch Support"
        depends on PRPMC800
@@ -744,11 +783,6 @@ config SERIAL_CONSOLE
        depends on 8xx
        default y
 
-config SERIAL_CONSOLE_BAUD
-       int
-       depends on EV64260
-       default "115200"
-
 config PPCBUG_NVRAM
        bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC
        default y if PPC_PREP
@@ -1363,11 +1397,11 @@ config BOOTX_TEXT
 
 config SERIAL_TEXT_DEBUG
        bool "Support for early boot texts over serial port"
-       depends on 4xx || GT64260 || LOPEC || PPLUS || PRPMC800 || PPC_GEN550
+       depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || PPC_GEN550
 
 config PPC_OCP
        bool
-       depends on IBM_OCP || FSL_OCP
+       depends on IBM_OCP || FSL_OCP || MV64X60
        default y
 
 endmenu
index fadc771..4404fe8 100644 (file)
@@ -59,7 +59,8 @@ static int _cvt(unsigned long val, char *buf, long radix, char *digits);
 void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap);
 unsigned char *ISA_io = NULL;
 
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+       defined(CONFIG_SERIAL_MPSC_CONSOLE)
 extern unsigned long com_port;
 
 extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@ void exit(void)
 
 int tstc(void)
 {
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+       defined(CONFIG_SERIAL_MPSC_CONSOLE)
        if(keyb_present)
                return (CRT_tstc() || serial_tstc(com_port));
        else
@@ -93,7 +95,8 @@ int tstc(void)
 int getc(void)
 {
        while (1) {
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+       defined(CONFIG_SERIAL_MPSC_CONSOLE)
                if (serial_tstc(com_port))
                        return (serial_getc(com_port));
 #endif /* serial console */
@@ -108,7 +111,8 @@ putc(const char c)
 {
        int x,y;
 
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+       defined(CONFIG_SERIAL_MPSC_CONSOLE)
        serial_putc(com_port, c);
        if ( c == '\n' )
                serial_putc(com_port, '\r');
@@ -155,7 +159,8 @@ void puts(const char *s)
        y = orig_y;
 
        while ( ( c = *s++ ) != '\0' ) {
-#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) || \
+       defined(CONFIG_SERIAL_MPSC_CONSOLE)
                serial_putc(com_port, c);
                if ( c == '\n' ) serial_putc(com_port, '\r');
 #endif /* serial console */
index d497a93..2bae1ea 100644 (file)
@@ -65,7 +65,7 @@ zimageinitrd-$(CONFIG_OCOTEA)         := zImage.initrd-TREE
          end-$(CONFIG_OCOTEA)          := ocotea
   entrypoint-$(CONFIG_OCOTEA)          := 0x01000000
 
-     extra.o-$(CONFIG_EV64260)         := direct.o misc-ev64260.o
+     extra.o-$(CONFIG_EV64260)         := misc-ev64260.o
          end-$(CONFIG_EV64260)         := ev64260
    cacheflag-$(CONFIG_EV64260)         := -include $(clear_L2_L3)
 
@@ -136,14 +136,16 @@ boot-$(CONFIG_8xx)                += embed_config.o
 boot-$(CONFIG_8260)            += embed_config.o
 boot-$(CONFIG_BSEIP)           += iic.o
 boot-$(CONFIG_MBX)             += iic.o pci.o qspan_pci.o
+boot-$(CONFIG_MV64X60)         += misc-mv64x60.o
+boot-$(CONFIG_DMV182)          += mv64x60_stub.o
 boot-$(CONFIG_RPXCLASSIC)      += iic.o pci.o qspan_pci.o
 boot-$(CONFIG_RPXLITE)         += iic.o
 # Different boards need different serial implementations.
 ifeq ($(CONFIG_SERIAL_CONSOLE),y)
 boot-$(CONFIG_8xx)             += m8xx_tty.o
 boot-$(CONFIG_8260)            += m8260_tty.o
-boot-$(CONFIG_GT64260_CONSOLE) += gt64260_tty.o
 endif
+boot-$(CONFIG_SERIAL_MPSC_CONSOLE)     += mv64x60_tty.o
 
 LIBS                           := $(common)/lib.a $(bootlib)/lib.a
 ifeq ($(CONFIG_PPC_PREP),y)
index cb95484..e80c7d8 100644 (file)
@@ -135,9 +135,9 @@ haveOF:
                         */
 #endif
 
-#ifdef CONFIG_EV64260
-       /* Move 64260's base regs & CS window for external UART */
-       bl      ev64260_init
+#ifdef CONFIG_MV64X60
+       /* mv64x60 specific hook to do things like moving register base, etc. */
+       bl      mv64x60_init
 #endif
 
        /* Get the load address.
index 7ce6815..957e0f6 100644 (file)
@@ -1,60 +1,70 @@
 /*
  * arch/ppc/boot/simple/misc-ev64260.S
- *
+ * 
  * Host bridge init code for the Marvell/Galileo EV-64260-BP evaluation board
  * with a GT64260 onboard.
  *
  * Author: Mark Greer <mgreer@mvista.com>
  *
- * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
  */
 
 #include <asm/ppc_asm.h>
+#include <asm/processor.h>
 #include <asm/cache.h>
-#include <asm/gt64260_defs.h>
-
+#include <asm/mv64x60_defs.h>
 #include <platforms/ev64260.h>
 
-       .globl  ev64260_init
-ev64260_init:
-       li      r20,0
+       .globl  mv64x60_board_init
+mv64x60_board_init:
+       /* DINK doesn't enable 745x timebase, so enable here (Adrian Cox) */
+       mfspr   r25,PVR
+       srwi    r25,r25,16
+       cmplwi  r25,(PVR_7450 >> 16)
+       bne     1f
+       mfspr   r25,HID0
+       oris    r25,r25,(HID0_TBEN >> 16)
+       mtspr   HID0,r25
+1:
+#if (CONFIG_MV64X60_NEW_BASE != CONFIG_MV64X60_BASE)
        li      r23,20
 
-       /* Relocate galileo's regs */
-        addis  r25,0,GT64260_INTERNAL_SPACE_DEFAULT_ADDR@h
-        ori    r25,r25,GT64260_INTERNAL_SPACE_DECODE
-        lwbrx  r26,0,(r25)
-       lis     r24,0xffff
-       and     r26,r26,r24
-       addis   r24,0,EV64260_BRIDGE_REG_BASE@h
-       srw     r24,r24,r23
-       or      r26,r26,r24
-        stwbrx  r26,0,(r25)
-       sync
-
-       /* Wait for write to take effect */
-        addis  r25,0,EV64260_BRIDGE_REG_BASE@h
-       ori     r25,r25,GT64260_INTERNAL_SPACE_DECODE
-1:     lwbrx   r24,0,(r25)
-       cmpw    r24,r26
-       bne     1b
-
-        /* Change CS2 (UARTS on device module) window */
-        addis  r25,0,EV64260_BRIDGE_REG_BASE@h
-        ori    r25,r25,GT64260_CPU_CS_DECODE_2_BOT
+       /*
+        * Change the CS2 window for the UART so that the bootloader
+        * can do I/O thru the UARTs.
+        */
+        addis  r25,0,CONFIG_MV64X60_NEW_BASE@h
+        ori    r25,r25,MV64x60_CPU2DEV_2_BASE             
        addis   r26,0,EV64260_UART_BASE@h
        srw     r26,r26,r23
         stwbrx  r26,0,(r25)
        sync
 
-        addis  r25,0,EV64260_BRIDGE_REG_BASE@h
-        ori    r25,r25,GT64260_CPU_CS_DECODE_2_TOP
+        addis  r25,0,CONFIG_MV64X60_NEW_BASE@h
+        ori    r25,r25,MV64x60_CPU2DEV_2_SIZE
        addis   r26,0,EV64260_UART_END@h
        srw     r26,r26,r23
         stwbrx  r26,0,(r25)
        sync
-
+#endif
         blr
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+.data
+       .globl  mv64x60_console_baud
+mv64x60_console_baud:
+.long  EV64260_DEFAULT_BAUD
+
+       .globl  mv64x60_mpsc_clk_src
+mv64x60_mpsc_clk_src:
+.long  EV64260_MPSC_CLK_SRC
+
+       .globl  mv64x60_mpsc_clk_freq
+mv64x60_mpsc_clk_freq:
+.long  EV64260_MPSC_CLK_FREQ
+#endif
index dd4bdde..4126588 100644 (file)
@@ -50,7 +50,7 @@
  * user to edit the cmdline or not.
  */
 #if (defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_VGA_CONSOLE)) \
-       && !defined(CONFIG_GEMINI)
+       && !defined(CONFIG_GEMINI) || defined(CONFIG_SERIAL_MPSC_CONSOLE)
 #define INTERACTIVE_CONSOLE    1
 #endif
 
@@ -98,7 +98,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
        unsigned long initrd_loc, TotalMemory = 0;
 
        serial_fixups();
-#ifdef CONFIG_SERIAL_8250_CONSOLE
+#if defined(CONFIG_SERIAL_8250_CONSOLE) || defined(CONFIG_SERIAL_MPSC_CONSOLE)
        com_port = serial_init(0, NULL);
 #endif
 
index c5bfc64..b0f304c 100644 (file)
@@ -4,23 +4,39 @@
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 
 #
 # Loadable module support
@@ -33,24 +49,26 @@ CONFIG_OBSOLETE_MODPARM=y
 CONFIG_KMOD=y
 
 #
-# Platform support
+# Processor
 #
-CONFIG_PPC=y
-CONFIG_PPC32=y
 CONFIG_6xx=y
 # CONFIG_40x is not set
+# CONFIG_44x is not set
 # CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
+CONFIG_ALTIVEC=y
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_STD_MMU=y
 
 #
-# IBM 4xx options
+# Platform options
 #
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
 # CONFIG_PPC_MULTIPLATFORM is not set
 # CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
+# CONFIG_KATANA is not set
+# CONFIG_WILLOW is not set
 # CONFIG_PCORE is not set
 # CONFIG_POWERPMC250 is not set
 CONFIG_EV64260=y
@@ -66,37 +84,37 @@ CONFIG_EV64260=y
 # CONFIG_K2 is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX6 is not set
+# CONFIG_TQM8260 is not set
+
+#
+# Set bridge base address
+#
+CONFIG_MV64X60_BASE=0xf1000000
+CONFIG_MV64X60_NEW_BASE=0xfbe00000
+CONFIG_PPC_GEN550=y
 CONFIG_GT64260=y
+CONFIG_MV64X60=y
 CONFIG_SERIAL_CONSOLE_BAUD=115200
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
-CONFIG_ALTIVEC=y
-CONFIG_TAU=y
-# CONFIG_TAU_INT is not set
-# CONFIG_TAU_AVERAGE is not set
-# CONFIG_CPU_FREQ is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200 ip=on"
 
 #
-# General setup
+# Bus options
 #
-# CONFIG_HIGHMEM is not set
+CONFIG_GENERIC_ISA_DMA=y
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-CONFIG_BINFMT_MISC=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-# CONFIG_PPC601_SYNC_FIX is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0,115200 ip=on"
 
 #
 # Advanced setup
@@ -112,15 +130,27 @@ CONFIG_KERNEL_START=0xc0000000
 CONFIG_TASK_SIZE=0x80000000
 CONFIG_BOOT_LOAD=0x00800000
 
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+
 #
 # Memory Technology Devices (MTD)
 #
 # CONFIG_MTD is not set
 
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -131,32 +161,35 @@ CONFIG_BOOT_LOAD=0x00800000
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
 
 #
-# Multi-device support (RAID and LVM)
+# ATA/ATAPI/MFM/RLL support
 #
-# CONFIG_MD is not set
+# CONFIG_IDE is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# SCSI device support
 #
-# CONFIG_IDE is not set
+# CONFIG_SCSI is not set
 
 #
-# SCSI support
+# Multi-device support (RAID and LVM)
 #
-# CONFIG_SCSI is not set
+# CONFIG_MD is not set
 
 #
 # Fusion MPT device support
 #
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
@@ -165,6 +198,10 @@ CONFIG_BLK_DEV_INITRD=y
 #
 # CONFIG_I2O is not set
 
+#
+# Macintosh device drivers
+#
+
 #
 # Networking support
 #
@@ -176,8 +213,6 @@ CONFIG_NET=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 # CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -191,34 +226,24 @@ CONFIG_IP_PNP_DHCP=y
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 # CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
 # CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
+# CONFIG_NETFILTER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
 # CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_NET_DIVERT is not set
@@ -236,23 +261,27 @@ CONFIG_IPV6_SCTP__=y
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 
 #
 # ARCnet devices
 #
 # CONFIG_ARCNET is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=y
 # CONFIG_OAKNET is not set
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
@@ -261,13 +290,22 @@ CONFIG_NET_ETHERNET=y
 #
 # Tulip family network device support
 #
-# CONFIG_NET_TULIP is not set
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
 # CONFIG_PCNET32 is not set
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
 # CONFIG_EEPRO100_PIO is not set
@@ -300,60 +338,55 @@ CONFIG_EEPRO100=y
 # Ethernet (10000 Mbit)
 #
 # CONFIG_IXGB is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
+# CONFIG_S2IO is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Token Ring devices
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
 
 #
-# Token Ring devices (depends on LLC=y)
+# Wireless LAN (non-hamradio)
 #
-# CONFIG_RCPCI is not set
-# CONFIG_SHAPER is not set
+# CONFIG_NET_RADIO is not set
 
 #
 # Wan interfaces
 #
 # CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
+# CONFIG_ISDN is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Telephony Support
 #
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
 
 #
 # Userland interfaces
 #
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
 
 #
 # Input I/O drivers
@@ -361,18 +394,23 @@ CONFIG_EEPRO100=y
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
 #
-
-#
-# Macintosh device drivers
-#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Character devices
 #
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -380,50 +418,18 @@ CONFIG_SOUND_GAMEPORT=y
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
 # Non-8250 serial port support
 #
+# CONFIG_SERIAL_MPSC is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=m
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-CONFIG_I2C_CHARDEV=m
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_I2C_SENSOR is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -449,7 +455,15 @@ CONFIG_GEN_RTC=y
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
 
 #
 # Multimedia devices
@@ -461,6 +475,33 @@ CONFIG_GEN_RTC=y
 #
 # CONFIG_DVB is not set
 
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
 #
 # File systems
 #
@@ -493,12 +534,14 @@ CONFIG_EXT2_FS=y
 # Pseudo filesystems
 #
 CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
 CONFIG_DEVFS_FS=y
 # CONFIG_DEVFS_MOUNT is not set
 # CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_DEVPTS_FS_XATTR is not set
 CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
 #
@@ -507,6 +550,7 @@ CONFIG_RAMFS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
@@ -523,18 +567,18 @@ CONFIG_RAMFS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
 # CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -544,32 +588,22 @@ CONFIG_SUNRPC=y
 CONFIG_MSDOS_PARTITION=y
 
 #
-# Sound
+# Native Language Support
 #
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_NLS is not set
 
 #
 # Library routines
 #
-# CONFIG_CRC32 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
 # CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_PPC_OCP=y
 
 #
 # Security options
index c32d662..2dddc00 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/tty.h> /* for linux/serial_core.h */
 #include <linux/serial_core.h>
 #include <linux/module.h>
+#include <linux/initrd.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -92,6 +93,7 @@ sbc8560_early_serial_map(void)
         uart_req.iotype = SERIAL_IO_MEM;
         uart_req.mapbase = UARTA_ADDR;
         uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART0_SIZE);
+       uart_req.type = PORT_16650;
 
 #if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
         gen550_init(0, &uart_req);
index 5c86187..6475d30 100644 (file)
 #define BASE_BAUD ( 1843200 / 16 )
  
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
 #else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
+#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
 #endif
+
 #define STD_SERIAL_PORT_DFNS \
         { 0, BASE_BAUD, UARTA_ADDR, MPC85xx_IRQ_EXT9, STD_COM_FLAGS, /* ttyS0 */ \
                 iomem_base: (u8 *)UARTA_ADDR,                       \
index a7a33fd..8cc3323 100644 (file)
@@ -61,38 +61,38 @@ extern unsigned long total_memory;  /* in mm/init */
 /* Internal interrupts are all Level Sensitive, and Positive Polarity */
 
 static u_char sbc8560_openpic_initsenses[] __initdata = {
-       (IRQ_POLARITY_POSITIVE),        /* Internal  0: L2 Cache */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  1: ECM */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  2: DDR DRAM */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  3: LBIU */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  4: DMA 0 */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  5: DMA 1 */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  6: DMA 2 */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  7: DMA 3 */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  8: PCI/PCI-X */
-       (IRQ_POLARITY_POSITIVE),        /* Internal  9: RIO Inbound Port Write Error */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 10: RIO Doorbell Inbound */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 11: RIO Outbound Message */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 12: RIO Inbound Message */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 13: TSEC 0 Transmit */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 14: TSEC 0 Receive */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 15: Unused */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 16: Unused */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 17: Unused */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 18: TSEC 0 Receive/Transmit Error */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 19: TSEC 1 Transmit */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 20: TSEC 1 Receive */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 21: Unused */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 22: Unused */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 23: Unused */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 24: TSEC 1 Receive/Transmit Error */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 25: Fast Ethernet */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 26: DUART */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 27: I2C */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 28: Performance Monitor */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 29: Unused */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 30: CPM */
-       (IRQ_POLARITY_POSITIVE),        /* Internal 31: Unused */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  0: L2 Cache */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  1: ECM */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  2: DDR DRAM */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  3: LBIU */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  4: DMA 0 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  5: DMA 1 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  6: DMA 2 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  7: DMA 3 */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  8: PCI/PCI-X */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal  9: RIO Inbound Port Write Error */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 10: RIO Doorbell Inbound */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 11: RIO Outbound Message */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 12: RIO Inbound Message */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 13: TSEC 0 Transmit */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 14: TSEC 0 Receive */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 15: Unused */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 16: Unused */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 17: Unused */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 18: TSEC 0 Receive/Transmit Error */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 19: TSEC 1 Transmit */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 20: TSEC 1 Receive */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 21: Unused */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 22: Unused */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 23: Unused */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 24: TSEC 1 Receive/Transmit Error */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 25: Fast Ethernet */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 26: DUART */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 27: I2C */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 28: Performance Monitor */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 29: Unused */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 30: CPM */
+       (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),      /* Internal 31: Unused */
        0x0,                            /* External  0: */
        0x0,                            /* External  1: */
 #if defined(CONFIG_PCI)
index 42273c0..3a1c3c0 100644 (file)
@@ -32,7 +32,8 @@ obj-$(CONFIG_ADIR)            += adir_setup.o adir_pic.o adir_pci.o
 obj-$(CONFIG_EST8260)          += est8260_setup.o
 obj-$(CONFIG_PQ2ADS)           += pq2ads_setup.o
 obj-$(CONFIG_TQM8260)          += tqm8260_setup.o
-obj-$(CONFIG_EV64260)          += ev64260_setup.o
+obj-$(CONFIG_EV64260)          += ev64260.o
+obj-$(CONFIG_DMV182)           += dmv182.o
 obj-$(CONFIG_GEMINI)           += gemini_pci.o gemini_setup.o gemini_prom.o
 obj-$(CONFIG_K2)               += k2.o
 obj-$(CONFIG_LOPEC)            += lopec_setup.o lopec_pci.o
index bc826d6..156bfa8 100644 (file)
 /*
  * arch/ppc/platforms/ev64260.h
- *
+ * 
  * Definitions for Marvell/Galileo EV-64260-BP Evaluation Board.
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
  *
- * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
  * the terms of the GNU General Public License version 2.  This program
  * is licensed "as is" without any warranty of any kind, whether express
  * or implied.
  */
 
 /*
- * The GT64260 has 2 PCI buses each with 1 window from the CPU bus to
+ * The MV64x60 has 2 PCI buses each with 1 window from the CPU bus to
  * PCI I/O space and 4 windows from the CPU bus to PCI MEM space.
  * We'll only use one PCI MEM window on each PCI bus.
+ *
+ * This is the CPU physical memory map (windows must be at least 1MB and start
+ * on a boundary that is a multiple of the window size):
+ *
+ *     0xfc000000-0xffffffff           - External FLASH on device module
+ *     0xfbf00000-0xfbffffff           - Embedded (on board) FLASH
+ *     0xfbe00000-0xfbefffff           - GT64260 Registers (preferably)
+ *                                       but really a config option
+ *     0xfbd00000-0xfbdfffff           - External SRAM on device module
+ *     0xfbc00000-0xfbcfffff           - TODC chip on device module
+ *     0xfbb00000-0xfbbfffff           - External UART on device module
+ *     0xa2000000-0xfbafffff           - <hole>
+ *     0xa1000000-0xa1ffffff           - PCI 1 I/O (defined in gt64260.h)
+ *     0xa0000000-0xa0ffffff           - PCI 0 I/O (defined in gt64260.h)
+ *     0x90000000-0x9fffffff           - PCI 1 MEM (defined in gt64260.h)
+ *     0x80000000-0x8fffffff           - PCI 0 MEM (defined in gt64260.h)
  */
 
 #ifndef __PPC_PLATFORMS_EV64260_H
 #define __PPC_PLATFORMS_EV64260_H
 
-#define        EV64260_BRIDGE_REG_BASE         0xf8000000
-#define        EV64260_BRIDGE_REG_BASE_TO_TOP  0x08000000U
+#ifndef        MAX
+#define        MAX(a,b)        (((a) > (b)) ? (a) : (b))
+#endif
+
+/*
+ * CPU Physical Memory Map setup.
+ */
+#define        EV64260_EXT_FLASH_BASE          0xfc000000
+#define        EV64260_EMB_FLASH_BASE          0xfbf00000
+#define        EV64260_EXT_SRAM_BASE           0xfbd00000
+#define        EV64260_TODC_BASE               0xfbc00000
+#define        EV64260_UART_BASE               0xfbb00000
 
-#define        EV64260_TODC_BASE               0xfc800000
-#define        EV64260_TODC_LEN                0x00800000
-#define        EV64260_TODC_END                (EV64260_TODC_BASE + \
-                                        EV64260_TODC_LEN - 1)
+#define        EV64260_EXT_FLASH_SIZE_ACTUAL   0x04000000  /* <= 64MB Extern FLASH */
+#define        EV64260_EMB_FLASH_SIZE_ACTUAL   0x00080000  /* 512KB of Embed FLASH */
+#define        EV64260_EXT_SRAM_SIZE_ACTUAL    0x00100000  /* 1MB SDRAM */
+#define        EV64260_TODC_SIZE_ACTUAL        0x00000020  /* 32 bytes for TODC */
+#define        EV64260_UART_SIZE_ACTUAL        0x00000040  /* 64 bytes for DUART */
+
+#define        EV64260_EXT_FLASH_SIZE          MAX(GT64260_WINDOW_SIZE_MIN,    \
+                                               EV64260_EXT_FLASH_SIZE_ACTUAL)
+#define        EV64260_EMB_FLASH_SIZE          MAX(GT64260_WINDOW_SIZE_MIN,    \
+                                               EV64260_EMB_FLASH_SIZE_ACTUAL)
+#define        EV64260_EXT_SRAM_SIZE           MAX(GT64260_WINDOW_SIZE_MIN,    \
+                                               EV64260_EXT_SRAM_SIZE_ACTUAL)
+#define        EV64260_TODC_SIZE               MAX(GT64260_WINDOW_SIZE_MIN,    \
+                                               EV64260_TODC_SIZE_ACTUAL)
+#if 0  /* XXXX blows up assembler in bootloader */
+#define        EV64260_UART_SIZE               MAX(GT64260_WINDOW_SIZE_MIN,    \
+                                               EV64260_UART_SIZE_ACTUAL)
+#else
+#define        EV64260_UART_SIZE               GT64260_WINDOW_SIZE_MIN
+#endif
+#define        EV64260_UART_END                ((EV64260_UART_BASE +           \
+                                       EV64260_UART_SIZE - 1) & 0xfff00000)
+
+/*
+ * Board-specific IRQ info
+ */
+#define        EV64260_UART_0_IRQ              85
+#define        EV64260_UART_1_IRQ              86
+#define        EV64260_PCI_0_IRQ               91
+#define        EV64260_PCI_1_IRQ               93
 
-#define        EV64260_UART_BASE               0xfd000000
-#define        EV64260_UART_LEN                0x00800000
-#define        EV64260_UART_END                (EV64260_UART_BASE + \
-                                        EV64260_UART_LEN - 1)
-/* Serial driver setup.  */
+/*
+ * Serial port setup.
+ */
+#define        EV64260_DEFAULT_BAUD            115200
+
+#if defined(CONFIG_SERIAL_MPSC_CONSOLE)
+#define SERIAL_PORT_DFNS
+
+#define        EV64260_MPSC_CLK_SRC            8               /* TCLK */
+#define        EV64260_MPSC_CLK_FREQ           100000000       /* 100MHz clk */
+#else
 #define EV64260_SERIAL_0               (EV64260_UART_BASE + 0x20)
 #define EV64260_SERIAL_1               EV64260_UART_BASE
 
-#define BASE_BAUD ( 3686400 / 16 )
+#define BASE_BAUD      (EV64260_DEFAULT_BAUD * 2)
 
 #ifdef CONFIG_SERIAL_MANY_PORTS
 #define RS_TABLE_SIZE  64
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
 #endif
 
-#if    !defined(CONFIG_GT64260_CONSOLE)
 /* Required for bootloader's ns16550.c code */
 #define STD_SERIAL_PORT_DFNS                                           \
-        { 0, BASE_BAUD, EV64260_SERIAL_0, 85, STD_COM_FLAGS, /* ttyS0 */\
-       iomem_base: (u8 *)EV64260_SERIAL_0,                             \
+        { 0, BASE_BAUD, EV64260_SERIAL_0, EV64260_UART_0_IRQ, STD_COM_FLAGS, \
+       iomem_base: (u8 *)EV64260_SERIAL_0,     /* ttyS0 */             \
+       iomem_reg_shift: 2,                                             \
+       io_type: SERIAL_IO_MEM },                                       
+
+#if 0
+        { 1, BASE_BAUD, EV64260_SERIAL_1, EV64260_UART_1_IRQ, STD_COM_FLAGS, \
+       iomem_base: (u8 *)EV64260_SERIAL_1,     /* ttyS1 */             \
        iomem_reg_shift: 2,                                             \
        io_type: SERIAL_IO_MEM },
+#endif
 
 #define SERIAL_PORT_DFNS \
         STD_SERIAL_PORT_DFNS
-#else
-#define SERIAL_PORT_DFNS
 #endif
-
 #endif /* __PPC_PLATFORMS_EV64260_H */
index 313fe20..fde6c4e 100644 (file)
@@ -43,9 +43,10 @@ obj-$(CONFIG_PPC_PREP)               += open_pic.o indirect_pci.o i8259.o todc_time.o
 obj-$(CONFIG_ADIR)             += i8259.o indirect_pci.o pci_auto.o \
                                        todc_time.o
 obj-$(CONFIG_EBONY)            += indirect_pci.o pci_auto.o todc_time.o
-obj-$(CONFIG_EV64260)          += gt64260_common.o gt64260_pic.o \
-                                       indirect_pci.o todc_time.o pci_auto.o
+obj-$(CONFIG_EV64260)          += indirect_pci.o todc_time.o pci_auto.o
+obj-$(CONFIG_DMV182)           += indirect_pci.o todc_time.o pci_auto.o
 obj-$(CONFIG_GEMINI)           += open_pic.o indirect_pci.o
+obj-$(CONFIG_GT64260)          += gt64260_pic.o
 obj-$(CONFIG_K2)               += i8259.o indirect_pci.o todc_time.o \
                                        pci_auto.o
 obj-$(CONFIG_LOPEC)            += i8259.o pci_auto.o todc_time.o
@@ -53,6 +54,8 @@ obj-$(CONFIG_MCPN765)         += todc_time.o indirect_pci.o pci_auto.o \
                                        open_pic.o i8259.o hawk_common.o
 obj-$(CONFIG_MENF1)            += todc_time.o i8259.o mpc10x_common.o \
                                        pci_auto.o indirect_pci.o
+obj-$(CONFIG_MV64360)          += mv64360_pic.o
+obj-$(CONFIG_MV64X60)          += mv64x60.o mv64x60_ocp.o
 obj-$(CONFIG_MVME5100)         += open_pic.o todc_time.o indirect_pci.o \
                                        i8259.o pci_auto.o hawk_common.o
 obj-$(CONFIG_OCOTEA)           += indirect_pci.o pci_auto.o todc_time.o
index 70cb577..e6f680a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Interrupt controller support for Galileo's GT64260.
  *
- * Author: Chris Zankel <chris@mvista.com>
+ * Author: Chris Zankel <source@mvista.com>
  * Modified by: Mark A. Greer <mgreer@mvista.com>
  *
  * Based on sources from Rabeeh Khoury / Galileo Technology
@@ -43,7 +43,8 @@
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/irq.h>
-#include <asm/gt64260.h>
+#include <asm/ocp.h>
+#include <asm/mv64x60.h>
 
 
 /* ========================== forward declaration ========================== */
@@ -66,6 +67,9 @@ struct hw_interrupt_type gt64260_pic = {
 
 u32 gt64260_irq_base = 0;      /* GT64260 handles the next 96 IRQs from here */
 
+static mv64x60_handle_t base_bh;
+static mv64x60_handle_t ic_bh;
+
 /* gt64260_init_irq()
  *
  *  This function initializes the interrupt controller. It assigns
@@ -87,19 +91,38 @@ u32 gt64260_irq_base = 0;      /* GT64260 handles the next 96 IRQs from here */
 __init void
 gt64260_init_irq(void)
 {
+       struct ocp_def  *def;
        int i;
 
+/* XXXX extract reg base, irq base from ocp */
+/* XXXX rewrite read/write macros to not use 'bh'?? */
+/* XXXX Have to use ocp b/c can pass arg to this routine */
+
        if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: enter", 0x0);
 
+       if ((def = ocp_get_one_device(OCP_VENDOR_MARVELL, OCP_FUNC_HB,
+                                       OCP_ANY_INDEX)) == NULL) {
+               /* XXXX SCREAM */
+               return;
+       }
+       base_bh.v_base = (u32)ioremap(def->paddr, 0x10000); /* XXXX */
+
+       if ((def = ocp_get_one_device(OCP_VENDOR_MARVELL, OCP_FUNC_PIC,
+                                       OCP_ANY_INDEX)) == NULL) {
+               /* XXXX SCREAM */
+               return;
+       }
+       ic_bh.v_base = (u32)ioremap(def->paddr, 0x1000); /* XXXX */
+
        ppc_cached_irq_mask[0] = 0;
        ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */
        ppc_cached_irq_mask[2] = 0;
 
        /* disable all interrupts and clear current interrupts */
-       gt_write(GT64260_GPP_INTR_MASK, ppc_cached_irq_mask[2]);
-       gt_write(GT64260_GPP_INTR_CAUSE,0);
-       gt_write(GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]);
-       gt_write(GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]);
+       mv64x60_write(&base_bh, MV64x60_GPP_INTR_MASK, ppc_cached_irq_mask[2]);
+       mv64x60_write(&base_bh, MV64x60_GPP_INTR_CAUSE,0);
+       mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]);
+       mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]);
 
        /* use the gt64260 for all (possible) interrupt sources */
        for( i = gt64260_irq_base;  i < (gt64260_irq_base + 96);  i++ )  {
@@ -110,7 +133,8 @@ gt64260_init_irq(void)
 }
 
 
-/* gt64260_get_irq()
+/*
+ * gt64260_get_irq()
  *
  *  This function returns the lowest interrupt number of all interrupts that
  *  are currently asserted.
@@ -131,18 +155,18 @@ gt64260_get_irq(struct pt_regs *regs)
        int irq;
        int irq_gpp;
 
-       irq = gt_read(GT64260_IC_MAIN_CAUSE_LO);
+       irq = mv64x60_read(&ic_bh, GT64260_IC_MAIN_CAUSE_LO);
        irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]);
 
        if (irq == -1) {
-               irq = gt_read(GT64260_IC_MAIN_CAUSE_HI);
+               irq = mv64x60_read(&ic_bh, GT64260_IC_MAIN_CAUSE_HI);
                irq = __ilog2((irq & 0x0f000db7) & ppc_cached_irq_mask[1]);
 
                if (irq == -1) {
                        irq = -2;   /* bogus interrupt, should never happen */
                } else {
                        if (irq >= 24) {
-                               irq_gpp = gt_read(GT64260_GPP_INTR_CAUSE);
+                               irq_gpp = mv64x60_read(&base_bh, MV64x60_GPP_INTR_CAUSE);
                                irq_gpp = __ilog2(irq_gpp &
                                                  ppc_cached_irq_mask[2]);
 
@@ -150,7 +174,7 @@ gt64260_get_irq(struct pt_regs *regs)
                                        irq = -2;
                                } else {
                                        irq = irq_gpp + 64;
-                                       gt_write(GT64260_GPP_INTR_CAUSE, ~(1<<(irq-64)));
+                                       mv64x60_write(&base_bh, MV64x60_GPP_INTR_CAUSE, ~(1<<(irq-64)));
                                }
                        } else {
                                irq += 32;
@@ -182,20 +206,23 @@ gt64260_get_irq(struct pt_regs *regs)
 static void
 gt64260_unmask_irq(unsigned int irq)
 {
+       /* XXXX
+       printk("XXXX: *** unmask irq: %d\n", irq);
+       */
        irq -= gt64260_irq_base;
        if (irq > 31) {
                if (irq > 63) {
                        /* unmask GPP irq */
-                       gt_write(GT64260_GPP_INTR_MASK,
+                       mv64x60_write(&base_bh, MV64x60_GPP_INTR_MASK,
                                     ppc_cached_irq_mask[2] |= (1<<(irq-64)));
                } else {
                        /* mask high interrupt register */
-                       gt_write(GT64260_IC_CPU_INTR_MASK_HI,
+                       mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_HI,
                                     ppc_cached_irq_mask[1] |= (1<<(irq-32)));
                }
        } else {
                /* mask low interrupt register */
-               gt_write(GT64260_IC_CPU_INTR_MASK_LO,
+               mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_LO,
                             ppc_cached_irq_mask[0] |= (1<<irq));
        }
 }
@@ -218,20 +245,23 @@ gt64260_unmask_irq(unsigned int irq)
 static void
 gt64260_mask_irq(unsigned int irq)
 {
+       /* XXXX
+       printk("XXXX: *** mask irq: %d\n", irq);
+       */
        irq -= gt64260_irq_base;
        if (irq > 31) {
                if (irq > 63) {
                        /* mask GPP irq */
-                       gt_write(GT64260_GPP_INTR_MASK,
+                       mv64x60_write(&base_bh, MV64x60_GPP_INTR_MASK,
                                     ppc_cached_irq_mask[2] &= ~(1<<(irq-64)));
                } else {
                        /* mask high interrupt register */
-                       gt_write(GT64260_IC_CPU_INTR_MASK_HI,
+                       mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_HI,
                                     ppc_cached_irq_mask[1] &= ~(1<<(irq-32)));
                }
        } else {
                /* mask low interrupt register */
-               gt_write(GT64260_IC_CPU_INTR_MASK_LO,
+               mv64x60_write(&ic_bh, GT64260_IC_CPU_INTR_MASK_LO,
                             ppc_cached_irq_mask[0] &= ~(1<<irq));
        }
 
index e39c88f..0b58789 100644 (file)
@@ -64,14 +64,14 @@ static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *);
 
 /* Timer Interrupts */
 static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
-static void openpic_maptimer(u_int timer, u_int cpumask);
+static void openpic_maptimer(u_int timer, cpumask_t cpumask);
 
 /* Interrupt Sources */
 static void openpic_enable_irq(u_int irq);
 static void openpic_disable_irq(u_int irq);
 static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
                            int is_level);
-static void openpic_mapirq(u_int irq, u_int cpumask, u_int keepmask);
+static void openpic_mapirq(u_int irq, cpumask_t cpumask, cpumask_t keepmask);
 
 /*
  * These functions are not used but the code is kept here
@@ -89,17 +89,15 @@ static void openpic_set_sense(u_int irq, int sense);
  */
 static void openpic_end_irq(unsigned int irq_nr);
 static void openpic_ack_irq(unsigned int irq_nr);
-static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
+static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
 
 struct hw_interrupt_type open_pic = {
-       " OpenPIC  ",
-       NULL,
-       NULL,
-       openpic_enable_irq,
-       openpic_disable_irq,
-       openpic_ack_irq,
-       openpic_end_irq,
-       openpic_set_affinity
+       .typename       = " OpenPIC  ",
+       .enable         = openpic_enable_irq,
+       .disable        = openpic_disable_irq,
+       .ack            = openpic_ack_irq,
+       .end            = openpic_end_irq,
+       .set_affinity   = openpic_set_affinity,
 };
 
 #ifdef CONFIG_SMP
@@ -109,14 +107,11 @@ static void openpic_enable_ipi(unsigned int irq_nr);
 static void openpic_disable_ipi(unsigned int irq_nr);
 
 struct hw_interrupt_type open_pic_ipi = {
-       " OpenPIC  ",
-       NULL,
-       NULL,
-       openpic_enable_ipi,
-       openpic_disable_ipi,
-       openpic_ack_ipi,
-       openpic_end_ipi,
-       0
+       .typename       = " OpenPIC  ",
+       .enable         = openpic_enable_ipi,
+       .disable        = openpic_disable_ipi,
+       .ack            = openpic_ack_ipi,
+       .end            = openpic_end_ipi,
 };
 #endif /* CONFIG_SMP */
 
@@ -368,7 +363,7 @@ void __init openpic_init(int offset)
                /* Disabled, Priority 0 */
                openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
                /* No processor */
-               openpic_maptimer(i, 0);
+               openpic_maptimer(i, CPU_MASK_NONE);
        }
 
 #ifdef CONFIG_SMP
@@ -408,7 +403,7 @@ void __init openpic_init(int offset)
                openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
                                (sense & IRQ_SENSE_MASK));
                /* Processor 0 */
-               openpic_mapirq(i, 1<<0, 0);
+               openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
        }
 
        /* Init descriptors */
@@ -509,14 +504,17 @@ static void openpic_set_spurious(u_int vec)
 /*
  * Convert a cpu mask from logical to physical cpu numbers.
  */
-static inline u32 physmask(u32 cpumask)
+static inline cpumask_t physmask(cpumask_t cpumask)
 {
        int i;
-       u32 mask = 0;
+       cpumask_t mask = CPU_MASK_NONE;
+
+       cpus_and(cpumask, cpu_online_map, cpumask);
+
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_isset(i, cpumask))
+                       cpu_set(smp_hw_index[i], mask);
 
-       for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
-               if (cpu_online(i))
-                       mask |= (cpumask & 1) << smp_hw_index[i];
        return mask;
 }
 #else
@@ -607,12 +605,12 @@ void __devinit do_openpic_setup_cpu(void)
 {
 #ifdef CONFIG_IRQ_ALL_CPUS
        int i;
-       u32 msk;
+       cpumask_t msk = CPU_MASK_NONE;
 #endif
        spin_lock(&openpic_setup_lock);
 
 #ifdef CONFIG_IRQ_ALL_CPUS
-       msk = 1 << smp_hw_index[smp_processor_id()];
+       cpu_set(smp_hw_index[smp_processor_id()], mask);
 
        /* let the openpic know we want intrs. default affinity
         * is 0xffffffff until changed via /proc
@@ -621,7 +619,7 @@ void __devinit do_openpic_setup_cpu(void)
         * in irq.c.
         */
        for (i = 0; i < NumSources; i++)
-               openpic_mapirq(i, msk, ~0U);
+               openpic_mapirq(i, msk, CPU_MASK_ALL);
 #endif /* CONFIG_IRQ_ALL_CPUS */
        openpic_set_priority(0);
 
@@ -649,11 +647,12 @@ static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
 /*
  *  Map a timer interrupt to one or more CPUs
  */
-static void __init openpic_maptimer(u_int timer, u_int cpumask)
+static void __init openpic_maptimer(u_int timer, cpumask_t cpumask)
 {
+       cpumask_t phys = physmask(cpumask);
        check_arg_timer(timer);
        openpic_write(&OpenPIC->Global.Timer[timer].Destination,
-                     physmask(cpumask));
+                     cpus_addr(phys)[0]);
 }
 
 /*
@@ -770,13 +769,16 @@ openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
 /*
  *  Map an interrupt source to one or more CPUs
  */
-static void openpic_mapirq(u_int irq, u_int physmask, u_int keepmask)
+static void openpic_mapirq(u_int irq, cpumask_t physmask, cpumask_t keepmask)
 {
        if (ISR[irq] == 0)
                return;
-       if (keepmask != 0)
-               physmask |= openpic_read(&ISR[irq]->Destination) & keepmask;
-       openpic_write(&ISR[irq]->Destination, physmask);
+       if (!cpus_empty(keepmask)) {
+               cpumask_t irqdest = { .bits[0] = openpic_read(&ISR[irq]->Destination) };
+               cpus_and(irqdest, irqdest, keepmask);
+               cpus_or(physmask, physmask, irqdest);
+       }
+       openpic_write(&ISR[irq]->Destination, cpus_addr(physmask)[0]);
 }
 
 #ifdef notused
@@ -820,9 +822,9 @@ static void openpic_end_irq(unsigned int irq_nr)
 #endif
 }
 
-static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
+static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask)
 {
-       openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), 0);
+       openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), CPU_MASK_NONE);
 }
 
 #ifdef CONFIG_SMP
index 3e9e0b9..01e6cf2 100644 (file)
@@ -284,7 +284,8 @@ CONFIG_MTD=m
 CONFIG_MTD_PARTITIONS=m
 CONFIG_MTD_CONCAT=m
 CONFIG_MTD_REDBOOT_PARTS=m
-CONFIG_MTD_CMDLINE_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 
 #
 # User Modules And Translation Layers
@@ -304,9 +305,21 @@ CONFIG_MTD_CFI=m
 CONFIG_MTD_JEDECPROBE=m
 CONFIG_MTD_GEN_PROBE=m
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=m
 CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=3
 CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
 CONFIG_MTD_RAM=m
 CONFIG_MTD_ROM=m
 CONFIG_MTD_ABSENT=m
@@ -324,7 +337,7 @@ CONFIG_MTD_SBC_GXX=m
 CONFIG_MTD_ELAN_104NC=m
 CONFIG_MTD_SCx200_DOCFLASH=m
 CONFIG_MTD_AMD76XROM=m
-CONFIG_MTD_ICH2ROM=m
+# CONFIG_MTD_ICHXROM is not set
 CONFIG_MTD_SCB2_FLASH=m
 # CONFIG_MTD_NETtel is not set
 # CONFIG_MTD_DILNETPC is not set
@@ -338,6 +351,7 @@ CONFIG_MTD_PMC551=m
 # CONFIG_MTD_PMC551_BUGFIX is not set
 # CONFIG_MTD_PMC551_DEBUG is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 CONFIG_MTD_MTDRAM=m
 CONFIG_MTDRAM_TOTAL_SIZE=4096
 CONFIG_MTDRAM_ERASE_SIZE=128
@@ -350,6 +364,7 @@ CONFIG_MTD_DOC2000=m
 # CONFIG_MTD_DOC2001 is not set
 CONFIG_MTD_DOC2001PLUS=m
 CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
 # CONFIG_MTD_DOCPROBE_ADVANCED is not set
 CONFIG_MTD_DOCPROBE_ADDRESS=0
 
@@ -359,6 +374,7 @@ CONFIG_MTD_DOCPROBE_ADDRESS=0
 CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
 
 #
 # Parallel port support
@@ -2275,6 +2291,11 @@ CONFIG_EFS_FS=m
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_PROC is not set
 CONFIG_CRAMFS=m
 CONFIG_VXFS_FS=m
 # CONFIG_HPFS_FS is not set
index f3994f0..e54092d 100644 (file)
@@ -276,7 +276,8 @@ CONFIG_MTD=m
 CONFIG_MTD_PARTITIONS=m
 CONFIG_MTD_CONCAT=m
 CONFIG_MTD_REDBOOT_PARTS=m
-CONFIG_MTD_CMDLINE_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 
 #
 # User Modules And Translation Layers
@@ -296,9 +297,21 @@ CONFIG_MTD_CFI=m
 CONFIG_MTD_JEDECPROBE=m
 CONFIG_MTD_GEN_PROBE=m
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=m
 CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=3
 CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
 CONFIG_MTD_RAM=m
 CONFIG_MTD_ROM=m
 CONFIG_MTD_ABSENT=m
@@ -316,7 +329,7 @@ CONFIG_MTD_SBC_GXX=m
 CONFIG_MTD_ELAN_104NC=m
 CONFIG_MTD_SCx200_DOCFLASH=m
 CONFIG_MTD_AMD76XROM=m
-CONFIG_MTD_ICH2ROM=m
+# CONFIG_MTD_ICHXROM is not set
 CONFIG_MTD_SCB2_FLASH=m
 # CONFIG_MTD_NETtel is not set
 # CONFIG_MTD_DILNETPC is not set
@@ -330,6 +343,7 @@ CONFIG_MTD_PMC551=m
 # CONFIG_MTD_PMC551_BUGFIX is not set
 # CONFIG_MTD_PMC551_DEBUG is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 CONFIG_MTD_MTDRAM=m
 CONFIG_MTDRAM_TOTAL_SIZE=4096
 CONFIG_MTDRAM_ERASE_SIZE=128
@@ -342,6 +356,7 @@ CONFIG_MTD_DOC2000=m
 # CONFIG_MTD_DOC2001 is not set
 CONFIG_MTD_DOC2001PLUS=m
 CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
 # CONFIG_MTD_DOCPROBE_ADVANCED is not set
 CONFIG_MTD_DOCPROBE_ADDRESS=0
 
@@ -351,6 +366,7 @@ CONFIG_MTD_DOCPROBE_ADDRESS=0
 CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
 
 #
 # Parallel port support
@@ -2298,6 +2314,11 @@ CONFIG_EFS_FS=m
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_PROC is not set
 CONFIG_CRAMFS=m
 CONFIG_VXFS_FS=m
 # CONFIG_HPFS_FS is not set
index 6551b56..33f49bf 100644 (file)
@@ -288,7 +288,8 @@ CONFIG_MTD=m
 CONFIG_MTD_PARTITIONS=m
 CONFIG_MTD_CONCAT=m
 CONFIG_MTD_REDBOOT_PARTS=m
-CONFIG_MTD_CMDLINE_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 
 #
 # User Modules And Translation Layers
@@ -308,9 +309,21 @@ CONFIG_MTD_CFI=m
 CONFIG_MTD_JEDECPROBE=m
 CONFIG_MTD_GEN_PROBE=m
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=m
 CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=3
 CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
 CONFIG_MTD_RAM=m
 CONFIG_MTD_ROM=m
 CONFIG_MTD_ABSENT=m
@@ -328,7 +341,7 @@ CONFIG_MTD_SBC_GXX=m
 CONFIG_MTD_ELAN_104NC=m
 CONFIG_MTD_SCx200_DOCFLASH=m
 CONFIG_MTD_AMD76XROM=m
-CONFIG_MTD_ICH2ROM=m
+# CONFIG_MTD_ICHXROM is not set
 CONFIG_MTD_SCB2_FLASH=m
 # CONFIG_MTD_NETtel is not set
 # CONFIG_MTD_DILNETPC is not set
@@ -342,6 +355,7 @@ CONFIG_MTD_PMC551=m
 # CONFIG_MTD_PMC551_BUGFIX is not set
 # CONFIG_MTD_PMC551_DEBUG is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 CONFIG_MTD_MTDRAM=m
 CONFIG_MTDRAM_TOTAL_SIZE=4096
 CONFIG_MTDRAM_ERASE_SIZE=128
@@ -354,6 +368,7 @@ CONFIG_MTD_DOC2000=m
 # CONFIG_MTD_DOC2001 is not set
 CONFIG_MTD_DOC2001PLUS=m
 CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
 # CONFIG_MTD_DOCPROBE_ADVANCED is not set
 CONFIG_MTD_DOCPROBE_ADDRESS=0
 
@@ -363,6 +378,7 @@ CONFIG_MTD_DOCPROBE_ADDRESS=0
 CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
 
 #
 # Parallel port support
@@ -2278,6 +2294,11 @@ CONFIG_EFS_FS=m
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_PROC is not set
 CONFIG_CRAMFS=m
 CONFIG_VXFS_FS=m
 # CONFIG_HPFS_FS is not set
index e7007e9..9c13093 100644 (file)
@@ -277,7 +277,8 @@ CONFIG_MTD=m
 CONFIG_MTD_PARTITIONS=m
 CONFIG_MTD_CONCAT=m
 CONFIG_MTD_REDBOOT_PARTS=m
-CONFIG_MTD_CMDLINE_PARTS=m
+# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
+# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
 
 #
 # User Modules And Translation Layers
@@ -297,9 +298,21 @@ CONFIG_MTD_CFI=m
 CONFIG_MTD_JEDECPROBE=m
 CONFIG_MTD_GEN_PROBE=m
 # CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
 CONFIG_MTD_CFI_INTELEXT=m
 CONFIG_MTD_CFI_AMDSTD=m
+CONFIG_MTD_CFI_AMDSTD_RETRY=3
 CONFIG_MTD_CFI_STAA=m
+CONFIG_MTD_CFI_UTIL=m
 CONFIG_MTD_RAM=m
 CONFIG_MTD_ROM=m
 CONFIG_MTD_ABSENT=m
@@ -317,7 +330,7 @@ CONFIG_MTD_SBC_GXX=m
 CONFIG_MTD_ELAN_104NC=m
 CONFIG_MTD_SCx200_DOCFLASH=m
 CONFIG_MTD_AMD76XROM=m
-CONFIG_MTD_ICH2ROM=m
+# CONFIG_MTD_ICHXROM is not set
 CONFIG_MTD_SCB2_FLASH=m
 # CONFIG_MTD_NETtel is not set
 # CONFIG_MTD_DILNETPC is not set
@@ -331,6 +344,7 @@ CONFIG_MTD_PMC551=m
 # CONFIG_MTD_PMC551_BUGFIX is not set
 # CONFIG_MTD_PMC551_DEBUG is not set
 # CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
 CONFIG_MTD_MTDRAM=m
 CONFIG_MTDRAM_TOTAL_SIZE=4096
 CONFIG_MTDRAM_ERASE_SIZE=128
@@ -343,6 +357,7 @@ CONFIG_MTD_DOC2000=m
 # CONFIG_MTD_DOC2001 is not set
 CONFIG_MTD_DOC2001PLUS=m
 CONFIG_MTD_DOCPROBE=m
+CONFIG_MTD_DOCECC=m
 # CONFIG_MTD_DOCPROBE_ADVANCED is not set
 CONFIG_MTD_DOCPROBE_ADDRESS=0
 
@@ -352,6 +367,7 @@ CONFIG_MTD_DOCPROBE_ADDRESS=0
 CONFIG_MTD_NAND=m
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
 
 #
 # Parallel port support
@@ -2299,6 +2315,11 @@ CONFIG_EFS_FS=m
 CONFIG_JFFS2_FS=m
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_PROC is not set
 CONFIG_CRAMFS=m
 CONFIG_VXFS_FS=m
 # CONFIG_HPFS_FS is not set
index 5fb011c..2839166 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Kconfig,v 1.3 2003/05/28 11:02:23 dwmw2 Exp $
+# $Id: Kconfig,v 1.5 2004/06/04 15:59:32 gleixner Exp $
 
 menu "Memory Technology Devices (MTD)"
 
@@ -68,9 +68,23 @@ config MTD_REDBOOT_PARTS
          SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
          example.
 
+config MTD_REDBOOT_PARTS_UNALLOCATED
+       bool "  Include unallocated flash regions"
+       depends on MTD_REDBOOT_PARTS
+       help
+         If you need to register each unallocated flash region as a MTD
+         'partition', enable this option.
+
+config MTD_REDBOOT_PARTS_READONLY
+       bool "  Force read-only for RedBoot system images"
+       depends on MTD_REDBOOT_PARTS
+       help
+         If you need to force read-only for 'RedBoot', 'RedBoot Config' and
+         'FIS directory' images, enable this option.
+
 config MTD_CMDLINE_PARTS
-       tristate "Command line partition table parsing"
-       depends on MTD_PARTITIONS
+       bool "Command line partition table parsing"
+       depends on MTD_PARTITIONS = "y"
        ---help---
          Allow generic configuration of the MTD paritition tables via the kernel
          command line. Multiple flash resources are supported for hardware where
index 2915a53..85239c9 100644 (file)
@@ -1,23 +1,7 @@
 #
 # Makefile for the memory technology device drivers.
 #
-# $Id: Makefile.common,v 1.2 2003/05/23 11:38:29 dwmw2 Exp $
-
-#                       *** BIG UGLY NOTE ***
-#
-# The shiny new inter_module_xxx has introduced yet another ugly link
-# order dependency, which I'd previously taken great care to avoid.
-# We now have to ensure that the chip drivers are initialised before the
-# map drivers, and that the doc200[01] drivers are initialised before
-# docprobe.
-#
-# We'll hopefully merge the doc200[01] drivers and docprobe back into
-# a single driver some time soon, but the CFI drivers are going to have
-# to stay like that.
-#
-# Urgh.
-# 
-# dwmw2 21/11/0
+# $Id: Makefile.common,v 1.3 2004/07/12 16:07:30 dwmw2 Exp $
 
 # Core functionality.
 obj-$(CONFIG_MTD)              += mtdcore.o
index 4ea08f5..801e6c7 100644 (file)
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: afs.c,v 1.12 2003/06/13 15:31:06 rmk Exp $
+   $Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $
 
 ======================================================================*/
 
index e1c40ec..1247669 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.3 2003/05/28 15:13:24 dwmw2 Exp $
+# $Id: Kconfig,v 1.8 2004/07/13 22:32:02 dwmw2 Exp $
 
 menu "RAM/ROM/Flash chip drivers"
        depends on MTD!=n
@@ -85,59 +85,72 @@ config MTD_CFI_GEOMETRY
          arrangements of CFI chips. If unsure, say 'N' and all options 
          which are supported by the current code will be enabled.
 
-config MTD_CFI_B1
-       bool "Support  8-bit buswidth"
-       depends on MTD_CFI_GEOMETRY
+config MTD_MAP_BANK_WIDTH_1
+       bool "Support  8-bit buswidth" if MTD_CFI_GEOMETRY
+       default y
        help
          If you wish to support CFI devices on a physical bus which is
          8 bits wide, say 'Y'.
 
-config MTD_CFI_B2
-       bool "Support 16-bit buswidth"
-       depends on MTD_CFI_GEOMETRY
+config MTD_MAP_BANK_WIDTH_2
+       bool "Support 16-bit buswidth" if MTD_CFI_GEOMETRY
+       default y
        help
          If you wish to support CFI devices on a physical bus which is
          16 bits wide, say 'Y'.
 
-config MTD_CFI_B4
-       bool "Support 32-bit buswidth"
-       depends on MTD_CFI_GEOMETRY
+config MTD_MAP_BANK_WIDTH_4
+       bool "Support 32-bit buswidth" if MTD_CFI_GEOMETRY
+       default y
        help
          If you wish to support CFI devices on a physical bus which is
          32 bits wide, say 'Y'.
 
-config MTD_CFI_B8
-       bool "Support 64-bit buswidth"
-       depends on MTD_CFI_GEOMETRY
+config MTD_MAP_BANK_WIDTH_8
+       bool "Support 64-bit buswidth" if MTD_CFI_GEOMETRY
+       default n
        help
          If you wish to support CFI devices on a physical bus which is
          64 bits wide, say 'Y'.
 
+config MTD_MAP_BANK_WIDTH_16
+       bool "Support 128-bit buswidth" if MTD_CFI_GEOMETRY
+       default n
+       help
+         If you wish to support CFI devices on a physical bus which is
+         128 bits wide, say 'Y'.
+
+config MTD_MAP_BANK_WIDTH_32
+       bool "Support 256-bit buswidth" if MTD_CFI_GEOMETRY
+       default n
+       help
+         If you wish to support CFI devices on a physical bus which is
+         256 bits wide, say 'Y'.
+
 config MTD_CFI_I1
-       bool "Support 1-chip flash interleave" if !MTD_CFI_B1
-       depends on MTD_CFI_GEOMETRY
-       default y if MTD_CFI_B1
+       bool "Support 1-chip flash interleave" if MTD_CFI_GEOMETRY
+       default y
        help
          If your flash chips are not interleaved - i.e. you only have one
          flash chip addressed by each bus cycle, then say 'Y'.
 
 config MTD_CFI_I2
-       bool "Support 2-chip flash interleave"
-       depends on MTD_CFI_GEOMETRY
+       bool "Support 2-chip flash interleave" if MTD_CFI_GEOMETRY
+       default y
        help
          If your flash chips are interleaved in pairs - i.e. you have two
          flash chips addressed by each bus cycle, then say 'Y'.
 
 config MTD_CFI_I4
-       bool "Support 4-chip flash interleave"
-       depends on MTD_CFI_GEOMETRY
+       bool "Support 4-chip flash interleave" if MTD_CFI_GEOMETRY
+       default n
        help
          If your flash chips are interleaved in fours - i.e. you have four
          flash chips addressed by each bus cycle, then say 'Y'.
 
 config MTD_CFI_I8
-       bool "Support 8-chip flash interleave"
-       depends on MTD_CFI_GEOMETRY
+       bool "Support 8-chip flash interleave" if MTD_CFI_GEOMETRY
+       default n
        help
          If your flash chips are interleaved in eights - i.e. you have eight
          flash chips addressed by each bus cycle, then say 'Y'.
@@ -160,6 +173,27 @@ config MTD_CFI_AMDSTD
          provides support for one of those command sets, used on chips 
          including the AMD Am29LV320.
 
+config MTD_CFI_AMDSTD_RETRY
+       int "Retry failed commands (erase/program)"
+       depends on MTD_CFI_AMDSTD
+       default "0"
+       help
+         Some chips, when attached to a shared bus, don't properly filter
+         bus traffic that is destined to other devices.  This broken
+         behavior causes erase and program sequences to be aborted when
+         the sequences are mixed with traffic for other devices.
+
+         SST49LF040 (and related) chips are know to be broken.
+
+config MTD_CFI_AMDSTD_RETRY_MAX
+       int "Max retries of failed commands (erase/program)"
+       depends on MTD_CFI_AMDSTD_RETRY
+       default "0"
+       help
+         If you have an SST49LF040 (or related chip) then this value should
+         be set to at least 1.  This can also be adjusted at driver load
+         time with the retry_cmd_max module parameter.
+
 config MTD_CFI_STAA
        tristate "Support for ST (Advanced Architecture) flash chips"
        depends on MTD_GEN_PROBE
@@ -168,6 +202,11 @@ config MTD_CFI_STAA
          sets which a CFI-compliant chip may claim to implement. This code
          provides support for one of those command sets.
 
+config MTD_CFI_UTIL
+       tristate
+       default y if MTD_CFI_INTELEXT=y || MTD_CFI_AMDSTD=y || MTD_CFI_STAA=y
+       default m if MTD_CFI_INTELEXT=m || MTD_CFI_AMDSTD=m || MTD_CFI_STAA=m
+
 config MTD_RAM
        tristate "Support for RAM chips in bus mapping"
        depends on MTD
index 7293717..6830489 100644 (file)
@@ -1,18 +1,19 @@
 #
 # linux/drivers/chips/Makefile
 #
-# $Id: Makefile.common,v 1.1 2003/05/21 15:00:01 dwmw2 Exp $
+# $Id: Makefile.common,v 1.4 2004/07/12 16:07:30 dwmw2 Exp $
 
 #                       *** BIG UGLY NOTE ***
 #
 # The removal of get_module_symbol() and replacement with
 # inter_module_register() et al has introduced a link order dependency
 # here where previously there was none.  We now have to ensure that
-# the CFI command set drivers are linked before cfi_probe.o
+# the CFI command set drivers are linked before gen_probe.o
 
 obj-$(CONFIG_MTD)              += chipreg.o
 obj-$(CONFIG_MTD_AMDSTD)       += amd_flash.o 
 obj-$(CONFIG_MTD_CFI)          += cfi_probe.o
+obj-$(CONFIG_MTD_CFI_UTIL)     += cfi_util.o
 obj-$(CONFIG_MTD_CFI_STAA)     += cfi_cmdset_0020.o
 obj-$(CONFIG_MTD_CFI_AMDSTD)   += cfi_cmdset_0002.o
 obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
index fc7d0f2..ca710c7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
  *
- * $Id: amd_flash.c,v 1.23 2003/06/12 09:24:13 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.24 2004/07/12 13:34:30 dwmw2 Exp $
  *
  * Copyright (c) 2001 Axis Communications AB
  *
index 25a40ec..a36168e 100644 (file)
@@ -4,7 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
- * $Id: cfi_cmdset_0001.c,v 1.126 2003/06/23 07:45:48 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.153 2004/07/12 21:52:20 dwmw2 Exp $
  *
  * 
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
 #include <linux/mtd/compatmac.h>
 #include <linux/mtd/cfi.h>
 
+/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */
+
 // debugging, turns off buffer write mode if set to 1
 #define FORCE_WORD_WRITE 0
 
 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_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 *);
@@ -54,6 +56,7 @@ static void cfi_intelext_destroy(struct mtd_info *);
 struct mtd_info *cfi_cmdset_0001(struct map_info *, int);
 
 static struct mtd_info *cfi_intelext_setup (struct map_info *);
+static int cfi_intelext_partition_fixup(struct map_info *, struct cfi_private **);
 
 static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
                     size_t *retlen, u_char **mtdbuf);
@@ -79,17 +82,18 @@ static struct mtd_chip_driver cfi_intelext_chipdrv = {
 static void cfi_tell_features(struct cfi_pri_intelext *extp)
 {
        int i;
-       printk("  Feature/Command Support: %4.4X\n", extp->FeatureSupport);
-       printk("     - Chip Erase:         %s\n", extp->FeatureSupport&1?"supported":"unsupported");
-       printk("     - Suspend Erase:      %s\n", extp->FeatureSupport&2?"supported":"unsupported");
-       printk("     - Suspend Program:    %s\n", extp->FeatureSupport&4?"supported":"unsupported");
-       printk("     - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported");
-       printk("     - Queued Erase:       %s\n", extp->FeatureSupport&16?"supported":"unsupported");
-       printk("     - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported");
-       printk("     - Protection Bits:    %s\n", extp->FeatureSupport&64?"supported":"unsupported");
-       printk("     - Page-mode read:     %s\n", extp->FeatureSupport&128?"supported":"unsupported");
-       printk("     - Synchronous read:   %s\n", extp->FeatureSupport&256?"supported":"unsupported");
-       for (i=9; i<32; i++) {
+       printk("  Feature/Command Support:      %4.4X\n", extp->FeatureSupport);
+       printk("     - Chip Erase:              %s\n", extp->FeatureSupport&1?"supported":"unsupported");
+       printk("     - Suspend Erase:           %s\n", extp->FeatureSupport&2?"supported":"unsupported");
+       printk("     - Suspend Program:         %s\n", extp->FeatureSupport&4?"supported":"unsupported");
+       printk("     - Legacy Lock/Unlock:      %s\n", extp->FeatureSupport&8?"supported":"unsupported");
+       printk("     - Queued Erase:            %s\n", extp->FeatureSupport&16?"supported":"unsupported");
+       printk("     - Instant block lock:      %s\n", extp->FeatureSupport&32?"supported":"unsupported");
+       printk("     - Protection Bits:         %s\n", extp->FeatureSupport&64?"supported":"unsupported");
+       printk("     - Page-mode read:          %s\n", extp->FeatureSupport&128?"supported":"unsupported");
+       printk("     - Synchronous read:        %s\n", extp->FeatureSupport&256?"supported":"unsupported");
+       printk("     - Simultaneous operations: %s\n", extp->FeatureSupport&512?"supported":"unsupported");
+       for (i=10; i<32; i++) {
                if (extp->FeatureSupport & (1<<i)) 
                        printk("     - Unknown Bit %X:      supported\n", i);
        }
@@ -110,12 +114,62 @@ static void cfi_tell_features(struct cfi_pri_intelext *extp)
        }
        
        printk("  Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", 
-              extp->VccOptimal >> 8, extp->VccOptimal & 0xf);
+              extp->VccOptimal >> 4, extp->VccOptimal & 0xf);
        if (extp->VppOptimal)
                printk("  Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", 
-                      extp->VppOptimal >> 8, extp->VppOptimal & 0xf);
+                      extp->VppOptimal >> 4, extp->VppOptimal & 0xf);
+}
+#endif
+
+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ 
+static void fixup_intel_strataflash(struct map_info *map, void* param)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+
+       printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
+                           "erase on write disabled.\n");
+       extp->SuspendCmdSupport &= ~1;
+}
+#endif
+
+static void fixup_st_m28w320ct(struct map_info *map, void* param)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       
+       cfi->cfiq->BufWriteTimeoutTyp = 0;      /* Not supported */
+       cfi->cfiq->BufWriteTimeoutMax = 0;      /* Not supported */
 }
+
+static void fixup_st_m28w320cb(struct map_info *map, void* param)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       
+       /* Note this is done after the region info is endian swapped */
+       cfi->cfiq->EraseRegionInfo[1] =
+               (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e;
+};
+
+static struct cfi_fixup fixup_table[] = {
+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
+       {
+               CFI_MFR_ANY, CFI_ID_ANY,
+               fixup_intel_strataflash, NULL
+       }, 
 #endif
+       {
+               0x0020, /* STMicroelectronics */
+               0x00ba, /* M28W320CT */
+               fixup_st_m28w320ct, NULL
+       }, {
+               0x0020, /* STMicroelectronics */
+               0x00bb, /* M28W320CB */
+               fixup_st_m28w320cb, NULL
+       }, {
+               0, 0, NULL, NULL
+       }
+};
 
 /* This routine is made available to other mtd code via
  * inter_module_register.  It must only be accessed through
@@ -128,7 +182,6 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        int i;
-       __u32 base = cfi->chips[0].start;
 
        if (cfi->cfi_mode == CFI_MODE_CFI) {
                /* 
@@ -138,40 +191,20 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
                 */
                __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
                struct cfi_pri_intelext *extp;
-               int ofs_factor = cfi->interleave * cfi->device_type;
 
-               //printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr);
-               if (!adr)
+               extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp");
+               if (!extp)
                        return NULL;
-
-               /* Switch it into Query Mode */
-               cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
-               extp = kmalloc(sizeof(*extp), GFP_KERNEL);
-               if (!extp) {
-                       printk(KERN_ERR "Failed to allocate memory\n");
-                       return NULL;
-               }
-               
-               /* Read in the Extended Query Table */
-               for (i=0; i<sizeof(*extp); i++) {
-                       ((unsigned char *)extp)[i] = 
-                               cfi_read_query(map, (base+((adr+i)*ofs_factor)));
-               }
-               
-               if (extp->MajorVersion != '1' || 
-                   (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
-                       printk(KERN_WARNING "  Unknown IntelExt Extended Query "
-                              "version %c.%c.\n",  extp->MajorVersion,
-                              extp->MinorVersion);
-                       kfree(extp);
-                       return NULL;
-               }
                
                /* Do some byteswapping if necessary */
                extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport);
                extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask);
                extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr);
+
+               /* Install our own private info structure */
+               cfi->cmdset_priv = extp;        
+
+               cfi_fixup(map, fixup_table);
                        
 #ifdef DEBUG_CFI_FEATURES
                /* Tell the user about it in lots of lovely detail */
@@ -179,18 +212,8 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
 #endif 
 
                if(extp->SuspendCmdSupport & 1) {
-//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ 
-                       printk(KERN_WARNING "cfi_cmdset_0001: Suspend "
-                              "erase on write disabled.\n");
-                       extp->SuspendCmdSupport &= ~1;
-#else
                        printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n");
-#endif
                }
-               /* Install our own private info structure */
-               cfi->cmdset_priv = extp;        
        }
 
        for (i=0; i< cfi->numchips; i++) {
@@ -202,8 +225,6 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
 
        map->fldrv = &cfi_intelext_chipdrv;
        
-       /* Make sure it's in read mode */
-       cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
        return cfi_intelext_setup(map);
 }
 
@@ -281,8 +302,10 @@ static struct mtd_info *cfi_intelext_setup(struct map_info *map)
                printk(KERN_INFO "Using word write method\n" );
                mtd->write = cfi_intelext_write_words;
        }
+#if 0
        mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
        mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+#endif
        mtd->sync = cfi_intelext_sync;
        mtd->lock = cfi_intelext_lock;
        mtd->unlock = cfi_intelext_unlock;
@@ -291,6 +314,12 @@ static struct mtd_info *cfi_intelext_setup(struct map_info *map)
        mtd->flags = MTD_CAP_NORFLASH;
        map->fldrv = &cfi_intelext_chipdrv;
        mtd->name = map->name;
+
+       /* This function has the potential to distort the reality
+          a bit and therefore should be called last. */
+       if (cfi_intelext_partition_fixup(map, &cfi) != 0)
+               goto setup_err;
+
        __module_get(THIS_MODULE);
        return mtd;
 
@@ -301,10 +330,87 @@ static struct mtd_info *cfi_intelext_setup(struct map_info *map)
                kfree(mtd);
        }
        kfree(cfi->cmdset_priv);
-       kfree(cfi->cfiq);
        return NULL;
 }
 
+static int cfi_intelext_partition_fixup(struct map_info *map,
+                                       struct cfi_private **pcfi)
+{
+       struct cfi_private *cfi = *pcfi;
+       struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+
+       /*
+        * Probing of multi-partition flash ships.
+        *
+        * This is extremely crude at the moment and should probably be
+        * extracted entirely from the Intel extended query data instead.
+        * Right now a L18 flash is assumed if multiple operations is
+        * detected.
+        *
+        * To support multiple partitions when available, we simply arrange
+        * for each of them to have their own flchip structure even if they
+        * are on the same physical chip.  This means completely recreating
+        * a new cfi_private structure right here which is a blatent code
+        * layering violation, but this is still the least intrusive
+        * arrangement at this point. This can be rearranged in the future
+        * if someone feels motivated enough.  --nico
+        */
+       if (extp && extp->FeatureSupport & (1 << 9)) {
+               struct cfi_private *newcfi;
+               struct flchip *chip;
+               struct flchip_shared *shared;
+               int numparts, partshift, numvirtchips, i, j;
+
+               /*
+                * The L18 flash memory array is divided
+                * into multiple 8-Mbit partitions.
+                */
+               numparts = 1 << (cfi->cfiq->DevSize - 20);
+               partshift = 20 + __ffs(cfi->interleave);
+               numvirtchips = cfi->numchips * numparts;
+
+               newcfi = kmalloc(sizeof(struct cfi_private) + numvirtchips * sizeof(struct flchip), GFP_KERNEL);
+               if (!newcfi)
+                       return -ENOMEM;
+               shared = kmalloc(sizeof(struct flchip_shared) * cfi->numchips, GFP_KERNEL);
+               if (!shared) {
+                       kfree(newcfi);
+                       return -ENOMEM;
+               }
+               memcpy(newcfi, cfi, sizeof(struct cfi_private));
+               newcfi->numchips = numvirtchips;
+               newcfi->chipshift = partshift;
+
+               chip = &newcfi->chips[0];
+               for (i = 0; i < cfi->numchips; i++) {
+                       shared[i].writing = shared[i].erasing = NULL;
+                       spin_lock_init(&shared[i].lock);
+                       for (j = 0; j < numparts; j++) {
+                               *chip = cfi->chips[i];
+                               chip->start += j << partshift;
+                               chip->priv = &shared[i];
+                               /* those should be reset too since
+                                  they create memory references. */
+                               init_waitqueue_head(&chip->wq);
+                               spin_lock_init(&chip->_spinlock);
+                               chip->mutex = &chip->_spinlock;
+                               chip++;
+                       }
+               }
+
+               printk(KERN_DEBUG "%s: %d sets of %d interleaved chips "
+                                 "--> %d partitions of %#x bytes\n",
+                                 map->name, cfi->numchips, cfi->interleave,
+                                 newcfi->numchips, 1<<newcfi->chipshift);
+
+               map->fldrv_priv = newcfi;
+               *pcfi = newcfi;
+               kfree(cfi);
+       }
+
+       return 0;
+}
+
 /*
  *  *********** CHIP ACCESS FUNCTIONS ***********
  */
@@ -313,25 +419,87 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
 {
        DECLARE_WAITQUEUE(wait, current);
        struct cfi_private *cfi = map->fldrv_priv;
-       cfi_word status, status_OK = CMD(0x80);
+       map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01);
        unsigned long timeo;
-       struct cfi_pri_intelext *cfip = (struct cfi_pri_intelext *)cfi->cmdset_priv;
+       struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
 
  resettime:
        timeo = jiffies + HZ;
  retry:
+       if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) {
+               /*
+                * OK. We have possibility for contension on the write/erase
+                * operations which are global to the real chip and not per
+                * partition.  So let's fight it over in the partition which
+                * currently has authority on the operation.
+                *
+                * The rules are as follows:
+                *
+                * - any write operation must own shared->writing.
+                *
+                * - any erase operation must own _both_ shared->writing and
+                *   shared->erasing.
+                *
+                * - contension arbitration is handled in the owner's context.
+                *
+                * The 'shared' struct can be read when its lock is taken.
+                * However any writes to it can only be made when the current
+                * owner's lock is also held.
+                */
+               struct flchip_shared *shared = chip->priv;
+               struct flchip *contender;
+               spin_lock(&shared->lock);
+               contender = shared->writing;
+               if (contender && contender != chip) {
+                       /*
+                        * The engine to perform desired operation on this
+                        * partition is already in use by someone else.
+                        * Let's fight over it in the context of the chip
+                        * currently using it.  If it is possible to suspend,
+                        * that other partition will do just that, otherwise
+                        * it'll happily send us to sleep.  In any case, when
+                        * get_chip returns success we're clear to go ahead.
+                        */
+                       int ret = spin_trylock(contender->mutex);
+                       spin_unlock(&shared->lock);
+                       if (!ret)
+                               goto retry;
+                       spin_unlock(chip->mutex);
+                       ret = get_chip(map, contender, contender->start, mode);
+                       spin_lock(chip->mutex);
+                       if (ret) {
+                               spin_unlock(contender->mutex);
+                               return ret;
+                       }
+                       timeo = jiffies + HZ;
+                       spin_lock(&shared->lock);
+               }
+
+               /* We now own it */
+               shared->writing = chip;
+               if (mode == FL_ERASING)
+                       shared->erasing = chip;
+               if (contender && contender != chip)
+                       spin_unlock(contender->mutex);
+               spin_unlock(&shared->lock);
+       }
+
        switch (chip->state) {
 
        case FL_STATUS:
                for (;;) {
-                       status = cfi_read(map, adr);
-                       if ((status & status_OK) == status_OK)
+                       status = map_read(map, adr);
+                       if (map_word_andequal(map, status, status_OK, status_OK))
+                               break;
+
+                       /* At this point we're fine with write operations
+                          in other partitions as they don't conflict. */
+                       if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS))
                                break;
 
                        if (time_after(jiffies, timeo)) {
-                               printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n", 
-                                      (long long)status);
-                               spin_unlock(chip->mutex);
+                               printk(KERN_ERR "Waiting for chip to be ready timed out. Status %lx\n", 
+                                      status.x[0]);
                                return -EIO;
                        }
                        spin_unlock(chip->mutex);
@@ -354,31 +522,31 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
 
 
                /* Erase suspend */
-               cfi_write(map, CMD(0xB0), adr);
+               map_write(map, CMD(0xB0), adr);
 
                /* If the flash has finished erasing, then 'erase suspend'
                 * appears to make some (28F320) flash devices switch to
                 * 'read' mode.  Make sure that we switch to 'read status'
                 * mode so we get the right data. --rmk
                 */
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x70), adr);
                chip->oldstate = FL_ERASING;
                chip->state = FL_ERASE_SUSPENDING;
                chip->erase_suspended = 1;
                for (;;) {
-                       status = cfi_read(map, adr);
-                       if ((status & status_OK) == status_OK)
+                       status = map_read(map, adr);
+                       if (map_word_andequal(map, status, status_OK, status_OK))
                                break;
 
                        if (time_after(jiffies, timeo)) {
                                /* Urgh. Resume and pretend we weren't here.  */
-                               cfi_write(map, CMD(0xd0), adr);
+                               map_write(map, CMD(0xd0), adr);
                                /* Make sure we're in 'read status' mode if it had finished */
-                               cfi_write(map, CMD(0x70), adr);
+                               map_write(map, CMD(0x70), adr);
                                chip->state = FL_ERASING;
                                chip->oldstate = FL_READY;
                                printk(KERN_ERR "Chip not ready after erase "
-                                      "suspended: status = 0x%llx\n", status);
+                                      "suspended: status = 0x%lx\n", status.x[0]);
                                return -EIO;
                        }
 
@@ -412,6 +580,32 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
 {
        struct cfi_private *cfi = map->fldrv_priv;
 
+       if (chip->priv) {
+               struct flchip_shared *shared = chip->priv;
+               spin_lock(&shared->lock);
+               if (shared->writing == chip) {
+                       /* We own the ability to write, but we're done */
+                       shared->writing = shared->erasing;
+                       if (shared->writing && shared->writing != chip) {
+                               /* give back ownership to who we loaned it from */
+                               struct flchip *loaner = shared->writing;
+                               spin_lock(loaner->mutex);
+                               spin_unlock(&shared->lock);
+                               spin_unlock(chip->mutex);
+                               put_chip(map, loaner, loaner->start);
+                               spin_lock(chip->mutex);
+                               spin_unlock(loaner->mutex);
+                       } else {
+                               if (chip->oldstate != FL_ERASING) {
+                                       shared->erasing = NULL;
+                                       if (chip->oldstate != FL_WRITING)
+                                               shared->writing = NULL;
+                               }
+                               spin_unlock(&shared->lock);
+                       }
+               }
+       }
+
        switch(chip->oldstate) {
        case FL_ERASING:
                chip->state = chip->oldstate;
@@ -424,14 +618,15 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
                   sending the 0x70 (Read Status) command to an erasing
                   chip and expecting it to be ignored, that's what we 
                   do. */
-               cfi_write(map, CMD(0xd0), adr);
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0xd0), adr);
+               map_write(map, CMD(0x70), adr);
                chip->oldstate = FL_READY;
                chip->state = FL_ERASING;
                break;
 
        case FL_READY:
        case FL_STATUS:
+       case FL_JEDEC_QUERY:
                /* We should really make set_vpp() count, rather than doing this */
                DISABLE_VPP(map);
                break;
@@ -450,7 +645,7 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
        adr += chip->start;
 
        /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+       cmd_addr = adr & ~(map_bankwidth(map)-1); 
 
        spin_lock(chip->mutex);
 
@@ -458,7 +653,7 @@ static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t a
 
        if (!ret) {
                if (chip->state != FL_POINT && chip->state != FL_READY)
-                       cfi_write(map, CMD(0xff), cmd_addr);
+                       map_write(map, CMD(0xff), cmd_addr);
 
                chip->state = FL_POINT;
                chip->ref_point_counter++;
@@ -476,12 +671,10 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, si
        int chipnum;
        int ret = 0;
 
-       if (from + len > mtd->size)
+       if (!map->virt || (from + len > mtd->size))
                return -EINVAL;
        
        *mtdbuf = (void *)map->virt + from;
-       if(*mtdbuf == NULL)
-               return -EINVAL; /* can not point this region */
        *retlen = 0;
 
        /* Now lock the chip(s) to POINT state */
@@ -566,7 +759,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
        adr += chip->start;
 
        /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+       cmd_addr = adr & ~(map_bankwidth(map)-1); 
 
        spin_lock(chip->mutex);
        ret = get_chip(map, chip, cmd_addr, FL_READY);
@@ -576,7 +769,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
        }
 
        if (chip->state != FL_POINT && chip->state != FL_READY) {
-               cfi_write(map, CMD(0xff), cmd_addr);
+               map_write(map, CMD(0xff), cmd_addr);
 
                chip->state = FL_READY;
        }
@@ -627,7 +820,7 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
        }
        return ret;
 }
-
+#if 0
 static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
 {
        struct map_info *map = mtd->priv;
@@ -658,7 +851,7 @@ static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t
                }
 
                if (chip->state != FL_JEDEC_QUERY) {
-                       cfi_write(map, CMD(0x90), chip->start);
+                       map_write(map, CMD(0x90), chip->start);
                        chip->state = FL_JEDEC_QUERY;
                }
 
@@ -718,12 +911,12 @@ static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, s
 
        return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
 }
+#endif
 
-
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum)
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       cfi_word status, status_OK;
+       map_word status, status_OK;
        unsigned long timeo;
        int z, ret=0;
 
@@ -740,11 +933,12 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
        }
 
        ENABLE_VPP(map);
-       cfi_write(map, CMD(0x40), adr);
-       cfi_write(map, datum, adr);
+       map_write(map, CMD(0x40), adr);
+       map_write(map, datum, adr);
        chip->state = FL_WRITING;
 
        spin_unlock(chip->mutex);
+       INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
        cfi_udelay(chip->word_write_time);
        spin_lock(chip->mutex);
 
@@ -765,8 +959,8 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
                        continue;
                }
 
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                
                /* OK Still waiting */
@@ -794,11 +988,11 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
        /* Done and happy. */
        chip->state = FL_STATUS;
        /* check for lock bit */
-       if (status & CMD(0x02)) {
+       if (map_word_bitsset(map, status, CMD(0x02))) {
                /* clear status */
-               cfi_write(map, CMD(0x50), adr);
+               map_write(map, CMD(0x50), adr);
                /* put back into read status register mode */
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x70), adr);
                ret = -EROFS;
        }
  out:
@@ -825,35 +1019,22 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
        ofs = to  - (chipnum << cfi->chipshift);
 
        /* If it's not bus-aligned, do the first byte write */
-       if (ofs & (CFIDEV_BUSWIDTH-1)) {
-               unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
+       if (ofs & (map_bankwidth(map)-1)) {
+               unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
                int gap = ofs - bus_ofs;
-               int i = 0, n = 0;
-               u_char tmp_buf[8];
-               cfi_word datum;
-
-               while (gap--)
-                       tmp_buf[i++] = 0xff;
-               while (len && i < CFIDEV_BUSWIDTH)
-                       tmp_buf[i++] = buf[n++], len--;
-               while (i < CFIDEV_BUSWIDTH)
-                       tmp_buf[i++] = 0xff;
-
-               if (cfi_buswidth_is_2()) {
-                       datum = *(__u16*)tmp_buf;
-               } else if (cfi_buswidth_is_4()) {
-                       datum = *(__u32*)tmp_buf;
-               } else if (cfi_buswidth_is_8()) {
-                       datum = *(__u64*)tmp_buf;
-               } else {
-                       return -EINVAL;  /* should never happen, but be safe */
-               }
+               int n;
+               map_word datum;
+
+               n = min_t(int, len, map_bankwidth(map)-gap);
+               datum = map_word_ff(map);
+               datum = map_word_load_partial(map, datum, buf, gap, n);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
                                               bus_ofs, datum);
                if (ret) 
                        return ret;
-               
+
+               len -= n;
                ofs += n;
                buf += n;
                (*retlen) += n;
@@ -866,30 +1047,18 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                }
        }
        
-       while(len >= CFIDEV_BUSWIDTH) {
-               cfi_word datum;
-
-               if (cfi_buswidth_is_1()) {
-                       datum = *(__u8*)buf;
-               } else if (cfi_buswidth_is_2()) {
-                       datum = *(__u16*)buf;
-               } else if (cfi_buswidth_is_4()) {
-                       datum = *(__u32*)buf;
-               } else if (cfi_buswidth_is_8()) {
-                       datum = *(__u64*)buf;
-               } else {
-                       return -EINVAL;
-               }
+       while(len >= map_bankwidth(map)) {
+               map_word datum = map_word_load(map, buf);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
                                ofs, datum);
                if (ret)
                        return ret;
 
-               ofs += CFIDEV_BUSWIDTH;
-               buf += CFIDEV_BUSWIDTH;
-               (*retlen) += CFIDEV_BUSWIDTH;
-               len -= CFIDEV_BUSWIDTH;
+               ofs += map_bankwidth(map);
+               buf += map_bankwidth(map);
+               (*retlen) += map_bankwidth(map);
+               len -= map_bankwidth(map);
 
                if (ofs >> cfi->chipshift) {
                        chipnum ++; 
@@ -899,32 +1068,18 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
                }
        }
 
-       if (len & (CFIDEV_BUSWIDTH-1)) {
-               int i = 0, n = 0;
-               u_char tmp_buf[8];
-               cfi_word datum;
-
-               while (len--)
-                       tmp_buf[i++] = buf[n++];
-               while (i < CFIDEV_BUSWIDTH)
-                       tmp_buf[i++] = 0xff;
-
-               if (cfi_buswidth_is_2()) {
-                       datum = *(__u16*)tmp_buf;
-               } else if (cfi_buswidth_is_4()) {
-                       datum = *(__u32*)tmp_buf;
-               } else if (cfi_buswidth_is_8()) {
-                       datum = *(__u64*)tmp_buf;
-               } else {
-                       return -EINVAL;  /* should never happen, but be safe */
-               }
+       if (len & (map_bankwidth(map)-1)) {
+               map_word datum;
+
+               datum = map_word_ff(map);
+               datum = map_word_load_partial(map, datum, buf, 0, len);
 
                ret = do_write_oneword(map, &cfi->chips[chipnum],
                                               ofs, datum);
                if (ret) 
                        return ret;
                
-               (*retlen) += n;
+               (*retlen) += len;
        }
 
        return 0;
@@ -935,11 +1090,11 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                                  unsigned long adr, const u_char *buf, int len)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       cfi_word status, status_OK;
+       map_word status, status_OK;
        unsigned long cmd_adr, timeo;
        int wbufsize, z, ret=0, bytes, words;
 
-       wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+       wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        adr += chip->start;
        cmd_adr = adr & ~(wbufsize-1);
        
@@ -953,29 +1108,28 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                return ret;
        }
 
-       if (chip->state != FL_STATUS)
-               cfi_write(map, CMD(0x70), cmd_adr);
-
-       status = cfi_read(map, cmd_adr);
-
        /* Â§4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
           [...], the device will not accept any more Write to Buffer commands". 
           So we must check here and reset those bits if they're set. Otherwise
           we're just pissing in the wind */
-       if (status & CMD(0x30)) {
-               printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %llx). Clearing.\n", status);
-               cfi_write(map, CMD(0x50), cmd_adr);
-               cfi_write(map, CMD(0x70), cmd_adr);
+       if (chip->state != FL_STATUS)
+               map_write(map, CMD(0x70), cmd_adr);
+       status = map_read(map, cmd_adr);
+       if (map_word_bitsset(map, status, CMD(0x30))) {
+               printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %lx). Clearing.\n", status.x[0]);
+               map_write(map, CMD(0x50), cmd_adr);
+               map_write(map, CMD(0x70), cmd_adr);
        }
+
        ENABLE_VPP(map);
        chip->state = FL_WRITING_TO_BUFFER;
 
        z = 0;
        for (;;) {
-               cfi_write(map, CMD(0xe8), cmd_adr);
+               map_write(map, CMD(0xe8), cmd_adr);
 
-               status = cfi_read(map, cmd_adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, cmd_adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
 
                spin_unlock(chip->mutex);
@@ -984,84 +1138,47 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
 
                if (++z > 20) {
                        /* Argh. Not ready for write to buffer */
-                       cfi_write(map, CMD(0x70), cmd_adr);
+                       map_write(map, CMD(0x70), cmd_adr);
                        chip->state = FL_STATUS;
-                       printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr));
+                       printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
+                              status.x[0], map_read(map, cmd_adr).x[0]);
                        /* Odd. Clear status bits */
-                       cfi_write(map, CMD(0x50), cmd_adr);
-                       cfi_write(map, CMD(0x70), cmd_adr);
+                       map_write(map, CMD(0x50), cmd_adr);
+                       map_write(map, CMD(0x70), cmd_adr);
                        ret = -EIO;
                        goto out;
                }
        }
 
        /* Write length of data to come */
-       bytes = len & (CFIDEV_BUSWIDTH-1);
-       words = len / CFIDEV_BUSWIDTH;
-       cfi_write(map, CMD(words - !bytes), cmd_adr );
+       bytes = len & (map_bankwidth(map)-1);
+       words = len / map_bankwidth(map);
+       map_write(map, CMD(words - !bytes), cmd_adr );
 
        /* Write data */
        z = 0;
-       while(z < words * CFIDEV_BUSWIDTH) {
-               if (cfi_buswidth_is_1()) {
-                       u8 *b = (u8 *)buf;
-
-                       map_write8 (map, *b++, adr+z);
-                       buf = (const u_char *)b;
-               } else if (cfi_buswidth_is_2()) {
-                       u16 *b = (u16 *)buf;
-
-                       map_write16 (map, *b++, adr+z);
-                       buf = (const u_char *)b;
-               } else if (cfi_buswidth_is_4()) {
-                       u32 *b = (u32 *)buf;
-
-                       map_write32 (map, *b++, adr+z);
-                       buf = (const u_char *)b;
-               } else if (cfi_buswidth_is_8()) {
-                       u64 *b = (u64 *)buf;
-
-                       map_write64 (map, *b++, adr+z);
-                       buf = (const u_char *)b;
-               } else {
-                       ret = -EINVAL;
-                       goto out;
-               }
-               z += CFIDEV_BUSWIDTH;
+       while(z < words * map_bankwidth(map)) {
+               map_word datum = map_word_load(map, buf);
+               map_write(map, datum, adr+z);
+
+               z += map_bankwidth(map);
+               buf += map_bankwidth(map);
        }
+
        if (bytes) {
-               int i = 0, n = 0;
-               u_char tmp_buf[8], *tmp_p = tmp_buf;
-
-               while (bytes--)
-                       tmp_buf[i++] = buf[n++];
-               while (i < CFIDEV_BUSWIDTH)
-                       tmp_buf[i++] = 0xff;
-               if (cfi_buswidth_is_2()) {
-                       u16 *b = (u16 *)tmp_p;
-
-                       map_write16 (map, *b++, adr+z);
-                       tmp_p = (u_char *)b;
-               } else if (cfi_buswidth_is_4()) {
-                       u32 *b = (u32 *)tmp_p;
-
-                       map_write32 (map, *b++, adr+z);
-                       tmp_p = (u_char *)b;
-               } else if (cfi_buswidth_is_8()) {
-                       u64 *b = (u64 *)tmp_p;
-
-                       map_write64 (map, *b++, adr+z);
-                       tmp_p = (u_char *)b;
-               } else {
-                       ret = -EINVAL;
-                       goto out;
-               }
+               map_word datum;
+
+               datum = map_word_ff(map);
+               datum = map_word_load_partial(map, datum, buf, 0, bytes);
+               map_write(map, datum, adr+z);
        }
+
        /* GO GO GO */
-       cfi_write(map, CMD(0xd0), cmd_adr);
+       map_write(map, CMD(0xd0), cmd_adr);
        chip->state = FL_WRITING;
 
        spin_unlock(chip->mutex);
+       INVALIDATE_CACHED_RANGE(map, adr, len);
        cfi_udelay(chip->buffer_write_time);
        spin_lock(chip->mutex);
 
@@ -1081,8 +1198,8 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                        continue;
                }
 
-               status = cfi_read(map, cmd_adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, cmd_adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
 
                /* OK Still waiting */
@@ -1111,11 +1228,11 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        chip->state = FL_STATUS;
 
        /* check for lock bit */
-       if (status & CMD(0x02)) {
+       if (map_word_bitsset(map, status, CMD(0x02))) {
                /* clear status */
-               cfi_write(map, CMD(0x50), cmd_adr);
+               map_write(map, CMD(0x50), cmd_adr);
                /* put back into read status register mode */
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x70), adr);
                ret = -EROFS;
        }
 
@@ -1130,7 +1247,7 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+       int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        int ret = 0;
        int chipnum;
        unsigned long ofs;
@@ -1143,8 +1260,8 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
        ofs = to  - (chipnum << cfi->chipshift);
 
        /* If it's not bus-aligned, do the first word write */
-       if (ofs & (CFIDEV_BUSWIDTH-1)) {
-               size_t local_len = (-ofs)&(CFIDEV_BUSWIDTH-1);
+       if (ofs & (map_bankwidth(map)-1)) {
+               size_t local_len = (-ofs)&(map_bankwidth(map)-1);
                if (local_len > len)
                        local_len = len;
                ret = cfi_intelext_write_words(mtd, to, local_len,
@@ -1163,7 +1280,6 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
                }
        }
 
-       /* Write buffer is worth it only if more than one word to write... */
        while(len) {
                /* We must not cross write block boundaries */
                int size = wbufsize - (ofs & (wbufsize-1));
@@ -1191,7 +1307,7 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
 }
 
 typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
-                             unsigned long adr, void *thunk);
+                             unsigned long adr, int len, void *thunk);
 
 static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
                                     loff_t ofs, size_t len, void *thunk)
@@ -1258,15 +1374,19 @@ static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
        i=first;
 
        while(len) {
-               ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
+               unsigned long chipmask;
+               int size = regions[i].erasesize;
+
+               ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
                
                if (ret)
                        return ret;
 
-               adr += regions[i].erasesize;
-               len -= regions[i].erasesize;
+               adr += size;
+               len -= size;
 
-               if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
+               chipmask = (1 << cfi->chipshift) - 1;
+               if ((adr & chipmask) == ((regions[i].offset + size * regions[i].numblocks) & chipmask))
                        i++;
 
                if (adr >> cfi->chipshift) {
@@ -1282,10 +1402,11 @@ static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
 }
 
 
-static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
+                            unsigned long adr, int len, void *thunk)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       cfi_word status, status_OK;
+       map_word status, status_OK;
        unsigned long timeo;
        int retries = 3;
        DECLARE_WAITQUEUE(wait, current);
@@ -1306,15 +1427,16 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned
 
        ENABLE_VPP(map);
        /* Clear the status register first */
-       cfi_write(map, CMD(0x50), adr);
+       map_write(map, CMD(0x50), adr);
 
        /* Now erase */
-       cfi_write(map, CMD(0x20), adr);
-       cfi_write(map, CMD(0xD0), adr);
+       map_write(map, CMD(0x20), adr);
+       map_write(map, CMD(0xD0), adr);
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
 
        spin_unlock(chip->mutex);
+       INVALIDATE_CACHED_RANGE(map, adr, len);
        set_current_state(TASK_UNINTERRUPTIBLE);
        schedule_timeout((chip->erase_time*HZ)/(2*1000));
        spin_lock(chip->mutex);
@@ -1341,19 +1463,19 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned
                        chip->erase_suspended = 0;
                }
 
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       cfi_write(map, CMD(0x70), adr);
+                       map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %llx, status = %llx.\n",
-                              adr, (__u64)status, (__u64)cfi_read(map, adr));
+                       printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %lx, status = %lx.\n",
+                              adr, status.x[0], map_read(map, adr).x[0]);
                        /* Clear status bits */
-                       cfi_write(map, CMD(0x50), adr);
-                       cfi_write(map, CMD(0x70), adr);
+                       map_write(map, CMD(0x50), adr);
+                       map_write(map, CMD(0x70), adr);
                        DISABLE_VPP(map);
                        spin_unlock(chip->mutex);
                        return -EIO;
@@ -1370,43 +1492,46 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned
        ret = 0;
 
        /* We've broken this before. It doesn't hurt to be safe */
-       cfi_write(map, CMD(0x70), adr);
+       map_write(map, CMD(0x70), adr);
        chip->state = FL_STATUS;
-       status = cfi_read(map, adr);
+       status = map_read(map, adr);
 
        /* check for lock bit */
-       if (status & CMD(0x3a)) {
-               unsigned char chipstatus = status;
-               if (status != CMD(status & 0xff)) {
-                       int i;
-                       for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
-                                     chipstatus |= status >> (cfi->device_type * 8);
+       if (map_word_bitsset(map, status, CMD(0x3a))) {
+               unsigned char chipstatus = status.x[0];
+               if (!map_word_equal(map, status, CMD(chipstatus))) {
+                       int i, w;
+                       for (w=0; w<map_words(map); w++) {
+                               for (i = 0; i<cfi_interleave(cfi); i++) {
+                                       chipstatus |= status.x[w] >> (cfi->device_type * 8);
+                               }
                        }
-                       printk(KERN_WARNING "Status is not identical for all chips: 0x%llx. Merging to give 0x%02x\n", (__u64)status, chipstatus);
+                       printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
+                              status.x[0], chipstatus);
                }
                /* Reset the error bits */
-               cfi_write(map, CMD(0x50), adr);
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x50), adr);
+               map_write(map, CMD(0x70), adr);
                
                if ((chipstatus & 0x30) == 0x30) {
-                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%llx\n", (__u64)status);
+                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\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%llx\n", (__u64)status);
+                       printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
                        ret = -EIO;
                } else if (chipstatus & 0x20) {
                        if (retries--) {
-                               printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx. Retrying...\n", adr, (__u64)status);
+                               printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
                                timeo = jiffies + HZ;
                                chip->state = FL_STATUS;
                                spin_unlock(chip->mutex);
                                goto retry;
                        }
-                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx\n", adr, (__u64)status);
+                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
                        ret = -EIO;
                }
        }
@@ -1476,7 +1601,8 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
 }
 
 #ifdef DEBUG_LOCK_BITS
-static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip,
+                                      unsigned long adr, int len, void *thunk)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        int ofs_factor = cfi->interleave * cfi->device_type;
@@ -1484,8 +1610,7 @@ static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip
        cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
        printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
               adr, cfi_read_query(map, adr+(2*ofs_factor)));
-       cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
-       
+       chip->state = FL_JEDEC_QUERY;
        return 0;
 }
 #endif
@@ -1493,10 +1618,11 @@ static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip
 #define DO_XXLOCK_ONEBLOCK_LOCK                ((void *) 1)
 #define DO_XXLOCK_ONEBLOCK_UNLOCK      ((void *) 2)
 
-static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
+                             unsigned long adr, int len, void *thunk)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       cfi_word status, status_OK;
+       map_word status, status_OK;
        unsigned long timeo = jiffies + HZ;
        int ret;
 
@@ -1513,13 +1639,13 @@ static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigne
        }
 
        ENABLE_VPP(map);
-       cfi_write(map, CMD(0x60), adr);
+       map_write(map, CMD(0x60), adr);
 
        if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) {
-               cfi_write(map, CMD(0x01), adr);
+               map_write(map, CMD(0x01), adr);
                chip->state = FL_LOCKING;
        } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) {
-               cfi_write(map, CMD(0xD0), adr);
+               map_write(map, CMD(0xD0), adr);
                chip->state = FL_UNLOCKING;
        } else
                BUG();
@@ -1534,15 +1660,16 @@ static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigne
        timeo = jiffies + (HZ*20);
        for (;;) {
 
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       cfi_write(map, CMD(0x70), adr);
+                       map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %llx, status = %llx.\n", (__u64)status, (__u64)cfi_read(map, adr));
+                       printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n",
+                              status.x[0], map_read(map, adr).x[0]);
                        DISABLE_VPP(map);
                        spin_unlock(chip->mutex);
                        return -EIO;
@@ -1576,8 +1703,8 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
                                        ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
        
 #ifdef DEBUG_LOCK_BITS
-       printk(KERN_DEBUG
-              "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+       printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
+              __FUNCTION__, ret);
        cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
                                  ofs, len, 0);
 #endif
@@ -1600,7 +1727,8 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
                                        ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
        
 #ifdef DEBUG_LOCK_BITS
-       printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
+       printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
+              __FUNCTION__, ret);
        cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, 
                                  ofs, len, 0);
 #endif
@@ -1680,7 +1808,7 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
                
                /* Go to known state. Chip may have been power cycled */
                if (chip->state == FL_PM_SUSPENDED) {
-                       cfi_write(map, CMD(0xFF), 0);
+                       map_write(map, CMD(0xFF), cfi->chips[i].start);
                        chip->state = FL_READY;
                        wake_up(&chip->wq);
                }
@@ -1695,6 +1823,7 @@ static void cfi_intelext_destroy(struct mtd_info *mtd)
        struct cfi_private *cfi = map->fldrv_priv;
        kfree(cfi->cmdset_priv);
        kfree(cfi->cfiq);
+       kfree(cfi->chips[0].priv);
        kfree(cfi);
        kfree(mtd->eraseregions);
 }
index cb5fcfc..d7b54d8 100644 (file)
@@ -3,15 +3,21 @@
  *   AMD & Fujitsu Standard Vendor Command Set (ID 0x0002)
  *
  * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
+ * Copyright (C) 2004 Arcom Control Systems Ltd <linux@arcom.com>
  *
  * 2_by_8 routines added by Simon Munton
  *
+ * 4_by_16 work by Carolyn J. Smith
+ *
+ * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
+ *
  * This code is GPL
  *
- * $Id: cfi_cmdset_0002.c,v 1.74 2003/05/28 12:51:48 dwmw2 Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.103 2004/07/14 16:24:03 dwmw2 Exp $
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/mtd/compatmac.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/cfi.h>
-#include <linux/mtd/compatmac.h>
 
 #define AMD_BOOTLOC_BUG
+#define FORCE_WORD_WRITE 0
+
+#define MAX_WORD_RETRIES 3
 
 static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
+static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *);
-static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *);
 static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *);
+static int cfi_amdstd_lock_varsize(struct mtd_info *, loff_t, size_t);
+static int cfi_amdstd_unlock_varsize(struct mtd_info *, loff_t, size_t);
 static void cfi_amdstd_sync (struct mtd_info *);
 static int cfi_amdstd_suspend (struct mtd_info *);
 static void cfi_amdstd_resume (struct mtd_info *);
@@ -55,50 +66,129 @@ static struct mtd_chip_driver cfi_amdstd_chipdrv = {
 };
 
 
+/* #define DEBUG_LOCK_BITS */
+/* #define DEBUG_CFI_FEATURES */
+
+
+#ifdef DEBUG_CFI_FEATURES
+static void cfi_tell_features(struct cfi_pri_amdstd *extp)
+{
+       const char* erase_suspend[3] = {
+               "Not supported", "Read only", "Read/write"
+       };
+       const char* top_bottom[6] = {
+               "No WP", "8x8KiB sectors at top & bottom, no WP",
+               "Bottom boot", "Top boot",
+               "Uniform, Bottom WP", "Uniform, Top WP"
+       };
+
+       printk("  Silicon revision: %d\n", extp->SiliconRevision >> 1);
+       printk("  Address sensitive unlock: %s\n", 
+              (extp->SiliconRevision & 1) ? "Not required" : "Required");
+
+       if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend))
+               printk("  Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]);
+       else
+               printk("  Erase Suspend: Unknown value %d\n", extp->EraseSuspend);
+
+       if (extp->BlkProt == 0)
+               printk("  Block protection: Not supported\n");
+       else
+               printk("  Block protection: %d sectors per group\n", extp->BlkProt);
+
+
+       printk("  Temporary block unprotect: %s\n",
+              extp->TmpBlkUnprotect ? "Supported" : "Not supported");
+       printk("  Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot);
+       printk("  Number of simultaneous operations: %d\n", extp->SimultaneousOps);
+       printk("  Burst mode: %s\n",
+              extp->BurstMode ? "Supported" : "Not supported");
+       if (extp->PageMode == 0)
+               printk("  Page mode: Not supported\n");
+       else
+               printk("  Page mode: %d word page\n", extp->PageMode << 2);
+
+       printk("  Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", 
+              extp->VppMin >> 4, extp->VppMin & 0xf);
+       printk("  Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", 
+              extp->VppMax >> 4, extp->VppMax & 0xf);
+
+       if (extp->TopBottom < ARRAY_SIZE(top_bottom))
+               printk("  Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]);
+       else
+               printk("  Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom);
+}
+#endif
+
+#ifdef AMD_BOOTLOC_BUG
+/* Wheee. Bring me the head of someone at AMD. */
+static void fixup_amd_bootblock(struct map_info *map, void* param)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+       __u8 major = extp->MajorVersion;
+       __u8 minor = extp->MinorVersion;
+
+       if (((major << 8) | minor) < 0x3131) {
+               /* CFI version 1.0 => don't trust bootloc */
+               if (cfi->id & 0x80) {
+                       printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
+                       extp->TopBottom = 3;    /* top boot */
+               } else {
+                       extp->TopBottom = 2;    /* bottom boot */
+               }
+       }
+}
+#endif
+
+static struct cfi_fixup fixup_table[] = {
+#ifdef AMD_BOOTLOC_BUG
+       {
+               0x0001,         /* AMD */
+               CFI_ID_ANY,
+               fixup_amd_bootblock, NULL
+       },
+#endif
+       { 0, 0, NULL, NULL }
+};
+
+
 struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        unsigned char bootloc;
-       int ofs_factor = cfi->interleave * cfi->device_type;
        int i;
-       __u8 major, minor;
-       __u32 base = cfi->chips[0].start;
 
        if (cfi->cfi_mode==CFI_MODE_CFI){
+               /* 
+                * It's a real CFI chip, not one for which the probe
+                * routine faked a CFI structure. So we read the feature
+                * table from it.
+                */
                __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
+               struct cfi_pri_amdstd *extp;
+
+               extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
+               if (!extp)
+                       return NULL;
+
+               /* Install our own private info structure */
+               cfi->cmdset_priv = extp;        
+
+               cfi_fixup(map, fixup_table);
+
+#ifdef DEBUG_CFI_FEATURES
+               /* Tell the user about it in lots of lovely detail */
+               cfi_tell_features(extp);
+#endif 
+
+               bootloc = extp->TopBottom;
+               if ((bootloc != 2) && (bootloc != 3)) {
+                       printk(KERN_WARNING "%s: CFI does not contain boot "
+                              "bank location. Assuming top.\n", map->name);
+                       bootloc = 2;
+               }
 
-               cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-               
-               major = cfi_read_query(map, base + (adr+3)*ofs_factor);
-               minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
-               
-               printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n",
-                      major, minor, adr);
-                               cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
-               
-               cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
-               cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
-               cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
-               /* FIXME - should have a delay before continuing */
-               cfi->mfr = cfi_read_query(map, base);
-               cfi->id = cfi_read_query(map, base + ofs_factor);    
-
-               /* Wheee. Bring me the head of someone at AMD. */
-#ifdef AMD_BOOTLOC_BUG
-               if (((major << 8) | minor) < 0x3131) {
-                       /* CFI version 1.0 => don't trust bootloc */
-                       if (cfi->id & 0x80) {
-                               printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id);
-                               bootloc = 3;    /* top boot */
-                       } else {
-                               bootloc = 2;    /* bottom boot */
-                       }
-               } else
-#endif
-                       {
-                               cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-                               bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor);
-                       }
                if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) {
                        printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name);
                        
@@ -112,31 +202,41 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
                        }
                }
                /*
-                * FIXME - These might already be setup (more correctly)
-                * buy jedec_probe.c.
+                * These might already be setup (more correctly) by
+                * jedec_probe.c - still need it for cfi_probe.c path.
                 */
-               switch (cfi->device_type) {
-               case CFI_DEVICETYPE_X8:
-                       cfi->addr_unlock1 = 0x555; 
-                       cfi->addr_unlock2 = 0x2aa; 
-                       break;
-               case CFI_DEVICETYPE_X16:
-                       cfi->addr_unlock1 = 0xaaa;
-                       if (map->buswidth == cfi->interleave) {
-                               /* X16 chip(s) in X8 mode */
-                               cfi->addr_unlock2 = 0x555;
-                       } else {
-                               cfi->addr_unlock2 = 0x554;
+               if ( ! (cfi->addr_unlock1 && cfi->addr_unlock2) ) {
+                       switch (cfi->device_type) {
+                       case CFI_DEVICETYPE_X8:
+                               cfi->addr_unlock1 = 0x555; 
+                               cfi->addr_unlock2 = 0x2aa; 
+                               break;
+                       case CFI_DEVICETYPE_X16:
+                               cfi->addr_unlock1 = 0xaaa;
+                               if (map_bankwidth(map) == cfi_interleave(cfi)) {
+                                       /* X16 chip(s) in X8 mode */
+                                       cfi->addr_unlock2 = 0x555;
+                               } else {
+                                       cfi->addr_unlock2 = 0x554;
+                               }
+                               break;
+                       case CFI_DEVICETYPE_X32:
+                               cfi->addr_unlock1 = 0x1554;
+                               if (map_bankwidth(map) == cfi_interleave(cfi)*2) {
+                                       /* X32 chip(s) in X16 mode */
+                                       cfi->addr_unlock1 = 0xaaa;
+                               } else {
+                                       cfi->addr_unlock2 = 0xaa8; 
+                               }
+                               break;
+                       default:
+                               printk(KERN_WARNING
+                                      "MTD %s(): Unsupported device type %d\n",
+                                      __func__, cfi->device_type);
+                               return NULL;
                        }
-                       break;
-               case CFI_DEVICETYPE_X32:
-                       cfi->addr_unlock1 = 0x1555; 
-                       cfi->addr_unlock2 = 0xaaa; 
-                       break;
-               default:
-                       printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type);
-                       return NULL;
                }
+
        } /* CFI mode */
 
        for (i=0; i< cfi->numchips; i++) {
@@ -147,23 +247,25 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
        
        map->fldrv = &cfi_amdstd_chipdrv;
 
-       cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
        return cfi_amdstd_setup(map);
 }
 
+
 static struct mtd_info *cfi_amdstd_setup(struct map_info *map)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        struct mtd_info *mtd;
        unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
+       unsigned long offset = 0;
+       int i,j;
 
        mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
        printk(KERN_NOTICE "number of %s chips: %d\n", 
-               (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
+              (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips);
 
        if (!mtd) {
-         printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
-         goto setup_err;
+               printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
+               goto setup_err;
        }
 
        memset(mtd, 0, sizeof(*mtd));
@@ -171,86 +273,69 @@ static struct mtd_info *cfi_amdstd_setup(struct map_info *map)
        mtd->type = MTD_NORFLASH;
        /* Also select the correct geometry setup too */ 
        mtd->size = devsize * cfi->numchips;
-       
-       if (cfi->cfiq->NumEraseRegions == 1) {
-               /* No need to muck about with multiple erase sizes */
-               mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave;
-       } else {
-               unsigned long offset = 0;
-               int i,j;
-
-               mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
-               mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
-               if (!mtd->eraseregions) { 
-                       printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
-                       goto setup_err;
-               }
+
+       mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
+       mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
+                                   * mtd->numeraseregions, GFP_KERNEL);
+       if (!mtd->eraseregions) { 
+               printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
+               goto setup_err;
+       }
                        
-               for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
-                       unsigned long ernum, ersize;
-                       ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
-                       ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
+       for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
+               unsigned long ernum, ersize;
+               ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
+               ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
                        
-                       if (mtd->erasesize < ersize) {
-                               mtd->erasesize = ersize;
-                       }
-                       for (j=0; j<cfi->numchips; j++) {
-                               mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
-                               mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
-                               mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
-                       }
-                       offset += (ersize * ernum);
+               if (mtd->erasesize < ersize) {
+                       mtd->erasesize = ersize;
                }
-               if (offset != devsize) {
-                       /* Argh */
-                       printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
-                       goto setup_err;
+               for (j=0; j<cfi->numchips; j++) {
+                       mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
+                       mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
+                       mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
                }
+               offset += (ersize * ernum);
+       }
+       if (offset != devsize) {
+               /* Argh */
+               printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
+               goto setup_err;
+       }
 #if 0
-               // debug
-               for (i=0; i<mtd->numeraseregions;i++){
-                       printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
-                              i,mtd->eraseregions[i].offset,
-                              mtd->eraseregions[i].erasesize,
-                              mtd->eraseregions[i].numblocks);
-               }
-#endif
+       // debug
+       for (i=0; i<mtd->numeraseregions;i++){
+               printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
+                      i,mtd->eraseregions[i].offset,
+                      mtd->eraseregions[i].erasesize,
+                      mtd->eraseregions[i].numblocks);
        }
-
-       switch (CFIDEV_BUSWIDTH)
-       {
-       case 1:
-       case 2:
-       case 4:
-#if 1
-               if (mtd->numeraseregions > 1)
-                       mtd->erase = cfi_amdstd_erase_varsize;
-               else
 #endif
-               if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1)
-                       mtd->erase = cfi_amdstd_erase_chip;
-               else
-                       mtd->erase = cfi_amdstd_erase_onesize;
-               mtd->read = cfi_amdstd_read;
-               mtd->write = cfi_amdstd_write;
-               break;
 
-       default:
-               printk(KERN_WARNING "Unsupported buswidth\n");
-               goto setup_err;
-               break;
+       if (mtd->numeraseregions == 1
+           && ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) {
+               mtd->erase = cfi_amdstd_erase_chip;
+       } else {
+               mtd->erase = cfi_amdstd_erase_varsize;
+               mtd->lock = cfi_amdstd_lock_varsize;
+               mtd->unlock = cfi_amdstd_unlock_varsize;
        }
-       if (cfi->fast_prog) {
-               /* In cfi_amdstd_write() we frob the protection stuff
-                  without paying any attention to the state machine.
-                  This upsets in-progress erases. So we turn this flag
-                  off for now till the code gets fixed. */
-               printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n");
-               cfi->fast_prog = 0;
+
+       if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) {
+               DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" );
+               mtd->write = cfi_amdstd_write_buffers;
+       } else {
+               DEBUG(MTD_DEBUG_LEVEL1, "Using word write method\n" );
+               mtd->write = cfi_amdstd_write_words;
        }
 
+       mtd->read = cfi_amdstd_read;
 
-        /* does this chip have a secsi area? */
+       /* FIXME: erase-suspend-program is broken.  See
+          http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
+       printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
+
+       /* does this chip have a secsi area? */
        if(cfi->mfr==1){
                
                switch(cfi->id){
@@ -289,46 +374,181 @@ static struct mtd_info *cfi_amdstd_setup(struct map_info *map)
        return NULL;
 }
 
-static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+/*
+ * Return true if the chip is ready.
+ *
+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
+ * non-suspended sector) and is indicated by no toggle bits toggling.
+ *
+ * Note that anything more complicated than checking if no bits are toggling
+ * (including checking DQ5 for an error status) is tricky to get working
+ * correctly and is therefore not done (particulary with interleaved chips
+ * as each chip must be checked independantly of the others).
+ */
+static int chip_ready(struct map_info *map, unsigned long addr)
+{
+       map_word d, t;
+
+       d = map_read(map, addr);
+       t = map_read(map, addr);
+
+       return map_word_equal(map, d, t);
+}
+
+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
 {
        DECLARE_WAITQUEUE(wait, current);
-       unsigned long timeo = jiffies + HZ;
+       struct cfi_private *cfi = map->fldrv_priv;
+       unsigned long timeo;
+       struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv;
 
+ resettime:
+       timeo = jiffies + HZ;
  retry:
-       cfi_spin_lock(chip->mutex);
+       switch (chip->state) {
 
-       if (chip->state != FL_READY){
-#if 0
-               printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
-#endif
+       case FL_STATUS:
+               for (;;) {
+                       if (chip_ready(map, adr))
+                               break;
+
+                       if (time_after(jiffies, timeo)) {
+                               printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
+                               cfi_spin_unlock(chip->mutex);
+                               return -EIO;
+                       }
+                       cfi_spin_unlock(chip->mutex);
+                       cfi_udelay(1);
+                       cfi_spin_lock(chip->mutex);
+                       /* Someone else might have been playing with it. */
+                       goto retry;
+               }
+                               
+       case FL_READY:
+       case FL_CFI_QUERY:
+       case FL_JEDEC_QUERY:
+               return 0;
+
+       case FL_ERASING:
+               if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
+                       goto sleep;
+
+               if (!(mode == FL_READY || mode == FL_POINT
+                     || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
+                     || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
+                       goto sleep;
+
+               /* We could check to see if we're trying to access the sector
+                * that is currently being erased. However, no user will try
+                * anything like that so we just wait for the timeout. */
+
+               /* Erase suspend */
+               /* It's harmless to issue the Erase-Suspend and Erase-Resume
+                * commands when the erase algorithm isn't in progress. */
+               map_write(map, CMD(0xB0), chip->in_progress_block_addr);
+               chip->oldstate = FL_ERASING;
+               chip->state = FL_ERASE_SUSPENDING;
+               chip->erase_suspended = 1;
+               for (;;) {
+                       if (chip_ready(map, adr))
+                               break;
+
+                       if (time_after(jiffies, timeo)) {
+                               /* Should have suspended the erase by now.
+                                * Send an Erase-Resume command as either
+                                * there was an error (so leave the erase
+                                * routine to recover from it) or we trying to
+                                * use the erase-in-progress sector. */
+                               map_write(map, CMD(0x30), chip->in_progress_block_addr);
+                               chip->state = FL_ERASING;
+                               chip->oldstate = FL_READY;
+                               printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
+                               return -EIO;
+                       }
+                       
+                       cfi_spin_unlock(chip->mutex);
+                       cfi_udelay(1);
+                       cfi_spin_lock(chip->mutex);
+                       /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
+                          So we can just loop here. */
+               }
+               chip->state = FL_READY;
+               return 0;
+
+       case FL_POINT:
+               /* Only if there's no operation suspended... */
+               if (mode == FL_READY && chip->oldstate == FL_READY)
+                       return 0;
+
+       default:
+       sleep:
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
-                
                cfi_spin_unlock(chip->mutex);
-
                schedule();
                remove_wait_queue(&chip->wq, &wait);
-#if 0
-               if(signal_pending(current))
-                       return -EINTR;
-#endif
-               timeo = jiffies + HZ;
+               cfi_spin_lock(chip->mutex);
+               goto resettime;
+       }
+}
 
-               goto retry;
-       }       
+
+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+
+       switch(chip->oldstate) {
+       case FL_ERASING:
+               chip->state = chip->oldstate;
+               map_write(map, CMD(0x30), chip->in_progress_block_addr);
+               chip->oldstate = FL_READY;
+               chip->state = FL_ERASING;
+               break;
+
+       case FL_READY:
+       case FL_STATUS:
+               /* We should really make set_vpp() count, rather than doing this */
+               DISABLE_VPP(map);
+               break;
+       default:
+               printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate);
+       }
+       wake_up(&chip->wq);
+}
+
+
+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
+{
+       unsigned long cmd_addr;
+       struct cfi_private *cfi = map->fldrv_priv;
+       int ret;
 
        adr += chip->start;
 
-       chip->state = FL_READY;
+       /* Ensure cmd read/writes are aligned. */ 
+       cmd_addr = adr & ~(map_bankwidth(map)-1); 
+
+       cfi_spin_lock(chip->mutex);
+       ret = get_chip(map, chip, cmd_addr, FL_READY);
+       if (ret) {
+               cfi_spin_unlock(chip->mutex);
+               return ret;
+       }
+
+       if (chip->state != FL_POINT && chip->state != FL_READY) {
+               map_write(map, CMD(0xf0), cmd_addr);
+               chip->state = FL_READY;
+       }
 
        map_copy_from(map, buf, adr, len);
 
-       wake_up(&chip->wq);
-       cfi_spin_unlock(chip->mutex);
+       put_chip(map, chip, cmd_addr);
 
+       cfi_spin_unlock(chip->mutex);
        return 0;
 }
 
+
 static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
 {
        struct map_info *map = mtd->priv;
@@ -370,6 +590,7 @@ static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_
        return ret;
 }
 
+
 static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
 {
        DECLARE_WAITQUEUE(wait, current);
@@ -381,11 +602,11 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
 
        if (chip->state != FL_READY){
 #if 0
-               printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
+               printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state);
 #endif
                set_current_state(TASK_UNINTERRUPTIBLE);
                add_wait_queue(&chip->wq, &wait);
-                
+               
                cfi_spin_unlock(chip->mutex);
 
                schedule();
@@ -402,13 +623,15 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
        adr += chip->start;
 
        chip->state = FL_READY;
-       
+
+       /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        
        map_copy_from(map, buf, adr, len);
 
+       /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -463,215 +686,136 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
        return ret;
 }
 
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum, int fast)
+
+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
 {
-       unsigned long timeo = jiffies + HZ;
-       unsigned int oldstatus, status, prev_oldstatus, prev_status;
-       unsigned int dq6;
        struct cfi_private *cfi = map->fldrv_priv;
-    /* We use a 1ms + 1 jiffies generic timeout for writes (most devices have
-       a max write time of a few hundreds usec). However, we should use the
-       maximum timeout value given by the chip at probe time instead. 
-       Unfortunately, struct flchip does have a field for maximum timeout, 
-       only for typical which can be far too short depending of the conditions.
-       The ' + 1' is to avoid having a timeout of 0 jiffies if HZ is smaller
-       than 1000. Using a static variable allows makes us save the costly
-       divide operation at each word write.*/ 
-    static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
-       DECLARE_WAITQUEUE(wait, current);
+       unsigned long timeo = jiffies + HZ;
+       /*
+        * We use a 1ms + 1 jiffies generic timeout for writes (most devices
+        * have a max write time of a few hundreds usec). However, we should
+        * use the maximum timeout value given by the chip at probe time
+        * instead.  Unfortunately, struct flchip does have a field for
+        * maximum timeout, only for typical which can be far too short
+        * depending of the conditions.  The ' + 1' is to avoid having a
+        * timeout of 0 jiffies if HZ is smaller than 1000.
+        */
+       unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
        int ret = 0;
-       int ta = 0;
+       map_word oldd, curd;
+       int retry_cnt = 0;
 
- retry:
-       cfi_spin_lock(chip->mutex);
+       adr += chip->start;
 
-       if (chip->state != FL_READY) {
-#if 0
-               printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state);
-#endif
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-                
+       cfi_spin_lock(chip->mutex);
+       ret = get_chip(map, chip, adr, FL_WRITING);
+       if (ret) {
                cfi_spin_unlock(chip->mutex);
+               return ret;
+       }
 
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-#if 0
-               printk(KERN_DEBUG "Wake up to write:\n");
-               if(signal_pending(current))
-                       return -EINTR;
-#endif
-               timeo = jiffies + HZ;
-
-               goto retry;
-       }       
-
-       chip->state = FL_WRITING;
+       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
+              __func__, adr, datum.x[0] );
 
-       adr += chip->start;
-       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8llx)\n",
-              __func__, adr, datum );
+       /*
+        * Check for a NOP for the case when the datum to write is already
+        * present - it saves time and works around buggy chips that corrupt
+        * data at other locations when 0xff is written to a location that
+        * already contains 0xff.
+        */
+       oldd = map_read(map, adr);
+       if (map_word_equal(map, oldd, datum)) {
+               DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n",
+                      __func__);
+               goto op_done;
+       }
 
        ENABLE_VPP(map);
-       if (fast) { /* Unlock bypass */
-               cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);
-       }
-       else {
-               cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-               cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-               cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-       }
-       cfi_write(map, datum, adr);
+ retry:
+       /*
+        * The CFI_DEVICETYPE_X8 argument is needed even when
+        * cfi->device_type != CFI_DEVICETYPE_X8.  The addresses for
+        * command sequences don't scale even when the device is
+        * wider.  This is the case for many of the cfi_send_gen_cmd()
+        * below.  I'm not sure, however, why some use
+        * cfi->device_type.
+        */
+       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       map_write(map, datum, adr);
+       chip->state = FL_WRITING;
 
        cfi_spin_unlock(chip->mutex);
        cfi_udelay(chip->word_write_time);
        cfi_spin_lock(chip->mutex);
 
-       /*
-        * Polling toggle bits instead of reading back many times
-        * This ensures that write operation is really completed,
-        * or tells us why it failed.
-        *
-        * It appears tha the polling and decoding of error state might
-        * be simplified.  Don't do it unless you really know what you
-        * are doing.  You must remember that JESD21-C 3.5.3 states that
-        * the status must be read back an _additional_ two times before
-        * a failure is determined.  This is because these devices have
-        * internal state machines that are asynchronous to the external
-        * data bus.  During an erase or write the read-back status of the
-        * polling bits might be transitioning internaly when the external
-        * read-back occurs.  This means that the bits aren't in the final
-        * state and they might appear to report an error as they transition
-        * and are in a weird state.  This will produce infrequent errors
-        * that will usually disappear the next time an erase or write
-        * happens (Try tracking those errors down!).  To ensure that
-        * the bits are not in transition the location must be read-back
-        * two more times and compared against what was written - BOTH reads
-        * MUST match what was written - don't think this can be simplified
-        * to only the last read matching.  If the comparison fails, error
-        * state can then be decoded.
-        *
-        * - Thayne Harbaugh
-        */
-       dq6 = CMD(1<<6);
        /* See comment above for timeout value. */
        timeo = jiffies + uWriteTimeout; 
-               
-       oldstatus = cfi_read(map, adr);
-       status = cfi_read(map, adr);
-       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-              __func__, oldstatus, status );
-
-       /*
-        * This only checks if dq6 is still toggling and that our
-        * timer hasn't expired.  We purposefully ignore the chips
-        * internal timer that will assert dq5 and leave dq6 toggling.
-        * This is done for a variety of reasons:
-        * 1) Not all chips support dq5.
-        * 2) Dealing with asynchronous status bit and data updates
-        *    and reading a device two more times creates _messy_
-        *    logic when trying to deal with interleaved devices -
-        *    some may be changing while others are still busy.
-        * 3) Checking dq5 only helps to optimize an error case that
-        *    should at worst be infrequent and at best non-existent.
-        *
-        * If our timeout occurs _then_ we will check dq5 to see
-        * if the device also had an internal timeout.
-        */
-       while( ( ( status ^ oldstatus ) & dq6 )
-              && ! ( ta = time_after(jiffies, timeo) ) ) {
+       for (;;) {
+               if (chip->state != FL_WRITING) {
+                       /* Someone's suspended the write. Sleep */
+                       DECLARE_WAITQUEUE(wait, current);
 
-               if (need_resched()) {
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       add_wait_queue(&chip->wq, &wait);
                        cfi_spin_unlock(chip->mutex);
-                       yield();
+                       schedule();
+                       remove_wait_queue(&chip->wq, &wait);
+                       timeo = jiffies + (HZ / 2); /* FIXME */
                        cfi_spin_lock(chip->mutex);
-               } else 
-                       udelay(1);
-
-               oldstatus = cfi_read( map, adr );
-               status = cfi_read( map, adr );
-               DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-                      __func__, oldstatus, status );
-       }
+                       continue;
+               }
 
-       /*
-        * Something kicked us out of the read-back loop.  We'll
-        * check success befor checking failure.
-        * Even though dq6 might be true data, it is unkown if
-        * all of the other bits have changed to true data due to
-        * the asynchronous nature of the internal state machine.
-        * We will read two more times and use this to either
-        * verify that the write completed successfully or
-        * that something really went wrong.  BOTH reads
-        * must match what was written - this certifies that
-        * bits aren't still changing  and that the status
-        * bits erroneously match the datum that was written.
-        */
-       prev_oldstatus = oldstatus;
-       prev_status = status;
-       oldstatus = cfi_read(map, adr);
-       status = cfi_read(map, adr);
-       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-              __func__, oldstatus, status );
-
-       if ( oldstatus == datum && status == datum ) {
-               /* success - do nothing */
-               goto write_done;
-       }
+               /* Test to see if toggling has stopped. */
+               oldd = map_read(map, adr);
+               curd = map_read(map, adr);
+               if (map_word_equal(map, curd, oldd)) {
+                       /* Do we have the correct value? */
+                       if (map_word_equal(map, curd, datum)) {
+                               goto op_done;
+                       }
+                       /* Nope something has gone wrong. */
+                       break;
+               }
 
-       if ( ta ) {
-               int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
-               if ( status & dq5mask ) {
-                       /* dq5 asserted - decode interleave chips */
-                       printk( KERN_WARNING
-                               "MTD %s(): FLASH internal timeout: 0x%.8x\n",
-                               __func__,
-                               status & dq5mask );
-               } else {
-                       printk( KERN_WARNING
-                               "MTD %s(): Software timed out during write.\n",
+               if (time_after(jiffies, timeo)) {
+                       printk(KERN_WARNING "MTD %s(): software timeout\n",
                                __func__ );
+                       break;
                }
-               goto write_failed;
-       }
-
-       /*
-        * If we get to here then it means that something
-        * is wrong and it's not a timeout.  Something
-        * is seriously wacky!  Dump some debug info.
-        */
-       printk(KERN_WARNING
-              "MTD %s(): Wacky!  Unable to decode failure status\n",
-              __func__ );
 
-       printk(KERN_WARNING
-              "MTD %s(): 0x%.8lx(0x%.8llx): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
-              __func__, adr, datum,
-              prev_oldstatus, prev_status,
-              oldstatus, status);
+               /* Latency issues. Drop the lock, wait a while and retry */
+               cfi_spin_unlock(chip->mutex);
+               cfi_udelay(1);
+               cfi_spin_lock(chip->mutex);
+       }
 
- write_failed:
-       ret = -EIO;
        /* reset on all failures. */
-       cfi_write( map, CMD(0xF0), chip->start );
+       map_write( map, CMD(0xF0), chip->start );
        /* FIXME - should have reset delay before continuing */
+       if (++retry_cnt <= MAX_WORD_RETRIES) 
+               goto retry;
 
- write_done:
-       DISABLE_VPP(map);
+       ret = -EIO;
+ op_done:
        chip->state = FL_READY;
-       wake_up(&chip->wq);
+       put_chip(map, chip, adr);
        cfi_spin_unlock(chip->mutex);
 
        return ret;
 }
 
-static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
+
+static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
+                                 size_t *retlen, const u_char *buf)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
        int ret = 0;
        int chipnum;
        unsigned long ofs, chipstart;
+       DECLARE_WAITQUEUE(wait, current);
 
        *retlen = 0;
        if (!len)
@@ -682,33 +826,52 @@ static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_
        chipstart = cfi->chips[chipnum].start;
 
        /* If it's not bus-aligned, do the first byte write */
-       if (ofs & (CFIDEV_BUSWIDTH-1)) {
-               unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
+       if (ofs & (map_bankwidth(map)-1)) {
+               unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
                int i = ofs - bus_ofs;
                int n = 0;
-               u_char tmp_buf[8];
-               cfi_word datum;
+               map_word tmp_buf;
 
-               map_copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
-               while (len && i < CFIDEV_BUSWIDTH)
-                       tmp_buf[i++] = buf[n++], len--;
+ retry:
+               cfi_spin_lock(cfi->chips[chipnum].mutex);
 
-               if (cfi_buswidth_is_2()) {
-                       datum = *(__u16*)tmp_buf;
-               } else if (cfi_buswidth_is_4()) {
-                       datum = *(__u32*)tmp_buf;
-               } else {
-                       return -EINVAL;  /* should never happen, but be safe */
+               if (cfi->chips[chipnum].state != FL_READY) {
+#if 0
+                       printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
+#endif
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       add_wait_queue(&cfi->chips[chipnum].wq, &wait);
+
+                       cfi_spin_unlock(cfi->chips[chipnum].mutex);
+
+                       schedule();
+                       remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
+#if 0
+                       if(signal_pending(current))
+                               return -EINTR;
+#endif
+                       goto retry;
                }
 
+               /* Load 'tmp_buf' with old contents of flash */
+               tmp_buf = map_read(map, bus_ofs+chipstart);
+
+               cfi_spin_unlock(cfi->chips[chipnum].mutex);
+
+               /* Number of bytes to copy from buffer */
+               n = min_t(int, len, map_bankwidth(map)-i);
+               
+               tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n);
+
                ret = do_write_oneword(map, &cfi->chips[chipnum], 
-                                      bus_ofs, datum, 0);
+                                      bus_ofs, tmp_buf);
                if (ret) 
                        return ret;
                
                ofs += n;
                buf += n;
                (*retlen) += n;
+               len -= n;
 
                if (ofs >> cfi->chipshift) {
                        chipnum ++; 
@@ -718,315 +881,286 @@ static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_
                }
        }
        
-       if (cfi->fast_prog) {
-               /* Go into unlock bypass mode */
-               cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-               cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-               cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-       }
-
        /* We are now aligned, write as much as possible */
-       while(len >= CFIDEV_BUSWIDTH) {
-               cfi_word datum;
-
-               if (cfi_buswidth_is_1()) {
-                       datum = *(__u8*)buf;
-               } else if (cfi_buswidth_is_2()) {
-                       datum = *(__u16*)buf;
-               } else if (cfi_buswidth_is_4()) {
-                       datum = *(__u32*)buf;
-               } else {
-                       return -EINVAL;
-               }
-               ret = do_write_oneword(map, &cfi->chips[chipnum],
-                                      ofs, datum, cfi->fast_prog);
-               if (ret) {
-                       if (cfi->fast_prog){
-                               /* Get out of unlock bypass mode */
-                               cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
-                               cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
-                       }
-                       return ret;
-               }
+       while(len >= map_bankwidth(map)) {
+               map_word datum;
 
-               ofs += CFIDEV_BUSWIDTH;
-               buf += CFIDEV_BUSWIDTH;
-               (*retlen) += CFIDEV_BUSWIDTH;
-               len -= CFIDEV_BUSWIDTH;
+               datum = map_word_load(map, buf);
 
-               if (ofs >> cfi->chipshift) {
-                       if (cfi->fast_prog){
-                               /* Get out of unlock bypass mode */
-                               cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
-                               cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
-                       }
+               ret = do_write_oneword(map, &cfi->chips[chipnum],
+                                      ofs, datum);
+               if (ret)
+                       return ret;
+
+               ofs += map_bankwidth(map);
+               buf += map_bankwidth(map);
+               (*retlen) += map_bankwidth(map);
+               len -= map_bankwidth(map);
 
+               if (ofs >> cfi->chipshift) {
                        chipnum ++; 
                        ofs = 0;
                        if (chipnum == cfi->numchips)
                                return 0;
                        chipstart = cfi->chips[chipnum].start;
-                       if (cfi->fast_prog){
-                               /* Go into unlock bypass mode for next set of chips */
-                               cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-                               cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-                               cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL);
-                       }
                }
        }
 
-       if (cfi->fast_prog){
-               /* Get out of unlock bypass mode */
-               cfi_send_gen_cmd(0x90, 0, chipstart, map, cfi, cfi->device_type, NULL);
-               cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL);
-       }
-
        /* Write the trailing bytes if any */
-       if (len & (CFIDEV_BUSWIDTH-1)) {
-               int i = 0, n = 0;
-               u_char tmp_buf[8];
-               cfi_word datum;
-
-               map_copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
-               while (len--)
-                       tmp_buf[i++] = buf[n++];
-
-               if (cfi_buswidth_is_2()) {
-                       datum = *(__u16*)tmp_buf;
-               } else if (cfi_buswidth_is_4()) {
-                       datum = *(__u32*)tmp_buf;
-               } else {
-                       return -EINVAL;  /* should never happen, but be safe */
+       if (len & (map_bankwidth(map)-1)) {
+               map_word tmp_buf;
+
+ retry1:
+               cfi_spin_lock(cfi->chips[chipnum].mutex);
+
+               if (cfi->chips[chipnum].state != FL_READY) {
+#if 0
+                       printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
+#endif
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       add_wait_queue(&cfi->chips[chipnum].wq, &wait);
+
+                       cfi_spin_unlock(cfi->chips[chipnum].mutex);
+
+                       schedule();
+                       remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
+#if 0
+                       if(signal_pending(current))
+                               return -EINTR;
+#endif
+                       goto retry1;
                }
 
+               tmp_buf = map_read(map, ofs + chipstart);
+
+               cfi_spin_unlock(cfi->chips[chipnum].mutex);
+
+               tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
+       
                ret = do_write_oneword(map, &cfi->chips[chipnum], 
-                               ofs, datum, 0);
+                               ofs, tmp_buf);
                if (ret) 
                        return ret;
                
-               (*retlen) += n;
+               (*retlen) += len;
        }
 
        return 0;
 }
 
-static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+
+/*
+ * FIXME: interleaved mode not tested, and probably not supported!
+ */
+static inline int do_write_buffer(struct map_info *map, struct flchip *chip, 
+                                 unsigned long adr, const u_char *buf, int len)
 {
-       unsigned int oldstatus, status, prev_oldstatus, prev_status;
-       unsigned int dq6;
-       unsigned long timeo = jiffies + HZ;
-       unsigned long int adr;
        struct cfi_private *cfi = map->fldrv_priv;
-       DECLARE_WAITQUEUE(wait, current);
-       int ret = 0;
-       int ta = 0;
-       cfi_word ones = 0;
+       unsigned long timeo = jiffies + HZ;
+       /* see comments in do_write_oneword() regarding uWriteTimeo. */
+       static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
+       int ret = -EIO;
+       unsigned long cmd_adr;
+       int z, words;
+       map_word datum;
 
- retry:
-       cfi_spin_lock(chip->mutex);
+       adr += chip->start;
+       cmd_adr = adr;
 
-       if (chip->state != FL_READY){
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-                
+       cfi_spin_lock(chip->mutex);
+       ret = get_chip(map, chip, adr, FL_WRITING);
+       if (ret) {
                cfi_spin_unlock(chip->mutex);
+               return ret;
+       }
 
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-#if 0
-               if(signal_pending(current))
-                       return -EINTR;
-#endif
-               timeo = jiffies + HZ;
+       datum = map_word_load(map, buf);
 
-               goto retry;
-       }       
+       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
+              __func__, adr, datum.x[0] );
 
-       chip->state = FL_ERASING;
-       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
-              __func__, chip->start );
-       
-       /* Handle devices with one erase region, that only implement
-        * the chip erase command.
-        */
        ENABLE_VPP(map);
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-       cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-       cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-       timeo = jiffies + (HZ*20);
-       adr = cfi->addr_unlock1;
+       //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 
-       /* Wait for the end of programing/erasure by using the toggle method.
-        * As long as there is a programming procedure going on, bit 6
-        * is toggling it's state with each consecutive read.
-        * The toggling stops as soon as the procedure is completed.
-        *
-        * If the process has gone on for too long on the chip bit 5 gets.
-        * After bit5 is set you can kill the operation by sending a reset
-        * command to the chip.
-        */
-       /* see comments in do_write_oneword */
-       dq6 = CMD(1<<6);
+       /* Write Buffer Load */
+       map_write(map, CMD(0x25), cmd_adr);
 
-       oldstatus = cfi_read(map, adr);
-       status = cfi_read(map, adr);
-       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-              __func__, oldstatus, status );
+       chip->state = FL_WRITING_TO_BUFFER;
 
-       while( ( ( status ^ oldstatus ) & dq6 )
-              && ! ( ta = time_after(jiffies, timeo) ) ) {
-               int wait_reps;
+       /* Write length of data to come */
+       words = len / map_bankwidth(map);
+       map_write(map, CMD(words - 1), cmd_adr);
+       /* Write data */
+       z = 0;
+       while(z < words * map_bankwidth(map)) {
+               datum = map_word_load(map, buf);
+               map_write(map, datum, adr + z);
 
-               /* an initial short sleep */
-               cfi_spin_unlock(chip->mutex);
-               schedule_timeout(HZ/100);
-               cfi_spin_lock(chip->mutex);
+               z += map_bankwidth(map);
+               buf += map_bankwidth(map);
+       }
+       z -= map_bankwidth(map);
+
+       adr += z;
+
+       /* Write Buffer Program Confirm: GO GO GO */
+       map_write(map, CMD(0x29), cmd_adr);
+       chip->state = FL_WRITING;
+
+       cfi_spin_unlock(chip->mutex);
+       cfi_udelay(chip->buffer_write_time);
+       cfi_spin_lock(chip->mutex);
+
+       timeo = jiffies + uWriteTimeout; 
                
-               if (chip->state != FL_ERASING) {
-                       /* Someone's suspended the erase. Sleep */
+       for (;;) {
+               if (chip->state != FL_WRITING) {
+                       /* Someone's suspended the write. Sleep */
+                       DECLARE_WAITQUEUE(wait, current);
+
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&chip->wq, &wait);
-                       
                        cfi_spin_unlock(chip->mutex);
-                       printk("erase suspended. Sleeping\n");
-                       
                        schedule();
                        remove_wait_queue(&chip->wq, &wait);
-#if 0                  
-                       if (signal_pending(current))
-                               return -EINTR;
-#endif                 
-                       timeo = jiffies + (HZ*2); /* FIXME */
+                       timeo = jiffies + (HZ / 2); /* FIXME */
                        cfi_spin_lock(chip->mutex);
                        continue;
                }
 
-               /* Busy wait for 1/10 of a milisecond */
-               for(wait_reps = 0;
-                   (wait_reps < 100)
-                           && ( ( status ^ oldstatus ) & dq6 );
-                   wait_reps++) {
-                       
-                       /* Latency issues. Drop the lock, wait a while and retry */
-                       cfi_spin_unlock(chip->mutex);
-
-                       cfi_udelay(1);
-
-                       cfi_spin_lock(chip->mutex);
-                       oldstatus = cfi_read(map, adr);
-                       status = cfi_read(map, adr);
-                       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-                              __func__, oldstatus, status );
-               }
-               oldstatus = cfi_read(map, adr);
-               status = cfi_read(map, adr);
-               DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-                      __func__, oldstatus, status );
-       }
-
-       prev_oldstatus = oldstatus;
-       prev_status = status;
-       oldstatus = cfi_read(map, adr);
-       status = cfi_read(map, adr);
-       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-              __func__, oldstatus, status );
-
-       if ( cfi_buswidth_is_1() ) {
-               ones =  (__u8)~0;
-       } else if ( cfi_buswidth_is_2() ) {
-               ones = (__u16)~0;
-       } else if ( cfi_buswidth_is_4() ) {
-               ones = (__u32)~0;
-       } else {
-               printk(KERN_WARNING "Unsupported buswidth\n");
-               goto erase_failed;
-       }
-       
-       if ( oldstatus == ones && status == ones ) {
-               /* success - do nothing */
-               goto erase_done;
-       }
+               if (chip_ready(map, adr))
+                       goto op_done;
+                   
+               if( time_after(jiffies, timeo))
+                       break;
 
-       if ( ta ) {
-               int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
-               if ( status & dq5mask ) {
-                       /* dq5 asserted - decode interleave chips */
-                       printk( KERN_WARNING
-                               "MTD %s(): FLASH internal timeout: 0x%.8x\n",
-                               __func__,
-                               status & dq5mask );
-               } else {
-                       printk( KERN_WARNING
-                               "MTD %s(): Software timed out during write.\n",
-                               __func__ );
-               }
-               goto erase_failed;
+               /* Latency issues. Drop the lock, wait a while and retry */
+               cfi_spin_unlock(chip->mutex);
+               cfi_udelay(1);
+               cfi_spin_lock(chip->mutex);
        }
 
-       printk(KERN_WARNING
-              "MTD %s(): Wacky!  Unable to decode failure status\n",
+       printk(KERN_WARNING "MTD %s(): software timeout\n",
               __func__ );
 
-       printk(KERN_WARNING
-              "MTD %s(): 0x%.8lx(0x%.8llx): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
-              __func__, adr, ones,
-              prev_oldstatus, prev_status,
-              oldstatus, status);
-
- erase_failed:
-       ret = -EIO;
        /* reset on all failures. */
-       cfi_write( map, CMD(0xF0), chip->start );
+       map_write( map, CMD(0xF0), chip->start );
        /* FIXME - should have reset delay before continuing */
 
- erase_done:
-       DISABLE_VPP(map);
+       ret = -EIO;
+ op_done:
        chip->state = FL_READY;
-       wake_up(&chip->wq);
+       put_chip(map, chip, adr);
        cfi_spin_unlock(chip->mutex);
+
        return ret;
 }
 
 
-static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
+static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
+                                   size_t *retlen, const u_char *buf)
 {
-       unsigned int oldstatus, status, prev_oldstatus, prev_status;
-       unsigned int dq6;
-       unsigned long timeo = jiffies + HZ;
+       struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       DECLARE_WAITQUEUE(wait, current);
+       int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        int ret = 0;
-       int ta = 0;
-       cfi_word ones = 0;
+       int chipnum;
+       unsigned long ofs;
 
- retry:
-       cfi_spin_lock(chip->mutex);
+       *retlen = 0;
+       if (!len)
+               return 0;
 
-       if (chip->state != FL_READY){
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               add_wait_queue(&chip->wq, &wait);
-                
-               cfi_spin_unlock(chip->mutex);
+       chipnum = to >> cfi->chipshift;
+       ofs = to  - (chipnum << cfi->chipshift);
 
-               schedule();
-               remove_wait_queue(&chip->wq, &wait);
-#if 0
-               if(signal_pending(current))
-                       return -EINTR;
-#endif
-               timeo = jiffies + HZ;
+       /* If it's not bus-aligned, do the first word write */
+       if (ofs & (map_bankwidth(map)-1)) {
+               size_t local_len = (-ofs)&(map_bankwidth(map)-1);
+               if (local_len > len)
+                       local_len = len;
+               ret = cfi_amdstd_write_words(mtd, to, local_len,
+                                              retlen, buf);
+               if (ret)
+                       return ret;
+               ofs += local_len;
+               buf += local_len;
+               len -= local_len;
 
-               goto retry;
-       }       
+               if (ofs >> cfi->chipshift) {
+                       chipnum ++;
+                       ofs = 0;
+                       if (chipnum == cfi->numchips)
+                               return 0;
+               }
+       }
 
-       chip->state = FL_ERASING;
+       /* Write buffer is worth it only if more than one word to write... */
+       while (len >= map_bankwidth(map) * 2) {
+               /* We must not cross write block boundaries */
+               int size = wbufsize - (ofs & (wbufsize-1));
+
+               if (size > len)
+                       size = len;
+               if (size % map_bankwidth(map))
+                       size -= size % map_bankwidth(map);
+
+               ret = do_write_buffer(map, &cfi->chips[chipnum], 
+                                     ofs, buf, size);
+               if (ret)
+                       return ret;
+
+               ofs += size;
+               buf += size;
+               (*retlen) += size;
+               len -= size;
+
+               if (ofs >> cfi->chipshift) {
+                       chipnum ++; 
+                       ofs = 0;
+                       if (chipnum == cfi->numchips)
+                               return 0;
+               }
+       }
+
+       if (len) {
+               size_t retlen_dregs = 0;
+
+               ret = cfi_amdstd_write_words(mtd, to, len, &retlen_dregs, buf);
+
+               *retlen += retlen_dregs;
+               return ret;
+       }
+
+       return 0;
+}
+
+
+/*
+ * Handle devices with one erase region, that only implement
+ * the chip erase command.
+ */
+static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       unsigned long timeo = jiffies + HZ;
+       unsigned long int adr;
+       DECLARE_WAITQUEUE(wait, current);
+       int ret = 0;
+
+       adr = cfi->addr_unlock1;
+
+       cfi_spin_lock(chip->mutex);
+       ret = get_chip(map, chip, adr, FL_WRITING);
+       if (ret) {
+               cfi_spin_unlock(chip->mutex);
+               return ret;
+       }
 
-       adr += chip->start;
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
-              __func__, adr );
+              __func__, chip->start );
 
        ENABLE_VPP(map);
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
@@ -1034,155 +1168,85 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
        cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
        cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
        cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
 
-       cfi_write(map, CMD(0x30), adr);
-       
-       timeo = jiffies + (HZ*20);
-
-       /* Wait for the end of programing/erasure by using the toggle method.
-        * As long as there is a programming procedure going on, bit 6
-        * is toggling it's state with each consecutive read.
-        * The toggling stops as soon as the procedure is completed.
-        *
-        * If the process has gone on for too long on the chip bit 5 gets.
-        * After bit5 is set you can kill the operation by sending a reset
-        * command to the chip.
-        */
-       /* see comments in do_write_oneword */
-       dq6 = CMD(1<<6);
+       chip->state = FL_ERASING;
+       chip->erase_suspended = 0;
+       chip->in_progress_block_addr = adr;
 
-       oldstatus = cfi_read(map, adr);
-       status = cfi_read(map, adr);
-       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-              __func__, oldstatus, status );
+       cfi_spin_unlock(chip->mutex);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout((chip->erase_time*HZ)/(2*1000));
+       cfi_spin_lock(chip->mutex);
 
-       while( ( ( status ^ oldstatus ) & dq6 )
-              && ! ( ta = time_after(jiffies, timeo) ) ) {
-               int wait_reps;
+       timeo = jiffies + (HZ*20);
 
-               /* an initial short sleep */
-               cfi_spin_unlock(chip->mutex);
-               schedule_timeout(HZ/100);
-               cfi_spin_lock(chip->mutex);
-               
+       for (;;) {
                if (chip->state != FL_ERASING) {
                        /* Someone's suspended the erase. Sleep */
                        set_current_state(TASK_UNINTERRUPTIBLE);
                        add_wait_queue(&chip->wq, &wait);
-                       
                        cfi_spin_unlock(chip->mutex);
-                       printk(KERN_DEBUG "erase suspended. Sleeping\n");
-                       
                        schedule();
                        remove_wait_queue(&chip->wq, &wait);
-#if 0                  
-                       if (signal_pending(current))
-                               return -EINTR;
-#endif                 
-                       timeo = jiffies + (HZ*2); /* FIXME */
                        cfi_spin_lock(chip->mutex);
                        continue;
                }
-
-               /* Busy wait for 1/10 of a milisecond */
-               for(wait_reps = 0;
-                   (wait_reps < 100)
-                           && ( ( status ^ oldstatus ) & dq6 );
-                   wait_reps++) {
-                       
-                       /* Latency issues. Drop the lock, wait a while and retry */
-                       cfi_spin_unlock(chip->mutex);
-                       
-                       cfi_udelay(1);
-               
-                       cfi_spin_lock(chip->mutex);
-                       oldstatus = cfi_read(map, adr);
-                       status = cfi_read(map, adr);
-                       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-                              __func__, oldstatus, status );
+               if (chip->erase_suspended) {
+                       /* This erase was suspended and resumed.
+                          Adjust the timeout */
+                       timeo = jiffies + (HZ*20); /* FIXME */
+                       chip->erase_suspended = 0;
                }
-               oldstatus = cfi_read(map, adr);
-               status = cfi_read(map, adr);
-               DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-                      __func__, oldstatus, status );
-       }
 
-       prev_oldstatus = oldstatus;
-       prev_status = status;
-       oldstatus = cfi_read(map, adr);
-       status = cfi_read(map, adr);
-       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n",
-              __func__, oldstatus, status );
-
-       if ( cfi_buswidth_is_1() ) {
-               ones =  (__u8)~0;
-       } else if ( cfi_buswidth_is_2() ) {
-               ones = (__u16)~0;
-       } else if ( cfi_buswidth_is_4() ) {
-               ones = (__u32)~0;
-       } else {
-               printk(KERN_WARNING "Unsupported buswidth\n");
-               goto erase_failed;
-       }
+               if (chip_ready(map, adr))
+                       goto op_done;
 
-       if ( oldstatus == ones && status == ones ) {
-               /* success - do nothing */
-               goto erase_done;
-       }
+               if (time_after(jiffies, timeo))
+                       break;
 
-       if ( ta ) {
-               int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1;
-               if ( status & dq5mask ) {
-                       /* dq5 asserted - decode interleave chips */
-                       printk( KERN_WARNING
-                               "MTD %s(): FLASH internal timeout: 0x%.8x\n",
-                               __func__,
-                               status & dq5mask );
-               } else {
-                       printk( KERN_WARNING
-                               "MTD %s(): Software timed out during write.\n",
-                               __func__ );
-               }
-               goto erase_failed;
+               /* Latency issues. Drop the lock, wait a while and retry */
+               cfi_spin_unlock(chip->mutex);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+               cfi_spin_lock(chip->mutex);
        }
 
-       printk(KERN_WARNING
-              "MTD %s(): Wacky!  Unable to decode failure status\n",
+       printk(KERN_WARNING "MTD %s(): software timeout\n",
               __func__ );
 
-       printk(KERN_WARNING
-              "MTD %s(): 0x%.8lx(0x%.8llx): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
-              __func__, adr, ones,
-              prev_oldstatus, prev_status,
-              oldstatus, status);
-
- erase_failed:
-       ret = -EIO;
        /* reset on all failures. */
-       cfi_write( map, CMD(0xF0), chip->start );
+       map_write( map, CMD(0xF0), chip->start );
        /* FIXME - should have reset delay before continuing */
 
- erase_done:
-       DISABLE_VPP(map);
+       ret = -EIO;
+ op_done:
        chip->state = FL_READY;
-       wake_up(&chip->wq);
+       put_chip(map, chip, adr);
        cfi_spin_unlock(chip->mutex);
+
        return ret;
 }
 
-static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+
+typedef int (*frob_t)(struct map_info *map, struct flchip *chip,
+                     unsigned long adr, void *thunk);
+
+
+static int cfi_amdstd_varsize_frob(struct mtd_info *mtd, frob_t frob,
+                                  loff_t ofs, size_t len, void *thunk)
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       unsigned long adr, len;
+       unsigned long adr;
        int chipnum, ret = 0;
        int i, first;
        struct mtd_erase_region_info *regions = mtd->eraseregions;
 
-       if (instr->addr > mtd->size)
+       if (ofs > mtd->size)
                return -EINVAL;
 
-       if ((instr->len + instr->addr) > mtd->size)
+       if ((len + ofs) > mtd->size)
                return -EINVAL;
 
        /* Check that both start and end of the requested erase are
@@ -1197,7 +1261,7 @@ static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *ins
           start of the requested erase, and then go back one.
        */
        
-       while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
+       while (i < mtd->numeraseregions && ofs >= regions[i].offset)
               i++;
        i--;
 
@@ -1207,7 +1271,7 @@ static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *ins
           effect here.
        */
 
-       if (instr->addr & (regions[i].erasesize-1))
+       if (ofs & (regions[i].erasesize-1))
                return -EINVAL;
 
        /* Remember the erase region we start on */
@@ -1217,7 +1281,7 @@ static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *ins
         * with the erase region at that address.
         */
 
-       while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
+       while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
                i++;
 
        /* As before, drop back one to point at the region in which
@@ -1225,18 +1289,17 @@ static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *ins
        */
        i--;
        
-       if ((instr->addr + instr->len) & (regions[i].erasesize-1))
+       if ((ofs + len) & (regions[i].erasesize-1))
                return -EINVAL;
-       
-       chipnum = instr->addr >> cfi->chipshift;
-       adr = instr->addr - (chipnum << cfi->chipshift);
-       len = instr->len;
 
-       i=first;
+       chipnum = ofs >> cfi->chipshift;
+       adr = ofs - (chipnum << cfi->chipshift);
 
-       while(len) {
-               ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+       i=first;
 
+       while (len) {
+               ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
+               
                if (ret)
                        return ret;
 
@@ -1255,51 +1318,107 @@ static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *ins
                }
        }
 
-       instr->state = MTD_ERASE_DONE;
-       if (instr->callback)
-               instr->callback(instr);
-       
        return 0;
 }
 
-static int cfi_amdstd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr)
+
+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
 {
-       struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       unsigned long adr, len;
-       int chipnum, ret = 0;
+       unsigned long timeo = jiffies + HZ;
+       DECLARE_WAITQUEUE(wait, current);
+       int ret = 0;
 
-       if (instr->addr & (mtd->erasesize - 1))
-               return -EINVAL;
+       adr += chip->start;
 
-       if (instr->len & (mtd->erasesize -1))
-               return -EINVAL;
+       cfi_spin_lock(chip->mutex);
+       ret = get_chip(map, chip, adr, FL_ERASING);
+       if (ret) {
+               cfi_spin_unlock(chip->mutex);
+               return ret;
+       }
 
-       if ((instr->len + instr->addr) > mtd->size)
-               return -EINVAL;
+       DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
+              __func__, adr );
 
-       chipnum = instr->addr >> cfi->chipshift;
-       adr = instr->addr - (chipnum << cfi->chipshift);
-       len = instr->len;
+       ENABLE_VPP(map);
+       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       map_write(map, CMD(0x30), adr);
+
+       chip->state = FL_ERASING;
+       chip->erase_suspended = 0;
+       chip->in_progress_block_addr = adr;
+       
+       cfi_spin_unlock(chip->mutex);
+       set_current_state(TASK_UNINTERRUPTIBLE);
+       schedule_timeout((chip->erase_time*HZ)/(2*1000));
+       cfi_spin_lock(chip->mutex);
 
-       while(len) {
-               ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
+       timeo = jiffies + (HZ*20);
 
-               if (ret)
-                       return ret;
+       for (;;) {
+               if (chip->state != FL_ERASING) {
+                       /* Someone's suspended the erase. Sleep */
+                       set_current_state(TASK_UNINTERRUPTIBLE);
+                       add_wait_queue(&chip->wq, &wait);
+                       cfi_spin_unlock(chip->mutex);
+                       schedule();
+                       remove_wait_queue(&chip->wq, &wait);
+                       cfi_spin_lock(chip->mutex);
+                       continue;
+               }
+               if (chip->erase_suspended) {
+                       /* This erase was suspended and resumed.
+                          Adjust the timeout */
+                       timeo = jiffies + (HZ*20); /* FIXME */
+                       chip->erase_suspended = 0;
+               }
 
-               adr += mtd->erasesize;
-               len -= mtd->erasesize;
+               if (chip_ready(map, adr))
+                       goto op_done;
 
-               if (adr >> cfi->chipshift) {
-                       adr = 0;
-                       chipnum++;
-                       
-                       if (chipnum >= cfi->numchips)
+               if (time_after(jiffies, timeo))
                        break;
-               }
+
+               /* Latency issues. Drop the lock, wait a while and retry */
+               cfi_spin_unlock(chip->mutex);
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+               cfi_spin_lock(chip->mutex);
        }
-               
+       
+       printk(KERN_WARNING "MTD %s(): software timeout\n",
+              __func__ );
+       
+       /* reset on all failures. */
+       map_write( map, CMD(0xF0), chip->start );
+       /* FIXME - should have reset delay before continuing */
+
+       ret = -EIO;
+ op_done:
+       chip->state = FL_READY;
+       put_chip(map, chip, adr);
+       cfi_spin_unlock(chip->mutex);
+       return ret;
+}
+
+
+int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
+{
+       unsigned long ofs, len;
+       int ret;
+
+       ofs = instr->addr;
+       len = instr->len;
+
+       ret = cfi_amdstd_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0);
+       if (ret)
+               return ret;
+
        instr->state = MTD_ERASE_DONE;
        if (instr->callback)
                instr->callback(instr);
@@ -1307,6 +1426,7 @@ static int cfi_amdstd_erase_onesize(struct mtd_info *mtd, struct erase_info *ins
        return 0;
 }
 
+
 static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
 {
        struct map_info *map = mtd->priv;
@@ -1330,6 +1450,7 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
        return 0;
 }
 
+
 static void cfi_amdstd_sync (struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
@@ -1368,7 +1489,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
 
                        schedule();
 
-                       remove_wait_queue(&chip->wq, &wait);
+                       remove_wait_queue(&chip->wq, &wait);
                        
                        goto retry;
                }
@@ -1427,7 +1548,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
        /* Unlock the chips again */
 
        if (ret) {
-               for (i--; i >=0; i--) {
+               for (i--; i >=0; i--) {
                        chip = &cfi->chips[i];
 
                        cfi_spin_lock(chip->mutex);
@@ -1443,6 +1564,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
        return ret;
 }
 
+
 static void cfi_amdstd_resume(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
@@ -1458,7 +1580,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd)
                
                if (chip->state == FL_PM_SUSPENDED) {
                        chip->state = FL_READY;
-                       cfi_write(map, CMD(0xF0), chip->start);
+                       map_write(map, CMD(0xF0), chip->start);
                        wake_up(&chip->wq);
                }
                else
@@ -1468,6 +1590,137 @@ static void cfi_amdstd_resume(struct mtd_info *mtd)
        }
 }
 
+
+#ifdef DEBUG_LOCK_BITS
+
+static int do_printlockstatus_oneblock(struct map_info *map,
+                                      struct flchip *chip,
+                                      unsigned long adr,
+                                      void *thunk)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       int ofs_factor = cfi->interleave * cfi->device_type;
+
+       cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+       printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
+              adr, cfi_read_query(map, adr+(2*ofs_factor)));
+       cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL);
+       
+       return 0;
+}
+
+
+#define debug_dump_locks(mtd, frob, ofs, len, thunk) \
+       cfi_amdstd_varsize_frob((mtd), (frob), (ofs), (len), (thunk))
+
+#else
+
+#define debug_dump_locks(...)
+
+#endif /* DEBUG_LOCK_BITS */
+
+
+struct xxlock_thunk {
+       uint8_t val;
+       flstate_t state;
+};
+
+
+#define DO_XXLOCK_ONEBLOCK_LOCK   ((struct xxlock_thunk){0x01, FL_LOCKING})
+#define DO_XXLOCK_ONEBLOCK_UNLOCK ((struct xxlock_thunk){0x00, FL_UNLOCKING})
+
+
+/*
+ * FIXME - this is *very* specific to a particular chip.  It likely won't
+ * work for all chips that require unlock.  It also hasn't been tested
+ * with interleaved chips.
+ */
+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       struct xxlock_thunk *xxlt = (struct xxlock_thunk *)thunk;
+       int ret;
+
+       /*
+        * This is easy because these are writes to registers and not writes
+        * to flash memory - that means that we don't have to check status
+        * and timeout.
+        */
+
+       adr += chip->start;
+       /*
+        * lock block registers:
+        * - on 64k boundariesand
+        * - bit 1 set high
+        * - block lock registers are 4MiB lower - overflow subtract (danger)
+        */
+       adr = ((adr & ~0xffff) | 0x2) + ~0x3fffff;
+
+       cfi_spin_lock(chip->mutex);
+       ret = get_chip(map, chip, adr, FL_LOCKING);
+       if (ret) {
+               cfi_spin_unlock(chip->mutex);
+               return ret;
+       }
+
+       chip->state = xxlt->state;
+       map_write(map, CMD(xxlt->val), adr);
+       
+       /* Done and happy. */
+       chip->state = FL_READY;
+       put_chip(map, chip, adr);
+       cfi_spin_unlock(chip->mutex);
+       return 0;
+}
+
+
+static int cfi_amdstd_lock_varsize(struct mtd_info *mtd,
+                                  loff_t ofs,
+                                  size_t len)
+{
+       int ret;
+
+       DEBUG(MTD_DEBUG_LEVEL3,
+             "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+             __func__, ofs, len);
+       debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+       ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len,
+                                     (void *)&DO_XXLOCK_ONEBLOCK_LOCK);
+       
+       DEBUG(MTD_DEBUG_LEVEL3,
+             "%s: lock status after, ret=%d\n",
+             __func__, ret);
+
+       debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+       return ret;
+}
+
+
+static int cfi_amdstd_unlock_varsize(struct mtd_info *mtd,
+                                    loff_t ofs,
+                                    size_t len)
+{
+       int ret;
+
+       DEBUG(MTD_DEBUG_LEVEL3,
+             "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
+             __func__, ofs, len);
+       debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+
+       ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len,
+                                     (void *)&DO_XXLOCK_ONEBLOCK_UNLOCK);
+       
+       DEBUG(MTD_DEBUG_LEVEL3,
+             "%s: lock status after, ret=%d\n",
+             __func__, ret);
+       debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0);
+       
+       return ret;
+}
+
+
 static void cfi_amdstd_destroy(struct mtd_info *mtd)
 {
        struct map_info *map = mtd->priv;
@@ -1480,21 +1733,23 @@ static void cfi_amdstd_destroy(struct mtd_info *mtd)
 
 static char im_name[]="cfi_cmdset_0002";
 
+
 int __init cfi_amdstd_init(void)
 {
        inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002);
        return 0;
 }
 
+
 static void __exit cfi_amdstd_exit(void)
 {
        inter_module_unregister(im_name);
 }
 
+
 module_init(cfi_amdstd_init);
 module_exit(cfi_amdstd_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al.");
 MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips");
-
index f1fd121..98817c2 100644 (file)
@@ -4,6 +4,7 @@
  *
  * (C) 2000 Red Hat. GPL'd
  *
+ * $Id: cfi_cmdset_0020.c,v 1.13 2004/07/12 21:52:50 dwmw2 Exp $
  * 
  * 10/10/2000  Nicolas Pitre <nico@cam.org>
  *     - completely revamped method functions so they are aware and
@@ -116,7 +117,6 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
 {
        struct cfi_private *cfi = map->fldrv_priv;
        int i;
-       __u32 base = cfi->chips[0].start;
 
        if (cfi->cfi_mode) {
                /* 
@@ -126,36 +126,11 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
                 */
                __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
                struct cfi_pri_intelext *extp;
-               int ofs_factor = cfi->interleave * cfi->device_type;
 
-                printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr);
-               if (!adr)
+               extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "ST Microelectronics");
+               if (!extp)
                        return NULL;
 
-               /* Switch it into Query Mode */
-               cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-
-               extp = kmalloc(sizeof(*extp), GFP_KERNEL);
-               if (!extp) {
-                       printk(KERN_ERR "Failed to allocate memory\n");
-                       return NULL;
-               }
-               
-               /* Read in the Extended Query Table */
-               for (i=0; i<sizeof(*extp); i++) {
-                       ((unsigned char *)extp)[i] = 
-                               cfi_read_query(map, (base+((adr+i)*ofs_factor)));
-               }
-               
-               if (extp->MajorVersion != '1' || 
-                    (extp->MinorVersion < '0' || extp->MinorVersion > '2')) {
-                    printk(KERN_WARNING "  Unknown staa Extended Query "
-                           "version %c.%c.\n",  extp->MajorVersion,
-                           extp->MinorVersion);
-                    kfree(extp);
-                    return NULL;
-               }
-               
                /* Do some byteswapping if necessary */
                extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport);
                extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask);
@@ -175,8 +150,6 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary)
                cfi->chips[i].erase_time = 1024;
        }               
 
-       /* Make sure it's in read mode */
-       cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL);
        return cfi_staa_setup(map);
 }
 
@@ -266,7 +239,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
 
 static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
 {
-       __u32 status, status_OK;
+       map_word status, status_OK;
        unsigned long timeo;
        DECLARE_WAITQUEUE(wait, current);
        int suspended = 0;
@@ -276,7 +249,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
        adr += chip->start;
 
        /* Ensure cmd read/writes are aligned. */ 
-       cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); 
+       cmd_addr = adr & ~(map_bankwidth(map)-1); 
 
        /* Let's determine this according to the interleave only once */
        status_OK = CMD(0x80);
@@ -290,33 +263,33 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
         */
        switch (chip->state) {
        case FL_ERASING:
-               if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)
+               if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2))
                        goto sleep; /* We don't support erase suspend */
                
-               cfi_write (map, CMD(0xb0), cmd_addr);
+               map_write (map, CMD(0xb0), cmd_addr);
                /* If the flash has finished erasing, then 'erase suspend'
                 * appears to make some (28F320) flash devices switch to
                 * 'read' mode.  Make sure that we switch to 'read status'
                 * mode so we get the right data. --rmk
                 */
-               cfi_write(map, CMD(0x70), cmd_addr);
+               map_write(map, CMD(0x70), cmd_addr);
                chip->oldstate = FL_ERASING;
                chip->state = FL_ERASE_SUSPENDING;
                //              printk("Erase suspending at 0x%lx\n", cmd_addr);
                for (;;) {
-                       status = cfi_read(map, cmd_addr);
-                       if ((status & status_OK) == status_OK)
+                       status = map_read(map, cmd_addr);
+                       if (map_word_andequal(map, status, status_OK, status_OK))
                                break;
                        
                        if (time_after(jiffies, timeo)) {
                                /* Urgh */
-                               cfi_write(map, CMD(0xd0), cmd_addr);
+                               map_write(map, CMD(0xd0), cmd_addr);
                                /* make sure we're in 'read status' mode */
-                               cfi_write(map, CMD(0x70), cmd_addr);
+                               map_write(map, CMD(0x70), cmd_addr);
                                chip->state = FL_ERASING;
                                spin_unlock_bh(chip->mutex);
                                printk(KERN_ERR "Chip not ready after erase "
-                                      "suspended: status = 0x%x\n", status);
+                                      "suspended: status = 0x%lx\n", status.x[0]);
                                return -EIO;
                        }
                        
@@ -326,7 +299,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
                }
                
                suspended = 1;
-               cfi_write(map, CMD(0xff), cmd_addr);
+               map_write(map, CMD(0xff), cmd_addr);
                chip->state = FL_READY;
                break;
        
@@ -340,13 +313,13 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
 
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
-               cfi_write(map, CMD(0x70), cmd_addr);
+               map_write(map, CMD(0x70), cmd_addr);
                chip->state = FL_STATUS;
 
        case FL_STATUS:
-               status = cfi_read(map, cmd_addr);
-               if ((status & status_OK) == status_OK) {
-                       cfi_write(map, CMD(0xff), cmd_addr);
+               status = map_read(map, cmd_addr);
+               if (map_word_andequal(map, status, status_OK, status_OK)) {
+                       map_write(map, CMD(0xff), cmd_addr);
                        chip->state = FL_READY;
                        break;
                }
@@ -354,7 +327,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
                /* Urgh. Chip not yet ready to talk to us. */
                if (time_after(jiffies, timeo)) {
                        spin_unlock_bh(chip->mutex);
-                       printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status);
+                       printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %lx\n", status.x[0]);
                        return -EIO;
                }
 
@@ -389,8 +362,8 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
                   sending the 0x70 (Read Status) command to an erasing
                   chip and expecting it to be ignored, that's what we 
                   do. */
-               cfi_write(map, CMD(0xd0), cmd_addr);
-               cfi_write(map, CMD(0x70), cmd_addr);            
+               map_write(map, CMD(0xd0), cmd_addr);
+               map_write(map, CMD(0x70), cmd_addr);            
        }
 
        wake_up(&chip->wq);
@@ -441,16 +414,16 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                                  unsigned long adr, const u_char *buf, int len)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       __u32 status, status_OK;
+       map_word status, status_OK;
        unsigned long cmd_adr, timeo;
        DECLARE_WAITQUEUE(wait, current);
        int wbufsize, z;
         
         /* M58LW064A requires bus alignment for buffer wriets -- saw */
-        if (adr & (CFIDEV_BUSWIDTH-1))
+        if (adr & (map_bankwidth(map)-1))
             return -EINVAL;
 
-        wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+        wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
         adr += chip->start;
        cmd_adr = adr & ~(wbufsize-1);
        
@@ -476,21 +449,21 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
-               cfi_write(map, CMD(0x70), cmd_adr);
+               map_write(map, CMD(0x70), cmd_adr);
                 chip->state = FL_STATUS;
 #ifdef DEBUG_CFI_FEATURES
-        printk("%s: 1 status[%x]\n", __FUNCTION__, cfi_read(map, cmd_adr));
+        printk("%s: 1 status[%x]\n", __FUNCTION__, map_read(map, cmd_adr));
 #endif
 
        case FL_STATUS:
-               status = cfi_read(map, cmd_adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, cmd_adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                /* Urgh. Chip not yet ready to talk to us. */
                if (time_after(jiffies, timeo)) {
                        spin_unlock_bh(chip->mutex);
-                        printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %x, status = %llx\n",
-                               status, cfi_read(map, cmd_adr));
+                        printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %lx, status = %lx\n",
+                               status.x[0], map_read(map, cmd_adr).x[0]);
                        return -EIO;
                }
 
@@ -512,13 +485,13 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        }
 
        ENABLE_VPP(map);
-       cfi_write(map, CMD(0xe8), cmd_adr);
+       map_write(map, CMD(0xe8), cmd_adr);
        chip->state = FL_WRITING_TO_BUFFER;
 
        z = 0;
        for (;;) {
-               status = cfi_read(map, cmd_adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, cmd_adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
 
                spin_unlock_bh(chip->mutex);
@@ -528,41 +501,26 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                if (++z > 100) {
                        /* Argh. Not ready for write to buffer */
                        DISABLE_VPP(map);
-                        cfi_write(map, CMD(0x70), cmd_adr);
+                        map_write(map, CMD(0x70), cmd_adr);
                        chip->state = FL_STATUS;
                        spin_unlock_bh(chip->mutex);
-                       printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x\n", status);
+                       printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %lx\n", status.x[0]);
                        return -EIO;
                }
        }
 
        /* Write length of data to come */
-       cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr );
+       map_write(map, CMD(len/map_bankwidth(map)-1), cmd_adr );
         
        /* Write data */
-       for (z = 0; z < len; z += CFIDEV_BUSWIDTH) {
-               if (cfi_buswidth_is_1()) {
-                       u8 *b = (u8 *)buf;
-
-                       map_write8 (map, *b++, adr+z);
-                       buf = (const u_char *)b;
-               } else if (cfi_buswidth_is_2()) {
-                       u16 *b = (u16 *)buf;
-
-                       map_write16 (map, *b++, adr+z);
-                       buf = (const u_char *)b;
-               } else if (cfi_buswidth_is_4()) {
-                       u32 *b = (u32 *)buf;
-
-                       map_write32 (map, *b++, adr+z);
-                       buf = (const u_char *)b;
-               } else {
-                       DISABLE_VPP(map);
-                       return -EINVAL;
-               }
+       for (z = 0; z < len;
+            z += map_bankwidth(map), buf += map_bankwidth(map)) {
+               map_word d;
+               d = map_word_load(map, buf);
+               map_write(map, d, adr+z);
        }
        /* GO GO GO */
-       cfi_write(map, CMD(0xd0), cmd_adr);
+       map_write(map, CMD(0xd0), cmd_adr);
        chip->state = FL_WRITING;
 
        spin_unlock_bh(chip->mutex);
@@ -584,16 +542,16 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
                        continue;
                }
 
-               status = cfi_read(map, cmd_adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, cmd_adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
 
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
                         /* clear status */
-                        cfi_write(map, CMD(0x50), cmd_adr);
+                        map_write(map, CMD(0x50), cmd_adr);
                         /* put back into read status register mode */
-                        cfi_write(map, CMD(0x70), adr);
+                        map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
                        DISABLE_VPP(map);
                        spin_unlock_bh(chip->mutex);
@@ -620,19 +578,18 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
        chip->state = FL_STATUS;
 
         /* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */
-        if ((status & CMD(0x02)) || (status & CMD(0x08)) ||
-            (status & CMD(0x10)) || (status & CMD(0x20))) {
+        if (map_word_bitsset(map, status, CMD(0x3a))) {
 #ifdef DEBUG_CFI_FEATURES
-            printk("%s: 2 status[%x]\n", __FUNCTION__, status);
+               printk("%s: 2 status[%lx]\n", __FUNCTION__, status.x[0]);
 #endif
-            /* clear status */
-            cfi_write(map, CMD(0x50), cmd_adr);
-            /* put back into read status register mode */
-            cfi_write(map, CMD(0x70), adr);
-            wake_up(&chip->wq);
-            spin_unlock_bh(chip->mutex);
-            return (status & CMD(0x02)) ? -EROFS : -EIO;
-        }
+               /* clear status */
+               map_write(map, CMD(0x50), cmd_adr);
+               /* put back into read status register mode */
+               map_write(map, CMD(0x70), adr);
+               wake_up(&chip->wq);
+               spin_unlock_bh(chip->mutex);
+               return map_word_bitsset(map, status, CMD(0x02)) ? -EROFS : -EIO;
+       }
        wake_up(&chip->wq);
        spin_unlock_bh(chip->mutex);
 
@@ -644,7 +601,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
 {
        struct map_info *map = mtd->priv;
        struct cfi_private *cfi = map->fldrv_priv;
-       int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize;
+       int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
        int ret = 0;
        int chipnum;
        unsigned long ofs;
@@ -657,7 +614,7 @@ static int cfi_staa_write_buffers (struct mtd_info *mtd, loff_t to,
        ofs = to  - (chipnum << cfi->chipshift);
 
 #ifdef DEBUG_CFI_FEATURES
-        printk("%s: CFIDEV_BUSWIDTH[%x]\n", __FUNCTION__, CFIDEV_BUSWIDTH);
+        printk("%s: map_bankwidth(map)[%x]\n", __FUNCTION__, map_bankwidth(map));
         printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize);
         printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len);
 #endif
@@ -769,7 +726,7 @@ write_error:
 static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       __u32 status, status_OK;
+       map_word status, status_OK;
        unsigned long timeo;
        int retries = 3;
        DECLARE_WAITQUEUE(wait, current);
@@ -789,12 +746,12 @@ retry:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
        case FL_READY:
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x70), adr);
                chip->state = FL_STATUS;
 
        case FL_STATUS:
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                
                /* Urgh. Chip not yet ready to talk to us. */
@@ -823,11 +780,11 @@ retry:
 
        ENABLE_VPP(map);
        /* Clear the status register first */
-       cfi_write(map, CMD(0x50), adr);
+       map_write(map, CMD(0x50), adr);
 
        /* Now erase */
-       cfi_write(map, CMD(0x20), adr);
-       cfi_write(map, CMD(0xD0), adr);
+       map_write(map, CMD(0x20), adr);
+       map_write(map, CMD(0xD0), adr);
        chip->state = FL_ERASING;
        
        spin_unlock_bh(chip->mutex);
@@ -851,15 +808,15 @@ retry:
                        continue;
                }
 
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       cfi_write(map, CMD(0x70), adr);
+                       map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %llx.\n", status, cfi_read(map, adr));
+                       printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
                        DISABLE_VPP(map);
                        spin_unlock_bh(chip->mutex);
                        return -EIO;
@@ -875,43 +832,46 @@ retry:
        ret = 0;
 
        /* We've broken this before. It doesn't hurt to be safe */
-       cfi_write(map, CMD(0x70), adr);
+       map_write(map, CMD(0x70), adr);
        chip->state = FL_STATUS;
-       status = cfi_read(map, adr);
+       status = map_read(map, adr);
 
        /* check for lock bit */
-       if (status & CMD(0x3a)) {
-               unsigned char chipstatus = status;
-               if (status != CMD(status & 0xff)) {
-                       int i;
-                       for (i = 1; i<CFIDEV_INTERLEAVE; i++) {
-                                     chipstatus |= status >> (cfi->device_type * 8);
+       if (map_word_bitsset(map, status, CMD(0x3a))) {
+               unsigned char chipstatus = status.x[0];
+               if (!map_word_equal(map, status, CMD(chipstatus))) {
+                       int i, w;
+                       for (w=0; w<map_words(map); w++) {
+                               for (i = 0; i<cfi_interleave(cfi); i++) {
+                                       chipstatus |= status.x[w] >> (cfi->device_type * 8);
+                               }
                        }
-                       printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus);
+                       printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
+                              status.x[0], chipstatus);
                }
                /* Reset the error bits */
-               cfi_write(map, CMD(0x50), adr);
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x50), adr);
+               map_write(map, CMD(0x70), adr);
                
                if ((chipstatus & 0x30) == 0x30) {
-                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status);
+                       printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\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", status);
+                       printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\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, status);
+                               printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
                                timeo = jiffies + HZ;
                                chip->state = FL_STATUS;
                                spin_unlock_bh(chip->mutex);
                                goto retry;
                        }
-                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status);
+                       printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
                        ret = -EIO;
                }
        }
@@ -1072,7 +1032,7 @@ static void cfi_staa_sync (struct mtd_info *mtd)
 static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       __u32 status, status_OK;
+       map_word status, status_OK;
        unsigned long timeo = jiffies + HZ;
        DECLARE_WAITQUEUE(wait, current);
 
@@ -1090,12 +1050,12 @@ retry:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
        case FL_READY:
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x70), adr);
                chip->state = FL_STATUS;
 
        case FL_STATUS:
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK)
                        break;
                
                /* Urgh. Chip not yet ready to talk to us. */
@@ -1123,8 +1083,8 @@ retry:
        }
 
        ENABLE_VPP(map);
-       cfi_write(map, CMD(0x60), adr);
-       cfi_write(map, CMD(0x01), adr);
+       map_write(map, CMD(0x60), adr);
+       map_write(map, CMD(0x01), adr);
        chip->state = FL_LOCKING;
        
        spin_unlock_bh(chip->mutex);
@@ -1137,15 +1097,15 @@ retry:
        timeo = jiffies + (HZ*2);
        for (;;) {
 
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       cfi_write(map, CMD(0x70), adr);
+                       map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %llx.\n", status, cfi_read(map, adr));
+                       printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
                        DISABLE_VPP(map);
                        spin_unlock_bh(chip->mutex);
                        return -EIO;
@@ -1221,7 +1181,7 @@ static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
 static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
 {
        struct cfi_private *cfi = map->fldrv_priv;
-       __u32 status, status_OK;
+       map_word status, status_OK;
        unsigned long timeo = jiffies + HZ;
        DECLARE_WAITQUEUE(wait, current);
 
@@ -1239,12 +1199,12 @@ retry:
        case FL_CFI_QUERY:
        case FL_JEDEC_QUERY:
        case FL_READY:
-               cfi_write(map, CMD(0x70), adr);
+               map_write(map, CMD(0x70), adr);
                chip->state = FL_STATUS;
 
        case FL_STATUS:
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                
                /* Urgh. Chip not yet ready to talk to us. */
@@ -1272,8 +1232,8 @@ retry:
        }
 
        ENABLE_VPP(map);
-       cfi_write(map, CMD(0x60), adr);
-       cfi_write(map, CMD(0xD0), adr);
+       map_write(map, CMD(0x60), adr);
+       map_write(map, CMD(0xD0), adr);
        chip->state = FL_UNLOCKING;
        
        spin_unlock_bh(chip->mutex);
@@ -1286,15 +1246,15 @@ retry:
        timeo = jiffies + (HZ*2);
        for (;;) {
 
-               status = cfi_read(map, adr);
-               if ((status & status_OK) == status_OK)
+               status = map_read(map, adr);
+               if (map_word_andequal(map, status, status_OK, status_OK))
                        break;
                
                /* OK Still waiting */
                if (time_after(jiffies, timeo)) {
-                       cfi_write(map, CMD(0x70), adr);
+                       map_write(map, CMD(0x70), adr);
                        chip->state = FL_STATUS;
-                       printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %llx.\n", status, cfi_read(map, adr));
+                       printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n", status.x[0], map_read(map, adr).x[0]);
                        DISABLE_VPP(map);
                        spin_unlock_bh(chip->mutex);
                        return -EIO;
@@ -1423,7 +1383,7 @@ static void cfi_staa_resume(struct mtd_info *mtd)
                
                /* Go to known state. Chip may have been power cycled */
                if (chip->state == FL_PM_SUSPENDED) {
-                       cfi_write(map, CMD(0xFF), 0);
+                       map_write(map, CMD(0xFF), 0);
                        chip->state = FL_READY;
                        wake_up(&chip->wq);
                }
index fba4ddf..071be42 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: cfi_probe.c,v 1.71 2003/05/28 12:51:48 dwmw2 Exp $
+   $Id: cfi_probe.c,v 1.77 2004/07/14 08:38:44 dwmw2 Exp $
 */
 
 #include <linux/config.h>
@@ -26,7 +26,7 @@ static void print_cfi_ident(struct cfi_ident *);
 #endif
 
 static int cfi_probe_chip(struct map_info *map, __u32 base,
-                         struct flchip *chips, struct cfi_private *cfi);
+                         unsigned long *chip_map, struct cfi_private *cfi);
 static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
 
 struct mtd_info *cfi_probe(struct map_info *map);
@@ -35,21 +35,36 @@ struct mtd_info *cfi_probe(struct map_info *map);
    in: interleave,type,mode
    ret: table index, <0 for error
  */
-static inline int qry_present(struct map_info *map, __u32 base,
+static int qry_present(struct map_info *map, __u32 base,
                                struct cfi_private *cfi)
 {
        int osf = cfi->interleave * cfi->device_type;   // scale factor
+       map_word val;
+       map_word qry;
 
-       if (cfi_read(map,base+osf*0x10)==cfi_build_cmd('Q',map,cfi) &&
-           cfi_read(map,base+osf*0x11)==cfi_build_cmd('R',map,cfi) &&
-           cfi_read(map,base+osf*0x12)==cfi_build_cmd('Y',map,cfi))
-               return 1;       // ok !
+       qry =  cfi_build_cmd('Q', map, cfi);
+       val = map_read(map, base + osf*0x10);
 
-       return 0;       // nothing found
+       if (!map_word_equal(map, qry, val))
+               return 0;
+
+       qry =  cfi_build_cmd('R', map, cfi);
+       val = map_read(map, base + osf*0x11);
+
+       if (!map_word_equal(map, qry, val))
+               return 0;
+
+       qry =  cfi_build_cmd('Y', map, cfi);
+       val = map_read(map, base + osf*0x12);
+
+       if (!map_word_equal(map, qry, val))
+               return 0;
+
+       return 1;       // nothing found
 }
 
 static int cfi_probe_chip(struct map_info *map, __u32 base,
-                         struct flchip *chips, struct cfi_private *cfi)
+                         unsigned long *chip_map, struct cfi_private *cfi)
 {
        int i;
        
@@ -66,6 +81,7 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
                return 0;
        }
        cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
        cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
 
        if (!qry_present(map,base,cfi))
@@ -78,18 +94,25 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
        }
 
        /* Check each previous chip to see if it's an alias */
-       for (i=0; i<cfi->numchips; i++) {
+       for (i=0; i < (base >> cfi->chipshift); i++) {
+               unsigned long start;
+               if(!test_bit(i, chip_map)) {
+                       /* Skip location; no valid chip at this address */
+                       continue; 
+               }
+               start = i << cfi->chipshift;
                /* This chip should be in read mode if it's one
                   we've already touched. */
-               if (qry_present(map,chips[i].start,cfi)) {
+               if (qry_present(map, start, cfi)) {
                        /* Eep. This chip also had the QRY marker. 
                         * Is it an alias for the new one? */
-                       cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
+                       cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL);
+                       cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
 
                        /* If the QRY marker goes away, it's an alias */
-                       if (!qry_present(map, chips[i].start, cfi)) {
+                       if (!qry_present(map, start, cfi)) {
                                printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-                                      map->name, base, chips[i].start);
+                                      map->name, base, start);
                                return 0;
                        }
                        /* Yes, it's actually got QRY for data. Most 
@@ -97,10 +120,11 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
                         * too and if it's the same, assume it's an alias. */
                        /* FIXME: Use other modes to do a proper check */
                        cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+                       cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
                        
                        if (qry_present(map, base, cfi)) {
                                printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-                                      map->name, base, chips[i].start);
+                                      map->name, base, start);
                                return 0;
                        }
                }
@@ -108,21 +132,16 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
        
        /* OK, if we got to here, then none of the previous chips appear to
           be aliases for the current one. */
-       if (cfi->numchips == MAX_CFI_CHIPS) {
-               printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-               /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
-               return -1;
-       }
-       chips[cfi->numchips].start = base;
-       chips[cfi->numchips].state = FL_READY;
+       set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
        cfi->numchips++;
        
        /* Put it back into Read Mode */
        cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
 
-       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
+       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
               map->name, cfi->interleave, cfi->device_type*8, base,
-              map->buswidth*8);
+              map->bankwidth*8);
        
        return 1;
 }
@@ -150,7 +169,6 @@ static int cfi_chip_setup(struct map_info *map,
        memset(cfi->cfiq,0,sizeof(struct cfi_ident));   
        
        cfi->cfi_mode = CFI_MODE_CFI;
-       cfi->fast_prog=1;               /* CFI supports fast programming */
        
        /* Read the CFI info structure */
        for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
@@ -180,8 +198,29 @@ static int cfi_chip_setup(struct map_info *map,
                       (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1);
 #endif
        }
+
+       /* Note we put the device back into Read Mode BEFORE going into Auto
+        * Select Mode, as some devices support nesting of modes, others
+        * don't. This way should always work.
+        * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
+        * so should be treated as nops or illegal (and so put the device
+        * back into Read Mode, which is a nop in this case).
+        */
+       cfi_send_gen_cmd(0xf0,     0, base, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
+       cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
+       cfi->mfr = cfi_read_query(map, base);
+       cfi->id = cfi_read_query(map, base + ofs_factor);    
+
        /* Put it back into Read Mode */
        cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+       /* ... even if it's an Intel chip */
+       cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+
+       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
+              map->name, cfi->interleave, cfi->device_type*8, base,
+              map->bankwidth*8);
 
        return 1;
 }
@@ -241,11 +280,11 @@ static void print_cfi_ident(struct cfi_ident *cfip)
                printk("No Alternate Algorithm Table\n");
                
                
-       printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
-       printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
+       printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf);
+       printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf);
        if (cfip->VppMin) {
-               printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
-               printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
+               printk("Vpp Minimum: %2d.%d V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf);
+               printk("Vpp Maximum: %2d.%d V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf);
        }
        else
                printk("No Vpp line\n");
index 3bc9199..1e45df0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: chipreg.c,v 1.15 2003/05/21 15:15:05 dwmw2 Exp $
+ * $Id: chipreg.c,v 1.16 2003/05/29 09:36:15 dwmw2 Exp $
  *
  * Registration for chip drivers
  *
index bae2fb5..3615fd8 100644 (file)
@@ -2,7 +2,7 @@
  * Routines common to all CFI-type probes.
  * (C) 2001-2003 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.c,v 1.13 2003/06/25 11:50:37 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.19 2004/07/13 22:33:32 dwmw2 Exp $
  */
 
 #include <linux/kernel.h>
@@ -50,16 +50,15 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
 EXPORT_SYMBOL(mtd_do_chip_probe);
 
 
-struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
+static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
 {
-       unsigned long base=0;
        struct cfi_private cfi;
        struct cfi_private *retcfi;
-       struct flchip chip[MAX_CFI_CHIPS];
-       int i;
+       unsigned long *chip_map;
+       int i, j, mapsize;
+       int max_chips;
 
        memset(&cfi, 0, sizeof(cfi));
-       memset(&chip[0], 0, sizeof(chip));
 
        /* Call the probetype-specific code with all permutations of 
           interleave and device type, etc. */
@@ -80,46 +79,47 @@ struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe
                return NULL;
        }
 #endif
-       chip[0].start = 0;
-       chip[0].state = FL_READY;
        cfi.chipshift = cfi.cfiq->DevSize;
 
-       switch(cfi.interleave) {
-#ifdef CFIDEV_INTERLEAVE_1
-       case 1:
-               break;
-#endif
-#ifdef CFIDEV_INTERLEAVE_2
-       case 2:
+       if (cfi_interleave_is_1(&cfi)) {
+               ;
+       } else if (cfi_interleave_is_2(&cfi)) {
                cfi.chipshift++;
-               break;
-#endif
-#ifdef CFIDEV_INTERLEAVE_4
-       case 4:
-               cfi.chipshift+=2;
-               break;
-#endif
-       default:
+       } else if (cfi_interleave_is_4((&cfi))) {
+               cfi.chipshift += 2;
+       } else if (cfi_interleave_is_8(&cfi)) {
+               cfi.chipshift += 3;
+       } else {
                BUG();
        }
                
        cfi.numchips = 1;
 
+       /* 
+        * Allocate memory for bitmap of valid chips. 
+        * Align bitmap storage size to full byte. 
+        */ 
+       max_chips = map->size >> cfi.chipshift;
+       mapsize = (max_chips / 8) + ((max_chips % 8) ? 1 : 0);
+       chip_map = kmalloc(mapsize, GFP_KERNEL);
+       if (!chip_map) {
+               printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
+               kfree(cfi.cfiq);
+               return NULL;
+       }
+       memset (chip_map, 0, mapsize);
+
+       set_bit(0, chip_map); /* Mark first chip valid */
+
        /*
         * Now probe for other chips, checking sensibly for aliases while
         * we're at it. The new_chip probe above should have let the first
         * chip in read mode.
-        *
-        * NOTE: Here, we're checking if there is room for another chip
-        *       the same size within the mapping. Therefore, 
-        *       base + chipsize <= map->size is the correct thing to do, 
-        *       because, base + chipsize would be the  _first_ byte of the
-        *       next chip, not the one we're currently pondering.
         */
 
-       for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size;
-            base += (1<<cfi.chipshift))
-               cp->probe_chip(map, base, &chip[0], &cfi);
+       for (i = 1; i < max_chips; i++) {
+               cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi);
+       }
 
        /*
         * Now allocate the space for the structures we need to return to 
@@ -131,19 +131,26 @@ struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe
        if (!retcfi) {
                printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
                kfree(cfi.cfiq);
+               kfree(chip_map);
                return NULL;
        }
 
        memcpy(retcfi, &cfi, sizeof(cfi));
-       memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips);
-
-       /* Fix up the stuff that breaks when you move it */
-       for (i=0; i< retcfi->numchips; i++) {
-               init_waitqueue_head(&retcfi->chips[i].wq);
-               spin_lock_init(&retcfi->chips[i]._spinlock);
-               retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock;
+       memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips);
+
+       for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) {
+               if(test_bit(i, chip_map)) {
+                       struct flchip *pchip = &retcfi->chips[j++];
+
+                       pchip->start = (i << cfi.chipshift);
+                       pchip->state = FL_READY;
+                       init_waitqueue_head(&pchip->wq);
+                       spin_lock_init(&pchip->_spinlock);
+                       pchip->mutex = &pchip->_spinlock;
+               }
        }
 
+       kfree(chip_map);
        return retcfi;
 }
 
@@ -151,131 +158,27 @@ struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe
 static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
                             struct cfi_private *cfi)
 {
-       switch (map->buswidth) {
-#ifdef CFIDEV_BUSWIDTH_1               
-       case CFIDEV_BUSWIDTH_1:
-               cfi->interleave = CFIDEV_INTERLEAVE_1;
-
-               cfi->device_type = CFI_DEVICETYPE_X8;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-
-               cfi->device_type = CFI_DEVICETYPE_X16;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-               break;                  
-#endif /* CFIDEV_BUSWITDH_1 */
-
-#ifdef CFIDEV_BUSWIDTH_2               
-       case CFIDEV_BUSWIDTH_2:
-#ifdef CFIDEV_INTERLEAVE_1
-               cfi->interleave = CFIDEV_INTERLEAVE_1;
-
-               cfi->device_type = CFI_DEVICETYPE_X16;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif /* CFIDEV_INTERLEAVE_1 */
-#ifdef CFIDEV_INTERLEAVE_2
-               cfi->interleave = CFIDEV_INTERLEAVE_2;
-
-               cfi->device_type = CFI_DEVICETYPE_X8;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-
-               cfi->device_type = CFI_DEVICETYPE_X16;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
-               break;                  
-#endif /* CFIDEV_BUSWIDTH_2 */
-
-#ifdef CFIDEV_BUSWIDTH_4
-       case CFIDEV_BUSWIDTH_4:
-#if defined(CFIDEV_INTERLEAVE_1) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
-                cfi->interleave = CFIDEV_INTERLEAVE_1;
-
-                cfi->device_type = CFI_DEVICETYPE_X32;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif /* CFIDEV_INTERLEAVE_1 */
-#ifdef CFIDEV_INTERLEAVE_2
-               cfi->interleave = CFIDEV_INTERLEAVE_2;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
-               cfi->device_type = CFI_DEVICETYPE_X32;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif
-               cfi->device_type = CFI_DEVICETYPE_X16;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-
-               cfi->device_type = CFI_DEVICETYPE_X8;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
-#ifdef CFIDEV_INTERLEAVE_4
-               cfi->interleave = CFIDEV_INTERLEAVE_4;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
-               cfi->device_type = CFI_DEVICETYPE_X32;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif
-               cfi->device_type = CFI_DEVICETYPE_X16;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-
-               cfi->device_type = CFI_DEVICETYPE_X8;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif /* CFIDEV_INTERLEAVE_4 */
-               break;
-#endif /* CFIDEV_BUSWIDTH_4 */
-
-#ifdef CFIDEV_BUSWIDTH_8
-       case CFIDEV_BUSWIDTH_8:
-#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE)
-                cfi->interleave = CFIDEV_INTERLEAVE_2;
-
-                cfi->device_type = CFI_DEVICETYPE_X32;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif /* CFIDEV_INTERLEAVE_2 */
-#ifdef CFIDEV_INTERLEAVE_4
-               cfi->interleave = CFIDEV_INTERLEAVE_4;
-
-#ifdef SOMEONE_ACTUALLY_MAKES_THESE
-               cfi->device_type = CFI_DEVICETYPE_X32;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif
-               cfi->device_type = CFI_DEVICETYPE_X16;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif /* CFIDEV_INTERLEAVE_4 */
-#ifdef CFIDEV_INTERLEAVE_8
-               cfi->interleave = CFIDEV_INTERLEAVE_8;
-
-               cfi->device_type = CFI_DEVICETYPE_X16;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-
-               cfi->device_type = CFI_DEVICETYPE_X8;
-               if (cp->probe_chip(map, 0, NULL, cfi))
-                       return 1;
-#endif /* CFIDEV_INTERLEAVE_8 */
-               break;
-#endif /* CFIDEV_BUSWIDTH_8 */
-
-       default:
-               printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth);
-               return 0;
+       int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
+       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) {
+
+               if (!cfi_interleave_supported(nr_chips))
+                   continue;
+
+               cfi->interleave = nr_chips;
+
+               for (type = 0; type < 3; type++) {
+                       cfi->device_type = 1<<type;
+
+                       if (cp->probe_chip(map, 0, NULL, cfi))
+                               return 1;
+               }
        }
        return 0;
 }
 
-
 typedef struct mtd_info *cfi_cmdset_fn_t(struct map_info *, int);
 
 extern cfi_cmdset_fn_t cfi_cmdset_0001;
index f0362fa..0b6e96f 100644 (file)
@@ -11,7 +11,7 @@
  * not going to guess how to send commands to them, plus I expect they will
  * all speak CFI..
  *
- * $Id: jedec.c,v 1.19 2003/05/29 09:25:23 dwmw2 Exp $
+ * $Id: jedec.c,v 1.20 2004/07/12 14:03:01 dwmw2 Exp $
  */
 
 #include <linux/init.h>
index cbef6f1..daf554c 100644 (file)
@@ -1,9 +1,11 @@
 /* 
    Common Flash Interface probe code.
    (C) 2000 Red Hat. GPL'd.
-   $Id: jedec_probe.c,v 1.29 2003/05/28 13:57:46 dwmw2 Exp $
+   $Id: jedec_probe.c,v 1.51 2004/07/14 14:44:30 thayne Exp $
    See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
    for the standard this probe goes back to.
+
+   Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
 */
 
 #include <linux/config.h>
@@ -16,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 
 
 /* AMD */
+#define AM29DL800BB    0x22C8
+#define AM29DL800BT    0x224A
+
 #define AM29F800BB     0x2258
 #define AM29F800BT     0x22D6
+#define AM29LV400BB    0x22BA
+#define AM29LV400BT    0x22B9
 #define AM29LV800BB    0x225B
 #define AM29LV800BT    0x22DA
 #define AM29LV160DT    0x22C4
@@ -58,6 +66,7 @@
 #define AT49BV32XT     0x00C9
 
 /* Fujitsu */
+#define MBM29F040C     0x00A4
 #define MBM29LV650UE   0x22D7
 #define MBM29LV320TE   0x22F6
 #define MBM29LV320BE   0x22F9
@@ -65,6 +74,9 @@
 #define MBM29LV160BE   0x2249
 #define MBM29LV800BA   0x225B
 #define MBM29LV800TA   0x22DA
+#define MBM29LV400TC   0x22B9
+#define MBM29LV400BC   0x22BA
+
 
 /* Intel */
 #define I28F004B3T     0x00d4
 #define M50FW016       0x002E
 
 /* SST */
+#define SST29EE020     0x0010
+#define SST29LE020     0x0012
 #define SST29EE512     0x005d
 #define SST29LE512     0x003d
 #define SST39LF800     0x2781
 #define SST39LF040     0x00D7
 #define SST39SF010A    0x00B5
 #define SST39SF020A    0x00B6
+#define SST49LF004B    0x0060
+#define SST49LF008A    0x005a
 #define SST49LF030A    0x001C
 #define SST49LF040A    0x0051
 #define SST49LF080A    0x005B
@@ -213,11 +229,10 @@ struct amd_flash_info {
        const __u16 dev_id;
        const char *name;
        const int DevSize;
-       const int InterfaceDesc;
        const int NumEraseRegions;
        const int CmdSet;
-       const __u8 uaddr[3];            /* unlock addrs for 8, 16, 32 modes */
-       const ulong regions[4];
+       const __u8 uaddr[4];            /* unlock addrs for 8, 16, 32, 64 */
+       const ulong regions[6];
 };
 
 #define ERASEINFO(size,blocks) (size<<8)|(blocks-1)
@@ -285,6 +300,40 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x08000,1),
                        ERASEINFO(0x10000,31)
                }
+       }, {
+               .mfr_id         = MANUFACTURER_AMD,
+               .dev_id         = AM29LV400BB,
+               .name           = "AMD AM29LV400BB",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x10000,7)
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_AMD,
+               .dev_id         = AM29LV400BT,
+               .name           = "AMD AM29LV400BT",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x10000,7),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x04000,1)
+               }
        }, {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29LV800BB,
@@ -303,6 +352,45 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x10000,15),
                }
        }, {
+/* add DL */
+               .mfr_id         = MANUFACTURER_AMD,
+               .dev_id         = AM29DL800BB,
+               .name           = "AMD AM29DL800BB",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_1MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 6,
+               .regions        = {
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x02000,4),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x10000,14)
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_AMD,
+               .dev_id         = AM29DL800BT,
+               .name           = "AMD AM29DL800BT",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_1MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 6,
+               .regions        = {
+                       ERASEINFO(0x10000,14),
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x02000,4),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x04000,1)
+               }
+       }, {
                .mfr_id         = MANUFACTURER_AMD,
                .dev_id         = AM29F800BB,
                .name           = "AMD AM29F800BB",
@@ -505,6 +593,19 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x10000,63),
                        ERASEINFO(0x02000,8)
                }
+       }, {
+               .mfr_id         = MANUFACTURER_FUJITSU,
+               .dev_id         = MBM29F040C,
+               .name           = "Fujitsu MBM29F040C",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 1,
+               .regions        = {
+                       ERASEINFO(0x10000,8)
+               }
        }, {
                .mfr_id         = MANUFACTURER_FUJITSU,
                .dev_id         = MBM29LV650UE,
@@ -616,6 +717,40 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x02000,2),
                        ERASEINFO(0x04000,1)
                }
+       }, {
+               .mfr_id         = MANUFACTURER_FUJITSU,
+               .dev_id         = MBM29LV400BC,
+               .name           = "Fujitsu MBM29LV400BC",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x04000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x10000,7)
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_FUJITSU,
+               .dev_id         = MBM29LV400TC,
+               .name           = "Fujitsu MBM29LV400TC",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x0AAA_0x0555,  /* x8 */
+                       [1] = MTD_UADDR_0x0555_0x02AA,  /* x16 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 4,
+               .regions        = {
+                       ERASEINFO(0x10000,7),
+                       ERASEINFO(0x08000,1),
+                       ERASEINFO(0x02000,2),
+                       ERASEINFO(0x04000,1)
+               }
        }, {
                .mfr_id         = MANUFACTURER_INTEL,
                .dev_id         = I28F004B3B,
@@ -1065,6 +1200,30 @@ static const struct amd_flash_info jedec_table[] = {
                        ERASEINFO(0x01000,32),
                }
         }, {
+               .mfr_id         = MANUFACTURER_SST,
+               .dev_id         = SST29EE020,
+               .name           = "SST 29EE020",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+               },
+               .DevSize        = SIZE_256KiB,
+               .CmdSet         = P_ID_SST_PAGE,
+               .NumEraseRegions= 1,
+               regions: {ERASEINFO(0x01000,64),
+               }
+         }, {
+               .mfr_id         = MANUFACTURER_SST,
+               .dev_id         = SST29LE020,
+               .name           = "SST 29LE020",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+               },
+               .DevSize        = SIZE_256KiB,
+               .CmdSet         = P_ID_SST_PAGE,
+               .NumEraseRegions= 1,
+               regions: {ERASEINFO(0x01000,64),
+               }
+       }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST39LF020,
                .name           = "SST 39LF020",
@@ -1116,6 +1275,32 @@ static const struct amd_flash_info jedec_table[] = {
                .regions        = {
                        ERASEINFO(0x01000,64),
                }
+       }, {
+               .mfr_id         = MANUFACTURER_SST,
+               .dev_id         = SST49LF004B,
+               .name           = "SST 49LF004B",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+               },
+               .DevSize        = SIZE_512KiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 1,
+               .regions        = {
+                       ERASEINFO(0x01000,128),
+               }
+       }, {
+               .mfr_id         = MANUFACTURER_SST,
+               .dev_id         = SST49LF008A,
+               .name           = "SST 49LF008A",
+               .uaddr          = {
+                       [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
+               },
+               .DevSize        = SIZE_1MiB,
+               .CmdSet         = P_ID_AMD_STD,
+               .NumEraseRegions= 1,
+               .regions        = {
+                       ERASEINFO(0x01000,256),
+               }
        }, {
                .mfr_id         = MANUFACTURER_SST,
                .dev_id         = SST49LF030A,
@@ -1392,37 +1577,50 @@ static const struct amd_flash_info jedec_table[] = {
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index);
 
 static int jedec_probe_chip(struct map_info *map, __u32 base,
-                           struct flchip *chips, struct cfi_private *cfi);
+                           unsigned long *chip_map, struct cfi_private *cfi);
 
 struct mtd_info *jedec_probe(struct map_info *map);
 
 static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, 
        struct cfi_private *cfi)
 {
-       u32 result, mask;
+       map_word result;
+       unsigned long mask;
        mask = (1 << (cfi->device_type * 8)) -1;
-       result = cfi_read(map, base);
-       result &= mask;
-       return result;
+       result = map_read(map, base);
+       return result.x[0] & mask;
 }
 
 static inline u32 jedec_read_id(struct map_info *map, __u32 base, 
        struct cfi_private *cfi)
 {
        int osf;
-       u32 result, mask;
+       map_word result;
+       unsigned long mask;
        osf = cfi->interleave *cfi->device_type;
        mask = (1 << (cfi->device_type * 8)) -1;
-       result = cfi_read(map, base + osf);
-       result &= mask;
-       return result;
+       result = map_read(map, base + osf);
+       return result.x[0] & mask;
 }
 
 static inline void jedec_reset(u32 base, struct map_info *map, 
        struct cfi_private *cfi)
 {
        /* Reset */
-       cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+
+       /* after checking the datasheets for SST, MACRONIX and ATMEL
+        * (oh and incidentaly the jedec spec - 3.5.3.3) the reset
+        * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at
+        * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips
+        * as they will ignore the writes and dont care what address
+        * the F0 is written to */
+       if(cfi->addr_unlock1) {
+               /*printk("reset unlock called %x %x \n",cfi->addr_unlock1,cfi->addr_unlock2);*/
+               cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+               cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
+       }
+
+       cfi_send_gen_cmd(0xF0, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
        /* Some misdesigned intel chips do not respond for 0xF0 for a reset,
         * so ensure we're in read mode.  Send both the Intel and the AMD command
         * for this.  Intel uses 0xff for this, AMD uses 0xff for NOP, so
@@ -1450,6 +1648,12 @@ static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_ty
 
        uaddr = finfo->uaddr[uaddr_idx];
 
+       if (uaddr != MTD_UADDR_NOT_SUPPORTED ) {
+               /* ASSERT("The unlock addresses for non-8-bit mode
+                  are bollocks. We don't really need an array."); */
+               uaddr = finfo->uaddr[0];
+       }
+
  uaddr_done:
        return uaddr;
 }
@@ -1458,6 +1662,7 @@ static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_ty
 static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
 {
        int i,num_erase_regions;
+       unsigned long mask;
        __u8 uaddr;
 
        printk("Found: %s\n",jedec_table[index].name);
@@ -1487,12 +1692,15 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
        p_cfi->id = jedec_table[index].dev_id;
 
        uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type);
-       if ( MTD_UADDR_NOT_SUPPORTED ) {
+       if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
                kfree( p_cfi->cfiq );
                return 0;
        }
-       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
-       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
+
+       /* Mask out address bits which are smaller than the device type */
+       mask = ~(p_cfi->device_type-1);
+       p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 & mask;
+       p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 & mask;
 
        return 1;       /* ok */
 }
@@ -1513,9 +1721,37 @@ static inline int jedec_match( __u32 base,
        int rc = 0;           /* failure until all tests pass */
        u32 mfr, id;
        __u8 uaddr;
+       unsigned long mask;
 
-       /* The ID's must match */
-       if ( cfi->mfr != finfo->mfr_id || cfi->id != finfo->dev_id ) {
+       /*
+        * The IDs must match.  For X16 and X32 devices operating in
+        * a lower width ( X8 or X16 ), the device ID's are usually just
+        * the lower byte(s) of the larger device ID for wider mode.  If
+        * a part is found that doesn't fit this assumption (device id for
+        * smaller width mode is completely unrealated to full-width mode)
+        * then the jedec_table[] will have to be augmented with the IDs
+        * for different widths.
+        */
+       switch (cfi->device_type) {
+       case CFI_DEVICETYPE_X8:
+               mfr = (__u8)finfo->mfr_id;
+               id = (__u8)finfo->dev_id;
+               break;
+       case CFI_DEVICETYPE_X16:
+               mfr = (__u16)finfo->mfr_id;
+               id = (__u16)finfo->dev_id;
+               break;
+       case CFI_DEVICETYPE_X32:
+               mfr = (__u16)finfo->mfr_id;
+               id = (__u32)finfo->dev_id;
+               break;
+       default:
+               printk(KERN_WARNING
+                      "MTD %s(): Unsupported device type %d\n",
+                      __func__, cfi->device_type);
+               goto match_done;
+       }
+       if ( cfi->mfr != mfr || cfi->id != id ) {
                goto match_done;
        }
 
@@ -1523,7 +1759,7 @@ static inline int jedec_match( __u32 base,
        DEBUG( MTD_DEBUG_LEVEL3,
               "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n",
               __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) );
-       if ( base + ( 1 << finfo->DevSize ) > map->size ) {
+       if ( base + cfi->interleave * ( 1 << finfo->DevSize ) > map->size ) {
                DEBUG( MTD_DEBUG_LEVEL3,
                       "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n",
                       __func__, finfo->mfr_id, finfo->dev_id,
@@ -1532,20 +1768,22 @@ static inline int jedec_match( __u32 base,
        }
 
        uaddr = finfo_uaddr(finfo, cfi->device_type);
-       if ( MTD_UADDR_NOT_SUPPORTED ) {
+       if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
                goto match_done;
        }
 
+       mask = ~(cfi->device_type-1);
+
        DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n",
               __func__, cfi->addr_unlock1, cfi->addr_unlock2 );
        if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr
-            && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1
-                 || unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
+            && ( (unlock_addrs[uaddr].addr1 & mask) != cfi->addr_unlock1 ||
+                 (unlock_addrs[uaddr].addr2 & mask) != cfi->addr_unlock2 ) ) {
                DEBUG( MTD_DEBUG_LEVEL3,
-                      "MTD %s(): 0x%.4x 0x%.4x did not match\n",
+                      "MTD %s(): 0x%.4lx 0x%.4lx did not match\n",
                       __func__,
-                      unlock_addrs[uaddr].addr1,
-                      unlock_addrs[uaddr].addr2 );
+                      unlock_addrs[uaddr].addr1 & mask,
+                      unlock_addrs[uaddr].addr2 & mask);
                goto match_done;
        }
 
@@ -1593,41 +1831,25 @@ static inline int jedec_match( __u32 base,
 
 
 static int jedec_probe_chip(struct map_info *map, __u32 base,
-                             struct flchip *chips, struct cfi_private *cfi)
+                           unsigned long *chip_map, struct cfi_private *cfi)
 {
        int i;
-       int unlockpass = 0;
+       enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED;
 
-       /*
-        * FIXME - eventually replace these unlock address seeds with
-        * information from unlock_addrs[].
-        */
+ retry:
        if (!cfi->numchips) {
-               switch (cfi->device_type) {
-               case CFI_DEVICETYPE_X8:
-                       cfi->addr_unlock1 = 0x555;
-                       cfi->addr_unlock2 = 0x2aa;
-                       break;
-               case CFI_DEVICETYPE_X16:
-                       cfi->addr_unlock1 = 0xaaa;
-                       if (map->buswidth == cfi->interleave) {
-                               /* X16 chip(s) in X8 mode */
-                               cfi->addr_unlock2 = 0x555;
-                       } else {
-                               cfi->addr_unlock2 = 0x554;
-                       }
-                       break;
-               case CFI_DEVICETYPE_X32:
-                       cfi->addr_unlock1 = 0x1555; 
-                       cfi->addr_unlock2 = 0xaaa; 
-                       break;
-               default:
-                       printk(KERN_NOTICE "Eep. Unknown jedec_probe device type %d\n", cfi->device_type);
-               return 0;
-               }
+               unsigned long mask = ~(cfi->device_type-1);
+
+               uaddr_idx++;
+
+               if (MTD_UADDR_UNNECESSARY == uaddr_idx)
+                       return 0;
+
+               /* Mask out address bits which are smaller than the device type */
+               cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 & mask;
+               cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 & mask;
        }
 
- retry:
        /* Make certain we aren't probing past the end of map */
        if (base >= map->size) {
                printk(KERN_NOTICE
@@ -1668,7 +1890,8 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                
                cfi->mfr = jedec_read_mfr(map, base, cfi);
                cfi->id = jedec_read_id(map, base, cfi);
-               printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
+               DEBUG(MTD_DEBUG_LEVEL3,
+                     "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
                        cfi->mfr, cfi->id, cfi->interleave, cfi->device_type);
                for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
                        if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
@@ -1681,16 +1904,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                                goto ok_out;
                        }
                }
-               switch(unlockpass++) {
-               case 0:
-                       cfi->addr_unlock1 |= cfi->addr_unlock1 << 4;
-                       cfi->addr_unlock2 |= cfi->addr_unlock2 << 4;
-                       goto retry;
-               case 1:
-                       cfi->addr_unlock1 = cfi->addr_unlock2 = 0;
-                       goto retry;
-               }
-               return 0;
+               goto retry;
        } else {
                __u16 mfr;
                __u16 id;
@@ -1707,21 +1921,24 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                }
        }
        
-       /* Check each previous chip to see if it's an alias */
-       for (i=0; i<cfi->numchips; i++) {
-               /* This chip should be in read mode if it's one
-                  we've already touched. */
-               if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr &&
-                   jedec_read_id(map, chips[i].start, cfi) == cfi->id) {
+       /* Check each previous chip locations to see if it's an alias */
+       for (i=0; i < (base >> cfi->chipshift); i++) {
+               unsigned long start;
+               if(!test_bit(i, chip_map)) {
+                       continue; /* Skip location; no valid chip at this address */
+               }
+               start = i << cfi->chipshift;
+               if (jedec_read_mfr(map, start, cfi) == cfi->mfr &&
+                   jedec_read_id(map, start, cfi) == cfi->id) {
                        /* Eep. This chip also looks like it's in autoselect mode.
                           Is it an alias for the new one? */
-                       jedec_reset(chips[i].start, map, cfi);
+                       jedec_reset(start, map, cfi);
 
                        /* If the device IDs go away, it's an alias */
                        if (jedec_read_mfr(map, base, cfi) != cfi->mfr ||
                            jedec_read_id(map, base, cfi) != cfi->id) {
                                printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-                                      map->name, base, chips[i].start);
+                                      map->name, base, start);
                                return 0;
                        }
                        
@@ -1733,7 +1950,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                        if (jedec_read_mfr(map, base, cfi) == cfi->mfr &&
                            jedec_read_id(map, base, cfi) == cfi->id) {
                                printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
-                                      map->name, base, chips[i].start);
+                                      map->name, base, start);
                                return 0;
                        }
                }
@@ -1741,22 +1958,16 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
                
        /* OK, if we got to here, then none of the previous chips appear to
           be aliases for the current one. */
-       if (cfi->numchips == MAX_CFI_CHIPS) {
-               printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS);
-               /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */
-               return -1;
-       }
-       chips[cfi->numchips].start = base;
-       chips[cfi->numchips].state = FL_READY;
+       set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */
        cfi->numchips++;
                
 ok_out:
        /* Put it back into Read Mode */
        jedec_reset(base, map, cfi);
 
-       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
+       printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
               map->name, cfi->interleave, cfi->device_type*8, base, 
-              map->buswidth*8);
+              map->bankwidth*8);
        
        return 1;
 }
index 7e17b45..db6f6c4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Common code to handle map devices which are simple RAM
  * (C) 2000 Red Hat. GPL'd.
- * $Id: map_ram.c,v 1.17 2003/05/28 12:51:49 dwmw2 Exp $
+ * $Id: map_ram.c,v 1.19 2004/07/12 21:58:44 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -104,10 +104,15 @@ static int mapram_erase (struct mtd_info *mtd, struct erase_info *instr)
        /* Yeah, it's inefficient. Who cares? It's faster than a _real_
           flash erase. */
        struct map_info *map = (struct map_info *)mtd->priv;
+       map_word allff;
        unsigned long i;
 
-       for (i=0; i<instr->len; i++)
-               map_write8(map, 0xFF, instr->addr + i);
+       allff = map_word_ff(map);
+
+       for (i=0; i<instr->len; i += map_bankwidth(map))
+               map_write(map, allff, instr->addr + i);
+
+       instr->state = MTD_ERASE_DONE;
 
        if (instr->callback)
                instr->callback(instr);
index 8ccf917..db2e2c6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Common code to handle map devices which are simple ROM
  * (C) 2000 Red Hat. GPL'd.
- * $Id: map_rom.c,v 1.20 2003/05/28 12:51:49 dwmw2 Exp $
+ * $Id: map_rom.c,v 1.21 2004/07/12 14:06:01 dwmw2 Exp $
  */
 
 #include <linux/module.h>
index bd0ed89..1313c70 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
  *           2000,2001 Lineo, Inc.
  *
- * $Id: sharp.c,v 1.12 2003/05/28 15:39:52 dwmw2 Exp $
+ * $Id: sharp.c,v 1.13 2004/07/12 14:06:34 dwmw2 Exp $
  *
  * Devices supported:
  *   LH28F016SCT Symmetrical block flash memory, 2Mx8
index a66e5a6..4e0f1a7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cmdlinepart.c,v 1.9 2003/05/16 17:08:24 dwmw2 Exp $
+ * $Id: cmdlinepart.c,v 1.14 2004/07/12 12:34:23 dwmw2 Exp $
  *
  * Read flash partition table from command line
  *
@@ -10,7 +10,7 @@
  * mtdparts=<mtddef>[;<mtddef]
  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
  * <partdef> := <size>[@offset][<name>][ro]
- * <mtd-id>  := unique id used in mapping driver/device
+ * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
  * <size>    := standard linux memsize OR "-" to denote all remaining space
  * <name>    := '(' NAME ')'
  * 
@@ -358,14 +358,7 @@ static int __init cmdline_parser_init(void)
        return register_mtd_parser(&cmdline_parser);
 }
 
-static void __exit cmdline_parser_exit(void)
-{
-       deregister_mtd_parser(&cmdline_parser);
-}
-
 module_init(cmdline_parser_init);
-module_exit(cmdline_parser_exit);
-
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
index d1df462..6ecd5ec 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.4 2003/05/28 15:18:54 dwmw2 Exp $
+# $Id: Kconfig,v 1.10 2004/07/15 00:34:49 dwmw2 Exp $
 
 menu "Self-contained MTD device drivers"
        depends on MTD!=n
@@ -9,9 +9,9 @@ config MTD_PMC551
        depends on MTD && PCI
        ---help---
          This provides a MTD device driver for the Ramix PMC551 RAM PCI card
-         from Ramix Inc. <http://www.ramix.com/products/>. These devices come
-         in memory configurations from 32M - 1G.  If you have one, you
-         probably want to enable this.
+         from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
+         These devices come in memory configurations from 32M - 1G.  If you
+         have one, you probably want to enable this.
 
          If this driver is compiled as a module you get the ability to select
          the size of the aperture window pointing into the devices memory.
@@ -40,9 +40,12 @@ config MTD_PMC551_DEBUG
 
 config MTD_MS02NV
        tristate "DEC MS02-NV NVRAM module support"
-       depends on CONFIG_MACH_DECSTATION
+       depends on MTD && MACH_DECSTATION
        help
-         Support for NVRAM module on DECstation.
+         This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery
+         backed-up NVRAM module.  The module was originally meant as an NFS
+         accelerator.  Say Y here if you have a DECstation 5000/2x0 or a
+         DECsystem 5900 equipped with such a module.
 
 config MTD_SLRAM
        tristate "Uncached system RAM"
@@ -52,6 +55,16 @@ config MTD_SLRAM
          you can still use it for storage or swap by using this driver to
          present it to the system as a Memory Technology Device.
 
+config MTD_PHRAM
+       tristate "Physical system RAM"
+       depends on MTD
+       help
+         This is a re-implementation of the slram driver above.
+
+         Use this driver to access physical memory that the kernel proper
+         doesn't have access to, memory beyond the mem=xxx limit, nvram,
+         memory on the video card, etc...
+
 config MTD_LART
        tristate "28F160xx flash driver for LART"
        depends on SA1100_LART && MTD
@@ -161,11 +174,18 @@ config MTD_DOC2001PLUS
 
 config MTD_DOCPROBE
        tristate
-       default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MOD_DOC2001PLUS=m)
+       default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MTD_DOC2001PLUS=m)
        default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y
        help
          This isn't a real config option, it's derived.
 
+config MTD_DOCECC
+       tristate
+       default m if MTD_DOCPROBE!=y && MTD_NAND_DISKONCHIP!=y && (MTD_DOCPROBE=m || MTD_NAND_DISKONCHIP=m)
+       default y if MTD_DOCPROBE=y || MTD_NAND_DISKONCHIP=y
+       help
+         This isn't a real config option, it's derived.
+
 config MTD_DOCPROBE_ADVANCED
        bool "Advanced detection options for DiskOnChip"
        depends on MTD_DOCPROBE
index 8ab580b..3bb872e 100644 (file)
@@ -1,7 +1,7 @@
 #
 # linux/drivers/devices/Makefile
 #
-# $Id: Makefile.common,v 1.3 2003/05/28 10:54:23 dwmw2 Exp $
+# $Id: Makefile.common,v 1.6 2004/07/12 16:07:30 dwmw2 Exp $
 
 #                       *** BIG UGLY NOTE ***
 #
 obj-$(CONFIG_MTD_DOC2000)      += doc2000.o
 obj-$(CONFIG_MTD_DOC2001)      += doc2001.o
 obj-$(CONFIG_MTD_DOC2001PLUS)  += doc2001plus.o
-obj-$(CONFIG_MTD_DOCPROBE)     += docprobe.o docecc.o
+obj-$(CONFIG_MTD_DOCPROBE)     += docprobe.o
+obj-$(CONFIG_MTD_DOCECC)       += docecc.o
 obj-$(CONFIG_MTD_SLRAM)                += slram.o
+obj-$(CONFIG_MTD_PHRAM)                += phram.o
 obj-$(CONFIG_MTD_PMC551)       += pmc551.o
 obj-$(CONFIG_MTD_MS02NV)       += ms02-nv.o
 obj-$(CONFIG_MTD_MTDRAM)       += mtdram.o
index 4bd5d32..a7e3a9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: blkmtd-25.c,v 1.5 2003/07/16 06:48:27 spse Exp $
+ * $Id: blkmtd-25.c,v 1.6 2004/07/15 15:09:15 dwmw2 Exp $
  *
  * blkmtd.c - use a block device as a fake MTD
  *
@@ -39,7 +39,7 @@
 
 /* Default erase size in K, always make it a multiple of PAGE_SIZE */
 #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)        /* 128KiB */
-#define VERSION "$Revision: 1.5 $"
+#define VERSION "$Revision: 1.6 $"
 
 /* Info for the block device */
 struct blkmtd_dev {
index fe70869..1a0c28e 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2000.c,v 1.53 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.60 2004/04/07 08:30:04 gleixner Exp $
  */
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/doc2000.h>
 
 #define DOC_SUPPORT_2000
+#define DOC_SUPPORT_2000TSOP
 #define DOC_SUPPORT_MILLENNIUM
 
 #ifdef DOC_SUPPORT_2000
@@ -33,7 +35,7 @@
 #define DoC_is_2000(doc) (0)
 #endif
 
-#ifdef DOC_SUPPORT_MILLENNIUM
+#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM)
 #define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
 #else
 #define DoC_is_Millennium(doc) (0)
@@ -53,11 +55,12 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *unused);
+                       size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-                        size_t *retlen, const u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *unused);
+                        size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs, 
+                         unsigned long count, loff_t to, size_t *retlen,
+                         u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -94,6 +97,10 @@ static int _DoC_WaitReady(struct DiskOnChip *doc)
 
        /* Out-of-line routine to wait for chip response */
        while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+               /* issue 2 read from NOP register after reading from CDSNControl register
+               see Software Requirement 11.4 item 2. */
+               DoC_Delay(doc, 2);
+
                if (time_after(jiffies, timeo)) {
                        DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
                        return -EIO;
@@ -147,6 +154,8 @@ static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
 
        /* Send the command */
        WriteDOC_(command, docptr, doc->ioreg);
+       if (DoC_is_Millennium(doc))
+               WriteDOC(command, docptr, WritePipeTerm);
 
        /* Lower the CLE line */
        WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
@@ -208,6 +217,9 @@ static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
                }
        }
 
+       if (DoC_is_Millennium(doc))
+               WriteDOC(ofs & 0xff, docptr, WritePipeTerm);
+
        DoC_Delay(doc, 2);      /* Needed for some slow flash chips. mf. */
        
        /* FIXME: The SlowIO's for millennium could be replaced by 
@@ -346,15 +358,25 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 
        /* Read the manufacturer and device id codes from the device */
 
-       /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
-       dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
-       DoC_Delay(doc, 2);
-       mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+       if (DoC_is_Millennium(doc)) {
+               DoC_Delay(doc, 2);
+               dummy = ReadDOC(doc->virtadr, ReadPipeInit);
+               mfr = ReadDOC(doc->virtadr, LastDataRead);
 
-       /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
-       dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
-       DoC_Delay(doc, 2);
-       id = ReadDOC_(doc->virtadr, doc->ioreg);
+               DoC_Delay(doc, 2);
+               dummy = ReadDOC(doc->virtadr, ReadPipeInit);
+               id = ReadDOC(doc->virtadr, LastDataRead);
+       } else {
+               /* CDSN Slow IO register see Software Req 11.4 item 5. */
+               dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+               DoC_Delay(doc, 2);
+               mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+
+               /* CDSN Slow IO register see Software Req 11.4 item 5. */
+               dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+               DoC_Delay(doc, 2);
+               id = ReadDOC_(doc->virtadr, doc->ioreg);
+       }
 
        /* No response - return failure */
        if (mfr == 0xff || mfr == 0)
@@ -388,11 +410,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                        if (!doc->mfr) {
                                doc->mfr = mfr;
                                doc->id = id;
-                               doc->chipshift =
-                                   nand_flash_ids[i].chipshift;
-                               doc->page256 = nand_flash_ids[i].page256;
-                               doc->pageadrlen =
-                                   nand_flash_ids[i].chipshift > 25 ? 3 : 2;
+                               doc->chipshift = 
+                                       ffs((nand_flash_ids[i].chipsize << 20)) - 1;
+                               doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0;
+                               doc->pageadrlen = doc->chipshift > 25 ? 3 : 2;
                                doc->erasesize =
                                    nand_flash_ids[i].erasesize;
                                return 1;
@@ -412,20 +433,16 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 
 /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
 
-static void DoC_ScanChips(struct DiskOnChip *this)
+static void DoC_ScanChips(struct DiskOnChip *this, int maxchips)
 {
        int floor, chip;
        int numchips[MAX_FLOORS];
-       int maxchips = MAX_CHIPS;
        int ret = 1;
 
        this->numchips = 0;
        this->mfr = 0;
        this->id = 0;
 
-       if (DoC_is_Millennium(this))
-               maxchips = MAX_CHIPS_MIL;
-
        /* For each floor, find the number of valid chips it contains */
        for (floor = 0; floor < MAX_FLOORS; floor++) {
                ret = 1;
@@ -517,6 +534,7 @@ static void DoC2k_init(struct mtd_info *mtd)
 {
        struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        struct DiskOnChip *old = NULL;
+       int maxchips;
 
        /* We must avoid being called twice for the same device. */
 
@@ -540,14 +558,28 @@ static void DoC2k_init(struct mtd_info *mtd)
 
 
        switch (this->ChipID) {
+       case DOC_ChipID_Doc2kTSOP:
+               mtd->name = "DiskOnChip 2000 TSOP";
+               this->ioreg = DoC_Mil_CDSN_IO;
+               /* Pretend it's a Millennium */
+               this->ChipID = DOC_ChipID_DocMil;
+               maxchips = MAX_CHIPS;
+               break;
        case DOC_ChipID_Doc2k:
                mtd->name = "DiskOnChip 2000";
                this->ioreg = DoC_2k_CDSN_IO;
+               maxchips = MAX_CHIPS;
                break;
        case DOC_ChipID_DocMil:
                mtd->name = "DiskOnChip Millennium";
                this->ioreg = DoC_Mil_CDSN_IO;
+               maxchips = MAX_CHIPS_MIL;
                break;
+       default:
+               printk("Unknown ChipID 0x%02x\n", this->ChipID);
+               kfree(mtd);
+               iounmap((void *) this->virtadr);
+               return;
        }
 
        printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name,
@@ -568,6 +600,7 @@ static void DoC2k_init(struct mtd_info *mtd)
        mtd->write = doc_write;
        mtd->read_ecc = doc_read_ecc;
        mtd->write_ecc = doc_write_ecc;
+       mtd->writev_ecc = doc_writev_ecc;
        mtd->read_oob = doc_read_oob;
        mtd->write_oob = doc_write_oob;
        mtd->sync = NULL;
@@ -580,7 +613,7 @@ static void DoC2k_init(struct mtd_info *mtd)
        init_MUTEX(&this->lock);
 
        /* Ident all the chips present. */
-       DoC_ScanChips(this);
+       DoC_ScanChips(this, maxchips);
 
        if (!this->totlen) {
                kfree(mtd);
@@ -599,12 +632,11 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
                    size_t * retlen, u_char * buf)
 {
        /* Just a special case of doc_read_ecc */
-       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t * retlen, u_char * buf, u_char * eccbuf,
-                       struct nand_oobinfo *unused)
+                       size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
 {
        struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        unsigned long docptr;
@@ -612,6 +644,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
        unsigned char syndrome[6];
        volatile char dummy;
        int i, len256 = 0, ret=0;
+       size_t left = len;
 
        docptr = this->virtadr;
 
@@ -621,122 +654,131 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
 
        down(&this->lock);
 
-       /* Don't allow a single read to cross a 512-byte block boundary */
-       if (from + len > ((from | 0x1ff) + 1))
-               len = ((from | 0x1ff) + 1) - from;
-
-       /* The ECC will not be calculated correctly if less than 512 is read */
-       if (len != 0x200 && eccbuf)
-               printk(KERN_WARNING
-                      "ECC needs a full sector read (adr: %lx size %lx)\n",
-                      (long) from, (long) len);
-
-       /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
+       *retlen = 0;
+       while (left) {
+               len = left;
 
+               /* Don't allow a single read to cross a 512-byte block boundary */
+               if (from + len > ((from | 0x1ff) + 1))
+                       len = ((from | 0x1ff) + 1) - from;
 
-       /* Find the chip which is to be used and select it */
-       mychip = &this->chips[from >> (this->chipshift)];
+               /* The ECC will not be calculated correctly if less than 512 is read */
+               if (len != 0x200 && eccbuf)
+                       printk(KERN_WARNING
+                              "ECC needs a full sector read (adr: %lx size %lx)\n",
+                              (long) from, (long) len);
 
-       if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(this, mychip->floor);
-               DoC_SelectChip(this, mychip->chip);
-       } else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(this, mychip->chip);
-       }
+               /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
 
-       this->curfloor = mychip->floor;
-       this->curchip = mychip->chip;
 
-       DoC_Command(this,
-                   (!this->page256
-                    && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
-                   CDSN_CTRL_WP);
-       DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
-                   CDSN_CTRL_ECC_IO);
-
-       if (eccbuf) {
-               /* Prime the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC(DOC_ECC_EN, docptr, ECCConf);
-       } else {
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-       }
+               /* Find the chip which is to be used and select it */
+               mychip = &this->chips[from >> (this->chipshift)];
 
-       /* treat crossing 256-byte sector for 2M x 8bits devices */
-       if (this->page256 && from + len > (from | 0xff) + 1) {
-               len256 = (from | 0xff) + 1 - from;
-               DoC_ReadBuf(this, buf, len256);
+               if (this->curfloor != mychip->floor) {
+                       DoC_SelectFloor(this, mychip->floor);
+                       DoC_SelectChip(this, mychip->chip);
+               } else if (this->curchip != mychip->chip) {
+                       DoC_SelectChip(this, mychip->chip);
+               }
 
-               DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
-               DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
-                           CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
-       }
+               this->curfloor = mychip->floor;
+               this->curchip = mychip->chip;
 
-       DoC_ReadBuf(this, &buf[len256], len - len256);
+               DoC_Command(this,
+                           (!this->page256
+                            && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+                           CDSN_CTRL_WP);
+               DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
+                           CDSN_CTRL_ECC_IO);
 
-       /* Let the caller know we completed it */
-       *retlen = len;
+               if (eccbuf) {
+                       /* Prime the ECC engine */
+                       WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+                       WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+               } else {
+                       /* disable the ECC engine */
+                       WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+                       WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+               }
 
-       if (eccbuf) {
-               /* Read the ECC data through the DiskOnChip ECC logic */
-               /* Note: this will work even with 2M x 8bit devices as   */
-               /*       they have 8 bytes of OOB per 256 page. mf.      */
-               DoC_ReadBuf(this, eccbuf, 6);
+               /* treat crossing 256-byte sector for 2M x 8bits devices */
+               if (this->page256 && from + len > (from | 0xff) + 1) {
+                       len256 = (from | 0xff) + 1 - from;
+                       DoC_ReadBuf(this, buf, len256);
 
-               /* Flush the pipeline */
-               if (DoC_is_Millennium(this)) {
-                       dummy = ReadDOC(docptr, ECCConf);
-                       dummy = ReadDOC(docptr, ECCConf);
-                       i = ReadDOC(docptr, ECCConf);
-               } else {
-                       dummy = ReadDOC(docptr, 2k_ECCStatus);
-                       dummy = ReadDOC(docptr, 2k_ECCStatus);
-                       i = ReadDOC(docptr, 2k_ECCStatus);
+                       DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+                       DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+                                   CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
                }
 
-               /* Check the ECC Status */
-               if (i & 0x80) {
-                       int nb_errors;
-                       /* There was an ECC error */
+               DoC_ReadBuf(this, &buf[len256], len - len256);
+
+               /* Let the caller know we completed it */
+               *retlen += len;
+
+               if (eccbuf) {
+                       /* Read the ECC data through the DiskOnChip ECC logic */
+                       /* Note: this will work even with 2M x 8bit devices as   */
+                       /*       they have 8 bytes of OOB per 256 page. mf.      */
+                       DoC_ReadBuf(this, eccbuf, 6);
+
+                       /* Flush the pipeline */
+                       if (DoC_is_Millennium(this)) {
+                               dummy = ReadDOC(docptr, ECCConf);
+                               dummy = ReadDOC(docptr, ECCConf);
+                               i = ReadDOC(docptr, ECCConf);
+                       } else {
+                               dummy = ReadDOC(docptr, 2k_ECCStatus);
+                               dummy = ReadDOC(docptr, 2k_ECCStatus);
+                               i = ReadDOC(docptr, 2k_ECCStatus);
+                       }
+
+                       /* Check the ECC Status */
+                       if (i & 0x80) {
+                               int nb_errors;
+                               /* There was an ECC error */
 #ifdef ECC_DEBUG
-                       printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
+                               printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
 #endif
-                       /* Read the ECC syndrom through the DiskOnChip ECC logic.
-                          These syndrome will be all ZERO when there is no error */
-                       for (i = 0; i < 6; i++) {
-                               syndrome[i] =
-                                   ReadDOC(docptr, ECCSyndrome0 + i);
-                       }
-                        nb_errors = doc_decode_ecc(buf, syndrome);
+                               /* Read the ECC syndrom through the DiskOnChip ECC logic.
+                                  These syndrome will be all ZERO when there is no error */
+                               for (i = 0; i < 6; i++) {
+                                       syndrome[i] =
+                                           ReadDOC(docptr, ECCSyndrome0 + i);
+                               }
+                               nb_errors = doc_decode_ecc(buf, syndrome);
 
 #ifdef ECC_DEBUG
-                       printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
+                               printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
 #endif
-                        if (nb_errors < 0) {
-                               /* We return error, but have actually done the read. Not that
-                                  this can be told to user-space, via sys_read(), but at least
-                                  MTD-aware stuff can know about it by checking *retlen */
-                               ret = -EIO;
-                        }
-               }
+                               if (nb_errors < 0) {
+                                       /* We return error, but have actually done the read. Not that
+                                          this can be told to user-space, via sys_read(), but at least
+                                          MTD-aware stuff can know about it by checking *retlen */
+                                       ret = -EIO;
+                               }
+                       }
 
 #ifdef PSYCHO_DEBUG
-               printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                            (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
-                            eccbuf[3], eccbuf[4], eccbuf[5]);
+                       printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                                    (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+                                    eccbuf[3], eccbuf[4], eccbuf[5]);
 #endif
                
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
-       }
+                       /* disable the ECC engine */
+                       WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+               }
 
-       /* according to 11.4.1, we need to wait for the busy line 
-         * drop if we read to the end of the page.  */
-       if(0 == ((from + *retlen) & 0x1ff))
-       {
-           DoC_WaitReady(this);
+               /* according to 11.4.1, we need to wait for the busy line 
+                * drop if we read to the end of the page.  */
+               if(0 == ((from + len) & 0x1ff))
+               {
+                   DoC_WaitReady(this);
+               }
+
+               from += len;
+               left -= len;
+               buf += len;
        }
 
        up(&this->lock);
@@ -748,13 +790,12 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                     size_t * retlen, const u_char * buf)
 {
        char eccbuf[6];
-       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
+       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
                         size_t * retlen, const u_char * buf,
-                        u_char * eccbuf,
-                        struct nand_oobinfo *unused)
+                        u_char * eccbuf, struct nand_oobinfo *oobsel)
 {
        struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
@@ -762,6 +803,8 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
        volatile char dummy;
        int len256 = 0;
        struct Nand *mychip;
+       size_t left = len;
+       int status;
 
        docptr = this->virtadr;
 
@@ -771,65 +814,133 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
 
        down(&this->lock);
 
-       /* Don't allow a single write to cross a 512-byte block boundary */
-       if (to + len > ((to | 0x1ff) + 1))
-               len = ((to | 0x1ff) + 1) - to;
+       *retlen = 0;
+       while (left) {
+               len = left;
 
-       /* The ECC will not be calculated correctly if less than 512 is written */
-       if (len != 0x200 && eccbuf)
-               printk(KERN_WARNING
-                      "ECC needs a full sector write (adr: %lx size %lx)\n",
-                      (long) to, (long) len);
+               /* Don't allow a single write to cross a 512-byte block boundary */
+               if (to + len > ((to | 0x1ff) + 1))
+                       len = ((to | 0x1ff) + 1) - to;
 
-       /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
+               /* The ECC will not be calculated correctly if less than 512 is written */
+/* DBB-
+               if (len != 0x200 && eccbuf)
+                       printk(KERN_WARNING
+                              "ECC needs a full sector write (adr: %lx size %lx)\n",
+                              (long) to, (long) len);
+   -DBB */
 
-       /* Find the chip which is to be used and select it */
-       mychip = &this->chips[to >> (this->chipshift)];
+               /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
 
-       if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(this, mychip->floor);
-               DoC_SelectChip(this, mychip->chip);
-       } else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(this, mychip->chip);
-       }
+               /* Find the chip which is to be used and select it */
+               mychip = &this->chips[to >> (this->chipshift)];
 
-       this->curfloor = mychip->floor;
-       this->curchip = mychip->chip;
+               if (this->curfloor != mychip->floor) {
+                       DoC_SelectFloor(this, mychip->floor);
+                       DoC_SelectChip(this, mychip->chip);
+               } else if (this->curchip != mychip->chip) {
+                       DoC_SelectChip(this, mychip->chip);
+               }
 
-       /* Set device to main plane of flash */
-       DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
-       DoC_Command(this,
-                   (!this->page256
-                    && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
-                   CDSN_CTRL_WP);
+               this->curfloor = mychip->floor;
+               this->curchip = mychip->chip;
 
-       DoC_Command(this, NAND_CMD_SEQIN, 0);
-       DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
+               /* Set device to main plane of flash */
+               DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+               DoC_Command(this,
+                           (!this->page256
+                            && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+                           CDSN_CTRL_WP);
 
-       if (eccbuf) {
-               /* Prime the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
-       } else {
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-       }
+               DoC_Command(this, NAND_CMD_SEQIN, 0);
+               DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
 
-       /* treat crossing 256-byte sector for 2M x 8bits devices */
-       if (this->page256 && to + len > (to | 0xff) + 1) {
-               len256 = (to | 0xff) + 1 - to;
-               DoC_WriteBuf(this, buf, len256);
+               if (eccbuf) {
+                       /* Prime the ECC engine */
+                       WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+                       WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+               } else {
+                       /* disable the ECC engine */
+                       WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+                       WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+               }
+
+               /* treat crossing 256-byte sector for 2M x 8bits devices */
+               if (this->page256 && to + len > (to | 0xff) + 1) {
+                       len256 = (to | 0xff) + 1 - to;
+                       DoC_WriteBuf(this, buf, len256);
+
+                       DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+                       DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+                       /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+                       dummy = ReadDOC(docptr, CDSNSlowIO);
+                       DoC_Delay(this, 2);
+
+                       if (ReadDOC_(docptr, this->ioreg) & 1) {
+                               printk(KERN_ERR "Error programming flash\n");
+                               /* Error in programming */
+                               *retlen = 0;
+                               up(&this->lock);
+                               return -EIO;
+                       }
+
+                       DoC_Command(this, NAND_CMD_SEQIN, 0);
+                       DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
+                                   CDSN_CTRL_ECC_IO);
+               }
+
+               DoC_WriteBuf(this, &buf[len256], len - len256);
+
+               if (eccbuf) {
+                       WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
+                                CDSNControl);
+
+                       if (DoC_is_Millennium(this)) {
+                               WriteDOC(0, docptr, NOP);
+                               WriteDOC(0, docptr, NOP);
+                               WriteDOC(0, docptr, NOP);
+                       } else {
+                               WriteDOC_(0, docptr, this->ioreg);
+                               WriteDOC_(0, docptr, this->ioreg);
+                               WriteDOC_(0, docptr, this->ioreg);
+                       }
+
+                       WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
+                                CDSNControl);
+
+                       /* Read the ECC data through the DiskOnChip ECC logic */
+                       for (di = 0; di < 6; di++) {
+                               eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+                       }
+
+                       /* Reset the ECC engine */
+                       WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+
+#ifdef PSYCHO_DEBUG
+                       printk
+                           ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                            (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+                            eccbuf[4], eccbuf[5]);
+#endif
+               }
 
                DoC_Command(this, NAND_CMD_PAGEPROG, 0);
 
                DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
                /* There's an implicit DoC_WaitReady() in DoC_Command */
 
-               dummy = ReadDOC(docptr, CDSNSlowIO);
-               DoC_Delay(this, 2);
+               if (DoC_is_Millennium(this)) {
+                       ReadDOC(docptr, ReadPipeInit);
+                       status = ReadDOC(docptr, LastDataRead);
+               } else {
+                       dummy = ReadDOC(docptr, CDSNSlowIO);
+                       DoC_Delay(this, 2);
+                       status = ReadDOC_(docptr, this->ioreg);
+               }
 
-               if (ReadDOC_(docptr, this->ioreg) & 1) {
+               if (status & 1) {
                        printk(KERN_ERR "Error programming flash\n");
                        /* Error in programming */
                        *retlen = 0;
@@ -837,82 +948,97 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
                        return -EIO;
                }
 
-               DoC_Command(this, NAND_CMD_SEQIN, 0);
-               DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
-                           CDSN_CTRL_ECC_IO);
+               /* Let the caller know we completed it */
+               *retlen += len;
+               
+               if (eccbuf) {
+                       unsigned char x[8];
+                       size_t dummy;
+                       int ret;
+
+                       /* Write the ECC data to flash */
+                       for (di=0; di<6; di++)
+                               x[di] = eccbuf[di];
+               
+                       x[6]=0x55;
+                       x[7]=0x55;
+               
+                       ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
+                       if (ret) {
+                               up(&this->lock);
+                               return ret;
+                       }
+               }
+
+               to += len;
+               left -= len;
+               buf += len;
        }
 
-       DoC_WriteBuf(this, &buf[len256], len - len256);
+       up(&this->lock);
+       return 0;
+}
 
-       if (eccbuf) {
-               WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
-                        CDSNControl);
+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs, 
+                         unsigned long count, loff_t to, size_t *retlen,
+                         u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+       static char static_buf[512];
+       static DECLARE_MUTEX(writev_buf_sem);
 
-               if (DoC_is_Millennium(this)) {
-                       WriteDOC(0, docptr, NOP);
-                       WriteDOC(0, docptr, NOP);
-                       WriteDOC(0, docptr, NOP);
-               } else {
-                       WriteDOC_(0, docptr, this->ioreg);
-                       WriteDOC_(0, docptr, this->ioreg);
-                       WriteDOC_(0, docptr, this->ioreg);
-               }
+       size_t totretlen = 0;
+       size_t thisvecofs = 0;
+       int ret= 0;
 
-               /* Read the ECC data through the DiskOnChip ECC logic */
-               for (di = 0; di < 6; di++) {
-                       eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
-               }
+       down(&writev_buf_sem);
 
-               /* Reset the ECC engine */
-               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+       while(count) {
+               size_t thislen, thisretlen;
+               unsigned char *buf;
 
-#ifdef PSYCHO_DEBUG
-               printk
-                   ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                    (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-                    eccbuf[4], eccbuf[5]);
-#endif
-       }
+               buf = vecs->iov_base + thisvecofs;
+               thislen = vecs->iov_len - thisvecofs;
 
-       DoC_Command(this, NAND_CMD_PAGEPROG, 0);
 
-       DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
-       /* There's an implicit DoC_WaitReady() in DoC_Command */
+               if (thislen >= 512) {
+                       thislen = thislen & ~(512-1);
+                       thisvecofs += thislen;
+               } else {
+                       /* Not enough to fill a page. Copy into buf */
+                       memcpy(static_buf, buf, thislen);
+                       buf = &static_buf[thislen];
+
+                       while(count && thislen < 512) {
+                               vecs++;
+                               count--;
+                               thisvecofs = min((512-thislen), vecs->iov_len);
+                               memcpy(buf, vecs->iov_base, thisvecofs);
+                               thislen += thisvecofs;
+                               buf += thisvecofs;
+                       }
+                       buf = static_buf;
+               }
+               if (count && thisvecofs == vecs->iov_len) {
+                       thisvecofs = 0;
+                       vecs++;
+                       count--;
+               }
+               ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel);
 
-       dummy = ReadDOC(docptr, CDSNSlowIO);
-       DoC_Delay(this, 2);
+               totretlen += thisretlen;
 
-       if (ReadDOC_(docptr, this->ioreg) & 1) {
-               printk(KERN_ERR "Error programming flash\n");
-               /* Error in programming */
-               *retlen = 0;
-               up(&this->lock);
-               return -EIO;
-       }
+               if (ret || thisretlen != thislen)
+                       break;
 
-       /* Let the caller know we completed it */
-       *retlen = len;
-               
-       if (eccbuf) {
-               unsigned char x[8];
-               size_t dummy;
-               int ret;
-
-               /* Write the ECC data to flash */
-               for (di=0; di<6; di++)
-                       x[di] = eccbuf[di];
-               
-               x[6]=0x55;
-               x[7]=0x55;
-               
-               ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
-               up(&this->lock);
-               return ret;
-       }
-       up(&this->lock);
-       return 0;
+               to += thislen;
+       }               
+
+       up(&writev_buf_sem);
+       *retlen = totretlen;
+       return ret;
 }
 
+
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        size_t * retlen, u_char * buf)
 {
@@ -982,6 +1108,7 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
        unsigned long docptr = this->virtadr;
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
        volatile int dummy;
+       int status;
 
        //      printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
        //   buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
@@ -1030,10 +1157,16 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
                DoC_Command(this, NAND_CMD_STATUS, 0);
                /* DoC_WaitReady() is implicit in DoC_Command */
 
-               dummy = ReadDOC(docptr, CDSNSlowIO);
-               DoC_Delay(this, 2);
+               if (DoC_is_Millennium(this)) {
+                       ReadDOC(docptr, ReadPipeInit);
+                       status = ReadDOC(docptr, LastDataRead);
+               } else {
+                       dummy = ReadDOC(docptr, CDSNSlowIO);
+                       DoC_Delay(this, 2);
+                       status = ReadDOC_(docptr, this->ioreg);
+               }
 
-               if (ReadDOC_(docptr, this->ioreg) & 1) {
+               if (status & 1) {
                        printk(KERN_ERR "Error programming oob data\n");
                        /* There was an error */
                        *retlen = 0;
@@ -1049,10 +1182,16 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
        DoC_Command(this, NAND_CMD_STATUS, 0);
        /* DoC_WaitReady() is implicit in DoC_Command */
 
-       dummy = ReadDOC(docptr, CDSNSlowIO);
-       DoC_Delay(this, 2);
+       if (DoC_is_Millennium(this)) {
+               ReadDOC(docptr, ReadPipeInit);
+               status = ReadDOC(docptr, LastDataRead);
+       } else {
+               dummy = ReadDOC(docptr, CDSNSlowIO);
+               DoC_Delay(this, 2);
+               status = ReadDOC_(docptr, this->ioreg);
+       }
 
-       if (ReadDOC_(docptr, this->ioreg) & 1) {
+       if (status & 1) {
                printk(KERN_ERR "Error programming oob data\n");
                /* There was an error */
                *retlen = 0;
@@ -1085,6 +1224,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
        volatile int dummy;
        unsigned long docptr;
        struct Nand *mychip;
+       int status;
 
        down(&this->lock);
 
@@ -1116,10 +1256,16 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
 
                DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
 
-               dummy = ReadDOC(docptr, CDSNSlowIO);
-               DoC_Delay(this, 2);
-               
-               if (ReadDOC_(docptr, this->ioreg) & 1) {
+               if (DoC_is_Millennium(this)) {
+                       ReadDOC(docptr, ReadPipeInit);
+                       status = ReadDOC(docptr, LastDataRead);
+               } else {
+                       dummy = ReadDOC(docptr, CDSNSlowIO);
+                       DoC_Delay(this, 2);
+                       status = ReadDOC_(docptr, this->ioreg);
+               }
+
+               if (status & 1) {
                        printk(KERN_ERR "Error erasing at 0x%x\n", ofs);
                        /* There was an error */
                        instr->state = MTD_ERASE_FAILED;
index 6d5d821..77ed2c4 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001.c,v 1.41 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2001.c,v 1.42 2004/04/04 12:36:45 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -37,12 +38,9 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *unused);
+                       size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-                        size_t *retlen, const u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *unused);
-
+                        size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -229,7 +227,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                               mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
                        doc->mfr = mfr;
                        doc->id = id;
-                       doc->chipshift = nand_flash_ids[i].chipshift;
+                       doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
                        break;
                }
        }
@@ -406,12 +404,11 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
                     size_t *retlen, u_char *buf)
 {
        /* Just a special case of doc_read_ecc */
-       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-                        size_t *retlen, u_char *buf, u_char *eccbuf,
-                        struct nand_oobinfo *unused)
+                        size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
 {
        int i, ret;
        volatile char dummy;
@@ -533,12 +530,11 @@ static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
                      size_t *retlen, const u_char *buf)
 {
        char eccbuf[6];
-       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
+       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-                         size_t *retlen, const u_char *buf, u_char *eccbuf,
-                         struct nand_oobinfo *unused)
+                         size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel)
 {
        int i,ret = 0;
        volatile char dummy;
index e5e5fda..da4275c 100644 (file)
@@ -6,7 +6,9 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001plus.c,v 1.5 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2001plus.c,v 1.8 2004/04/04 12:36:45 gleixner Exp $
+ *
+ * Released under GPL
  */
 
 #include <linux/kernel.h>
@@ -21,6 +23,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -183,24 +186,35 @@ static int DoC_SelectFloor(unsigned long docptr, int floor)
  *  | Data 0    | ECC 0 |Flags0 |Flags1 | Data 1       |ECC 1    | OOB 1 + 2 |
  *  +-----------+-------+-------+-------+--------------+---------+-----------+
  */
+/* FIXME: This lives in INFTL not here. Other users of flash devices
+   may not want it */
 static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from)
 {
-       unsigned int ofs = *from & 0x3ff;
-       unsigned int cmd;
+       struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
 
-       if (ofs < 512) {
-               cmd = NAND_CMD_READ0;
-               ofs &= 0x1ff;
-       } else if (ofs < 1014) {
-               cmd = NAND_CMD_READ1;
-               ofs = (ofs & 0x1ff) + 10;
+       if (this->interleave) {
+               unsigned int ofs = *from & 0x3ff;
+               unsigned int cmd;
+
+               if (ofs < 512) {
+                       cmd = NAND_CMD_READ0;
+                       ofs &= 0x1ff;
+               } else if (ofs < 1014) {
+                       cmd = NAND_CMD_READ1;
+                       ofs = (ofs & 0x1ff) + 10;
+               } else {
+                       cmd = NAND_CMD_READOOB;
+                       ofs = ofs - 1014;
+               }
+
+               *from = (*from & ~0x3ff) | ofs;
+               return cmd;
        } else {
-               cmd = NAND_CMD_READOOB;
-               ofs = ofs - 1014;
+               /* No interleave */
+               if ((*from) & 0x100)
+                       return NAND_CMD_READ1;
+               return NAND_CMD_READ0;
        }
-
-       *from = (*from & ~0x3ff) | ofs;
-       return cmd;
 }
 
 static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from)
@@ -294,10 +308,12 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
        dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
 
        mfr = ReadDOC(docptr, Mil_CDSN_IO);
-       dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
+       if (doc->interleave)
+               dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
 
        id  = ReadDOC(docptr, Mil_CDSN_IO);
-       dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
+       if (doc->interleave)
+               dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
 
        dummy = ReadDOC(docptr, Mplus_LastDataRead);
        dummy = ReadDOC(docptr, Mplus_LastDataRead);
@@ -321,10 +337,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                               nand_manuf_ids[j].name, nand_flash_ids[i].name);
                        doc->mfr = mfr;
                        doc->id = id;
-                       doc->interleave = 0;
-                       if (doc->ChipID == DOC_ChipID_DocMilPlus32)
-                               doc->interleave = 1;
-                       doc->chipshift = nand_flash_ids[i].chipshift;
+                       doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
                        doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave;
                        break;
                }
@@ -346,6 +359,21 @@ static void DoC_ScanChips(struct DiskOnChip *this)
        this->mfr = 0;
        this->id = 0;
 
+       /* Work out the intended interleave setting */
+       this->interleave = 0;
+       if (this->ChipID == DOC_ChipID_DocMilPlus32)
+               this->interleave = 1;
+
+       /* Check the ASIC agrees */
+       if ( (this->interleave << 2) != 
+            (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) {
+               u_char conf = ReadDOC(this->virtadr, Mplus_Configuration);
+               printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n",
+                      this->interleave?"on (16-bit)":"off (8-bit)");
+               conf ^= 4;
+               WriteDOC(this->virtadr, conf, Mplus_Configuration);
+       }
+
        /* For each floor, find the number of valid chips it contains */
        for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) {
                numchips[floor] = 0;
@@ -739,7 +767,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
                return -EINVAL;
 
        /* Determine position of OOB flags, before or after data */
-       before = to & 0x200;
+       before = (this->interleave && (to & 0x200));
 
        DoC_CheckASIC(docptr);
 
@@ -886,7 +914,10 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                /* Figure out which region we are accessing... */
                fofs = ofs;
                base = ofs & 0xf;
-               if (base < 6) {
+               if (!this->interleave) {
+                       DoC_Command(docptr, NAND_CMD_READOOB, 0);
+                       size = 16 - base;
+               } else if (base < 6) {
                        DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0);
                        size = 6 - base;
                } else if (base < 8) {
@@ -963,7 +994,10 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                /* Figure out which region we are accessing... */
                fofs = ofs;
                base = ofs & 0x0f;
-               if (base < 6) {
+               if (!this->interleave) {
+                       WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd);
+                       size = 16 - base;
+               } else if (base < 6) {
                        WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
                        size = 6 - base;
                } else if (base < 8) {
index f7a91fa..cb8b8a5 100644 (file)
@@ -4,7 +4,7 @@
 /* (C) 1999 Machine Vision Holdings, Inc.                      */
 /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>         */
 
-/* $Id: docprobe.c,v 1.36 2003/05/23 11:29:34 dwmw2 Exp $      */
+/* $Id: docprobe.c,v 1.41 2003/12/03 10:19:57 dwmw2 Exp $      */
 
 
 
@@ -135,6 +135,9 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
                 window, DOCControl);
 #endif /* !DOC_PASSIVE_PROBE */        
 
+       /* We need to read the ChipID register four times. For some
+          newer DiskOnChip 2000 units, the first three reads will
+          return the DiskOnChip Millennium ident. Don't ask. */
        ChipID = ReadDOC(window, ChipID);
   
        switch (ChipID) {
@@ -148,6 +151,12 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
                break;
                
        case DOC_ChipID_DocMil:
+               /* Check for the new 2000 with Millennium ASIC */
+               ReadDOC(window, ChipID);
+               ReadDOC(window, ChipID);
+               if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
+                       ChipID = DOC_ChipID_Doc2kTSOP;
+
                /* Check the TOGGLE bit in the ECC register */
                tmp  = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
                tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
@@ -191,7 +200,6 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
                        tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
                        if (tmp != tmpb && tmp == tmpc)
                                        return ChipID;
-                       break;
                default:
                        break;
                }
@@ -199,8 +207,8 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
 
        default:
 
-#ifndef CONFIG_MTD_DOCPROBE_55AA
-               printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+#ifdef CONFIG_MTD_DOCPROBE_55AA
+               printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
                       ChipID, physadr);
 #endif
 #ifndef DOC_PASSIVE_PROBE
@@ -241,6 +249,12 @@ static void __init DoC_Probe(unsigned long physadr)
                return;
        
        if ((ChipID = doccheck(docptr, physadr))) {
+               if (ChipID == DOC_ChipID_Doc2kTSOP) {
+                       /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
+                       printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
+                       iounmap((void *)docptr);
+                       return;
+               }
                docfound = 1;
                mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
 
@@ -262,6 +276,12 @@ static void __init DoC_Probe(unsigned long physadr)
                sprintf(namebuf, "with ChipID %2.2X", ChipID);
 
                switch(ChipID) {
+               case DOC_ChipID_Doc2kTSOP:
+                       name="2000 TSOP";
+                       im_funcname = "DoC2k_init";
+                       im_modname = "doc2000";
+                       break;
+                       
                case DOC_ChipID_Doc2k:
                        name="2000";
                        im_funcname = "DoC2k_init";
index f60195e..d67ca4c 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
  *
- * $Id: lart.c,v 1.5 2003/05/20 21:03:07 dwmw2 Exp $
+ * $Id: lart.c,v 1.6 2004/07/14 17:21:38 dwmw2 Exp $
  *
  * Author: Abraham vd Merwe <abraham@2d3d.co.za>
  *
index e7f49a5..3a331aa 100644 (file)
@@ -1,12 +1,12 @@
 /*
- *      Copyright (c) 2001 Maciej W. Rozycki
+ *     Copyright (c) 2001 Maciej W. Rozycki
  *
- *      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 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.
  *
- *     $Id: ms02-nv.c,v 1.4 2003/05/20 21:03:07 dwmw2 Exp $
+ *     $Id: ms02-nv.c,v 1.6 2003/08/19 09:25:36 dwmw2 Exp $
  */
 
 #include <linux/init.h>
@@ -29,7 +29,7 @@
 
 
 static char version[] __initdata =
-        "ms02-nv.c: v.1.0.0  13 Aug 2001  Maciej W. Rozycki.\n";
+       "ms02-nv.c: v.1.0.0  13 Aug 2001  Maciej W. Rozycki.\n";
 
 MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>");
 MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
@@ -38,9 +38,9 @@ MODULE_LICENSE("GPL");
 
 /*
  * Addresses we probe for an MS02-NV at.  Modules may be located
- * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB
- * boundary within a 0MB up to 448MB range.  We don't support a module
- * at 0MB, though.
+ * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB
+ * boundary within a 0MiB up to 448MiB range.  We don't support a module
+ * at 0MiB, though.
  */
 static ulong ms02nv_addrs[] __initdata = {
        0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
@@ -130,7 +130,7 @@ static int __init ms02nv_init_one(ulong addr)
 
        int ret = -ENODEV;
 
-       /* The module decodes 8MB of address space. */
+       /* The module decodes 8MiB of address space. */
        mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
        if (!mod_res)
                return -ENOMEM;
@@ -233,7 +233,7 @@ static int __init ms02nv_init_one(ulong addr)
                goto err_out_csr_res;
        }
 
-       printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n",
+       printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n",
                mtd->index, ms02nv_name, addr, size >> 20);
 
        mp->next = root_ms02nv_mtd;
@@ -293,12 +293,12 @@ static int __init ms02nv_init(void)
 
        switch (mips_machtype) {
        case MACH_DS5000_200:
-               csr = (volatile u32 *)KN02_CSR_ADDR;
+               csr = (volatile u32 *)KN02_CSR_BASE;
                if (*csr & KN02_CSR_BNK32M)
                        stride = 2;
                break;
        case MACH_DS5000_2X0:
-       case MACH_DS5000:
+       case MACH_DS5900:
                csr = (volatile u32 *)KN03_MCR_BASE;
                if (*csr & KN03_MCR_BNK32M)
                        stride = 2;
index fb1ec10..8a6eef7 100644 (file)
@@ -1,34 +1,96 @@
 /*
- *      Copyright (c) 2001 Maciej W. Rozycki
+ *     Copyright (c) 2001, 2003  Maciej W. Rozycki
  *
- *      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.
+ *     DEC MS02-NV (54-20948-01) battery backed-up NVRAM module for
+ *     DECstation/DECsystem 5000/2x0 and DECsystem 5900 and 5900/260
+ *     systems.
  *
- *     $Id: ms02-nv.h,v 1.1 2002/09/13 13:46:55 dwmw2 Exp $
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     $Id: ms02-nv.h,v 1.3 2003/08/19 09:25:36 dwmw2 Exp $
  */
 
 #include <linux/ioport.h>
 #include <linux/mtd/mtd.h>
 
+/*
+ * Addresses are decoded as follows:
+ *
+ * 0x000000 - 0x3fffff SRAM
+ * 0x400000 - 0x7fffff CSR
+ *
+ * Within the SRAM area the following ranges are forced by the system
+ * firmware:
+ *
+ * 0x000000 - 0x0003ff diagnostic area, destroyed upon a reboot
+ * 0x000400 - ENDofRAM storage area, available to operating systems
+ *
+ * but we can't really use the available area right from 0x000400 as
+ * the first word is used by the firmware as a status flag passed
+ * from an operating system.  If anything but the valid data magic
+ * ID value is found, the firmware considers the SRAM clean, i.e.
+ * containing no valid data, and disables the battery resulting in
+ * data being erased as soon as power is switched off.  So the choice
+ * for the start address of the user-available is 0x001000 which is
+ * nicely page aligned.  The area between 0x000404 and 0x000fff may
+ * be used by the driver for own needs.
+ *
+ * The diagnostic area defines two status words to be read by an
+ * operating system, a magic ID to distinguish a MS02-NV board from
+ * anything else and a status information providing results of tests
+ * as well as the size of SRAM available, which can be 1MiB or 2MiB
+ * (that's what the firmware handles; no idea if 2MiB modules ever
+ * existed).
+ *
+ * The firmware only handles the MS02-NV board if installed in the
+ * last (15th) slot, so for any other location the status information
+ * stored in the SRAM cannot be relied upon.  But from the hardware
+ * point of view there is no problem using up to 14 such boards in a
+ * system -- only the 1st slot needs to be filled with a DRAM module.
+ * The MS02-NV board is ECC-protected, like other MS02 memory boards.
+ *
+ * The state of the battery as provided by the CSR is reflected on
+ * the two onboard LEDs.  When facing the battery side of the board,
+ * with the LEDs at the top left and the battery at the bottom right
+ * (i.e. looking from the back side of the system box), their meaning
+ * is as follows (the system has to be powered on):
+ *
+ * left LED            battery disable status: lit = enabled
+ * right LED           battery condition status: lit = OK
+ */
+
 /* MS02-NV iomem register offsets. */
 #define MS02NV_CSR             0x400000        /* control & status register */
 
+/* MS02-NV CSR status bits. */
+#define MS02NV_CSR_BATT_OK     0x01            /* battery OK */
+#define MS02NV_CSR_BATT_OFF    0x02            /* battery disabled */
+
+
 /* MS02-NV memory offsets. */
 #define MS02NV_DIAG            0x0003f8        /* diagnostic status */
 #define MS02NV_MAGIC           0x0003fc        /* MS02-NV magic ID */
-#define MS02NV_RAM             0x000400        /* general-purpose RAM start */
+#define MS02NV_VALID           0x000400        /* valid data magic ID */
+#define MS02NV_RAM             0x001000        /* user-exposed RAM start */
 
-/* MS02-NV diagnostic status constants. */
-#define MS02NV_DIAG_SIZE_MASK  0xf0            /* RAM size mask */
-#define MS02NV_DIAG_SIZE_SHIFT 0x10            /* RAM size shift (left) */
+/* MS02-NV diagnostic status bits. */
+#define MS02NV_DIAG_TEST       0x01            /* SRAM test done (?) */
+#define MS02NV_DIAG_RO         0x02            /* SRAM r/o test done */
+#define MS02NV_DIAG_RW         0x04            /* SRAM r/w test done */
+#define MS02NV_DIAG_FAIL       0x08            /* SRAM test failed */
+#define MS02NV_DIAG_SIZE_MASK  0xf0            /* SRAM size mask */
+#define MS02NV_DIAG_SIZE_SHIFT 0x10            /* SRAM size shift (left) */
 
 /* MS02-NV general constants. */
 #define MS02NV_ID              0x03021966      /* MS02-NV magic ID value */
+#define MS02NV_VALID_ID                0xbd100248      /* valid data magic ID value */
 #define MS02NV_SLOT_SIZE       0x800000        /* size of the address space
                                                   decoded by the module */
 
+
 typedef volatile u32 ms02nv_uint;
 
 struct ms02nv_private {
index 1430885..80d4287 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.c,v 1.24 2003/05/20 21:03:08 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.26 2004/07/14 17:25:07 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
index 4e2d14c..b9892ac 100644 (file)
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -1093,7 +1093,7 @@ struct mtd_blktrans_ops ftl_tr = {
 
 int init_ftl(void)
 {
-       DEBUG(0, "$Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $\n");
+       DEBUG(0, "$Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $\n");
 
        return register_mtd_blktrans(&ftl_tr);
 }
index 2417fba..bc7e2bf 100644 (file)
@@ -7,7 +7,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * Author: David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: inftlcore.c,v 1.14 2003/06/26 08:28:26 dwmw2 Exp $
+ * $Id: inftlcore.c,v 1.16 2004/07/12 12:34:58 dwmw2 Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -55,9 +55,19 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        struct INFTLrecord *inftl;
        unsigned long temp;
 
-       if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
+       if (mtd->type != MTD_NANDFLASH)
+               return;
+       /* OK, this is moderately ugly.  But probably safe.  Alternatives? */
+       if (memcmp(mtd->name, "DiskOnChip", 10))
                return;
 
+       if (!mtd->block_isbad) {
+               printk(KERN_ERR
+"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
+"Please use the new diskonchip driver under the NAND subsystem.\n");
+               return;
+       }
+
        DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
 
        inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
@@ -72,6 +82,8 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        inftl->mbd.devnum = -1;
        inftl->mbd.blksize = 512;
        inftl->mbd.tr = tr;
+       memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
+       inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
 
         if (INFTL_mount(inftl) < 0) {
                printk(KERN_WARNING "INFTL: could not mount device\n");
@@ -284,21 +296,22 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
                 
-                ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+                ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
                        BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
-                       &retlen, movebuf, (char *)&oob, NULL); 
+                       &retlen, movebuf); 
                 if (ret < 0) {
-                       ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+                       ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
                                BlockMap[block]) + (block * SECTORSIZE),
-                               SECTORSIZE, &retlen, movebuf, (char *)&oob,
-                               NULL); 
+                               SECTORSIZE, &retlen, movebuf);
                        if (ret != -EIO) 
                                DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
                                        "away on retry?\n");
                 }
+                memset(&oob, 0xff, sizeof(struct inftl_oob));
+                oob.b.Status = oob.b.Status1 = SECTOR_USED;
                 MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
                        (block * SECTORSIZE), SECTORSIZE, &retlen,
-                       movebuf, (char *)&oob, NULL);
+                       movebuf, (char *)&oob, &inftl->oobinfo);
        }
 
        /*
@@ -326,7 +339,6 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                 if (INFTL_formatblock(inftl, thisEUN) < 0) {
                        /*
                         * Could not erase : mark block as reserved.
-                        * FixMe: Update Bad Unit Table on disk.
                         */
                        inftl->PUtable[thisEUN] = BLOCK_RESERVED;
                 } else {
@@ -668,7 +680,6 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
                 if (INFTL_formatblock(inftl, thisEUN) < 0) {
                        /*
                         * Could not erase : mark block as reserved.
-                        * FixMe: Update Bad Unit Table on medium.
                         */
                        inftl->PUtable[thisEUN] = BLOCK_RESERVED;
                 } else {
@@ -754,7 +765,7 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
        unsigned int writeEUN;
        unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
        size_t retlen;
-       u8 eccbuf[6];
+       struct inftl_oob oob;
        char *p, *pend;
 
        DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=0x%x,block=%ld,"
@@ -778,11 +789,13 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
                        return 1;
                }
 
+               memset(&oob, 0xff, sizeof(struct inftl_oob));
+               oob.b.Status = oob.b.Status1 = SECTOR_USED;
                MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
                        blockofs, SECTORSIZE, &retlen, (char *)buffer,
-                       (char *)eccbuf, NULL);
+                       (char *)&oob, &inftl->oobinfo);
                /*
-                * No need to write SECTOR_USED flags since they are written
+                * need to write SECTOR_USED flags since they are not written
                 * in mtd_writeecc
                 */
        } else {
@@ -846,9 +859,8 @@ foundit:
        } else {
                size_t retlen;
                loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
-               u_char eccbuf[6];
-               if (MTD_READECC(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
-                   buffer, eccbuf, NULL))
+               if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
+                   buffer))
                        return -EIO;
        }
        return 0;
@@ -881,7 +893,7 @@ extern char inftlmountrev[];
 
 int __init init_inftl(void)
 {
-       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.14 $, "
+       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.16 $, "
                "inftlmount.c %s\n", inftlmountrev);
 
        return register_mtd_blktrans(&inftl_tr);
index 042c4ee..a7075c2 100644 (file)
@@ -8,7 +8,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: inftlmount.c,v 1.11 2003/06/23 07:39:21 dwmw2 Exp $
+ * $Id: inftlmount.c,v 1.13 2004/06/28 16:06:36 dbrown Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@
 #include <linux/mtd/inftl.h>
 #include <linux/mtd/compatmac.h>
 
-char inftlmountrev[]="$Revision: 1.11 $";
+char inftlmountrev[]="$Revision: 1.13 $";
 
 /*
  * find_boot_record: Find the INFTL Media Header and its Spare copy which
@@ -54,7 +54,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
 {
        struct inftl_unittail h1;
        //struct inftl_oob oob;
-       unsigned int i, block, boot_record_count = 0;
+       unsigned int i, block;
        u8 buf[SECTORSIZE];
        struct INFTLMediaHeader *mh = &inftl->MediaHdr;
        struct INFTLPartition *ip;
@@ -72,7 +72,6 @@ static int find_boot_record(struct INFTLrecord *inftl)
         inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
 
        inftl->MediaUnit = BLOCK_NIL;
-       inftl->SpareMediaUnit = BLOCK_NIL;
 
        /* Search for a valid boot record */
        for (block = 0; block < inftl->nb_blocks; block++) {
@@ -82,8 +81,11 @@ static int find_boot_record(struct INFTLrecord *inftl)
                 * Check for BNAND header first. Then whinge if it's found
                 * but later checks fail.
                 */
-               if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
-                   SECTORSIZE, &retlen, buf))) {
+               ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
+                   SECTORSIZE, &retlen, buf);
+               /* We ignore ret in case the ECC of the MediaHeader is invalid
+                  (which is apparently acceptable) */
+               if (retlen != SECTORSIZE) {
                        static int warncount = 5;
 
                        if (warncount) {
@@ -114,36 +116,28 @@ static int find_boot_record(struct INFTLrecord *inftl)
                        continue;
                }
 
-               if (boot_record_count) {
-                       /*
-                        * We've already processed one. So we just check if
-                        * this one is the same as the first one we found.
-                        */
-                       if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
-                               printk(KERN_WARNING "INFTL: Media Headers at "
-                                       "0x%x and 0x%x disagree.\n",
-                                       inftl->MediaUnit * inftl->EraseSize,
-                                       block * inftl->EraseSize);
-                               return -1;
-                       }
-                       if (boot_record_count == 1)
-                               inftl->SpareMediaUnit = block;
-
-                       /*
-                        * Mark this boot record (INFTL MediaHeader) block as
-                        * reserved.
-                        */
-                       inftl->PUtable[block] = BLOCK_RESERVED;
-
-                       boot_record_count++;
-                       continue;
-               }
 
                /*
                 * This is the first we've seen.
                 * Copy the media header structure into place.
                 */
                memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
+
+               /* Read the spare media header at offset 4096 */
+               MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize + 4096,
+                   SECTORSIZE, &retlen, buf);
+               if (retlen != SECTORSIZE) {
+                       printk(KERN_WARNING "INFTL: Unable to read spare "
+                              "Media Header\n");
+                       return -1;
+               }
+               /* Check if this one is the same as the first one we found. */
+               if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
+                       printk(KERN_WARNING "INFTL: Primary and spare Media "
+                              "Headers disagree.\n");
+                       return -1;
+               }
+
                mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
                mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
                mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
@@ -197,8 +191,9 @@ static int find_boot_record(struct INFTLrecord *inftl)
                                "UnitSizeFactor 0x%02x is experimental\n",
                                mh->BlockMultiplierBits);
                        inftl->EraseSize = inftl->mbd.mtd->erasesize <<
-                               (0xff - mh->BlockMultiplierBits);
+                               mh->BlockMultiplierBits;
                        inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
+                       block >>= mh->BlockMultiplierBits;
                }
 
                /* Scan the partitions */
@@ -317,34 +312,23 @@ static int find_boot_record(struct INFTLrecord *inftl)
                /* Mark this boot record (NFTL MediaHeader) block as reserved */
                inftl->PUtable[block] = BLOCK_RESERVED;
 
-#if 0
                /* Read Bad Erase Unit Table and modify PUtable[] accordingly */
                for (i = 0; i < inftl->nb_blocks; i++) {
-                       if ((i & (SECTORSIZE - 1)) == 0) {
-                               /* read one sector for every SECTORSIZE of blocks */
-                               if ((ret = MTD_READECC(inftl->mbd.mtd,
-                                   block * inftl->EraseSize + i + SECTORSIZE,
-                                   SECTORSIZE, &retlen, buf,
-                                   (char *)&oob, NULL)) < 0) {
-                                       printk(KERN_WARNING "INFTL: read of "
-                                               "bad sector table failed "
-                                               "(err %d)\n", ret);
-                                       kfree(inftl->VUtable);
-                                       kfree(inftl->PUtable);
-                                       return -1;
-                               }
+                       int physblock;
+                       /* If any of the physical eraseblocks are bad, don't
+                          use the unit. */
+                       for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) {
+                               if (inftl->mbd.mtd->block_isbad(inftl->mbd.mtd, i * inftl->EraseSize + physblock))
+                                       inftl->PUtable[i] = BLOCK_RESERVED;
                        }
-                       /* Mark the Bad Erase Unit as RESERVED in PUtable */
-                       if (buf[i & (SECTORSIZE - 1)] != 0xff)
-                               inftl->PUtable[i] = BLOCK_RESERVED;
                }
-#endif
 
                inftl->MediaUnit = block;
-               boot_record_count++;
+               return 0;
        }
-               
-       return boot_record_count ? 0 : -1;
+
+       /* Not found. */
+       return -1;
 }
 
 static int memcmpb(void *a, int c, int n)
@@ -365,27 +349,20 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
        int len, int check_oob)
 {
        int i, retlen;
-       u8 buf[SECTORSIZE];
+       u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
 
        DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x,"
                "address=0x%x,len=%d,check_oob=%d)\n", (int)inftl,
                address, len, check_oob);
 
        for (i = 0; i < len; i += SECTORSIZE) {
-               /*
-                * We want to read the sector without ECC check here since a
-                * free sector does not have ECC syndrome on it yet.
-                */
-               if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
+               if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0)
                        return -1;
                if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
                        return -1;
 
                if (check_oob) {
-                       if (MTD_READOOB(inftl->mbd.mtd, address,
-                           inftl->mbd.mtd->oobsize, &retlen, buf) < 0)
-                               return -1;
-                       if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0)
+                       if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0)
                                return -1;
                }
                address += SECTORSIZE;
@@ -402,52 +379,62 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
  * Return: 0 when succeed, -1 on error.
  *
  * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
- *       2. UnitSizeFactor != 0xFF
  */
 int INFTL_formatblock(struct INFTLrecord *inftl, int block)
 {
        int retlen;
        struct inftl_unittail uci;
        struct erase_info *instr = &inftl->instr;
+       int physblock;
 
        DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x,"
                "block=%d)\n", (int)inftl, block);
 
        memset(instr, 0, sizeof(struct erase_info));
 
+       /* FIXME: Shouldn't we be setting the 'discarded' flag to zero
+          _first_? */
+
        /* Use async erase interface, test return code */
        instr->addr = block * inftl->EraseSize;
-       instr->len = inftl->EraseSize;
-       MTD_ERASE(inftl->mbd.mtd, instr);
+       instr->len = inftl->mbd.mtd->erasesize;
+       /* Erase one physical eraseblock at a time, even though the NAND api
+          allows us to group them.  This way we if we have a failure, we can
+          mark only the failed block in the bbt. */
+       for (physblock = 0; physblock < inftl->EraseSize; physblock += instr->len, instr->addr += instr->len) {
+               MTD_ERASE(inftl->mbd.mtd, instr);
+
+               if (instr->state == MTD_ERASE_FAILED) {
+                       printk(KERN_WARNING "INFTL: error while formatting block %d\n",
+                               block);
+                       goto fail;
+               }
 
-       if (instr->state == MTD_ERASE_FAILED) {
                /*
-                * Could not format, FixMe: We should update the BadUnitTable 
-                * both in memory and on disk.
-                */
-               printk(KERN_WARNING "INFTL: error while formatting block %d\n",
-                       block);
-               return -1;
+               * Check the "freeness" of Erase Unit before updating metadata.
+               * FixMe: is this check really necessary? Since we have check the
+               *        return code after the erase operation.
+               */
+               if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0)
+                       goto fail;
        }
 
-       /*
-        * Check the "freeness" of Erase Unit before updating metadata.
-        * FixMe: is this check really necessary? Since we have check the
-        *        return code after the erase operation.
-        */
-       if (check_free_sectors(inftl, instr->addr, inftl->EraseSize, 1) != 0)
-               return -1;
-
        uci.EraseMark = cpu_to_le16(ERASE_MARK);
        uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
        uci.Reserved[0] = 0;
        uci.Reserved[1] = 0;
        uci.Reserved[2] = 0;
        uci.Reserved[3] = 0;
-       if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 +
+       instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
+       if (MTD_WRITEOOB(inftl->mbd.mtd, instr->addr +
            8, 8, &retlen, (char *)&uci) < 0)
-               return -1;
+               goto fail;
        return 0;
+fail:
+       /* could not format, update the bad block table (caller is responsible
+          for setting the PUtable to BLOCK_RESERVED on failure) */
+       inftl->mbd.mtd->block_markbad(inftl->mbd.mtd, instr->addr);
+       return -1;
 }
 
 /*
@@ -472,7 +459,6 @@ static void format_chain(struct INFTLrecord *inftl, unsigned int first_block)
                if (INFTL_formatblock(inftl, block) < 0) {
                        /*
                         * Cannot format !!!! Mark it as Bad Unit,
-                        * FixMe: update the BadUnitTable on disk.
                         */
                        inftl->PUtable[block] = BLOCK_RESERVED;
                } else {
index 03d39d7..b1ad656 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.12 2003/06/23 07:38:11 dwmw2 Exp $
+# $Id: Kconfig,v 1.29 2004/07/15 15:29:17 dwmw2 Exp $
 
 menu "Mapping drivers for chip access"
        depends on MTD!=n
@@ -151,11 +151,11 @@ config MTD_AMD76XROM
 
          BE VERY CAREFUL.
 
-config MTD_ICH2ROM
-       tristate "BIOS flash chip on Intel Hub Controller 2"
+config MTD_ICHXROM
+       tristate "BIOS flash chip on Intel Controller Hub 2/3/4/5"
        depends on X86 && MTD_JEDECPROBE && MTD_COMPLEX_MAPPINGS
        help
-         Support for treating the BIOS flash chip on ICH2 motherboards
+         Support for treating the BIOS flash chip on ICHX motherboards
          as an MTD device - with this you can reprogram your BIOS.
 
          BE VERY CAREFUL.
@@ -177,7 +177,7 @@ config MTD_TSUNAMI
 
 config MTD_LASAT
        tristate "Flash chips on LASAT board"
-       depends on LASAT && MTD_CFI
+       depends on LASAT
        help
          Support for the flash chips on the Lasat 100 and 200 boards.
 
@@ -210,6 +210,52 @@ config MTD_PB1XXX_USER
          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_DILNETPC
        tristate "CFI Flash device mapped on DIL/Net PC"
        depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT
@@ -235,6 +281,13 @@ config MTD_L440GX
 
          BE VERY CAREFUL.
 
+config MTD_SBC8240
+       tristate "Flash device on SBC8240"
+       depends on PPC32 && MTD_JEDECPROBE && 6xx && 8260
+       help
+          Flash access on the SBC8240 board from Wind River.  See
+          <http://www.windriver.com/products/sbc8240/>
+
 config MTD_TQM8XXL
        tristate "CFI Flash device mapped on TQM8XXL"
        depends on MTD_CFI && PPC32 && 8xx && TQM8xxL
@@ -265,7 +318,7 @@ config MTD_MBX860
 
 config MTD_DBOX2
        tristate "CFI Flash device mapped on D-Box2"
-       depends on PPC32 && 8xx && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
+       depends on PPC32 && 8xx && DBOX2 && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD
        help
          This enables access routines for the flash chips on the Nokia/Sagem
          D-Box 2 board. If you have one of these boards and would like to use
@@ -457,6 +510,13 @@ config MTD_CEIVA
          PhotoMax Digital Picture Frame.
          If you have such a device, say 'Y'.
 
+config MTD_NOR_TOTO
+       tristate "NOR Flash device on TOTO board"
+       depends on ARM && ARCH_OMAP && OMAP_TOTO
+       help
+         This enables access to the NOR flash on the Texas Instruments
+         TOTO board.
+
 config MTD_H720X
        tristate "Hynix evaluation board mappings"
        depends on ARM && MTD_CFI && ( ARCH_H7201 || ARCH_H7202 )
@@ -464,6 +524,13 @@ config MTD_H720X
          This enables access to the flash chips on the Hynix evaluation boards.
          If you have such a board, say 'Y'.
 
+config MTD_MPC1211
+       tristate "CFI Flash device mapped on Interface MPC-1211"
+       depends on SUPERH && SH_MPC1211 && MTD_CFI
+       help
+         This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02).
+         If you have such a board, say 'Y'.
+
 # This needs CFI or JEDEC, depending on the cards found.
 config MTD_PCI
        tristate "PCI MTD driver"
@@ -491,11 +558,26 @@ config MTD_UCLINUX
 
 config MTD_WRSBC8260
        tristate "Map driver for WindRiver PowerQUICC II MPC82xx board"
-       depends on MTD_PARTITIONS && SBC82xx
+       depends on (SBC82xx || SBC8560)
+       select MTD_PARTITIONS
+       select MTD_MAP_BANK_WIDTH_4
+       select MTD_MAP_BANK_WIDTH_1
+       select MTD_CFI_I1
+       select MTD_CFI_I4
        help
          Map driver for WindRiver PowerQUICC II MPC82xx board. Drives
          all three flash regions on CS0, CS1 and CS6 if they are configured
          correctly by the boot loader.
 
+config MTD_DMV182
+        tristate "Map driver for Dy-4 SVME/DMV-182 board."
+        depends on DMV182
+        select MTD_PARTITIONS
+       select MTD_MAP_BANK_WIDTH_32
+       select MTD_CFI_I8
+       select MTD_CFI_AMDSTD
+        help
+          Map driver for Dy-4 SVME/DMV-182 board.
+
 endmenu
 
index 929d668..505178f 100644 (file)
@@ -1,7 +1,7 @@
 #
 # linux/drivers/maps/Makefile
 #
-# $Id: Makefile.common,v 1.2 2003/05/28 10:48:41 dwmw2 Exp $
+# $Id: Makefile.common,v 1.14 2004/07/12 16:07:31 dwmw2 Exp $
 
 ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
 obj-$(CONFIG_MTD)              += map_funcs.o
@@ -19,7 +19,7 @@ obj-$(CONFIG_MTD_EPXA10DB)    += epxa10db-flash.o
 obj-$(CONFIG_MTD_IQ80310)      += iq80310.o
 obj-$(CONFIG_MTD_L440GX)       += l440gx.o
 obj-$(CONFIG_MTD_AMD76XROM)    += amd76xrom.o
-obj-$(CONFIG_MTD_ICH2ROM)      += ich2rom.o
+obj-$(CONFIG_MTD_ICHXROM)      += ichxrom.o
 obj-$(CONFIG_MTD_TSUNAMI)      += tsunami_flash.o
 obj-$(CONFIG_MTD_LUBBOCK)      += lubbock-flash.o
 obj-$(CONFIG_MTD_MBX860)       += mbx860.o
@@ -42,6 +42,9 @@ 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_LASAT)                += lasat.o
 obj-$(CONFIG_MTD_AUTCPU12)     += autcpu12-nvram.o
 obj-$(CONFIG_MTD_EDB7312)      += edb7312.o
@@ -55,5 +58,9 @@ obj-$(CONFIG_MTD_EBONY)               += ebony.o
 obj-$(CONFIG_MTD_BEECH)                += beech-mtd.o
 obj-$(CONFIG_MTD_ARCTIC)       += arctic-mtd.o
 obj-$(CONFIG_MTD_H720X)                += h720x-flash.o
+obj-$(CONFIG_MTD_SBC8240)      += sbc8240.o
+obj-$(CONFIG_MTD_NOR_TOTO)     += omap-toto-flash.o
+obj-$(CONFIG_MTD_MPC1211)      += mpc1211.o
 obj-$(CONFIG_MTD_IXP4XX)       += ixp4xx.o
 obj-$(CONFIG_MTD_WRSBC8260)    += wr_sbc82xx_flash.o
+obj-$(CONFIG_MTD_DMV182)       += dmv182.o
index 39fdeae..7f3ab37 100644 (file)
@@ -2,7 +2,7 @@
  * amd76xrom.c
  *
  * Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.8 2003/05/28 15:44:28 dwmw2 Exp $
+ * $Id: amd76xrom.c,v 1.12 2004/07/14 14:44:31 thayne Exp $
  */
 
 #include <linux/module.h>
 #include <linux/pci_ids.h>
 
 
+#define xstr(s) str(s)
+#define str(s) #s
+#define MOD_NAME xstr(KBUILD_BASENAME)
+
+#define MTD_DEV_NAME_LENGTH 16
+
 struct amd76xrom_map_info {
        struct map_info map;
        struct mtd_info *mtd;
        unsigned long window_addr;
        u32 window_start, window_size;
        struct pci_dev *pdev;
+       struct resource window_rsrc;
+       struct resource rom_rsrc;
+       char mtd_name[MTD_DEV_NAME_LENGTH];
 };
 
 
 static struct amd76xrom_map_info amd76xrom_map = {
        .map = {
-               .name = "AMD76X rom",
+               .name = MOD_NAME,
                .size = 0,
-               .buswidth = 1,
-       },
-       .mtd = NULL,
-       .window_addr = 0,
+               .bankwidth = 1,
+       }
+       /* remaining fields of structure are initialized to 0 */
 };
 
+
+static void amd76xrom_cleanup(struct amd76xrom_map_info *info)
+{
+       u8 byte;
+
+       /* Disable writes through the rom window */
+       pci_read_config_byte(info->pdev, 0x40, &byte);
+       pci_write_config_byte(info->pdev, 0x40, byte & ~1);
+
+       if (info->mtd) {
+               del_mtd_device(info->mtd);
+               map_destroy(info->mtd);
+               info->mtd = NULL;
+               info->map.virt = 0;
+       }
+       if (info->rom_rsrc.parent)
+               release_resource(&info->rom_rsrc);
+       if (info->window_rsrc.parent)
+               release_resource(&info->window_rsrc);
+
+       if (info->window_addr) {
+               iounmap((void *)(info->window_addr));
+               info->window_addr = 0;
+       }
+}
+
+
 static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
        const struct pci_device_id *ent)
 {
@@ -45,6 +80,10 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
                u8 segen_bits;
        };
        static struct rom_window rom_window[] = {
+               /*
+                * Need the 5MiB window for chips that have block lock/unlock
+                * registers located below 4MiB window.
+                */
                { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
                { 0xffc00000, 4*1024*1024, (1<<7), },
                { 0xffff0000, 64*1024,     0 },
@@ -60,80 +99,134 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
        int i;
        u32 rom_size;
 
+       info->pdev = pdev;
        window = &rom_window[0];
 
-       /* disabled because it fights with BIOS reserved regions */
-#define REQUEST_MEM_REGION 0
-#if REQUEST_MEM_REGION
-       while(window->size) {
-               if (request_mem_region(window->start, window->size, "amd76xrom")) {
-                       break;
+       while (window->size) {
+               /*
+                * Try to reserve the window mem region.  If this fails then
+                * it is likely due to a fragment of the window being
+                * "reseved" by the BIOS.  In the case that the
+                * request_mem_region() fails then once the rom size is
+                * discovered we will try to reserve the unreserved fragment.
+                */
+               info->window_rsrc.name = MOD_NAME;
+               info->window_rsrc.start = window->start;
+               info->window_rsrc.end = window->start + window->size - 1;
+               info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               if (request_resource(&iomem_resource, &info->window_rsrc)) {
+                       info->window_rsrc.parent = NULL;
+                       printk(KERN_ERR MOD_NAME
+                              " %s(): Unable to register resource"
+                              " 0x%.08lx-0x%.08lx - kernel bug?\n",
+                              __func__,
+                              info->window_rsrc.start, info->window_rsrc.end);
                }
-               window++;
-       }
-       if (!window->size) {
-               printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
-               goto err_out_none;
-       }
-#endif /* REQUEST_MEM_REGION */
 
-       /* Enable the selected rom window */
-       pci_read_config_byte(pdev, 0x43, &byte);
-       pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
+               /* Enable the selected rom window */
+               pci_read_config_byte(pdev, 0x43, &byte);
+               pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
 
-       /* Enable writes through the rom window */
-       pci_read_config_byte(pdev, 0x40, &byte);
-       pci_write_config_byte(pdev, 0x40, byte | 1);
+               /* Enable writes through the rom window */
+               pci_read_config_byte(pdev, 0x40, &byte);
+               pci_write_config_byte(pdev, 0x40, byte | 1);
 
-       /* FIXME handle registers 0x80 - 0x8C the bios region locks */
+               /* FIXME handle registers 0x80 - 0x8C the bios region locks */
 
-       printk(KERN_NOTICE "amd76xrom window : %x at %x\n", 
-               window->size, window->start);
-       /* For write accesses caches are useless */
-       info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size);
+               printk(KERN_NOTICE MOD_NAME " window : %x at %x\n", 
+                      window->size, window->start);
+               /* For write accesses caches are useless */
+               info->window_addr =
+                       (unsigned long)ioremap_nocache(window->start,
+                                                      window->size);
 
-       if (!info->window_addr) {
-               printk(KERN_ERR "Failed to ioremap\n");
-               goto err_out_free_mmio_region;
-       }
-       info->mtd = NULL;
-       for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
-               char **chip_type;
-               if (rom_size > window->size) {
+               if (!info->window_addr) {
+                       printk(KERN_ERR "Failed to ioremap\n");
                        continue;
                }
-               info->map.phys = window->start + window->size - rom_size;
-               info->map.virt = 
-                       info->window_addr + window->size - rom_size;
-               info->map.size = rom_size;
-               simple_map_init(&info->map);
-               chip_type = rom_probe_types;
-               for(; !info->mtd && *chip_type; chip_type++) {
-                       info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
-               }
-               if (info->mtd) {
-                       break;
+
+               info->mtd = NULL;
+
+               for(i = 0; (rom_size = rom_probe_sizes[i]); i++) {
+                       char **chip_type;
+                       if (rom_size > window->size) {
+                               continue;
+                       }
+                       info->map.phys = window->start + window->size - rom_size;
+                       info->map.virt = 
+                               info->window_addr + window->size - rom_size;
+                       info->map.size = rom_size;
+                       simple_map_init(&info->map);
+                       chip_type = rom_probe_types;
+                       for(; !info->mtd && *chip_type; chip_type++) {
+                               info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map);
+                       }
+                       if (info->mtd) goto found_mtd;
                }
+               iounmap((void *)(info->window_addr));
+               info->window_addr = 0;
+
+               /* Disable writes through the rom window */
+               pci_read_config_byte(pdev, 0x40, &byte);
+               pci_write_config_byte(pdev, 0x40, byte & ~1);
+
+               window++;
        }
-       if (!info->mtd) {
-               goto err_out_iounmap;
-       }
-       printk(KERN_NOTICE "amd76xrom chip at offset: 0x%x\n",
+       goto failed;
+
+ found_mtd:
+       printk(KERN_NOTICE MOD_NAME " chip at offset: 0x%x\n",
                window->size - rom_size);
-               
+
        info->mtd->owner = THIS_MODULE;
+
+       if (!info->window_rsrc.parent) {
+               /* failed to reserve entire window - try fragments */
+               info->window_rsrc.name = MOD_NAME;
+               info->window_rsrc.start = window->start;
+               info->window_rsrc.end = window->start + window->size - rom_size - 1;
+               info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               if (request_resource(&iomem_resource, &info->window_rsrc)) {
+                       printk(KERN_ERR MOD_NAME
+                              ": cannot reserve window resource fragment\n");
+#if 0
+                       /*
+                        * The BIOS e820 usually reserves this so it isn't
+                        * usually an error.
+                        */
+                       goto failed;
+#endif
+               }
+       }
+
        add_mtd_device(info->mtd);
        info->window_start = window->start;
        info->window_size = window->size;
+
+       if (info->window_rsrc.parent) {
+               /*
+                * Registering the MTD device in iomem may not be possible
+                * if there is a BIOS "reserved" and BUSY range.  If this
+                * fails then continue anyway.
+                */
+               snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH,
+                        "mtd%d", info->mtd->index);
+
+               info->rom_rsrc.name = info->mtd_name;
+               info->rom_rsrc.start = window->start + window->size - rom_size;
+               info->rom_rsrc.end = window->start + window->size - 1;
+               info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               if (request_resource(&info->window_rsrc, &info->rom_rsrc)) {
+                       printk(KERN_ERR MOD_NAME
+                              ": cannot reserve MTD resource\n");
+                       info->rom_rsrc.parent = NULL;
+               }
+       }
+
        return 0;
 
-err_out_iounmap:
-       iounmap((void *)(info->window_addr));
-err_out_free_mmio_region:
-#if REQUEST_MEM_REGION
-       release_mem_region(window->start, window->size);
-err_out_none:
-#endif /* REQUEST_MEM_REGION */
+ failed:
+       amd76xrom_cleanup(info);
        return -ENODEV;
 }
 
@@ -141,23 +234,8 @@ err_out_none:
 static void __devexit amd76xrom_remove_one (struct pci_dev *pdev)
 {
        struct amd76xrom_map_info *info = &amd76xrom_map;
-       u8 byte;
-
-       del_mtd_device(info->mtd);
-       map_destroy(info->mtd);
-       info->mtd = NULL;
-       info->map.virt = 0;
-
-       iounmap((void *)(info->window_addr));
-       info->window_addr = 0;
-
-       /* Disable writes through the rom window */
-       pci_read_config_byte(pdev, 0x40, &byte);
-       pci_write_config_byte(pdev, 0x40, byte & ~1);
 
-#if REQUEST_MEM_REGION
-       release_mem_region(info->window_start, info->window_size);
-#endif /* REQUEST_MEM_REGION */
+       amd76xrom_cleanup(info);
 }
 
 static struct pci_device_id amd76xrom_pci_tbl[] = {
@@ -173,7 +251,7 @@ MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl);
 
 #if 0
 static struct pci_driver amd76xrom_driver = {
-       .name =         "amd76xrom",
+       .name =         MOD_NAME,
        .id_table =     amd76xrom_pci_tbl,
        .probe =        amd76xrom_init_one,
        .remove =       amd76xrom_remove_one,
index c111b2d..2acf5b0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: arctic-mtd.c,v 1.10 2003/06/02 16:37:59 trini Exp $
+ * $Id: arctic-mtd.c,v 1.11 2004/07/12 21:59:43 dwmw2 Exp $
  * 
  * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for 
  *                              IBM 405LP Arctic boards.
@@ -72,7 +72,7 @@
 static struct map_info arctic_mtd_map = {
        .name           = NAME,
        .size           = SIZE,
-       .buswidth       = BUSWIDTH,
+       .bankwidth      = BUSWIDTH,
        .phys           = PADDR,
 };
 
index f4c27c4..31e9df6 100644 (file)
@@ -2,7 +2,7 @@
  * NV-RAM memory access on autcpu12 
  * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
  *
- * $Id: autcpu12-nvram.c,v 1.5 2003/05/21 12:45:18 dwmw2 Exp $ 
+ * $Id: autcpu12-nvram.c,v 1.6 2004/07/12 21:59:43 dwmw2 Exp $ 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ static struct mtd_info *sram_mtd;
 struct map_info autcpu12_sram_map = {
        .name = "SRAM",
        .size = 32768,
-       .buswidth = 4,
+       .bankwidth = 4,
        .phys = 0x12000000,
 };
 
index 61e2197..d8f737a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: beech-mtd.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: beech-mtd.c,v 1.8 2004/07/12 21:59:43 dwmw2 Exp $
  * 
  * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for 
  *                              IBM 405LP Beech boards.
@@ -51,7 +51,7 @@
 static struct map_info beech_mtd_map = {
        .name =         NAME,
        .size =         SIZE,
-       .buswidth =     BUSWIDTH,
+       .bankwidth =    BUSWIDTH,
        .phys =         PADDR
 };
 
index 1199689..e8c984e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Flash on Cirrus CDB89712
  *
- * $Id: cdb89712.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: cdb89712.c,v 1.8 2004/07/12 21:59:43 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -23,7 +23,7 @@ static struct mtd_info *flash_mtd;
 struct map_info cdb89712_flash_map = {
        .name = "flash",
        .size = FLASH_SIZE,
-       .buswidth = FLASH_WIDTH,
+       .bankwidth = FLASH_WIDTH,
        .phys = FLASH_START,
 };
 
@@ -93,7 +93,7 @@ static struct mtd_info *sram_mtd;
 struct map_info cdb89712_sram_map = {
        .name = "SRAM",
        .size = SRAM_SIZE,
-       .buswidth = SRAM_WIDTH,
+       .bankwidth = SRAM_WIDTH,
        .phys = SRAM_START,
 };
 
@@ -161,7 +161,7 @@ static struct mtd_info *bootrom_mtd;
 struct map_info cdb89712_bootrom_map = {
        .name = "BootROM",
        .size = BOOTROM_SIZE,
-       .buswidth = BOOTROM_WIDTH,
+       .bankwidth = BOOTROM_WIDTH,
        .phys = BOOTROM_START,
 };
 
index 01b867c..8475505 100644 (file)
@@ -11,7 +11,7 @@
  *
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  *
- * $Id: ceiva.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: ceiva.c,v 1.10 2004/07/12 21:59:43 dwmw2 Exp $
  */
 
 #include <linux/config.h>
@@ -151,7 +151,7 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info
                }
 
                clps[i].map->virt = (unsigned long)clps[i].vbase;
-               clps[i].map->buswidth = clps[i].width;
+               clps[i].map->bankwidth = clps[i].width;
                clps[i].map->size = clps[i].size;
 
                simple_map_init(&clps[i].map);
index ff08d85..28d59ff 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright Â© 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is>
  *
- *  $Id: cfi_flagadm.c,v 1.11 2003/05/21 12:45:18 dwmw2 Exp $
+ *  $Id: cfi_flagadm.c,v 1.12 2004/07/12 21:59:43 dwmw2 Exp $
  *  
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
@@ -60,7 +60,7 @@
 struct map_info flagadm_map = {
                .name =         "FlagaDM flash device",
                .size =         FLASH_SIZE,
-               .buswidth =     2,
+               .bankwidth =    2,
 };
 
 struct mtd_partition flagadm_parts[] = {
index 38f7e11..773b1ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cstm_mips_ixx.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: cstm_mips_ixx.c,v 1.10 2004/07/12 21:59:43 dwmw2 Exp $
  *
  * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
  * Config with both CFI and JEDEC device support.
@@ -104,7 +104,7 @@ struct cstm_mips_ixx_info {
        char *name;
        unsigned long window_addr;
        unsigned long window_size;
-       int buswidth;
+       int bankwidth;
        int num_partitions;
 };
 
@@ -116,7 +116,7 @@ const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
         "big flash",     // name
        0x08000000,      // window_addr
        0x02000000,      // window_size
-        4,               // buswidth
+        4,               // bankwidth
        1,               // num_partitions
     }
 
@@ -138,7 +138,7 @@ const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
         "MTD flash",                   // name
        CONFIG_MTD_CSTM_MIPS_IXX_START,      // window_addr
        CONFIG_MTD_CSTM_MIPS_IXX_LEN,        // window_size
-        CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH,   // buswidth
+        CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH,   // bankwidth
        1,                             // num_partitions
     },
 
@@ -177,7 +177,7 @@ int __init init_cstm_mips_ixx(void)
                }
                cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
                cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
-               cstm_mips_ixx_map[i].buswidth = cstm_mips_ixx_board_desc[i].buswidth;
+               cstm_mips_ixx_map[i].bankwidth = cstm_mips_ixx_board_desc[i].bankwidth;
 #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
                 cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp;
 #endif
index 6565afb..7c4de43 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dbox2-flash.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: dbox2-flash.c,v 1.11 2004/07/12 21:59:43 dwmw2 Exp $
  *
  * D-Box 2 flash driver
  */
@@ -13,6 +13,7 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
+#include <linux/errno.h>
 
 /* 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
@@ -25,31 +26,31 @@ static struct mtd_partition partition_info[]= {
        .mask_flags     = MTD_WRITEABLE
        },
        {
-       .name           = "flfs (ppcboot)",
+       .name           = "FLFS (U-Boot)",
        .size           = 128 * 1024, 
        .offset         = MTDPART_OFS_APPEND, 
        .mask_flags     = 0
        },
        {
-       .name           = "root (cramfs)",      
+       .name           = "Root (SquashFS)",    
        .size           = 7040 * 1024, 
        .offset         = MTDPART_OFS_APPEND, 
        .mask_flags     = 0
        },
        {
-       .name           = "var (jffs2)",
+       .name           = "var (JFFS2)",
        .size           = 896 * 1024, 
        .offset         = MTDPART_OFS_APPEND, 
        .mask_flags     = 0
        },
        {
-       .name           = "flash without bootloader",   
+       .name           = "Flash without bootloader",   
        .size           = MTDPART_SIZ_FULL, 
        .offset         = 128 * 1024, 
        .mask_flags     = 0
        },
        {
-       .name           = "complete flash",     
+       .name           = "Complete Flash",     
        .size           = MTDPART_SIZ_FULL, 
        .offset         = 0, 
        .mask_flags     = MTD_WRITEABLE
@@ -67,7 +68,7 @@ static struct mtd_info *mymtd;
 struct map_info dbox2_flash_map = {
        .name           = "D-Box 2 flash memory",
        .size           = WINDOW_SIZE,
-       .buswidth       = 4,
+       .bankwidth      = 4,
        .phys           = WINDOW_ADDR,
 };
 
@@ -86,7 +87,7 @@ int __init init_dbox2_flash(void)
        mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
        if (!mymtd) {
            // Probe for single Intel 28F640
-           dbox2_flash_map.buswidth = 2;
+           dbox2_flash_map.bankwidth = 2;
        
            mymtd = do_map_probe("cfi_probe", &dbox2_flash_map);
        }
index 8230cc5..fc72bb5 100644 (file)
@@ -5,13 +5,14 @@
  *
  * This code is GPL
  * 
- * $Id: dc21285.c,v 1.15 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: dc21285.c,v 1.20 2004/07/12 22:38:29 dwmw2 Exp $
  */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 
 #include <asm/io.h>
 #include <asm/hardware/dec21285.h>
+#include <asm/mach-types.h>
 
 
-static struct mtd_info *mymtd;
+static struct mtd_info *dc21285_mtd;
 
-__u8 dc21285_read8(struct map_info *map, unsigned long ofs)
+#ifdef CONFIG_ARCH_NETWINDER
+/* 
+ * This is really ugly, but it seams to be the only
+ * realiable way to do it, as the cpld state machine 
+ * is unpredictible. So we have a 25us penalty per
+ * write access.
+ */
+static void nw_en_write(void) {
+       extern spinlock_t gpio_lock;
+       unsigned long flags;
+
+       /*
+        * we want to write a bit pattern XXX1 to Xilinx to enable
+        * the write gate, which will be open for about the next 2ms.
+        */
+       spin_lock_irqsave(&gpio_lock, flags);
+       cpld_modify(1, 1);
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       /*
+        * let the ISA bus to catch on...
+        */
+       udelay(25);
+}
+#else
+#define nw_en_write() do { } while (0)
+#endif
+
+static map_word dc21285_read8(struct map_info *map, unsigned long ofs)
 {
-       return *(__u8*)(map->map_priv_1 + ofs);
+       return *(uint8_t*)(map->map_priv_1 + ofs);
 }
 
-__u16 dc21285_read16(struct map_info *map, unsigned long ofs)
+static map_word dc21285_read16(struct map_info *map, unsigned long ofs)
 {
-       return *(__u16*)(map->map_priv_1 + ofs);
+       return *(uint16_t*)(map->map_priv_1 + ofs);
 }
 
-__u32 dc21285_read32(struct map_info *map, unsigned long ofs)
+static map_word dc21285_read32(struct map_info *map, unsigned long ofs)
 {
-       return *(__u32*)(map->map_priv_1 + ofs);
+       return *(uint32_t*)(map->map_priv_1 + ofs);
 }
 
-void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
        memcpy(to, (void*)(map->map_priv_1 + from), len);
 }
 
-void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
+static void dc21285_write(struct map_info *map, map_word d, unsigned long adr)
 {
+       if (machine_is_netwinder())
+               nw_en_write();
        *CSR_ROMWRITEREG = adr & 3;
        adr &= ~3;
-       *(__u8*)(map->map_priv_1 + adr) = d;
+       *(uint8_t*)(map->map_priv_1 + adr) = d.x[0];
 }
 
-void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
+static void dc21285_write16(struct map_info *map, map_word d, unsigned long adr)
 {
+       if (machine_is_netwinder())
+               nw_en_write();
        *CSR_ROMWRITEREG = adr & 3;
        adr &= ~3;
-       *(__u16*)(map->map_priv_1 + adr) = d;
+       *(uint16_t*)(map->map_priv_1 + adr) = d.x[0];
 }
 
-void dc21285_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void dc21285_write32(struct map_info *map, map_word d, unsigned long adr)
 {
-       *(__u32*)(map->map_priv_1 + adr) = d;
+       if (machine_is_netwinder())
+               nw_en_write();
+       *(uint32_t*)(map->map_priv_1 + adr) = d.x[0];
 }
 
-void dc21285_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
-       switch (map->buswidth) {
-               case 4:
-                       while (len > 0) {
-                               __u32 d = *((__u32*)from)++;
-                               dc21285_write32(map, d, to);
-                               to += 4;
-                               len -= 4;
-                       }
-                       break;
-               case 2:
-                       while (len > 0) {
-                               __u16 d = *((__u16*)from)++;
-                               dc21285_write16(map, d, to);
-                               to += 2;
-                               len -= 2;
-                       }
-                       break;
-               case 1:
-                       while (len > 0) {
-                               __u8 d = *((__u8*)from)++;
-                               dc21285_write8(map, d, to);
-                               to++;
-                               len--;
-                       }
-                       break;
+       while (len > 0) {
+               uint32_t d = *((uint32_t*)from)++;
+               dc21285_write32(map, d, to);
+               to += 4;
+               len -= 4;
+       }
+}
+
+static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+       while (len > 0) {
+               uint16_t d = *((uint16_t*)from)++;
+               dc21285_write16(map, d, to);
+               to += 2;
+               len -= 2;
        }
 }
 
-struct map_info dc21285_map = {
+static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+       uint8_t d = *((uint8_t*)from)++;
+       dc21285_write8(map, d, to);
+       to++;
+       len--;
+}
+
+static struct map_info dc21285_map = {
        .name = "DC21285 flash",
        .phys = NO_XIP,
        .size = 16*1024*1024,
-       .read8 = dc21285_read8,
-       .read16 = dc21285_read16,
-       .read32 = dc21285_read32,
        .copy_from = dc21285_copy_from,
-       .write8 = dc21285_write8,
-       .write16 = dc21285_write16,
-       .write32 = dc21285_write32,
-       .copy_to = dc21285_copy_to
 };
 
 
@@ -113,39 +140,39 @@ static struct mtd_partition *dc21285_parts;
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 #endif
   
-int __init init_dc21285(void)
+static int __init init_dc21285(void)
 {
 
-       /* 
-        * Flash timing is determined with bits 19-16 of the
-        * CSR_SA110_CNTL.  The value is the number of wait cycles, or
-        * 0 for 16 cycles (the default).  Cycles are 20 ns.
-        * Here we use 7 for 140 ns flash chips.
-        */
-       /* access time */
-       *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
-       /* burst time */
-       *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
-       /* tristate time */
-       *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
-
-       /* Determine buswidth */
+#ifdef CONFIG_MTD_PARTITIONS
+       int nrparts;
+#endif
+
+       /* Determine bankwidth */
        switch (*CSR_SA110_CNTL & (3<<14)) {
                case SA110_CNTL_ROMWIDTH_8: 
-                       dc21285_map.buswidth = 1;
+                       dc21285_map.bankwidth = 1;
+                       dc21285_map.read = dc21285_read8;
+                       dc21285_map.write = dc21285_write8;
+                       dc21285_map.copy_to = dc21285_copy_to_8;
                        break;
                case SA110_CNTL_ROMWIDTH_16: 
-                       dc21285_map.buswidth = 2; 
+                       dc21285_map.bankwidth = 2; 
+                       dc21285_map.read = dc21285_read16;
+                       dc21285_map.write = dc21285_write16;
+                       dc21285_map.copy_to = dc21285_copy_to_16;
                        break;
                case SA110_CNTL_ROMWIDTH_32: 
-                       dc21285_map.buswidth = 4; 
+                       dc21285_map.bankwidth = 4; 
                        break;
+                       dc21285_map.read = dc21285_read32;
+                       dc21285_map.write = dc21285_write32;
+                       dc21285_map.copy_to = dc21285_copy_to_32;
                default:
-                       printk (KERN_ERR "DC21285 flash: undefined buswidth\n");
+                       printk (KERN_ERR "DC21285 flash: undefined bankwidth\n");
                        return -ENXIO;
        }
-       printk (KERN_NOTICE "DC21285 flash support (%d-bit buswidth)\n",
-               dc21285_map.buswidth*8);
+       printk (KERN_NOTICE "DC21285 flash support (%d-bit bankwidth)\n",
+               dc21285_map.bankwidth*8);
 
        /* Let's map the flash area */
        dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
@@ -154,40 +181,56 @@ int __init init_dc21285(void)
                return -EIO;
        }
 
-       mymtd = do_map_probe("cfi_probe", &dc21285_map);
-       if (mymtd) {
-               int nrparts = 0;
+       if (machine_is_ebsa285()) {
+               dc21285_mtd = do_map_probe("cfi_probe", &dc21285_map);
+       } else {
+               dc21285_mtd = do_map_probe("jedec_probe", &dc21285_map);
+       }
 
-               mymtd->owner = THIS_MODULE;
-                       
-               /* partition fixup */
+       if (!dc21285_mtd) {
+               iounmap((void *)dc21285_map.map_priv_1);
+               return -ENXIO;
+       }       
+       
+       dc21285_mtd->owner = THIS_MODULE;
 
 #ifdef CONFIG_MTD_PARTITIONS
-               nrparts = parse_mtd_partitions(mymtd, probes, &dc21285_parts, (void *)0);
-               if (nrparts > 0) {
-                       add_mtd_partitions(mymtd, dc21285_parts, nrparts);
-                       return 0;
-               }
-#endif
-               add_mtd_device(mymtd);
-               return 0;
+       nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, (void *)0);
+       if (nrparts > 0)
+               add_mtd_partitions(dc21285_mtd, dc21285_parts, nrparts);
+       else    
+#endif 
+               add_mtd_device(dc21285_mtd);
+                       
+       if(machine_is_ebsa285()) {
+               /* 
+                * Flash timing is determined with bits 19-16 of the
+                * CSR_SA110_CNTL.  The value is the number of wait cycles, or
+                * 0 for 16 cycles (the default).  Cycles are 20 ns.
+                * Here we use 7 for 140 ns flash chips.
+                */
+               /* access time */
+               *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16));
+               /* burst time */
+               *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20));
+               /* tristate time */
+               *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24));
        }
-
-       iounmap((void *)dc21285_map.map_priv_1);
-       return -ENXIO;
+       
+       return 0;
 }
 
 static void __exit cleanup_dc21285(void)
 {
 #ifdef CONFIG_MTD_PARTITIONS
        if (dc21285_parts) {
-               del_mtd_partitions(mymtd);
+               del_mtd_partitions(dc21285_mtd);
                kfree(dc21285_parts);
        } else
 #endif
-               del_mtd_device(mymtd);
+               del_mtd_device(dc21285_mtd);
 
-       map_destroy(mymtd);
+       map_destroy(dc21285_mtd);
        iounmap((void *)dc21285_map.map_priv_1);
 }
 
index d7521b3..feb38ba 100644 (file)
@@ -14,7 +14,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *
- * $Id: dilnetpc.c,v 1.12 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: dilnetpc.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
  * featuring the AMD Elan SC410 processor. There are two variants of this
@@ -252,7 +252,7 @@ static void adnp_set_vpp(struct map_info *not_used, int on)
 static struct map_info dnpc_map = {
        .name = "ADNP Flash Bank",
        .size = ADNP_WINDOW_SIZE,
-       .buswidth = 1,
+       .bankwidth = 1,
        .set_vpp = adnp_set_vpp,
        .phys = WINDOW_ADDR
 };
index 00e87e2..7add7b8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ebony.c,v 1.8 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: ebony.c,v 1.10 2004/07/12 21:59:44 dwmw2 Exp $
  * 
  * Mapping for Ebony user flash
  *
@@ -22,7 +22,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
 #include <asm/io.h>
-#include <asm/ibm440.h>
+#include <asm/ibm44x.h>
 #include <platforms/ebony.h>
 
 static struct mtd_info *flash;
@@ -30,13 +30,13 @@ static struct mtd_info *flash;
 static struct map_info ebony_small_map = {
        .name =         "Ebony small flash",
        .size =         EBONY_SMALL_FLASH_SIZE,
-       .buswidth =     1,
+       .bankwidth =    1,
 };
 
 static struct map_info ebony_large_map = {
        .name =         "Ebony large flash",
        .size =         EBONY_LARGE_FLASH_SIZE,
-       .buswidth =     1,
+       .bankwidth =    1,
 };
 
 static struct mtd_partition ebony_small_partitions[] = {
@@ -71,7 +71,7 @@ int __init init_ebony(void)
                return -ENOMEM;
 
        fpga0_reg = readb(fpga0_adr);
-       iounmap64(fpga0_adr);
+       iounmap(fpga0_adr);
 
        if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) &&
                        !EBONY_FLASH_SEL(fpga0_reg))
index 0ecac20..842f1b0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: edb7312.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: edb7312.c,v 1.11 2004/07/14 09:52:55 dwmw2 Exp $
  *
  * Handle mapping of the NOR flash on Cogent EDB7312 boards
  *
@@ -28,8 +28,8 @@
 #define BUSWIDTH    2
 #define FLASH_BLOCKSIZE_MAIN   0x20000
 #define FLASH_NUMBLOCKS_MAIN   128
-/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */
-#define PROBETYPES { "cfi_probe", 0 }
+/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */
+#define PROBETYPES { "cfi_probe", NULL }
 
 #define MSG_PREFIX "EDB7312-NOR:"   /* prefix for our printk()'s */
 #define MTDID      "edb7312-nor"    /* for mtdparts= partitioning */
@@ -39,7 +39,7 @@ static struct mtd_info *mymtd;
 struct map_info edb7312nor_map = {
        .name = "NOR flash on EDB7312",
        .size = WINDOW_SIZE,
-       .buswidth = BUSWIDTH,
+       .bankwidth = BUSWIDTH,
        .phys = WINDOW_ADDR,
 };
 
index 326e9cc..9410e1f 100644 (file)
@@ -16,7 +16,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
-   $Id: elan-104nc.c,v 1.18 2003/06/23 07:37:02 dwmw2 Exp $
+   $Id: elan-104nc.c,v 1.21 2004/07/12 22:38:29 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.
@@ -107,39 +107,19 @@ static inline void elan_104nc_page(struct map_info *map, unsigned long ofs)
 }
 
 
-static __u8 elan_104nc_read8(struct map_info *map, unsigned long ofs)
+static map_word elan_104nc_read16(struct map_info *map, unsigned long ofs)
 {
-       __u8 ret;
+       map_word ret;
        spin_lock(&elan_104nc_spin);
        elan_104nc_page(map, ofs);
-       ret = readb(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&elan_104nc_spin);
-       return ret;
-}
-
-static __u16 elan_104nc_read16(struct map_info *map, unsigned long ofs)
-{
-       __u16 ret;
-       spin_lock(&elan_104nc_spin);
-       elan_104nc_page(map, ofs);
-       ret = readw(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&elan_104nc_spin);
-       return ret;
-}
-
-static __u32 elan_104nc_read32(struct map_info *map, unsigned long ofs)
-{
-       __u32 ret;
-       spin_lock(&elan_104nc_spin);
-       elan_104nc_page(map, ofs);
-       ret = readl(iomapadr + (ofs & WINDOW_MASK));
+       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) {
+       while (len) {
                unsigned long thislen = len;
                if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
                        thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
@@ -154,27 +134,11 @@ static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long f
        }
 }
 
-static void elan_104nc_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-       spin_lock(&elan_104nc_spin);
-       elan_104nc_page(map, adr);
-       writeb(d, iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&elan_104nc_spin);
-}
-
-static void elan_104nc_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-       spin_lock(&elan_104nc_spin);
-       elan_104nc_page(map, adr);
-       writew(d, iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&elan_104nc_spin);
-}
-
-static void elan_104nc_write32(struct map_info *map, __u32 d, unsigned long adr)
+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);
-       writel(d, iomapadr + (adr & WINDOW_MASK));
+       writew(d.x[0], iomapadr + (adr & WINDOW_MASK));
        spin_unlock(&elan_104nc_spin);
 }
 
@@ -201,14 +165,10 @@ static struct map_info elan_104nc_map = {
        .size = 8*1024*1024, /* this must be set to a maximum possible amount
                        of flash so the cfi probe routines find all
                        the chips */
-       .buswidth = 2,
-       .read8 = elan_104nc_read8,
-       .read16 = elan_104nc_read16,
-       .read32 = elan_104nc_read32,
+       .bankwidth = 2,
+       .read = elan_104nc_read16,
        .copy_from = elan_104nc_copy_from,
-       .write8 = elan_104nc_write8,
-       .write16 = elan_104nc_write16,
-       .write32 = elan_104nc_write32,
+       .write = elan_104nc_write16,
        .copy_to = elan_104nc_copy_to
 };
 
index 5b83d5f..545a398 100644 (file)
@@ -5,7 +5,7 @@
  *  Copyright (C) 2001 Altera Corporation
  *  Copyright (C) 2001 Red Hat, Inc.
  *
- * $Id: epxa10db-flash.c,v 1.10 2003/05/21 12:45:18 dwmw2 Exp $ 
+ * $Id: epxa10db-flash.c,v 1.11 2004/07/12 21:59:44 dwmw2 Exp $ 
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -50,7 +50,7 @@ static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition
 static struct map_info epxa_map = {
        .name =         "EPXA flash",
        .size =         FLASH_SIZE,
-       .buswidth =     2,
+       .bankwidth =    2,
        .phys =         FLASH_START,
 };
 
index 0cc00cd..50409ef 100644 (file)
@@ -1,6 +1,6 @@
 /* fortunet.c memory map
  *
- * $Id: fortunet.c,v 1.6 2003/05/21 12:45:18 dwmw2 Exp $
+ * $Id: fortunet.c,v 1.7 2004/07/12 21:59:44 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -25,7 +25,7 @@
 struct map_region
 {
        int                     window_addr_physical;
-       int                     altbuswidth;
+       int                     altbankwidth;
        struct map_info         map_info;
        struct mtd_info         *mymtd;
        struct mtd_partition    parts[MAX_NUM_PARTITIONS];
@@ -41,7 +41,7 @@ static int                    map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
 
 struct map_info default_map = {
        .size = DEF_WINDOW_SIZE,
-       .buswidth = 4,
+       .bankwidth = 4,
 };
 
 static char * __init get_string_option(char *dest,int dest_size,char *sor)
@@ -102,7 +102,7 @@ static int __init MTD_New_Region(char *line)
        if(params[0]<1)
        {
                printk(MTD_FORTUNET_PK "Bad parameters for MTD Region "
-                       " name,region-number[,base,size,buswidth,altbuswidth]\n");
+                       " name,region-number[,base,size,bankwidth,altbankwidth]\n");
                return 1;
        }
        if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
@@ -116,7 +116,7 @@ static int __init MTD_New_Region(char *line)
                &default_map,sizeof(map_regions[params[1]].map_info));
         map_regions_set[params[1]] = 1;
         map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY;
-        map_regions[params[1]].altbuswidth = 2;
+        map_regions[params[1]].altbankwidth = 2;
         map_regions[params[1]].mymtd = NULL;
        map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
        strcpy(map_regions[params[1]].map_info.name,string);
@@ -130,11 +130,11 @@ static int __init MTD_New_Region(char *line)
        }
        if(params[0]>3)
        {
-               map_regions[params[1]].map_info.buswidth = params[4];
+               map_regions[params[1]].map_info.bankwidth = params[4];
        }
        if(params[0]>4)
        {
-               map_regions[params[1]].altbuswidth = params[5];
+               map_regions[params[1]].altbankwidth = params[5];
        }
        return 1;
 }
@@ -193,7 +193,7 @@ int __init init_fortunet(void)
                                sizeof(map_regions[ix].map_info));
                        map_regions_set[ix] = 1;
                        map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY;
-                       map_regions[ix].altbuswidth = 2;
+                       map_regions[ix].altbankwidth = 2;
                        map_regions[ix].mymtd = NULL;
                        map_regions[ix].map_info.name = map_regions[ix].map_name;
                        strcpy(map_regions[ix].map_info.name,"FORTUNET");
@@ -227,13 +227,13 @@ int __init init_fortunet(void)
                        map_regions[ix].mymtd = do_map_probe("cfi_probe",
                                &map_regions[ix].map_info);
                        if((!map_regions[ix].mymtd)&&(
-                               map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
+                               map_regions[ix].altbankwidth!=map_regions[ix].map_info.bankwidth))
                        {
-                               printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate buswidth "
+                               printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate bankwidth "
                                        "for %s flash.\n",
                                        map_regions[ix].map_info.name);
-                               map_regions[ix].map_info.buswidth =
-                                       map_regions[ix].altbuswidth;
+                               map_regions[ix].map_info.bankwidth =
+                                       map_regions[ix].altbankwidth;
                                map_regions[ix].mymtd = do_map_probe("cfi_probe",
                                        &map_regions[ix].map_info);
                        }
index 3a0c58d..e7cd7b0 100644 (file)
@@ -2,9 +2,11 @@
  * Flash memory access on Hynix GMS30C7201/HMS30C7202 based 
  * evaluation boards
  * 
+ * $Id: h720x-flash.c,v 1.9 2004/07/14 17:45:40 dwmw2 Exp $
+ *
  * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com>
  *     2003 Thomas Gleixner <tglx@linutronix.de>       
-*/
+ */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -24,7 +26,7 @@ static struct mtd_info *mymtd;
 
 static struct map_info h720x_map = {
        .name =         "H720X",
-       .buswidth =     4,
+       .bankwidth =    4,
        .size =         FLASH_SIZE,
        .phys =         FLASH_PHYS,
 };
@@ -80,13 +82,13 @@ int __init h720x_mtd_init(void)
 
        simple_map_init(&h720x_map);
 
-       // Probe for flash buswidth 4
+       // Probe for flash bankwidth 4
        printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n");
        mymtd = do_map_probe("cfi_probe", &h720x_map);
        if (!mymtd) {
                printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n");
-           // Probe for buswidth 2
-           h720x_map.buswidth = 2;
+           // Probe for bankwidth 2
+           h720x_map.bankwidth = 2;
            mymtd = do_map_probe("cfi_probe", &h720x_map);
        }
            
index fdf0dca..a05fc01 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: impa7.c,v 1.9 2003/06/23 11:47:43 dwmw2 Exp $
+ * $Id: impa7.c,v 1.11 2004/07/14 09:52:55 dwmw2 Exp $
  *
  * Handle mapping of the NOR flash on implementa A7 boards
  *
 #define NUM_FLASHBANKS 2
 #define BUSWIDTH     4
 
-/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */
-#define PROBETYPES { "jedec_probe", 0 }
+/* can be { "cfi_probe", "jedec_probe", "map_rom", NULL } */
+#define PROBETYPES { "jedec_probe", NULL }
 
 #define MSG_PREFIX "impA7:"   /* prefix for our printk()'s */
 #define MTDID      "impa7-%d"  /* for mtdparts= partitioning */
 
-static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
+static struct mtd_info *impa7_mtd[NUM_FLASHBANKS];
 
 
 static struct map_info impa7_map[NUM_FLASHBANKS] = {
        {
                .name = "impA7 NOR Flash Bank #0",
                .size = WINDOW_SIZE0,
-               .buswidth = BUSWIDTH,
+               .bankwidth = BUSWIDTH,
        },
        {
                .name = "impA7 NOR Flash Bank #1",
                .size = WINDOW_SIZE1,
-               .buswidth = BUSWIDTH,
+               .bankwidth = BUSWIDTH,
        },
 };
 
index b05dda1..1f23ab1 100644 (file)
@@ -22,7 +22,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: integrator-flash.c,v 1.15 2004/02/27 22:37:39 rmk Exp $
+   $Id: integrator-flash.c,v 1.16 2004/07/12 21:59:44 dwmw2 Exp $
 
 ======================================================================*/
 
@@ -108,7 +108,7 @@ static int armflash_probe(struct device *_dev)
         * look for CFI based flash parts fitted to this board
         */
        info->map.size          = size;
-       info->map.buswidth      = plat->width;
+       info->map.bankwidth     = plat->width;
        info->map.phys          = res->start;
        info->map.virt          = (unsigned long) base;
        info->map.name          = dev->dev.bus_id;
index f0b7b4d..17d7c77 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: iq80310.c,v 1.17 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: iq80310.c,v 1.18 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * Mapping for the Intel XScale IQ80310 evaluation board
  *
@@ -31,7 +31,7 @@ static struct mtd_info *mymtd;
 static struct map_info iq80310_map = {
        .name = "IQ80310 flash",
        .size = WINDOW_SIZE,
-       .buswidth = BUSWIDTH,
+       .bankwidth = BUSWIDTH,
        .phys = WINDOW_ADDR
 };
 
index a10f921..7ebc8cc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ixp4xx.c,v 1.1 2004/05/13 22:21:26 dsaxena Exp $
+ * $Id: ixp4xx.c,v 1.3 2004/07/12 22:38:29 dwmw2 Exp $
  *
  * drivers/mtd/maps/ixp4xx.c
  *
 #define        BYTE1(h)        ((h) & 0xFF)
 #endif
 
-static __u16
-ixp4xx_read16(struct map_info *map, unsigned long ofs)
+static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
 {
-       return *(__u16 *) (map->map_priv_1 + ofs);
+       map_word val;
+       val.x[0] = *(__u16 *) (map->map_priv_1 + ofs);
+       return val;
 }
 
 /*
@@ -50,9 +51,8 @@ ixp4xx_read16(struct map_info *map, unsigned long ofs)
  * when attached to a 16-bit wide device (such as the 28F128J3A),
  * so we can't just memcpy_fromio().
  */
-static void
-ixp4xx_copy_from(struct map_info *map, void *to,
-                unsigned long from, ssize_t len)
+static void ixp4xx_copy_from(struct map_info *map, void *to,
+                            unsigned long from, ssize_t len)
 {
        int i;
        u8 *dest = (u8 *) to;
@@ -69,10 +69,9 @@ ixp4xx_copy_from(struct map_info *map, void *to,
                dest[len - 1] = BYTE0(src[i]);
 }
 
-static void
-ixp4xx_write16(struct map_info *map, __u16 d, unsigned long adr)
+static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
 {
-       *(__u16 *) (map->map_priv_1 + adr) = d;
+       *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
 }
 
 struct ixp4xx_flash_info {
@@ -84,8 +83,7 @@ struct ixp4xx_flash_info {
 
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
 
-static int
-ixp4xx_flash_remove(struct device *_dev)
+static int ixp4xx_flash_remove(struct device *_dev)
 {
        struct platform_device *dev = to_platform_device(_dev);
        struct flash_platform_data *plat = dev->dev.platform_data;
@@ -168,10 +166,10 @@ static int ixp4xx_flash_probe(struct device *_dev)
         * any board use 8-bit access, we'll fixup the driver to
         * handle that.
         */
-       info->map.buswidth = 2;
+       info->map.bankwidth = 2;
        info->map.name = dev->dev.bus_id;
-       info->map.read16 = ixp4xx_read16,
-       info->map.write16 = ixp4xx_write16,
+       info->map.read = ixp4xx_read16,
+       info->map.write = ixp4xx_write16,
        info->map.copy_from = ixp4xx_copy_from,
 
        info->res = request_mem_region(dev->resource->start, 
index 2e410ef..046f7ef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: l440gx.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: l440gx.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * BIOS Flash chip on Intel 440GX board.
  *
@@ -46,7 +46,7 @@ void l440gx_set_vpp(struct map_info *map, int vpp)
 struct map_info l440gx_map = {
        .name = "L440GX BIOS",
        .size = WINDOW_SIZE,
-       .buswidth = BUSWIDTH,
+       .bankwidth = BUSWIDTH,
        .phys = WINDOW_ADDR,
 #if 0
        /* FIXME verify that this is the 
index 36a14d6..2a2efaa 100644 (file)
@@ -1,14 +1,13 @@
 /*
- * Flash device on lasat 100 and 200 boards
+ * Flash device on Lasat 100 and 200 boards
  *
- * Presumably (C) 2002 Brian Murphy <brian@murphy.dk> or whoever he
- * works for.
+ * (C) 2002 Brian Murphy <brian@murphy.dk>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License version
  * 2 as published by the Free Software Foundation.
  *
- * $Id: lasat.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: lasat.c,v 1.7 2004/07/12 21:59:44 dwmw2 Exp $
  *
  */
 
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
 #include <asm/lasat/lasat.h>
-#include <asm/lasat/lasat_mtd.h>
 
-static struct mtd_info *mymtd;
-
-static struct map_info sp_map = {
-       .name = "SP flash",
-       .buswidth = 4,
-};
+static struct mtd_info *lasat_mtd;
 
 static struct mtd_partition partition_info[LASAT_MTD_LAST];
 static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
 
-static int __init init_sp(void)
+static void lasat_set_vpp(struct map_info *map, int vpp)
 {
-       int i;
-       /* this does not play well with the old flash code which 
-        * protects and uprotects the flash when necessary */
-       /* FIXME: Implement set_vpp() */
-               printk(KERN_NOTICE "Unprotecting flash\n");
-       *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
+       if (vpp)
+           *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
+       else
+           *lasat_misc->flash_wp_reg &= ~(1 << lasat_misc->flash_wp_bit);
+}
+
+static struct map_info lasat_map = {
+       .name = "LASAT flash",
+       .bankwidth = 4,
+       .set_vpp = lasat_set_vpp
+};
 
-       sp_map.virt = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
-       sp_map.phys = virt_to_phys(sp_map.virt);
-       sp_map.size = lasat_board_info.li_flash_size;
+static int __init init_lasat(void)
+{
+       int i;
+       /* since we use AMD chips and set_vpp is not implimented
+        * for these (yet) we still have to permanently enable flash write */
+       printk(KERN_NOTICE "Unprotecting flash\n");
+       ENABLE_VPP((&lasat_map));
 
-       simple_map_init(&sp_map);
+       lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
+       lasat_map.virt = (unsigned long)ioremap_nocache(
+                       lasat_map.phys, lasat_board_info.li_flash_size);
+       lasat_map.size = lasat_board_info.li_flash_size;
 
-               printk(KERN_NOTICE "sp flash device: %lx at %lx\n", 
-                       sp_map.size, sp_map.phys);
+       simple_map_init(&lasat_map);
 
        for (i=0; i < LASAT_MTD_LAST; i++)
                partition_info[i].name = lasat_mtd_partnames[i];
 
-       mymtd = do_map_probe("cfi_probe", &sp_map);
-       if (mymtd) {
+       lasat_mtd = do_map_probe("cfi_probe", &lasat_map);
+
+       if (!lasat_mtd)
+           lasat_mtd = do_map_probe("jedec_probe", &lasat_map);
+
+       if (lasat_mtd) {
                u32 size, offset = 0;
 
-               mymtd->owner = THIS_MODULE;
+               lasat_mtd->owner = THIS_MODULE;
 
                for (i=0; i < LASAT_MTD_LAST; i++) {
                        size = lasat_flash_partition_size(i);
@@ -68,26 +76,26 @@ static int __init init_sp(void)
                        offset += size;
                }
 
-               add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST );
+               add_mtd_partitions( lasat_mtd, partition_info, LASAT_MTD_LAST );
                return 0;
        }
 
        return -ENXIO;
 }
 
-static void __exit cleanup_sp(void)
+static void __exit cleanup_lasat(void)
 {
-       if (mymtd) {
-               del_mtd_partitions(mymtd);
-               map_destroy(mymtd);
+       if (lasat_mtd) {
+               del_mtd_partitions(lasat_mtd);
+               map_destroy(lasat_mtd);
        }
-       if (sp_map.virt) {
-               sp_map.virt = 0;
+       if (lasat_map.virt) {
+               lasat_map.virt = 0;
        }
 }
 
-module_init(init_sp);
-module_exit(cleanup_sp);
+module_init(init_lasat);
+module_exit(cleanup_lasat);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>");
index 5f7bdd8..53e708b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: lubbock-flash.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: lubbock-flash.c,v 1.15 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * Map driver for the Lubbock developer platform.
  *
 
 #define WINDOW_SIZE    64*1024*1024
 
+static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
+{
+       consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+}
+
 static struct map_info lubbock_maps[2] = { {
        .size =         WINDOW_SIZE,
        .phys =         0x00000000,
+       .inval_cache =  lubbock_map_inval_cache,
 }, {
        .size =         WINDOW_SIZE,
        .phys =         0x04000000,
+       .inval_cache =  lubbock_map_inval_cache,
 } };
 
 static struct mtd_partition lubbock_partitions[] = {
@@ -64,7 +71,7 @@ static int __init init_lubbock(void)
        int flashboot = (LUB_CONF_SWITCHES & 1);
        int ret = 0, i;
 
-       lubbock_maps[0].buswidth = lubbock_maps[1].buswidth = 
+       lubbock_maps[0].bankwidth = lubbock_maps[1].bankwidth = 
                (BOOT_DEF & 1) ? 2 : 4;
 
        /* Compensate for the nROMBT switch which swaps the flash banks */
@@ -82,16 +89,23 @@ static int __init init_lubbock(void)
                                ret = -ENOMEM;
                        continue;
                }
+               lubbock_maps[i].cached = __ioremap(lubbock_maps[i].phys,
+                                                  WINDOW_SIZE,
+                                                  L_PTE_CACHEABLE, 1);
+               if (!lubbock_maps[i].cached)
+                       printk(KERN_WARNING "Failed to ioremap cached %s\n", lubbock_maps[i].name);
                simple_map_init(&lubbock_maps[i]);
 
-               printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit buswidth)\n",
+               printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
                       lubbock_maps[i].name, lubbock_maps[i].phys, 
-                      lubbock_maps[i].buswidth * 8);
+                      lubbock_maps[i].bankwidth * 8);
 
                mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]);
                
                if (!mymtds[i]) {
                        iounmap((void *)lubbock_maps[i].virt);
+                       if (lubbock_maps[i].cached)
+                               iounmap(lubbock_maps[i].cached);
                        if (!ret)
                                ret = -EIO;
                        continue;
@@ -138,6 +152,8 @@ static void __exit cleanup_lubbock(void)
 
                map_destroy(mymtds[i]);
                iounmap((void *)lubbock_maps[i].virt);
+               if (lubbock_maps[i].cached)
+                       iounmap(lubbock_maps[i].cached);
 
                if (parsed_parts[i])
                        kfree(parsed_parts[i]);
index 4bb4af6..38f6a7a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: map_funcs.c,v 1.2 2003/05/21 15:15:07 dwmw2 Exp $
+ * $Id: map_funcs.c,v 1.9 2004/07/13 22:33:15 dwmw2 Exp $
  *
  * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS
  * is enabled.
@@ -7,87 +7,35 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <asm/io.h>
 
 #include <linux/mtd/map.h>
-#include <linux/mtd/cfi.h>
 
-static u8 simple_map_read8(struct map_info *map, unsigned long ofs)
+static map_word simple_map_read(struct map_info *map, unsigned long ofs)
 {
-       return __raw_readb(map->virt + ofs);
+       return inline_map_read(map, ofs);
 }
 
-static u16 simple_map_read16(struct map_info *map, unsigned long ofs)
+static void simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
 {
-       return __raw_readw(map->virt + ofs);
-}
-
-static u32 simple_map_read32(struct map_info *map, unsigned long ofs)
-{
-       return __raw_readl(map->virt + ofs);
-}
-
-static u64 simple_map_read64(struct map_info *map, unsigned long ofs)
-{
-#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
-       BUG();
-       return 0;
-#else
-       return __raw_readll(map->virt + ofs);
-#endif
-}
-
-static void simple_map_write8(struct map_info *map, u8 datum, unsigned long ofs)
-{
-       __raw_writeb(datum, map->virt + ofs);
-       mb();
-}
-
-static void simple_map_write16(struct map_info *map, u16 datum, unsigned long ofs)
-{
-       __raw_writew(datum, map->virt + ofs);
-       mb();
-}
-
-static void simple_map_write32(struct map_info *map, u32 datum, unsigned long ofs)
-{
-       __raw_writel(datum, map->virt + ofs);
-       mb();
-}
-
-static void simple_map_write64(struct map_info *map, u64 datum, unsigned long ofs)
-{
-#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
-       BUG();
-#else
-       __raw_writell(datum, map->virt + ofs);
-       mb();
-#endif /* CFI_B8 */
+       inline_map_write(map, datum, ofs);
 }
 
 static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
-       memcpy_fromio(to, map->virt + from, len);
+       inline_map_copy_from(map, to, from, len);
 }
 
 static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
-       memcpy_toio(map->virt + to, from, len);
+       inline_map_copy_to(map, to, from, len);
 }
 
 void simple_map_init(struct map_info *map)
 {
-       map->read8 = simple_map_read8;
-       map->read16 = simple_map_read16;
-       map->read32 = simple_map_read32;
-       map->read64 = simple_map_read64;
-       map->write8 = simple_map_write8;
-       map->write16 = simple_map_write16;
-       map->write32 = simple_map_write32;
-       map->write64 = simple_map_write64;
+       BUG_ON(!map_bankwidth_supported(map->bankwidth));
+
+       map->read = simple_map_read;
+       map->write = simple_map_write;
        map->copy_from = simple_map_copy_from;
        map->copy_to = simple_map_copy_to;
 }
index 5adbec8..4c0f9e9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mbx860.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: mbx860.c,v 1.6 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * Handle mapping of the flash on MBX860 boards
  *
@@ -54,7 +54,7 @@ struct map_info mbx_map = {
        .name = "MBX flash",
        .size = WINDOW_SIZE,
        .phys = WINDOW_ADDR,
-       .buswidth = 4,
+       .bankwidth = 4,
 };
 
 int __init init_mbx(void)
index caaac71..afdf658 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
  *     based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
  *
- * $Id: netsc520.c,v 1.9 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: netsc520.c,v 1.10 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -84,7 +84,7 @@ static struct mtd_partition partition_info[]={
 static struct map_info netsc520_map = {
        .name = "netsc520 Flash Bank",
        .size = WINDOW_SIZE,
-       .buswidth = 4,
+       .bankwidth = 4,
        .phys = WINDOW_ADDR,
 };
 
index 53a9934..e06b073 100644 (file)
@@ -6,7 +6,7 @@
  *      (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
  *      (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
  *
- *     $Id: nettel.c,v 1.4 2003/05/20 20:59:30 dwmw2 Exp $
+ *     $Id: nettel.c,v 1.5 2004/07/12 21:59:44 dwmw2 Exp $
  */
 
 /****************************************************************************/
@@ -65,7 +65,7 @@ static struct mtd_info *amd_mtd;
 static struct map_info nettel_intel_map = {
        .name = "SnapGear Intel",
        .size = 0,
-       .buswidth = INTEL_BUSWIDTH,
+       .bankwidth = INTEL_BUSWIDTH,
 };
 
 static struct mtd_partition nettel_intel_partitions[] = {
@@ -103,7 +103,7 @@ static struct mtd_partition nettel_intel_partitions[] = {
 static struct map_info nettel_amd_map = {
        .name = "SnapGear AMD",
        .size = AMD_WINDOW_MAXSIZE,
-       .buswidth = AMD_BUSWIDTH,
+       .bankwidth = AMD_BUSWIDTH,
 };
 
 static struct mtd_partition nettel_amd_partitions[] = {
index 201f67a..40c524d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ocelot.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: ocelot.c,v 1.13 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * Flash on Momenco Ocelot
  */
@@ -49,14 +49,14 @@ static struct mtd_partition *parsed_parts;
 struct map_info ocelot_flash_map = {
        .name = "Ocelot boot flash",
        .size = FLASH_WINDOW_SIZE,
-       .buswidth = FLASH_BUSWIDTH,
+       .bankwidth = FLASH_BUSWIDTH,
        .phys = FLASH_WINDOW_ADDR,
 };
 
 struct map_info ocelot_nvram_map = {
        .name = "Ocelot NVRAM",
        .size = NVRAM_WINDOW_SIZE,
-       .buswidth = NVRAM_BUSWIDTH,
+       .bankwidth = NVRAM_BUSWIDTH,
        .phys = NVRAM_WINDOW_ADDR,
 };
 
index 176890b..10bd890 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: octagon-5066.c,v 1.24 2003/05/21 15:15:07 dwmw2 Exp $
+// $Id: octagon-5066.c,v 1.26 2004/07/12 22:38:29 dwmw2 Exp $
 /* ######################################################################
 
    Octagon 5066 MTD Driver. 
@@ -62,32 +62,12 @@ static inline void oct5066_page(struct map_info *map, unsigned long ofs)
 }
 
 
-static __u8 oct5066_read8(struct map_info *map, unsigned long ofs)
+static map_word oct5066_read8(struct map_info *map, unsigned long ofs)
 {
-       __u8 ret;
+       map_word ret;
        spin_lock(&oct5066_spin);
        oct5066_page(map, ofs);
-       ret = readb(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&oct5066_spin);
-       return ret;
-}
-
-static __u16 oct5066_read16(struct map_info *map, unsigned long ofs)
-{
-       __u16 ret;
-       spin_lock(&oct5066_spin);
-       oct5066_page(map, ofs);
-       ret = readw(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&oct5066_spin);
-       return ret;
-}
-
-static __u32 oct5066_read32(struct map_info *map, unsigned long ofs)
-{
-       __u32 ret;
-       spin_lock(&oct5066_spin);
-       oct5066_page(map, ofs);
-       ret = readl(iomapadr + (ofs & WINDOW_MASK));
+       ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
        spin_unlock(&oct5066_spin);
        return ret;
 }
@@ -109,27 +89,11 @@ static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from
        }
 }
 
-static void oct5066_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-       spin_lock(&oct5066_spin);
-       oct5066_page(map, adr);
-       writeb(d, iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&oct5066_spin);
-}
-
-static void oct5066_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-       spin_lock(&oct5066_spin);
-       oct5066_page(map, adr);
-       writew(d, iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&oct5066_spin);
-}
-
-static void oct5066_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void oct5066_write8(struct map_info *map, map_word d, unsigned long adr)
 {
        spin_lock(&oct5066_spin);
        oct5066_page(map, adr);
-       writel(d, iomapadr + (adr & WINDOW_MASK));
+       writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
        spin_unlock(&oct5066_spin);
 }
 
@@ -155,14 +119,10 @@ static struct map_info oct5066_map[2] = {
                .name = "Octagon 5066 Socket",
                .phys = NO_XIP,
                .size = 512 * 1024,
-               .buswidth = 1,
-               .read8 = oct5066_read8,
-               .read16 = oct5066_read16,
-               .read32 = oct5066_read32,
+               .bankwidth = 1,
+               .read = oct5066_read8,
                .copy_from = oct5066_copy_from,
-               .write8 = oct5066_write8,
-               .write16 = oct5066_write16,
-               .write32 = oct5066_write32,
+               .write = oct5066_write8,
                .copy_to = oct5066_copy_to,
                .map_priv_1 = 1<<6
        },
@@ -170,14 +130,10 @@ static struct map_info oct5066_map[2] = {
                .name = "Octagon 5066 Internal Flash",
                .phys = NO_XIP,
                .size = 2 * 1024 * 1024,
-               .buswidth = 1,
-               .read8 = oct5066_read8,
-               .read16 = oct5066_read16,
-               .read32 = oct5066_read32,
+               .bankwidth = 1,
+               .read = oct5066_read8,
                .copy_from = oct5066_copy_from,
-               .write8 = oct5066_write8,
-               .write16 = oct5066_write16,
-               .write32 = oct5066_write32,
+               .write = oct5066_write8,
                .copy_to = oct5066_copy_to,
                .map_priv_1 = 2<<6
        }
index 713c52b..b6b8ccf 100644 (file)
@@ -3,14 +3,14 @@
  * 
  * (C) 2001 Pete Popov <ppopov@mvista.com>
  * 
- * $Id: pb1xxx-flash.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: pb1xxx-flash.c,v 1.11 2004/07/12 21:59:44 dwmw2 Exp $
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/kernel.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #endif
 
 #ifdef CONFIG_MIPS_PB1000
+
 #define WINDOW_ADDR 0x1F800000
 #define WINDOW_SIZE 0x800000
-#endif
-
-
-static struct map_info pb1xxx_map = {
-       .name = "Pb1xxx flash",
-};
-
-
-#ifdef CONFIG_MIPS_PB1000
 
-static unsigned long flash_size = 0x00800000;
-static unsigned char flash_buswidth = 4;
 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
-        }
+                .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)
 
-static unsigned char flash_buswidth = 4;
 #if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-/* both 32MiB banks will be used. Combine the first 32MiB bank and the
- * first 28MiB of the second bank together into a single jffs/jffs2
+/* 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.
  */
-static unsigned long flash_size = 0x04000000;
 #define WINDOW_ADDR 0x1C000000
 #define WINDOW_SIZE 0x4000000
 static struct mtd_partition pb1xxx_partitions[] = {
         {
-                .name = "User FS",
-                .size =   0x3c00000,
-                .offset = 0x0000000
+                .name         =   "User FS",
+                .size         =   0x3c00000,
+                .offset       =   0x0000000
         },{
-                .name = "yamon",
-                .size = 0x0100000,
-                .offset = 0x3c00000,
-                .mask_flags = MTD_WRITEABLE
+                .name         =   "yamon",
+                .size         =   0x0100000,
+                .offset       =   0x3c00000,
+                .mask_flags   =   MTD_WRITEABLE
         },{
-                .name = "raw kernel",
-                .size = 0x02c0000,
-                .offset = 0x3d00000
+                .name         =   "raw kernel",
+                .size         =   0x02c0000,
+                .offset       =   0x3d00000
         }
 };
 #elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
-static unsigned long flash_size = 0x02000000;
 #define WINDOW_ADDR 0x1E000000
 #define WINDOW_SIZE 0x2000000
 static struct mtd_partition pb1xxx_partitions[] = {
         {
-                .name = "User FS",
-                .size =   0x1c00000,
-                .offset = 0x0000000
+                .name         =   "User FS",
+                .size         =   0x1c00000,
+                .offset       =   0x0000000
         },{
-                .name = "yamon",
-                .size = 0x0100000,
-                .offset = 0x1c00000,
-                .mask_flags = MTD_WRITEABLE
+                .name         =   "yamon",
+                .size         =   0x0100000,
+                .offset       =   0x1c00000,
+                .mask_flags   =   MTD_WRITEABLE
         },{
-                .name = "raw kernel",
-                .size = 0x02c0000,
-                .offset = 0x1d00000
+                .name         =   "raw kernel",
+                .size         =   0x02c0000,
+                .offset       =   0x1d00000
         }
 };
 #elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-static unsigned long flash_size = 0x02000000;
 #define WINDOW_ADDR 0x1C000000
 #define WINDOW_SIZE 0x2000000
 static struct mtd_partition pb1xxx_partitions[] = {
         {
-                .name = "User FS",
-                .size =   0x1e00000,
-                .offset = 0x0000000
+                .name         =   "User FS",
+                .size         =    0x1e00000,
+                .offset       =    0x0000000
         },{
-                .name = "raw kernel",
-                .size = 0x0200000,
-                .offset = 0x1e00000,
+                .name         =    "raw kernel",
+                .size         =    0x0200000,
+                .offset       =    0x1e00000,
         }
 };
 #else
@@ -131,8 +116,20 @@ static struct mtd_partition pb1xxx_partitions[] = {
 #error Unsupported board
 #endif
 
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *mymtd;
+#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)
 {
@@ -140,49 +137,38 @@ int __init pb1xxx_mtd_init(void)
        int nb_parts = 0;
        char *part_type;
        
-       /* Default flash buswidth */
-       pb1xxx_map.buswidth = flash_buswidth;
-
        /*
         * Static partition definition selection
         */
        part_type = "static";
        parts = pb1xxx_partitions;
        nb_parts = ARRAY_SIZE(pb1xxx_partitions);
-       pb1xxx_map.size = flash_size;
 
        /*
         * 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", 
-                       pb1xxx_map.buswidth*8);
-       pb1xxx_map.phys = WINDOW_ADDR;
-       pb1xxx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+                       BUSWIDTH*8);
+       pb1xxx_mtd_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 
-       simple_map_init(&pb1xxx_map);
+       simple_map_init(&pb1xxx_mtd_map);
 
-       mymtd = do_map_probe("cfi_probe", &pb1xxx_map);
-       if (!mymtd) {
-               iounmap(pb1xxx_map.virt);
-               return -ENXIO;
-       }
-       mymtd->owner = THIS_MODULE;
+       pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map);
+       if (!pb1xxx_mtd) return -ENXIO;
+       pb1xxx_mtd->owner = THIS_MODULE;
 
-       add_mtd_partitions(mymtd, parts, nb_parts);
+       add_mtd_partitions(pb1xxx_mtd, parts, nb_parts);
        return 0;
 }
 
 static void __exit pb1xxx_mtd_cleanup(void)
 {
-       if (mymtd) {
-               del_mtd_partitions(mymtd);
-               map_destroy(mymtd);
-               if (parsed_parts)
-                       kfree(parsed_parts);
+       if (pb1xxx_mtd) {
+               del_mtd_partitions(pb1xxx_mtd);
+               map_destroy(pb1xxx_mtd);
+               iounmap((void *) pb1xxx_mtd_map.virt);
        }
-       if (pb1xxx_map.virt)
-               iounmap(pb1xxx_map.virt);
 }
 
 module_init(pb1xxx_mtd_init);
index 8baca24..8b5d1ff 100644 (file)
@@ -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.5 2003/05/20 20:59:31 dwmw2 Exp $
+ *  $Id: pci.c,v 1.8 2004/07/12 22:38:29 dwmw2 Exp $
  * 
  * Generic PCI memory map driver.  We support the following boards:
  *  - Intel IQ80310 ATU.
@@ -39,6 +39,74 @@ struct map_pci_info {
        struct pci_dev *dev;
 };     
 
+static map_word mtd_pci_read8(struct map_info *_map, unsigned long ofs)
+{
+       struct map_pci_info *map = (struct map_pci_info *)_map;
+       map_word val;
+       val.x[0]= readb(map->base + map->translate(map, ofs));
+//     printk("read8 : %08lx => %02x\n", ofs, val.x[0]);
+       return val;
+}
+
+#if 0
+static map_word mtd_pci_read16(struct map_info *_map, unsigned long ofs)
+{
+       struct map_pci_info *map = (struct map_pci_info *)_map;
+       map_word val;
+       val.x[0] = readw(map->base + map->translate(map, ofs));
+//     printk("read16: %08lx => %04x\n", ofs, val.x[0]);
+       return val;
+}
+#endif
+static map_word mtd_pci_read32(struct map_info *_map, unsigned long ofs)
+{
+       struct map_pci_info *map = (struct map_pci_info *)_map;
+       map_word val;
+       val.x[0] = readl(map->base + map->translate(map, ofs));
+//     printk("read32: %08lx => %08x\n", ofs, val.x[0]);
+       return val;
+}
+
+static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
+{
+       struct map_pci_info *map = (struct map_pci_info *)_map;
+       memcpy_fromio(to, map->base + map->translate(map, from), len);
+}
+
+static void mtd_pci_write8(struct map_info *_map, map_word val, unsigned long ofs)
+{
+       struct map_pci_info *map = (struct map_pci_info *)_map;
+//     printk("write8 : %08lx <= %02x\n", ofs, val.x[0]);
+       writeb(val.x[0], map->base + map->translate(map, ofs));
+}
+
+#if 0
+static void mtd_pci_write16(struct map_info *_map, map_word val, unsigned long ofs)
+{
+       struct map_pci_info *map = (struct map_pci_info *)_map;
+//     printk("write16: %08lx <= %04x\n", ofs, val.x[0]);
+       writew(val.x[0], map->base + map->translate(map, ofs));
+}
+#endif
+static void mtd_pci_write32(struct map_info *_map, map_word val, unsigned long ofs)
+{
+       struct map_pci_info *map = (struct map_pci_info *)_map;
+//     printk("write32: %08lx <= %08x\n", ofs, val.x[0]);
+       writel(val.x[0], map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
+{
+       struct map_pci_info *map = (struct map_pci_info *)_map;
+       memcpy_toio(map->base + map->translate(map, to), from, len);
+}
+
+static struct map_info mtd_pci_map = {
+       .phys =         NO_XIP,
+       .copy_from =    mtd_pci_copyfrom,
+       .copy_to =      mtd_pci_copyto,
+};
+
 /*
  * Intel IOP80310 Flash driver
  */
@@ -48,7 +116,10 @@ intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map)
 {
        u32 win_base;
 
-       map->map.buswidth = 1;
+       map->map.bankwidth = 1;
+       map->map.read = mtd_pci_read8,
+       map->map.write = mtd_pci_write8,
+
        map->map.size     = 0x00800000;
        map->base         = ioremap_nocache(pci_resource_start(dev, 0),
                                            pci_resource_len(dev, 0));
@@ -147,7 +218,9 @@ intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)
        if (!len || !base)
                return -ENXIO;
 
-       map->map.buswidth = 4;
+       map->map.bankwidth = 4;
+       map->map.read = mtd_pci_read32,
+       map->map.write = mtd_pci_write32,
        map->map.size     = len;
        map->base         = ioremap_nocache(base, len);
 
@@ -215,75 +288,6 @@ static struct pci_device_id mtd_pci_ids[] = {
  * Generic code follows.
  */
 
-static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs)
-{
-       struct map_pci_info *map = (struct map_pci_info *)_map;
-       u8 val = readb(map->base + map->translate(map, ofs));
-//     printk("read8 : %08lx => %02x\n", ofs, val);
-       return val;
-}
-
-static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs)
-{
-       struct map_pci_info *map = (struct map_pci_info *)_map;
-       u16 val = readw(map->base + map->translate(map, ofs));
-//     printk("read16: %08lx => %04x\n", ofs, val);
-       return val;
-}
-
-static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs)
-{
-       struct map_pci_info *map = (struct map_pci_info *)_map;
-       u32 val = readl(map->base + map->translate(map, ofs));
-//     printk("read32: %08lx => %08x\n", ofs, val);
-       return val;
-}
-
-static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
-{
-       struct map_pci_info *map = (struct map_pci_info *)_map;
-       memcpy_fromio(to, map->base + map->translate(map, from), len);
-}
-
-static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs)
-{
-       struct map_pci_info *map = (struct map_pci_info *)_map;
-//     printk("write8 : %08lx <= %02x\n", ofs, val);
-       writeb(val, map->base + map->translate(map, ofs));
-}
-
-static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs)
-{
-       struct map_pci_info *map = (struct map_pci_info *)_map;
-//     printk("write16: %08lx <= %04x\n", ofs, val);
-       writew(val, map->base + map->translate(map, ofs));
-}
-
-static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs)
-{
-       struct map_pci_info *map = (struct map_pci_info *)_map;
-//     printk("write32: %08lx <= %08x\n", ofs, val);
-       writel(val, map->base + map->translate(map, ofs));
-}
-
-static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
-{
-       struct map_pci_info *map = (struct map_pci_info *)_map;
-       memcpy_toio(map->base + map->translate(map, to), from, len);
-}
-
-static struct map_info mtd_pci_map = {
-       .phys =         NO_XIP,
-       .read8 =        mtd_pci_read8,
-       .read16 =       mtd_pci_read16,
-       .read32 =       mtd_pci_read32,
-       .copy_from =    mtd_pci_copyfrom,
-       .write8 =       mtd_pci_write8,
-       .write16 =      mtd_pci_write16,
-       .write32 =      mtd_pci_write32,
-       .copy_to =      mtd_pci_copyto,
-};
-
 static int __devinit
 mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
index 4453a27..ec63e3b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: pcmciamtd.c,v 1.48 2003/06/24 07:14:38 spse Exp $
+ * $Id: pcmciamtd.c,v 1.51 2004/07/12 22:38:29 dwmw2 Exp $
  *
  * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
  *
@@ -49,7 +49,7 @@ static const int debug = 0;
 
 
 #define DRIVER_DESC    "PCMCIA Flash memory card driver"
-#define DRIVER_VERSION "$Revision: 1.48 $"
+#define DRIVER_VERSION "$Revision: 1.51 $"
 
 /* Size of the PCMCIA address space: 26 bits = 64 MB */
 #define MAX_PCMCIA_ADDR        0x4000000
@@ -73,7 +73,7 @@ static dev_link_t *dev_list;
 /* Module parameters */
 
 /* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
-static int buswidth = 2;
+static int bankwidth = 2;
 
 /* Speed of memory accesses, in ns */
 static int mem_speed;
@@ -93,8 +93,8 @@ static int mem_type;
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
 MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_PARM(buswidth, "i");
-MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
+MODULE_PARM(bankwidth, "i");
+MODULE_PARM_DESC(bankwidth, "Set bankwidth (1=8 bit, 2=16 bit, default=2)");
 MODULE_PARM(mem_speed, "i");
 MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
 MODULE_PARM(force_size, "i");
@@ -135,32 +135,32 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
 }
 
 
-static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
+static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
 {
        caddr_t addr;
-       u8 d;
+       map_word d = {{0}};
 
        addr = remap_window(map, ofs);
        if(!addr)
-               return 0;
+               return d;
 
-       d = readb(addr);
-       DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d);
+       d.x[0] = readb(addr);
+       DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d.x[0]);
        return d;
 }
 
 
-static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
+static map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
 {
        caddr_t addr;
-       u16 d;
+       map_word d = {{0}};
 
        addr = remap_window(map, ofs);
        if(!addr)
-               return 0;
+               return d;
 
-       d = readw(addr);
-       DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d);
+       d.x[0] = readw(addr);
+       DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d.x[0]);
        return d;
 }
 
@@ -191,26 +191,26 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long
 }
 
 
-static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr)
+static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long adr)
 {
        caddr_t addr = remap_window(map, adr);
 
        if(!addr)
                return;
 
-       DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02x", adr, addr, d);
-       writeb(d, addr);
+       DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02x", adr, addr, d.x[0]);
+       writeb(d.x[0], addr);
 }
 
 
-static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr)
+static void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long adr)
 {
        caddr_t addr = remap_window(map, adr);
        if(!addr)
                return;
 
-       DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04x", adr, addr, d);
-       writew(d, addr);
+       DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04x", adr, addr, d.x[0]);
+       writew(d.x[0], addr);
 }
 
 
@@ -244,30 +244,30 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v
 
 #define DEV_REMOVED(x)  (!(*(u_int *)x->map_priv_1 & DEV_PRESENT))
 
-static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
+static map_word pcmcia_read8(struct map_info *map, unsigned long ofs)
 {
        caddr_t win_base = (caddr_t)map->map_priv_2;
-       u8 d;
+       map_word d = {{0}};
 
        if(DEV_REMOVED(map))
-               return 0;
+               return d;
 
-       d = readb(win_base + ofs);
-       DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
+       d.x[0] = readb(win_base + ofs);
+       DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d.x[0]);
        return d;
 }
 
 
-static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
+static map_word pcmcia_read16(struct map_info *map, unsigned long ofs)
 {
        caddr_t win_base = (caddr_t)map->map_priv_2;
-       u16 d;
+       map_word d = {{0}};
 
        if(DEV_REMOVED(map))
-               return 0;
+               return d;
 
-       d = readw(win_base + ofs);
-       DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
+       d.x[0] = readw(win_base + ofs);
+       DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d.x[0]);
        return d;
 }
 
@@ -439,9 +439,9 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
                case CISTPL_DEVICE_GEO: {
                        cistpl_device_geo_t *t = &parse.device_geo;
                        int i;
-                       dev->pcmcia_map.buswidth = t->geo[0].buswidth;
+                       dev->pcmcia_map.bankwidth = t->geo[0].buswidth;
                        for(i = 0; i < t->ngeo; i++) {
-                               DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth);
+                               DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth);
                                DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
                                DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
                                DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
@@ -460,17 +460,17 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
        if(!dev->pcmcia_map.size)
                dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
 
-       if(!dev->pcmcia_map.buswidth)
-               dev->pcmcia_map.buswidth = 2;
+       if(!dev->pcmcia_map.bankwidth)
+               dev->pcmcia_map.bankwidth = 2;
 
        if(force_size) {
                dev->pcmcia_map.size = force_size << 20;
                DEBUG(2, "size forced to %dM", force_size);
        }
 
-       if(buswidth) {
-               dev->pcmcia_map.buswidth = buswidth;
-               DEBUG(2, "buswidth forced to %d", buswidth);
+       if(bankwidth) {
+               dev->pcmcia_map.bankwidth = bankwidth;
+               DEBUG(2, "bankwidth forced to %d", bankwidth);
        }               
 
        dev->pcmcia_map.name = dev->mtd_name;
@@ -480,7 +480,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_
        }
 
        DEBUG(1, "Device: Size: %lu Width:%d Name: %s",
-             dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name);
+             dev->pcmcia_map.size, dev->pcmcia_map.bankwidth << 3, dev->mtd_name);
 }
 
 
@@ -522,12 +522,15 @@ static void pcmciamtd_config(dev_link_t *link)
        card_settings(dev, link, &new_name);
 
        dev->pcmcia_map.phys = NO_XIP;
-       dev->pcmcia_map.read8 = pcmcia_read8_remap;
-       dev->pcmcia_map.read16 = pcmcia_read16_remap;
        dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
-       dev->pcmcia_map.write8 = pcmcia_write8_remap;
-       dev->pcmcia_map.write16 = pcmcia_write16_remap;
        dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
+       if (dev->pcmcia_map.bankwidth == 1) {
+               dev->pcmcia_map.read = pcmcia_read8_remap;
+               dev->pcmcia_map.write = pcmcia_write8_remap;
+       } else {
+               dev->pcmcia_map.read = pcmcia_read16_remap;
+               dev->pcmcia_map.write = pcmcia_write16_remap;
+       }
        if(setvpp == 1)
                dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
 
@@ -536,7 +539,7 @@ static void pcmciamtd_config(dev_link_t *link)
           whole card - otherwise we try smaller windows until we succeed */
 
        req.Attributes =  WIN_MEMORY_TYPE_CM | WIN_ENABLE;
-       req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
+       req.Attributes |= (dev->pcmcia_map.bankwidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
        req.Base = 0;
        req.AccessSpeed = mem_speed;
        link->win = (window_handle_t)link->handle;
@@ -657,11 +660,14 @@ static void pcmciamtd_config(dev_link_t *link)
                DEBUG(1, "Using non remapping memory functions");
                dev->pcmcia_map.map_priv_1 = (unsigned long)&(dev->link.state);
                dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
-               dev->pcmcia_map.read8 = pcmcia_read8;
-               dev->pcmcia_map.read16 = pcmcia_read16;
+               if (dev->pcmcia_map.bankwidth == 1) {
+                       dev->pcmcia_map.read = pcmcia_read8;
+                       dev->pcmcia_map.write = pcmcia_write8;
+               } else {
+                       dev->pcmcia_map.read = pcmcia_read16;
+                       dev->pcmcia_map.write = pcmcia_write16;
+               }
                dev->pcmcia_map.copy_from = pcmcia_copy_from;
-               dev->pcmcia_map.write8 = pcmcia_write8;
-               dev->pcmcia_map.write16 = pcmcia_write16;
                dev->pcmcia_map.copy_to = pcmcia_copy_to;
        }
 
@@ -828,9 +834,9 @@ static int __init init_pcmciamtd(void)
 {
        info(DRIVER_DESC " " DRIVER_VERSION);
 
-       if(buswidth && buswidth != 1 && buswidth != 2) {
-               info("bad buswidth (%d), using default", buswidth);
-               buswidth = 2;
+       if(bankwidth && bankwidth != 1 && bankwidth != 2) {
+               info("bad bankwidth (%d), using default", bankwidth);
+               bankwidth = 2;
        }
        if(force_size && (force_size < 1 || force_size > 64)) {
                info("bad force_size (%d), using default", force_size);
index 279d601..8dfd0b2 100644 (file)
@@ -1,7 +1,12 @@
 /*
- * $Id: physmap.c,v 1.29 2003/05/29 09:24:10 dwmw2 Exp $
+ * $Id: physmap.c,v 1.33 2004/07/12 14:37:24 dwmw2 Exp $
  *
  * Normal mappings of chips in physical memory
+ *
+ * Copyright (C) 2003 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * 031022 - [jsun] add run-time configure and partition setup
  */
 
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/mtd/partitions.h>
 
-#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START
-#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN
-#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH
-
 static struct mtd_info *mymtd;
 
-
-struct map_info physmap_map = {
-       .name = "Physically mapped flash",
-       .size = WINDOW_SIZE,
-       .buswidth = BUSWIDTH,
-       .phys = WINDOW_ADDR,
-};
+struct map_info physmap_map = {.name = "phys_mapped_flash"};
 
 #ifdef CONFIG_MTD_PARTITIONS
 static struct mtd_partition *mtd_parts;
 static int                   mtd_parts_nb;
 
-static struct mtd_partition physmap_partitions[] = {
-#if 0
-/* Put your own partition definitions here */
-       {
-               .name =         "bootROM",
-               .size =         0x80000,
-               .offset =       0,
-               .mask_flags =   MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name =         "zImage",
-               .size =         0x100000,
-               .offset =       MTDPART_OFS_APPEND,
-               .mask_flags =   MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name =         "ramdisk.gz",
-               .size =         0x300000,
-               .offset =       MTDPART_OFS_APPEND,
-               .mask_flags =   MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name =         "User FS",
-               .size =         MTDPART_SIZ_FULL,
-               .offset =       MTDPART_OFS_APPEND,
-       }
-#endif
-};
+static int num_physmap_partitions;
+static struct mtd_partition *physmap_partitions;
 
-#define NUM_PARTITIONS (sizeof(physmap_partitions)/sizeof(struct mtd_partition))
-const char *part_probes[] = {"cmdlinepart", "RedBoot", NULL};
+static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
 
+void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
+{
+       physmap_partitions=parts;
+       num_physmap_partitions=num_parts;
+}
 #endif /* CONFIG_MTD_PARTITIONS */
 
-int __init init_physmap(void)
+static int __init init_physmap(void)
 {
        static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
        const char **type;
 
-               printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
-       physmap_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
+               printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys);
+       physmap_map.virt = (unsigned long)ioremap(physmap_map.phys, physmap_map.size);
 
        if (!physmap_map.virt) {
                printk("Failed to ioremap\n");
@@ -97,11 +73,11 @@ int __init init_physmap(void)
                        return 0;
                }
 
-               if (NUM_PARTITIONS != 0) 
+               if (num_physmap_partitions != 0) 
                {
                        printk(KERN_NOTICE 
                               "Using physmap partition definition\n");
-                       add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS);
+                       add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions);
                        return 0;
                }
 
@@ -121,7 +97,7 @@ static void __exit cleanup_physmap(void)
        if (mtd_parts_nb) {
                del_mtd_partitions(mymtd);
                kfree(mtd_parts);
-       } else if (NUM_PARTITIONS) {
+       } else if (num_physmap_partitions) {
                del_mtd_partitions(mymtd);
        } else {
                del_mtd_device(mymtd);
index dcf68f2..b204786 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: pnc2000.c,v 1.14 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: pnc2000.c,v 1.15 2004/07/12 21:59:44 dwmw2 Exp $
  */
 
 #include <linux/module.h>
@@ -29,7 +29,7 @@
 struct map_info pnc_map = {
        .name = "PNC-2000",
        .size = WINDOW_SIZE,
-       .buswidth = 4,
+       .bankwidth = 4,
        .phys = 0xFFFFFFFF,
        .virt = WINDOW_ADDR,
 };
index 4ece1c8..acc3af9 100644 (file)
@@ -1,14 +1,13 @@
 /*
- * $Id: redwood.c,v 1.6 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: redwood.c,v 1.8 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * drivers/mtd/maps/redwood.c
  *
  * FLASH map for the IBM Redwood 4/5/6 boards.
  *
+ * Author: MontaVista Software, Inc. <source@mvista.com>
  *
- * Author: Armin Kuster <akuster@mvista.com>
- *
- * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
+ * 2001-2003 (c) MontaVista, Software, Inc. This file is licensed under
  * the terms of the GNU General Public License version 2. This program
  * is licensed "as is" without any warranty of any kind, whether express
  * or implied.
@@ -89,7 +88,7 @@ static struct mtd_partition redwood_flash_partitions[] = {
 
 static struct mtd_partition redwood_flash_partitions[] = {
        {
-               .name = "Redwood kernel",
+               .name = "Redwood filesystem",
                .offset = RW_PART0_OF,
                .size = RW_PART0_SZ
        },
@@ -100,7 +99,7 @@ static struct mtd_partition redwood_flash_partitions[] = {
                .mask_flags = MTD_WRITEABLE     /* force read-only */
        },
        {
-               .name = "Redwood filesystem",
+               .name = "Redwood kernel",
                .offset = RW_PART2_OF,
                .size = RW_PART2_SZ
        },
@@ -117,7 +116,7 @@ static struct mtd_partition redwood_flash_partitions[] = {
 struct map_info redwood_flash_map = {
        .name = "IBM Redwood",
        .size = WINDOW_SIZE,
-       .buswidth = 2,
+       .bankwidth = 2,
        .phys = WINDOW_ADDR,
 };
 
@@ -167,5 +166,5 @@ module_init(init_redwood_flash);
 module_exit(cleanup_redwood_flash);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Armin Kuster <akuster@mvista.com>");
+MODULE_AUTHOR("MontaVista Software <source@mvista.com>");
 MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards");
index 9c3e7da..837089a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: rpxlite.c,v 1.19 2003/05/21 12:45:19 dwmw2 Exp $
+ * $Id: rpxlite.c,v 1.20 2004/07/12 21:59:44 dwmw2 Exp $
  *
  * Handle mapping of the flash on the RPX Lite and CLLF boards
  */
@@ -21,7 +21,7 @@ static struct mtd_info *mymtd;
 static struct map_info rpxlite_map = {
        .name = "RPX",
        .size = WINDOW_SIZE,
-       .buswidth = 4,
+       .bankwidth = 4,
        .phys = WINDOW_ADDR,
 };
 
index 3ffedfa..c42ca6f 100644 (file)
@@ -3,7 +3,7 @@
  * 
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  * 
- * $Id: sa1100-flash.c,v 1.36 2003/05/29 08:59:35 dwmw2 Exp $
+ * $Id: sa1100-flash.c,v 1.39 2004/07/12 21:59:44 dwmw2 Exp $
  */
 
 #include <linux/config.h>
@@ -935,7 +935,7 @@ static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info *
                sa[i].map->virt = (unsigned long)sa[i].vbase;
                sa[i].map->phys = sa[i].base;
                sa[i].map->set_vpp = sa[i].set_vpp;
-               sa[i].map->buswidth = sa[i].width;
+               sa[i].map->bankwidth = sa[i].width;
                sa[i].map->size = sa[i].size;
 
                simple_map_init(sa[i].map);
@@ -1066,7 +1066,7 @@ static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
                return;
        }
 
-       sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4;
+       sa1100_probe_map.bankwidth = msc & MSC_RBW ? 2 : 4;
        sa1100_probe_map.size = SZ_1M;
        sa1100_probe_map.phys = phys;
        sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M);
@@ -1253,7 +1253,7 @@ static int __init sa1100_locate_flash(void)
                return nr;
 
        /*
-        * Retrieve the buswidth from the MSC registers.
+        * Retrieve the bankwidth from the MSC registers.
         * We currently only implement CS0 and CS1 here.
         */
        for (i = 0; i < nr; i++) {
index 4a1477f..7a9cb1d 100644 (file)
@@ -17,7 +17,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
-   $Id: sbc_gxx.c,v 1.26 2003/05/26 08:50:36 dwmw2 Exp $
+   $Id: sbc_gxx.c,v 1.29 2004/07/12 22:38:29 dwmw2 Exp $
 
 The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
 Intel StrataFlash (28F320/28F640) in x8 mode.  
@@ -114,32 +114,12 @@ static inline void sbc_gxx_page(struct map_info *map, unsigned long ofs)
 }
 
 
-static __u8 sbc_gxx_read8(struct map_info *map, unsigned long ofs)
+static map_word sbc_gxx_read8(struct map_info *map, unsigned long ofs)
 {
-       __u8 ret;
+       map_word ret;
        spin_lock(&sbc_gxx_spin);
        sbc_gxx_page(map, ofs);
-       ret = readb(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&sbc_gxx_spin);
-       return ret;
-}
-
-static __u16 sbc_gxx_read16(struct map_info *map, unsigned long ofs)
-{
-       __u16 ret;
-       spin_lock(&sbc_gxx_spin);
-       sbc_gxx_page(map, ofs);
-       ret = readw(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&sbc_gxx_spin);
-       return ret;
-}
-
-static __u32 sbc_gxx_read32(struct map_info *map, unsigned long ofs)
-{
-       __u32 ret;
-       spin_lock(&sbc_gxx_spin);
-       sbc_gxx_page(map, ofs);
-       ret = readl(iomapadr + (ofs & WINDOW_MASK));
+       ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
        spin_unlock(&sbc_gxx_spin);
        return ret;
 }
@@ -161,27 +141,11 @@ static void sbc_gxx_copy_from(struct map_info *map, void *to, unsigned long from
        }
 }
 
-static void sbc_gxx_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-       spin_lock(&sbc_gxx_spin);
-       sbc_gxx_page(map, adr);
-       writeb(d, iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&sbc_gxx_spin);
-}
-
-static void sbc_gxx_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-       spin_lock(&sbc_gxx_spin);
-       sbc_gxx_page(map, adr);
-       writew(d, iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&sbc_gxx_spin);
-}
-
-static void sbc_gxx_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void sbc_gxx_write8(struct map_info *map, map_word d, unsigned long adr)
 {
        spin_lock(&sbc_gxx_spin);
        sbc_gxx_page(map, adr);
-       writel(d, iomapadr + (adr & WINDOW_MASK));
+       writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
        spin_unlock(&sbc_gxx_spin);
 }
 
@@ -208,14 +172,10 @@ static struct map_info sbc_gxx_map = {
        .size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount
                         of flash so the cfi probe routines find all
                         the chips */
-       .buswidth = 1,
-       .read8 = sbc_gxx_read8,
-       .read16 = sbc_gxx_read16,
-       .read32 = sbc_gxx_read32,
+       .bankwidth = 1,
+       .read = sbc_gxx_read8,
        .copy_from = sbc_gxx_copy_from,
-       .write8 = sbc_gxx_write8,
-       .write16 = sbc_gxx_write16,
-       .write32 = sbc_gxx_write32,
+       .write = sbc_gxx_write8,
        .copy_to = sbc_gxx_copy_to
 };
 
index d446d55..8269b60 100644 (file)
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *
- * $Id: sc520cdp.c,v 1.15 2003/05/21 12:45:20 dwmw2 Exp $
+ * $Id: sc520cdp.c,v 1.16 2004/07/12 21:59:45 dwmw2 Exp $
  *
  *
  * The SC520CDP is an evaluation board for the Elan SC520 processor available
@@ -90,19 +90,19 @@ static struct map_info sc520cdp_map[] = {
        {
                .name = "SC520CDP Flash Bank #0",
                .size = WINDOW_SIZE_0,
-               .buswidth = 4,
+               .bankwidth = 4,
                .phys = WINDOW_ADDR_0
        },
        {
                .name = "SC520CDP Flash Bank #1",
                .size = WINDOW_SIZE_1,
-               .buswidth = 4,
+               .bankwidth = 4,
                .phys = WINDOW_ADDR_1
        },
        {
                .name = "SC520CDP DIL Flash",
                .size = WINDOW_SIZE_2,
-               .buswidth = 1,
+               .bankwidth = 1,
                .phys = WINDOW_ADDR_2
        },
 };
index d6d175f..ff2328d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * MTD map driver for BIOS Flash on Intel SCB2 boards
- * $Id: scb2_flash.c,v 1.6 2003/05/21 12:45:20 dwmw2 Exp $
+ * $Id: scb2_flash.c,v 1.8 2004/07/12 21:59:45 dwmw2 Exp $
  * Copyright (C) 2002 Sun Microsystems, Inc.
  * Tim Hockin <thockin@sun.com>
  *
@@ -67,7 +67,7 @@ static struct mtd_info *scb2_mtd;
 struct map_info scb2_map = {
        .name =      "SCB2 BIOS Flash",
        .size =      0,
-       .buswidth =  1,
+       .bankwidth =  1,
 };
 static int region_fail;
 
index c909f4b..58855a1 100644 (file)
@@ -2,7 +2,7 @@
 
    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
 
-   $Id: scx200_docflash.c,v 1.5 2003/05/21 12:45:20 dwmw2 Exp $ 
+   $Id: scx200_docflash.c,v 1.6 2004/07/12 21:59:45 dwmw2 Exp $ 
 
    National Semiconductor SCx200 flash mapped with DOCCS
 */
@@ -173,9 +173,9 @@ int __init init_scx200_docflash(void)
 
        scx200_docflash_map.size = size;
        if (width == 8)
-               scx200_docflash_map.buswidth = 1;
+               scx200_docflash_map.bankwidth = 1;
        else
-               scx200_docflash_map.buswidth = 2;
+               scx200_docflash_map.bankwidth = 2;
 
        simple_map_init(&scx200_docflash_map);
 
index ea2b7af..9b2eebe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: solutionengine.c,v 1.10 2003/05/21 12:45:20 dwmw2 Exp $
+ * $Id: solutionengine.c,v 1.13 2004/07/12 21:59:45 dwmw2 Exp $
  *
  * Flash and EPROM on Hitachi Solution Engine and similar boards.
  *
@@ -17,7 +17,7 @@
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/config.h>
-
+#include <linux/errno.h>
 
 static struct mtd_info *flash_mtd;
 static struct mtd_info *eprom_mtd;
@@ -27,13 +27,13 @@ static struct mtd_partition *parsed_parts;
 struct map_info soleng_eprom_map = {
        .name = "Solution Engine EPROM",
        .size = 0x400000,
-       .buswidth = 4,
+       .bankwidth = 4,
 };
 
 struct map_info soleng_flash_map = {
        .name = "Solution Engine FLASH",
        .size = 0x400000,
-       .buswidth = 4,
+       .bankwidth = 4,
 };
 
 static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
index b676e05..2a9932c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sun_uflash.c,v 1.7 2003/05/20 20:59:32 dwmw2 Exp $
+/* $Id: sun_uflash.c,v 1.9 2004/07/12 21:59:45 dwmw2 Exp $
  *
  * sun_uflash - Driver implementation for user-programmable flash
  * present on many Sun Microsystems SME boardsets.
@@ -51,7 +51,7 @@ struct uflash_dev {
 struct map_info uflash_map_templ = {
                .name =         "SUNW,???-????",
                .size =         UFLASH_WINDOW_SIZE,
-               .buswidth =     UFLASH_BUSWIDTH,
+               .bankwidth =    UFLASH_BUSWIDTH,
 };
 
 int uflash_devinit(struct linux_ebus_device* edev)
index 8ba73f1..496c985 100644 (file)
@@ -2,7 +2,7 @@
  * Handle mapping of the flash memory access routines 
  * on TQM8xxL based devices.
  *
- * $Id: tqm8xxl.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
+ * $Id: tqm8xxl.c,v 1.11 2004/07/12 21:59:45 dwmw2 Exp $
  *
  * based on rpxlite.c
  *
@@ -151,7 +151,7 @@ int __init init_tqm_mtd(void)
                sprintf(map_banks[idx]->name, "TQM8xxL%d", idx);
 
                map_banks[idx]->size = flash_size;
-               map_banks[idx]->buswidth = 4;
+               map_banks[idx]->bankwidth = 4;
 
                simple_map_init(map_banks[idx]);
 
index d4c9d28..170d712 100644 (file)
@@ -2,7 +2,7 @@
  * tsunami_flash.c
  *
  * flash chip on alpha ds10...
- * $Id: tsunami_flash.c,v 1.6 2003/05/21 15:15:08 dwmw2 Exp $
+ * $Id: tsunami_flash.c,v 1.9 2004/07/14 09:52:55 dwmw2 Exp $
  */
 #include <asm/io.h>
 #include <asm/core_tsunami.h>
 #define FLASH_DISABLE_BYTE 0x00
 
 #define MAX_TIG_FLASH_SIZE (12*1024*1024)
-static inline  __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset)
+static inline map_word tsunami_flash_read8(struct map_info *map, unsigned long offset)
 {
-       return tsunami_tig_readb(offset);
+       map_word val;
+       val.x[0] = tsunami_tig_readb(offset);
+       return val;
 }
 
-static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset)
+static void tsunami_flash_write8(struct map_info *map, map_word value, unsigned long offset)
 {
-       tsunami_tig_writeb(value, offset);
+       tsunami_tig_writeb(value.x[0], offset);
 }
 
 static void tsunami_flash_copy_from(
@@ -61,10 +63,10 @@ static struct map_info tsunami_flash_map = {
        .name = "flash chip on the Tsunami TIG bus",
        .size = MAX_TIG_FLASH_SIZE,
        .phys = NO_XIP;
-       .buswidth = 1,
-       .read8 = tsunami_flash_read8,
+       .bankwidth = 1,
+       .read = tsunami_flash_read8,
        .copy_from = tsunami_flash_copy_from,
-       .write8 = tsunami_flash_write8,
+       .write = tsunami_flash_write8,
        .copy_to = tsunami_flash_copy_to,
 };
 
@@ -84,7 +86,7 @@ static void __exit  cleanup_tsunami_flash(void)
 
 static int __init init_tsunami_flash(void)
 {
-       static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 };
+       static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
        char **type;
 
        tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT);
index 44d13f5..c5cd70b 100644 (file)
@@ -5,7 +5,7 @@
  *
  *     (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
  *
- *     $Id: uclinux.c,v 1.5 2003/05/20 20:59:32 dwmw2 Exp $
+ *     $Id: uclinux.c,v 1.7 2004/07/12 21:59:45 dwmw2 Exp $
  */
 
 /****************************************************************************/
@@ -64,7 +64,7 @@ int __init uclinux_mtd_init(void)
        mapp = &uclinux_ram_map;
        mapp->phys = (unsigned long) &_ebss;
        mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8)));
-       mapp->buswidth = 4;
+       mapp->bankwidth = 4;
 
        printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n",
                (int) mapp->map_priv_2, (int) mapp->size);
index a649609..9cf2629 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: vmax301.c,v 1.28 2003/05/21 15:15:08 dwmw2 Exp $
+// $Id: vmax301.c,v 1.30 2004/07/12 22:38:29 dwmw2 Exp $
 /* ######################################################################
 
    Tempustech VMAX SBC301 MTD Driver.
@@ -54,32 +54,12 @@ static inline void vmax301_page(struct map_info *map,
                __vmax301_page(map, page);
 }
 
-static __u8 vmax301_read8(struct map_info *map, unsigned long ofs)
+static map_word vmax301_read8(struct map_info *map, unsigned long ofs)
 {
-       __u8 ret;
+       map_word ret;
        spin_lock(&vmax301_spin);
        vmax301_page(map, ofs);
-       ret = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
-       spin_unlock(&vmax301_spin);
-       return ret;
-}
-
-static __u16 vmax301_read16(struct map_info *map, unsigned long ofs)
-{
-       __u16 ret;
-       spin_lock(&vmax301_spin);
-       vmax301_page(map, ofs);
-       ret = readw(map->map_priv_2 + (ofs & WINDOW_MASK));
-       spin_unlock(&vmax301_spin);
-       return ret;
-}
-
-static __u32 vmax301_read32(struct map_info *map, unsigned long ofs)
-{
-       __u32 ret;
-       spin_lock(&vmax301_spin);
-       vmax301_page(map, ofs);
-       ret =  readl(map->map_priv_2 + (ofs & WINDOW_MASK));
+       ret.x[0] = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
        spin_unlock(&vmax301_spin);
        return ret;
 }
@@ -100,27 +80,11 @@ static void vmax301_copy_from(struct map_info *map, void *to, unsigned long from
        }
 }
 
-static void vmax301_write8(struct map_info *map, __u8 d, unsigned long adr)
-{
-       spin_lock(&vmax301_spin);
-       vmax301_page(map, adr);
-       writeb(d, map->map_priv_2 + (adr & WINDOW_MASK));
-       spin_unlock(&vmax301_spin);
-}
-
-static void vmax301_write16(struct map_info *map, __u16 d, unsigned long adr)
-{
-       spin_lock(&vmax301_spin);
-       vmax301_page(map, adr);
-       writew(d, map->map_priv_2 + (adr & WINDOW_MASK));
-       spin_unlock(&vmax301_spin);
-}
-
-static void vmax301_write32(struct map_info *map, __u32 d, unsigned long adr)
+static void vmax301_write8(struct map_info *map, map_word d, unsigned long adr)
 {
        spin_lock(&vmax301_spin);
        vmax301_page(map, adr);
-       writel(d, map->map_priv_2 + (adr & WINDOW_MASK));
+       writeb(d.x[0], map->map_priv_2 + (adr & WINDOW_MASK));
        spin_unlock(&vmax301_spin);
 }
 
@@ -146,14 +110,10 @@ static struct map_info vmax_map[2] = {
                .name = "VMAX301 Internal Flash",
                .phys = NO_XIP,
                .size = 3*2*1024*1024,
-               .buswidth = 1,
-               .read8 = vmax301_read8,
-               .read16 = vmax301_read16,
-               .read32 = vmax301_read32,
+               .bankwidth = 1,
+               .read = vmax301_read8,
                .copy_from = vmax301_copy_from,
-               .write8 = vmax301_write8,
-               .write16 = vmax301_write16,
-               .write32 = vmax301_write32,
+               .write = vmax301_write8,
                .copy_to = vmax301_copy_to,
                .map_priv_1 = WINDOW_START + WINDOW_LENGTH,
                .map_priv_2 = 0xFFFFFFFF
@@ -162,14 +122,10 @@ static struct map_info vmax_map[2] = {
                .name = "VMAX301 Socket",
                .phys = NO_XIP,
                .size = 0,
-               .buswidth = 1,
-               .read8 = vmax301_read8,
-               .read16 = vmax301_read16,
-               .read32 = vmax301_read32,
+               .bankwidth = 1,
+               .read = vmax301_read8,
                .copy_from = vmax301_copy_from,
-               .write8 = vmax301_write8,
-               .write16 = vmax301_write16,
-               .write32 = vmax301_write32,
+               .write = vmax301_write8,
                .copy_to = vmax301_copy_to,
                .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
                .map_priv_2 = 0xFFFFFFFF
index 47216da..b7fdece 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: wr_sbc82xx_flash.c,v 1.1 2004/06/07 10:21:32 dwmw2 Exp $
+ * $Id: wr_sbc82xx_flash.c,v 1.5 2004/07/15 14:52:02 dwmw2 Exp $
  *
  * Map for flash chips on Wind River PowerQUICC II SBC82xx board.
  *
@@ -46,55 +46,69 @@ static struct mtd_partition smallflash_parts[] = {
 static struct mtd_partition bigflash_parts[] = {
        {
                .name =         "bootloader",
-               .size =         0x80000,
+               .size =         0x00100000,
                .offset =       0,
        }, {
                .name =         "file system",
-               .size =         MTDPART_SIZ_FULL,
+               .size =         0x01f00000,
+               .offset =       MTDPART_OFS_APPEND,
+       }, {
+               .name =         "boot config",
+               .size =         0x00100000,
+               .offset =       MTDPART_OFS_APPEND,
+       }, {
+               .name =         "space",
+               .size =         0x01f00000,
                .offset =       MTDPART_OFS_APPEND,
        }
 };
 
 static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
 
+#define init_sbc82xx_one_flash(map, br, or)                    \
+do {                                                           \
+       (map).phys = (br & 1) ? (br & 0xffff8000) : 0;          \
+       (map).size = (br & 1) ? (~(or & 0xffff8000) + 1) : 0;   \
+       switch (br & 0x00001800) {                              \
+       case 0x00000000:                                        \
+       case 0x00000800:        (map).bankwidth = 1;    break;  \
+       case 0x00001000:        (map).bankwidth = 2;    break;  \
+       case 0x00001800:        (map).bankwidth = 4;    break;  \
+       }                                                       \
+} while (0);
+
 int __init init_sbc82xx_flash(void)
 {
-       volatile  memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
+       volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
        int bigflash;
        int i;
 
-       /* First, register the boot flash, whichever we're booting from */
-       if ((mc->memc_br0 & 0x00001800) == 0x00001800) {
-               bigflash = 0;
-       } else if ((mc->memc_br0 & 0x00001800) == 0x00000800) {
-               bigflash = 1;
-       } else {
-               printk(KERN_WARNING "Bus Controller register BR0 is %08x. Cannot determine flash configuration\n", mc->memc_br0);
-               return 1;
-       }
+#ifdef CONFIG_SBC8560
+       mc = ioremap(0xff700000 + 0x5000, sizeof(memctl_cpm2_t));
+#else
+       mc = &cpm2_immr->im_memctl;
+#endif
 
-       /* Set parameters for the big flash chip (CS6 or CS0) */
-       sbc82xx_flash_map[bigflash].buswidth = 4;
-       sbc82xx_flash_map[bigflash].size = 0x4000000;
-
-       /* Set parameters for the small flash chip (CS0 or CS6) */
-       sbc82xx_flash_map[!bigflash].buswidth = 1;
-       sbc82xx_flash_map[!bigflash].size = 0x200000;
+       bigflash = 1;
+       if ((mc->memc_br0 & 0x00001800) == 0x00001800)
+               bigflash = 0;
 
-       /* Set parameters for the user flash chip (CS1) */
-       sbc82xx_flash_map[2].buswidth = 4;
-       sbc82xx_flash_map[2].size = 0x4000000;
+       init_sbc82xx_one_flash(sbc82xx_flash_map[0], mc->memc_br0, mc->memc_or0);
+       init_sbc82xx_one_flash(sbc82xx_flash_map[1], mc->memc_br6, mc->memc_or6);
+       init_sbc82xx_one_flash(sbc82xx_flash_map[2], mc->memc_br1, mc->memc_or1);
 
-       sbc82xx_flash_map[0].phys = mc->memc_br0 & 0xffff8000;
-       sbc82xx_flash_map[1].phys = mc->memc_br6 & 0xffff8000;
-       sbc82xx_flash_map[2].phys = mc->memc_br1 & 0xffff8000;
+#ifdef CONFIG_SBC8560
+       iounmap((void *) mc);
+#endif
 
        for (i=0; i<3; i++) {
                int8_t flashcs[3] = { 0, 6, 1 };
                int nr_parts;
 
                printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d",
-                      sbc82xx_flash_map[i].name, sbc82xx_flash_map[i].size >> 20, flashcs[i]);
+                      sbc82xx_flash_map[i].name,
+                      (sbc82xx_flash_map[i].size >> 20),
+                      flashcs[i]);
                if (!sbc82xx_flash_map[i].phys) {
                        /* We know it can't be at zero. */
                        printk("): disabled by bootloader.\n");
index e45b3fc..b134315 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtd_blkdevs.c,v 1.16 2003/06/23 13:34:43 dwmw2 Exp $
+ * $Id: mtd_blkdevs.c,v 1.22 2004/07/12 12:35:28 dwmw2 Exp $
  *
  * (C) 2003 David Woodhouse <dwmw2@infradead.org>
  *
@@ -295,7 +295,10 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        snprintf(gd->devfs_name, sizeof(gd->devfs_name),
                 "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
 
-       set_capacity(gd, new->size);
+       /* 2.5 has capacity in units of 512 bytes while still
+          having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
+       set_capacity(gd, (new->size * new->blksize) >> 9);
+
        gd->private_data = new;
        new->blkcore_priv = gd;
        gd->queue = tr->blkcore_priv->rq;
index fd096ea..c91d970 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * Direct MTD block device access
  *
- * $Id: mtdblock.c,v 1.63 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: mtdblock.c,v 1.64 2003/10/04 17:14:14 dwmw2 Exp $
  *
  * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
  * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
index b1a9257..02b93f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdchar.c,v 1.54 2003/05/21 10:50:43 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.62 2004/07/14 13:20:42 dwmw2 Exp $
  *
  * Character-device access to raw MTD devices.
  *
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/compatmac.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 
 #ifdef CONFIG_DEVFS_FS
 #include <linux/devfs_fs_kernel.h>
-static void mtd_notify_add(struct mtd_info* mtd);
-static void mtd_notify_remove(struct mtd_info* mtd);
+
+static void mtd_notify_add(struct mtd_info* mtd)
+{
+       if (!mtd)
+               return;
+
+       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
+                     S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
+               
+       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
+                     S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
+}
+
+static void mtd_notify_remove(struct mtd_info* mtd)
+{
+       if (!mtd)
+               return;
+       devfs_remove("mtd/%d", mtd->index);
+       devfs_remove("mtd/%dro", mtd->index);
+}
 
 static struct mtd_notifier notifier = {
        .add    = mtd_notify_add,
        .remove = mtd_notify_remove,
 };
 
+static inline void mtdchar_devfs_init(void)
+{
+       devfs_mk_dir("mtd");
+       register_mtd_user(&notifier);
+}
+
+static inline void mtdchar_devfs_exit(void)
+{
+       unregister_mtd_user(&notifier);
+       devfs_remove("mtd");
+}
+#else /* !DEVFS */
+#define mtdchar_devfs_init() do { } while(0)
+#define mtdchar_devfs_exit() do { } while(0)
 #endif
 
 static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
@@ -298,7 +331,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 
                        memset (erase,0,sizeof(struct erase_info));
                        if (copy_from_user(&erase->addr, argp,
-                                          2 * sizeof(u_long))) {
+                                   sizeof(struct erase_info_user))) {
                                kfree(erase);
                                return -EFAULT;
                        }
@@ -366,7 +399,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 
                ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
-               if (copy_to_user(argp + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+               if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t)))
                        ret = -EFAULT;
 
                kfree(databuf);
@@ -400,7 +433,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                
                ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
-               if (copy_to_user(argp + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+               if (put_user(retlen, (uint32_t __user *)argp))
                        ret = -EFAULT;
                else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
                        ret = -EFAULT;
@@ -411,29 +444,29 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 
        case MEMLOCK:
        {
-               unsigned long adrs[2];
+               struct erase_info_user info;
 
-               if (copy_from_user(adrs, argp, 2* sizeof(unsigned long)))
+               if (copy_from_user(&info, argp, sizeof(info)))
                        return -EFAULT;
 
                if (!mtd->lock)
                        ret = -EOPNOTSUPP;
                else
-                       ret = mtd->lock(mtd, adrs[0], adrs[1]);
+                       ret = mtd->lock(mtd, info.start, info.length);
                break;
        }
 
        case MEMUNLOCK:
        {
-               unsigned long adrs[2];
+               struct erase_info_user info;
 
-               if (copy_from_user(adrs, argp, 2* sizeof(unsigned long)))
+               if (copy_from_user(&info, argp, sizeof(info)))
                        return -EFAULT;
 
                if (!mtd->unlock)
                        ret = -EOPNOTSUPP;
                else
-                       ret = mtd->unlock(mtd, adrs[0], adrs[1]);
+                       ret = mtd->unlock(mtd, info.start, info.length);
                break;
        }
 
@@ -443,7 +476,40 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                        return -EFAULT;
                break;
        }
+
+       case MEMGETOOBSEL:
+       {
+               if (copy_to_user(argp, &(mtd->oobinfo), sizeof(struct nand_oobinfo)))
+                       return -EFAULT;
+               break;
+       }
+
+       case MEMGETBADBLOCK:
+       {
+               loff_t offs;
                
+               if (copy_from_user(&offs, argp, sizeof(loff_t)))
+                       return -EFAULT;
+               if (!mtd->block_isbad)
+                       ret = -EOPNOTSUPP;
+               else
+                       return mtd->block_isbad(mtd, offs);
+               break;
+       }
+
+       case MEMSETBADBLOCK:
+       {
+               loff_t offs;
+
+               if (copy_from_user(&offs, argp, sizeof(loff_t)))
+                       return -EFAULT;
+               if (!mtd->block_markbad)
+                       ret = -EOPNOTSUPP;
+               else
+                       return mtd->block_markbad(mtd, offs);
+               break;
+       }
+
        default:
                DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
                ret = -ENOTTY;
@@ -462,30 +528,6 @@ static struct file_operations mtd_fops = {
        .release        = mtd_close,
 };
 
-
-#ifdef CONFIG_DEVFS_FS
-/* Notification that a new device has been added. Create the devfs entry for
- * it. */
-
-static void mtd_notify_add(struct mtd_info* mtd)
-{
-       if (!mtd)
-               return;
-       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
-                       S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
-       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
-                       S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%dro", mtd->index);
-}
-
-static void mtd_notify_remove(struct mtd_info* mtd)
-{
-       if (!mtd)
-               return;
-       devfs_remove("mtd/%d", mtd->index);
-       devfs_remove("mtd/%dro", mtd->index);
-}
-#endif
-
 static int __init init_mtdchar(void)
 {
        if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {
@@ -494,20 +536,13 @@ static int __init init_mtdchar(void)
                return -EAGAIN;
        }
 
-#ifdef CONFIG_DEVFS_FS
-       devfs_mk_dir("mtd");
-
-       register_mtd_user(&notifier);
-#endif
+       mtdchar_devfs_init();
        return 0;
 }
 
 static void __exit cleanup_mtdchar(void)
 {
-#ifdef CONFIG_DEVFS_FS
-       unregister_mtd_user(&notifier);
-       devfs_remove("mtd");
-#endif
+       mtdchar_devfs_exit();
        unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
 }
 
index 5a4f02c..8f66d09 100644 (file)
@@ -7,7 +7,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdconcat.c,v 1.8 2003/06/30 11:01:26 dwmw2 Exp $
+ * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $
  */
 
 #include <linux/module.h>
@@ -391,7 +391,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
        struct mtd_concat *concat = CONCAT(mtd);
        struct mtd_info *subdev;
        int i, err;
-       u_int32_t length;
+       u_int32_t length, offset = 0;
        struct erase_info *erase;
 
        if (!(mtd->flags & MTD_WRITEABLE))
@@ -450,6 +450,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                        return -EINVAL;
        }
 
+       instr->fail_addr = 0xffffffff;
+
        /* make a local copy of instr to avoid modifying the caller's struct */
        erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
 
@@ -465,10 +467,12 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
         */
        for (i = 0; i < concat->num_subdev; i++) {
                subdev = concat->subdev[i];
-               if (subdev->size <= erase->addr)
+               if (subdev->size <= erase->addr) {
                        erase->addr -= subdev->size;
-               else
+                       offset += subdev->size;
+               } else {
                        break;
+               }
        }
 
        /* must never happen since size limit has been verified above */
@@ -497,6 +501,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                         * block alignment has been checked above */
                        if (err == -EINVAL)
                                BUG();
+                       if (erase->fail_addr != 0xffffffff)
+                               instr->fail_addr = erase->fail_addr + offset;
                        break;
                }
                /*
@@ -508,12 +514,13 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                 * current subdevice, i.e. at offset zero.
                 */
                erase->addr = 0;
+               offset += subdev->size;
        }
+       instr->state = erase->state;
        kfree(erase);
        if (err)
                return err;
 
-       instr->state = MTD_ERASE_DONE;
        if (instr->callback)
                instr->callback(instr);
        return 0;
index 1277556..9c5af1d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.42 2004/07/13 10:21:13 dwmw2 Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -334,10 +334,7 @@ static int mtd_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
 /* Support for /proc/mtd */
 
 #ifdef CONFIG_PROC_FS
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 static struct proc_dir_entry *proc_mtd;
-#endif
 
 static inline int mtd_proc_info (char *buf, int i)
 {
@@ -350,13 +347,8 @@ static inline int mtd_proc_info (char *buf, int i)
                       this->erasesize, this->name);
 }
 
-static int mtd_read_proc ( char *page, char **start, off_t off,int count
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-                       ,int *eof, void *data_unused
-#else
-                        ,int unused
-#endif
-                       )
+static int mtd_read_proc (char *page, char **start, off_t off, int count,
+                         int *eof, void *data_unused)
 {
        int len, l, i;
         off_t   begin = 0;
@@ -376,9 +368,7 @@ static int mtd_read_proc ( char *page, char **start, off_t off,int count
                 }
         }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
         *eof = 1;
-#endif
 
 done:
        up(&mtd_table_mutex);
@@ -388,18 +378,6 @@ done:
         return ((count < begin+len-off) ? count : begin+len-off);
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
-struct proc_dir_entry mtd_proc_entry = {
-        0,                 /* low_ino: the inode -- dynamic */
-        3, "mtd",     /* len of name and name */
-        S_IFREG | S_IRUGO, /* mode */
-        1, 0, 0,           /* nlinks, owner, group */
-        0, NULL,           /* size - unused; operations -- use default */
-        &mtd_read_proc,   /* function used to read data */
-        /* nothing more */
-    };
-#endif
-
 #endif /* CONFIG_PROC_FS */
 
 /*====================================================================*/
@@ -408,16 +386,8 @@ struct proc_dir_entry mtd_proc_entry = {
 int __init init_mtd(void)
 {
 #ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
        if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
-         proc_mtd->read_proc = mtd_read_proc;
-#else
-        proc_register_dynamic(&proc_root,&mtd_proc_entry);
-#endif
-#endif
-
-#if LINUX_VERSION_CODE < 0x20212
-       init_mtd_devices();
+               proc_mtd->read_proc = mtd_read_proc;
 #endif
 
 #ifdef CONFIG_PM
@@ -436,12 +406,8 @@ static void __exit cleanup_mtd(void)
 #endif
 
 #ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
         if (proc_mtd)
-          remove_proc_entry( "mtd", NULL);
-#else
-        proc_unregister(&proc_root,mtd_proc_entry.low_ino);
-#endif
+               remove_proc_entry( "mtd", NULL);
 #endif
 }
 
index e90064e..f007d07 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdpart.c,v 1.41 2003/06/18 14:53:02 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.46 2004/07/12 13:28:07 dwmw2 Exp $
  *
  *     02-21-2002      Thomas Gleixner <gleixner@autronix.de>
  *                     added support for read_oob, write_oob
@@ -239,12 +239,16 @@ static int part_readv_ecc (struct mtd_info *mtd,  struct kvec *vecs,
 static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
 {
        struct mtd_part *part = PART(mtd);
+       int ret;
        if (!(mtd->flags & MTD_WRITEABLE))
                return -EROFS;
        if (instr->addr >= mtd->size)
                return -EINVAL;
        instr->addr += part->offset;
-       return part->master->erase(part->master, instr);
+       ret = part->master->erase(part->master, instr);
+       if (instr->fail_addr != 0xffffffff)
+               instr->fail_addr -= part->offset;
+       return ret;
 }
 
 static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
@@ -281,6 +285,26 @@ static void part_resume(struct mtd_info *mtd)
        part->master->resume(part->master);
 }
 
+static int part_block_isbad (struct mtd_info *mtd, loff_t ofs)
+{
+       struct mtd_part *part = PART(mtd);
+       if (ofs >= mtd->size)
+               return -EINVAL;
+       ofs += part->offset;
+       return part->master->block_isbad(part->master, ofs);
+}
+
+static int part_block_markbad (struct mtd_info *mtd, loff_t ofs)
+{
+       struct mtd_part *part = PART(mtd);
+       if (!(mtd->flags & MTD_WRITEABLE))
+               return -EROFS;
+       if (ofs >= mtd->size)
+               return -EINVAL;
+       ofs += part->offset;
+       return part->master->block_markbad(part->master, ofs);
+}
+
 /* 
  * This function unregisters and destroy all slave MTD objects which are 
  * attached to the given master MTD object.
@@ -316,7 +340,7 @@ int del_mtd_partitions(struct mtd_info *master)
  */
 
 int add_mtd_partitions(struct mtd_info *master, 
-                      struct mtd_partition *parts,
+                      const struct mtd_partition *parts,
                       int nbparts)
 {
        struct mtd_part *slave;
@@ -391,6 +415,10 @@ int add_mtd_partitions(struct mtd_info *master,
                        slave->mtd.lock = part_lock;
                if (master->unlock)
                        slave->mtd.unlock = part_unlock;
+               if (master->block_isbad)
+                       slave->mtd.block_isbad = part_block_isbad;
+               if (master->block_markbad)
+                       slave->mtd.block_markbad = part_block_markbad;
                slave->mtd.erase = part_erase;
                slave->master = master;
                slave->offset = parts[i].offset;
@@ -461,6 +489,9 @@ int add_mtd_partitions(struct mtd_info *master,
                                parts[i].name);
                }
 
+               /* copy oobinfo from master */ 
+               memcpy(&slave->mtd.oobinfo, &master->oobinfo, sizeof(slave->mtd.oobinfo));
+
                if(parts[i].mtdp)
                {       /* store the object pointer (caller may or may not register it */
                        *parts[i].mtdp = &slave->mtd;
index f6ab472..ddd2930 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/nand/Kconfig
-# $Id: Kconfig,v 1.4 2003/05/28 10:04:23 dwmw2 Exp $
+# $Id: Kconfig,v 1.14 2004/07/13 00:14:35 dbrown Exp $
 
 menu "NAND Flash Device Drivers"
        depends on MTD!=n
@@ -9,7 +9,7 @@ config MTD_NAND
        depends on MTD
        help
          This enables support for accessing all type of NAND flash
-         devices with an 8-bit data bus interface. For further information see
+         devices. For further information see
          <http://www.linux-mtd.infradead.org/tech/nand.html>.
 
 config MTD_NAND_VERIFY_WRITE
@@ -42,10 +42,73 @@ config MTD_NAND_SPIA
        help
          If you had to ask, you don't have one. Say 'N'.
 
+config MTD_NAND_TOTO
+       tristate "NAND Flash device on TOTO board"
+       depends on ARM && ARCH_OMAP && MTD_NAND
+       help
+         Support for NAND flash on Texas Instruments Toto platform.
+
 config MTD_NAND_IDS
        tristate
        default y if MTD_NAND = y || MTD_DOC2000 = y || MTD_DOC2001 = y || MTD_DOC2001PLUS = y
        default m if MTD_NAND = m || MTD_DOC2000 = m || MTD_DOC2001 = m || MTD_DOC2001PLUS = m
-       
-endmenu
 
+config MTD_NAND_TX4925NDFMC
+       tristate "SmartMedia Card on Toshiba RBTX4925 reference board"
+       depends on TOSHIBA_RBTX4925 && MTD_NAND && TOSHIBA_RBTX4925_MPLEX_NAND
+       help
+         This enables the driver for the NAND flash device found on the
+         Toshiba RBTX4925 reference board, which is a SmartMediaCard.
+
+config MTD_NAND_TX4938NDFMC
+       tristate "NAND Flash device on Toshiba RBTX4938 reference board"
+       depends on TOSHIBA_RBTX4938 && MTD_NAND && TOSHIBA_RBTX4938_MPLEX_NAND 
+       help
+         This enables the driver for the NAND flash device found on the
+         Toshiba RBTX4938 reference board.
+
+config MTD_NAND_AU1550
+       tristate "Au1550 NAND support"
+       depends on SOC_AU1550 && MTD_NAND
+       help
+         This enables the driver for the NAND flash controller on the
+         AMD/Alchemy 1550 SOC.
+
+config MTD_NAND_PPCHAMELEONEVB
+       tristate "NAND Flash device on PPChameleonEVB board"
+       depends on PPCHAMELEONEVB && MTD_NAND
+       help
+         This enables the NAND flash driver on the PPChameleon EVB Board.      
+
+config MTD_NAND_DISKONCHIP
+       tristate "DiskOnChip 2000 and Millennium (NAND reimplementation) (EXPERIMENTAL)"
+       depends on MTD_NAND && EXPERIMENTAL
+       help
+         This is a reimplementation of M-Systems DiskOnChip 2000 and
+         Millennium as a standard NAND device driver, as opposed to the
+         earlier self-contained MTD device drivers.
+         This should enable, among other things, proper JFFS2 operation on
+         these devices.
+
+config MTD_NAND_DISKONCHIP_BBTWRITE
+       bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP"
+       depends on MTD_NAND_DISKONCHIP
+       help
+         On DiskOnChip devices shipped with the INFTL filesystem (Millennium
+         and 2000 TSOP/Alon), Linux reserves some space at the end of the
+         device for the Bad Block Table (BBT).  If you have existing INFTL
+         data on your device (created by non-Linux tools such as M-Systems'
+         DOS drivers), your data might overlap the area Linux wants to use for
+         the BBT.  If this is a concern for you, leave this option disabled and
+         Linux will not write BBT data into this area.
+         The downside of leaving this option disabled is that if bad blocks
+         are detected by Linux, they will not be recorded in the BBT, which
+         could cause future problems.
+         Once you enable this option, new filesystems (INFTL or others, created
+         in Linux or other operating systems) will not use the reserved area.
+         The only reason not to enable this option is to prevent damage to
+         preexisting filesystems.
+         Even if you leave this disabled, you can enable BBT writes at module
+         load time (assuming you build diskonchip as a module) with the module
+         parameter "inftl_bbt_write=1".
+endmenu
index dfc4c1f..db19399 100644 (file)
@@ -1,10 +1,19 @@
 #
 # linux/drivers/nand/Makefile
 #
-# $Id: Makefile.common,v 1.2 2003/05/28 11:38:54 dwmw2 Exp $
+# $Id: Makefile.common,v 1.9 2004/07/12 16:07:31 dwmw2 Exp $
 
-obj-$(CONFIG_MTD_NAND)         += nand.o nand_ecc.o
-obj-$(CONFIG_MTD_NAND_SPIA)    += spia.o
-obj-$(CONFIG_MTD_NAND_AUTCPU12)        += autcpu12.o
-obj-$(CONFIG_MTD_NAND_EDB7312)  += edb7312.o
-obj-$(CONFIG_MTD_NAND_IDS)     += nand_ids.o
+obj-$(CONFIG_MTD_NAND)                 += nand.o nand_ecc.o
+obj-$(CONFIG_MTD_NAND_IDS)             += nand_ids.o
+
+obj-$(CONFIG_MTD_NAND_SPIA)            += spia.o
+obj-$(CONFIG_MTD_NAND_TOTO)            += toto.o
+obj-$(CONFIG_MTD_NAND_AUTCPU12)                += autcpu12.o
+obj-$(CONFIG_MTD_NAND_EDB7312)         += edb7312.o
+obj-$(CONFIG_MTD_NAND_TX4925NDFMC)     += tx4925ndfmc.o
+obj-$(CONFIG_MTD_NAND_TX4938NDFMC)     += tx4938ndfmc.o
+obj-$(CONFIG_MTD_NAND_AU1550)          += au1550nd.o
+obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)  += ppchameleonevb.o
+obj-$(CONFIG_MTD_NAND_DISKONCHIP)      += diskonchip.o
+
+nand-objs = nand_base.o nand_bbt.o
index dc6df46..6d8ecf6 100644 (file)
@@ -6,7 +6,7 @@
  *  Derived from drivers/mtd/spia.c
  *      Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  * 
- * $Id: autcpu12.c,v 1.11 2003/06/04 17:04:09 gleixner Exp $
+ * $Id: autcpu12.c,v 1.19 2004/07/12 15:02:15 dwmw2 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
@@ -15,7 +15,7 @@
  *  Overview:
  *   This is a device driver for the NAND flash device found on the
  *   autronix autcpu12 board, which is a SmartMediaCard. It supports 
- *   16MB, 32MB and 64MB cards.
+ *   16MiB, 32MiB and 64MiB cards.
  *
  *
  *     02-12-2002 TG   Cleanup of module params
@@ -71,42 +71,40 @@ __setup("autcpu12_pedr=",autcpu12_pedr);
 /*
  * Define partitions for flash devices
  */
-extern struct nand_oobinfo jffs2_oobinfo;
-
 static struct mtd_partition partition_info16k[] = {
-       { .name = "AUTCPU12 flash partition 1",
-         .offset  = 0,
-         .size =    8 * SZ_1M },
-       { .name = "AUTCPU12 flash partition 2",
-         .offset  8 * SZ_1M,
-         .size =    8 * SZ_1M },
+       { .name         = "AUTCPU12 flash partition 1",
+         .offset       = 0,
+         .size         = 8 * SZ_1M },
+       { .name         = "AUTCPU12 flash partition 2",
+         .offset       = 8 * SZ_1M,
+         .size         = 8 * SZ_1M },
 };
 
 static struct mtd_partition partition_info32k[] = {
-       { .name = "AUTCPU12 flash partition 1",
-         .offset  = 0,
-         .size =    8 * SZ_1M },
-       { .name = "AUTCPU12 flash partition 2",
-         .offset  8 * SZ_1M,
-         .size =   24 * SZ_1M },
+       { .name         = "AUTCPU12 flash partition 1",
+         .offset       = 0,
+         .size         = 8 * SZ_1M },
+       { .name         = "AUTCPU12 flash partition 2",
+         .offset       = 8 * SZ_1M,
+         .size         = 24 * SZ_1M },
 };
 
 static struct mtd_partition partition_info64k[] = {
-       { .name = "AUTCPU12 flash partition 1",
-         .offset  = 0,
-         .size =   16 * SZ_1M },
-       { .name = "AUTCPU12 flash partition 2",
-         .offset = 16 * SZ_1M,
-         .size =   48 * SZ_1M },
+       { .name         = "AUTCPU12 flash partition 1",
+         .offset       = 0,
+         .size         = 16 * SZ_1M },
+       { .name         = "AUTCPU12 flash partition 2",
+         .offset       = 16 * SZ_1M,
+         .size         = 48 * SZ_1M },
 };
 
 static struct mtd_partition partition_info128k[] = {
-       { .name = "AUTCPU12 flash partition 1",
-         .offset  = 0,
-         .size =   16 * SZ_1M },
-       { .name = "AUTCPU12 flash partition 2",
-         .offset = 16 * SZ_1M,
-         .size =   112 * SZ_1M },
+       { .name         = "AUTCPU12 flash partition 1",
+         .offset       = 0,
+         .size         = 16 * SZ_1M },
+       { .name         = "AUTCPU12 flash partition 2",
+         .offset       = 16 * SZ_1M,
+         .size         = 112 * SZ_1M },
 };
 
 #define NUM_PARTITIONS16K 2
@@ -116,7 +114,7 @@ static struct mtd_partition partition_info128k[] = {
 /* 
  *     hardware specific access to control-lines
 */
-void autcpu12_hwcontrol(int cmd)
+static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd)
 {
 
        switch(cmd){
@@ -135,12 +133,13 @@ void autcpu12_hwcontrol(int cmd)
 /*
 *      read device ready pin
 */
-int autcpu12_device_ready(void)
+int autcpu12_device_ready(struct mtd_info *mtd)
 {
 
        return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0;
 
 }
+
 /*
  * Main initialization routine
  */
@@ -185,20 +184,18 @@ int __init autcpu12_init (void)
        this->chip_delay = 20;          
        this->eccmode = NAND_ECC_SOFT;
 
+       /* Enable the following for a flash based bad block table */
+       /*
+       this->options = NAND_USE_FLASH_BBT;
+       */
+       this->options = NAND_USE_FLASH_BBT;
+       
        /* Scan to find existance of the device */
-       if (nand_scan (autcpu12_mtd)) {
+       if (nand_scan (autcpu12_mtd, 1)) {
                err = -ENXIO;
                goto out_ior;
        }
-
-       /* Allocate memory for internal data buffer */
-       this->data_buf = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL);
-       if (!this->data_buf) {
-               printk ("Unable to allocate NAND data buffer for AUTCPU12.\n");
-               err = -ENOMEM;
-               goto out_ior;
-       }
-
+       
        /* Register the partitions */
        switch(autcpu12_mtd->size){
                case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break;
@@ -208,13 +205,11 @@ int __init autcpu12_init (void)
                default: {
                        printk ("Unsupported SmartMedia device\n"); 
                        err = -ENXIO;
-                       goto out_buf;
+                       goto out_ior;
                }
        }
        goto out;
 
-out_buf:
-       kfree (this->data_buf);    
 out_ior:
        iounmap((void *)autcpu12_fio_base);
 out_mtd:
@@ -231,20 +226,12 @@ module_init(autcpu12_init);
 #ifdef MODULE
 static void __exit autcpu12_cleanup (void)
 {
-       struct nand_chip *this = (struct nand_chip *) &autcpu12_mtd[1];
-
-       /* Unregister partitions */
-       del_mtd_partitions(autcpu12_mtd);
-       
-       /* Unregister the device */
-       del_mtd_device (autcpu12_mtd);
-
-       /* Free internal data buffers */
-       kfree (this->data_buf);
+       /* Release resources, unregister device */
+       nand_release (autcpu12_mtd);
 
        /* unmap physical adress */
        iounmap((void *)autcpu12_fio_base);
-
+       
        /* Free the MTD device structure */
        kfree (autcpu12_mtd);
 }
index db678bf..7977940 100644 (file)
@@ -6,7 +6,7 @@
  *  Derived from drivers/mtd/nand/autcpu12.c
  *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
  *
- * $Id: edb7312.c,v 1.5 2003/04/20 07:24:40 gleixner Exp $
+ * $Id: edb7312.c,v 1.8 2004/07/12 15:03:26 dwmw2 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
@@ -20,6 +20,7 @@
 
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
@@ -83,7 +84,7 @@ static struct mtd_partition partition_info[] = {
 /* 
  *     hardware specific access to control-lines
  */
-static void ep7312_hwcontrol(int cmd) 
+static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) 
 {
        switch(cmd) {
                
@@ -113,10 +114,13 @@ static void ep7312_hwcontrol(int cmd)
 /*
  *     read device ready pin
  */
-static int ep7312_device_ready(void)
+static int ep7312_device_ready(struct mtd_info *mtd)
 {
        return 1;
 }
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
 
 /*
  * Main initialization routine
@@ -171,7 +175,7 @@ static int __init ep7312_init (void)
        this->chip_delay = 15;
        
        /* Scan to find existence of the device */
-       if (nand_scan (ep7312_mtd)) {
+       if (nand_scan (ep7312_mtd, 1)) {
                iounmap((void *)ep7312_fio_base);
                kfree (ep7312_mtd);
                return -ENXIO;
@@ -186,16 +190,16 @@ static int __init ep7312_init (void)
                return -ENOMEM;
        }
        
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-       mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts, 
-                                               "edb7312-nand");
+#ifdef CONFIG_PARTITIONS
+       ep7312_mtd->name = "edb7312-nand";
+       mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes,
+                                           &mtd_parts, 0);
        if (mtd_parts_nb > 0)
-         part_type = "command line";
+               part_type = "command line";
        else
-         mtd_parts_nb = 0;
+               mtd_parts_nb = 0;
 #endif
-       if (mtd_parts_nb == 0)
-       {
+       if (mtd_parts_nb == 0) {
                mtd_parts = partition_info;
                mtd_parts_nb = NUM_PARTITIONS;
                part_type = "static";
index bb57398..2e341b7 100644 (file)
@@ -1,22 +1,44 @@
 /*
- *  drivers/mtd/nand_ecc.c
+ * This file contains an ECC algorithm from Toshiba that detects and
+ * corrects 1 bit errors in a 256 byte block of data.
  *
- *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *                     Toshiba America Electronics Components, Inc.
+ * drivers/mtd/nand/nand_ecc.c
  *
- * $Id: nand_ecc.c,v 1.9 2003/02/20 13:34:19 sjhill Exp $
+ * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com)
+ *                         Toshiba America Electronics Components, Inc.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1 as published by the Free Software Foundation.
+ * $Id: nand_ecc.c,v 1.14 2004/06/16 15:34:37 gleixner Exp $
  *
- * This file contains an ECC algorithm from Toshiba that detects and
- * corrects 1 bit errors in a 256 byte block of data.
+ * This file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 or (at your option) any
+ * later version.
+ * 
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this file; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ * 
+ * As a special exception, if other files instantiate templates or use
+ * macros or inline functions from these files, or you compile these
+ * files and link them with other works to produce a work based on these
+ * files, these files do not by themselves cause the resulting work to be
+ * covered by the GNU General Public License. However the source code for
+ * these files must still be made available in accordance with section (3)
+ * of the GNU General Public License.
+ * 
+ * This exception does not invalidate any other reasons why a work based on
+ * this file might be covered by the GNU General Public License.
  */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/mtd/nand_ecc.h>
 
 /*
  * Pre-calculated 256-way 1 byte column parity
@@ -41,7 +63,12 @@ static const u_char nand_ecc_precalc_table[] = {
 };
 
 
-/*
+/**
+ * nand_trans_result - [GENERIC] create non-inverted ECC
+ * @reg2:      line parity reg 2
+ * @reg3:      line parity reg 3
+ * @ecc_code:  ecc 
+ *
  * Creates non-inverted ECC code from line parity
  */
 static void nand_trans_result(u_char reg2, u_char reg3,
@@ -81,10 +108,13 @@ static void nand_trans_result(u_char reg2, u_char reg3,
        ecc_code[1] = tmp2;
 }
 
-/*
- * Calculate 3 byte ECC code for 256 byte block
+/**
+ * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code for 256 byte block
+ * @mtd:       MTD block structure
+ * @dat:       raw data
+ * @ecc_code:  buffer for ECC
  */
-void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
+int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
 {
        u_char idx, reg1, reg2, reg3;
        int j;
@@ -114,12 +144,19 @@ void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
        ecc_code[0] = ~ecc_code[0];
        ecc_code[1] = ~ecc_code[1];
        ecc_code[2] = ((~reg1) << 2) | 0x03;
+       return 0;
 }
 
-/*
+/**
+ * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
+ * @mtd:       MTD block structure
+ * @dat:       raw data read from the chip
+ * @read_ecc:  ECC from the chip
+ * @calc_ecc:  the ECC calculated from raw data
+ *
  * Detect and correct a 1 bit error for 256 byte block
  */
-int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
 {
        u_char a, b, c, d1, d2, d3, add, bit, i;
        
index 5a5518f..2d8c432 100644 (file)
@@ -2,9 +2,8 @@
  *  drivers/mtd/nandids.c
  *
  *  Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
- *
- *
- * $Id: nand_ids.c,v 1.4 2003/05/21 15:15:08 dwmw2 Exp $
+  *
+ * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  */
 #include <linux/module.h>
 #include <linux/mtd/nand.h>
-
 /*
 *      Chip ID list
+*      
+*      Name. ID code, pagesize, chipsize in MegaByte, eraseblock size,
+*      options
+* 
+*      Pagesize; 0, 256, 512
+*      0       get this information from the extended chip ID
++      256     256 Byte page size
+*      512     512 Byte page size      
 */
 struct nand_flash_dev nand_flash_ids[] = {
-       {"NAND 1MiB 5V", 0x6e, 20, 0x1000, 1},
-       {"NAND 2MiB 5V", 0x64, 21, 0x1000, 1},
-       {"NAND 4MiB 5V", 0x6b, 22, 0x2000, 0},
-       {"NAND 1MiB 3,3V", 0xe8, 20, 0x1000, 1},
-       {"NAND 1MiB 3,3V", 0xec, 20, 0x1000, 1},
-       {"NAND 2MiB 3,3V", 0xea, 21, 0x1000, 1},
-       {"NAND 4MiB 3,3V", 0xd5, 22, 0x2000, 0},
-       {"NAND 4MiB 3,3V", 0xe3, 22, 0x2000, 0},
-       {"NAND 4MiB 3,3V", 0xe5, 22, 0x2000, 0},
-       {"NAND 8MiB 3,3V", 0xd6, 23, 0x2000, 0},
-       {"NAND 8MiB 3,3V", 0xe6, 23, 0x2000, 0},
-       {"NAND 16MiB 3,3V", 0x73, 24, 0x4000, 0},
-       {"NAND 32MiB 3,3V", 0x75, 25, 0x4000, 0},
-       {"NAND 64MiB 3,3V", 0x76, 26, 0x4000, 0},
-       {"NAND 128MiB 3,3V", 0x79, 27, 0x4000, 0},
+       {"NAND 1MiB 5V 8-bit",          0x6e, 256, 1, 0x1000, 0},
+       {"NAND 2MiB 5V 8-bit",          0x64, 256, 2, 0x1000, 0},
+       {"NAND 4MiB 5V 8-bit",          0x6b, 512, 4, 0x2000, 0},
+       {"NAND 1MiB 3,3V 8-bit",        0xe8, 256, 1, 0x1000, 0},
+       {"NAND 1MiB 3,3V 8-bit",        0xec, 256, 1, 0x1000, 0},
+       {"NAND 2MiB 3,3V 8-bit",        0xea, 256, 2, 0x1000, 0},
+       {"NAND 4MiB 3,3V 8-bit",        0xd5, 512, 4, 0x2000, 0},
+       {"NAND 4MiB 3,3V 8-bit",        0xe3, 512, 4, 0x2000, 0},
+       {"NAND 4MiB 3,3V 8-bit",        0xe5, 512, 4, 0x2000, 0},
+       {"NAND 8MiB 3,3V 8-bit",        0xd6, 512, 8, 0x2000, 0},
+       
+       {"NAND 8MiB 1,8V 8-bit",        0x39, 512, 8, 0x2000, 0},
+       {"NAND 8MiB 3,3V 8-bit",        0xe6, 512, 8, 0x2000, 0},
+       {"NAND 8MiB 1,8V 16-bit",       0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+       {"NAND 8MiB 3,3V 16-bit",       0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+       
+       {"NAND 16MiB 1,8V 8-bit",       0x33, 512, 16, 0x4000, 0},
+       {"NAND 16MiB 3,3V 8-bit",       0x73, 512, 16, 0x4000, 0},
+       {"NAND 16MiB 1,8V 16-bit",      0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 16MiB 3,3V 16-bit",      0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+       
+       {"NAND 32MiB 1,8V 8-bit",       0x35, 512, 32, 0x4000, 0},
+       {"NAND 32MiB 3,3V 8-bit",       0x75, 512, 32, 0x4000, 0},
+       {"NAND 32MiB 1,8V 16-bit",      0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 32MiB 3,3V 16-bit",      0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+       
+       {"NAND 64MiB 1,8V 8-bit",       0x36, 512, 64, 0x4000, 0},
+       {"NAND 64MiB 3,3V 8-bit",       0x76, 512, 64, 0x4000, 0},
+       {"NAND 64MiB 1,8V 16-bit",      0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 64MiB 3,3V 16-bit",      0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+       
+       {"NAND 128MiB 1,8V 8-bit",      0x78, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 3,3V 8-bit",      0x79, 512, 128, 0x4000, 0},
+       {"NAND 128MiB 1,8V 16-bit",     0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       {"NAND 128MiB 3,3V 16-bit",     0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+       
+       {"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
+       */
+       /* 1 Gigabit */
+       {"NAND 128MiB 1,8V 8-bit",      0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 128MiB 3,3V 8-bit",      0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 128MiB 1,8V 16-bit",     0xB1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       {"NAND 128MiB 3,3V 16-bit",     0xC1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+       /* 2 Gigabit */
+       {"NAND 256MiB 1,8V 8-bit",      0xAA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 256MiB 3,3V 8-bit",      0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 256MiB 1,8V 16-bit",     0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       {"NAND 256MiB 3,3V 16-bit",     0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       
+       /* 4 Gigabit */
+       {"NAND 512MiB 1,8V 8-bit",      0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 512MiB 3,3V 8-bit",      0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 512MiB 1,8V 16-bit",     0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       {"NAND 512MiB 3,3V 16-bit",     0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       
+       /* 8 Gigabit */
+       {"NAND 1GiB 1,8V 8-bit",        0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 1GiB 3,3V 8-bit",        0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 1GiB 1,8V 16-bit",       0xB3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       {"NAND 1GiB 3,3V 16-bit",       0xC3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+       /* 16 Gigabit */
+       {"NAND 2GiB 1,8V 8-bit",        0xA5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 2GiB 3,3V 8-bit",        0xD5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+       {"NAND 2GiB 1,8V 16-bit",       0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+       {"NAND 2GiB 3,3V 16-bit",       0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
+       /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! 
+        * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes
+        * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7
+        * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
+        * There are more speed improvements for reads and writes possible, but not implemented now 
+        */
+       {"AND 128MiB 3,3V 8-bit",       0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+
        {NULL,}
 };
 
@@ -44,10 +116,11 @@ struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_SAMSUNG, "Samsung"},
        {NAND_MFR_FUJITSU, "Fujitsu"},
        {NAND_MFR_NATIONAL, "National"},
+       {NAND_MFR_RENESAS, "Renesas"},
+       {NAND_MFR_STMICRO, "ST Micro"},
        {0x0, "Unknown"}
 };
 
-
 EXPORT_SYMBOL (nand_manuf_ids);
 EXPORT_SYMBOL (nand_flash_ids);
 
index e5e25eb..acf6fc8 100644 (file)
@@ -8,7 +8,7 @@
  *                     to controllines (due to change in nand.c)
  *                     page_cache added
  *
- * $Id: spia.c,v 1.19 2003/04/20 07:24:40 gleixner Exp $
+ * $Id: spia.c,v 1.21 2003/07/11 15:12:29 dwmw2 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
@@ -20,6 +20,8 @@
  *   a 64Mibit (8MiB x 8 bits) NAND flash device.
  */
 
+#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
@@ -35,14 +37,14 @@ static struct mtd_info *spia_mtd = NULL;
 /*
  * Values specific to the SPIA board (used with EP7212 processor)
  */
-#define SPIA_IO_ADDR   = 0xd0000000    /* Start of EP7212 IO address space */
-#define SPIA_FIO_ADDR  = 0xf0000000    /* Address where flash is mapped */
-#define SPIA_PEDR      = 0x0080        /*
+#define SPIA_IO_BASE   0xd0000000      /* Start of EP7212 IO address space */
+#define SPIA_FIO_BASE  0xf0000000      /* Address where flash is mapped */
+#define SPIA_PEDR      0x0080          /*
                                         * IO offset to Port E data register
                                         * where the CLE, ALE and NCE pins
                                         * are wired to.
                                         */
-#define SPIA_PEDDR     = 0x00c0        /*
+#define SPIA_PEDDR     0x00c0          /*
                                         * IO offset to Port E data direction
                                         * register so we can control the IO
                                         * lines.
@@ -62,11 +64,6 @@ MODULE_PARM(spia_fio_base, "i");
 MODULE_PARM(spia_pedr, "i");
 MODULE_PARM(spia_peddr, "i");
 
-__setup("spia_io_base=",spia_io_base);
-__setup("spia_fio_base=",spia_fio_base);
-__setup("spia_pedr=",spia_pedr);
-__setup("spia_peddr=",spia_peddr);
-
 /*
  * Define partitions for flash device
  */
@@ -88,7 +85,7 @@ const static struct mtd_partition partition_info[] = {
 /* 
  *     hardware specific access to control-lines
 */
-void spia_hwcontrol(int cmd){
+static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
 
     switch(cmd){
 
@@ -143,7 +140,7 @@ int __init spia_init (void)
        this->chip_delay = 15;          
 
        /* Scan to find existence of the device */
-       if (nand_scan (spia_mtd)) {
+       if (nand_scan (spia_mtd, 1)) {
                kfree (spia_mtd);
                return -ENXIO;
        }
index ea709d7..4102a67 100644 (file)
@@ -1,7 +1,7 @@
 /* Linux driver for NAND Flash Translation Layer      */
 /* (c) 1999 Machine Vision Holdings, Inc.             */
 /* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftlcore.c,v 1.94 2003/06/23 12:00:08 dwmw2 Exp $ */
+/* $Id: nftlcore.c,v 1.96 2004/06/28 13:52:55 dbrown Exp $ */
 
 /*
   The contents of this file are distributed under the GNU General
@@ -43,9 +43,19 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        struct NFTLrecord *nftl;
        unsigned long temp;
 
-       if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
+       if (mtd->type != MTD_NANDFLASH)
+               return;
+       /* OK, this is moderately ugly.  But probably safe.  Alternatives? */
+       if (memcmp(mtd->name, "DiskOnChip", 10))
                return;
 
+       if (!mtd->block_isbad) {
+               printk(KERN_ERR
+"NFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
+"Please use the new diskonchip driver under the NAND subsystem.\n");
+               return;
+       }
+
        DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
 
        nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
@@ -60,6 +70,8 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        nftl->mbd.devnum = -1;
        nftl->mbd.blksize = 512;
        nftl->mbd.tr = tr;
+       memcpy(&nftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
+       nftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
 
         if (NFTL_mount(nftl) < 0) {
                printk(KERN_WARNING "NFTL: could not mount device\n");
@@ -350,17 +362,19 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
                 
-                ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
-                                 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
+                ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
+                                 512, &retlen, movebuf); 
                 if (ret < 0) {
-                    ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
+                    ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
                                       + (block * 512), 512, &retlen,
-                                      movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
+                                      movebuf); 
                     if (ret != -EIO) 
                         printk("Error went away on retry.\n");
                 }
+               memset(&oob, 0xff, sizeof(struct nftl_oob));
+               oob.b.Status = oob.b.Status1 = SECTOR_USED;
                 MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-                             512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
+                             512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
        }
         
         /* add the header so that it is now a valid chain */
@@ -390,7 +404,6 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
 
                 if (NFTL_formatblock(nftl, thisEUN) < 0) {
                        /* could not erase : mark block as reserved
-                        * FixMe: Update Bad Unit Table on disk
                         */
                        nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
                 } else {
@@ -617,7 +630,7 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
        u16 writeEUN;
        unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
        size_t retlen;
-       u8 eccbuf[6];
+       struct nftl_oob oob;
 
        writeEUN = NFTL_findwriteunit(nftl, block);
 
@@ -628,9 +641,11 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
                return 1;
        }
 
+       memset(&oob, 0xff, sizeof(struct nftl_oob));
+       oob.b.Status = oob.b.Status1 = SECTOR_USED;
        MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
-                    512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
-        /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
+                    512, &retlen, (char *)buffer, (char *)&oob, &nftl->oobinfo);
+        /* need to write SECTOR_USED flags since they are not written in mtd_writeecc */
 
        return 0;
 }
@@ -692,8 +707,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
        } else {
                loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
                size_t retlen;
-               u_char eccbuf[6];
-               if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
+               if (MTD_READ(nftl->mbd.mtd, ptr, 512, &retlen, buffer))
                        return -EIO;
        }
        return 0;
@@ -735,7 +749,7 @@ extern char nftlmountrev[];
 
 int __init init_nftl(void)
 {
-       printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.94 $, nftlmount.c %s\n", nftlmountrev);
+       printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.96 $, nftlmount.c %s\n", nftlmountrev);
 
        return register_mtd_blktrans(&nftl_tr);
 }
index 394a0a1..a8a4e1a 100644 (file)
@@ -4,7 +4,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.34 2003/05/21 10:54:10 dwmw2 Exp $
+ * $Id: nftlmount.c,v 1.36 2004/06/28 13:52:55 dbrown Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -31,7 +31,7 @@
 
 #define SECTORSIZE 512
 
-char nftlmountrev[]="$Revision: 1.34 $";
+char nftlmountrev[]="$Revision: 1.36 $";
 
 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
  *     various device information of the NFTL partition and Bad Unit Table. Update
@@ -50,6 +50,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
 
         /* Assume logical EraseSize == physical erasesize for starting the scan. 
           We'll sort it out later if we find a MediaHeader which says otherwise */
+       /* Actually, we won't.  The new DiskOnChip driver has already scanned
+          the MediaHeader and adjusted the virtual erasesize it presents in
+          the mtd device accordingly.  We could even get rid of
+          nftl->EraseSize if there were any point in doing so. */
        nftl->EraseSize = nftl->mbd.mtd->erasesize;
         nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
 
@@ -62,7 +66,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
 
                /* Check for ANAND header first. Then can whinge if it's found but later
                   checks fail */
-               if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
+               ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf);
+               /* We ignore ret in case the ECC of the MediaHeader is invalid
+                  (which is apparently acceptable) */
+               if (retlen != SECTORSIZE) {
                        static int warncount = 5;
 
                        if (warncount) {
@@ -104,7 +111,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
 
                /* Finally reread to check ECC */
                if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE,
-                               &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) {
+                               &retlen, buf, (char *)&oob, NULL) < 0)) {
                        printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
                               block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
                        continue;
@@ -149,6 +156,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
                memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
 
                /* Do some sanity checks on it */
+#if 0
+The new DiskOnChip driver scans the MediaHeader itself, and presents a virtual
+erasesize based on UnitSizeFactor.  So the erasesize we read from the mtd
+device is already correct.
                if (mh->UnitSizeFactor == 0) {
                        printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
                } else if (mh->UnitSizeFactor < 0xfc) {
@@ -161,6 +172,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
                        nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
                        nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
                }
+#endif
                nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
                if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
                        printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
@@ -213,11 +225,13 @@ static int find_boot_record(struct NFTLrecord *nftl)
 
                /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
                for (i = 0; i < nftl->nb_blocks; i++) {
+#if 0
+The new DiskOnChip driver already scanned the bad block table.  Just query it.
                        if ((i & (SECTORSIZE - 1)) == 0) {
                                /* read one sector for every SECTORSIZE of blocks */
                                if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize +
                                                       i + SECTORSIZE, SECTORSIZE, &retlen, buf,
-                                                      (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
+                                                      (char *)&oob, NULL)) < 0) {
                                        printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
                                               ret);
                                        kfree(nftl->ReplUnitTable);
@@ -228,6 +242,9 @@ static int find_boot_record(struct NFTLrecord *nftl)
                        /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
                        if (buf[i & (SECTORSIZE - 1)] != 0xff)
                                nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+#endif
+                       if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize))
+                               nftl->ReplUnitTable[i] = BLOCK_RESERVED;
                }
                
                nftl->MediaUnit = block;
@@ -253,21 +270,16 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int
                              int check_oob)
 {
        int i, retlen;
-       u8 buf[SECTORSIZE];
+       u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
 
        for (i = 0; i < len; i += SECTORSIZE) {
-               /* we want to read the sector without ECC check here since a free
-                  sector does not have ECC syndrome on it yet */
-               if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
+               if (MTD_READECC(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &nftl->oobinfo) < 0)
                        return -1;
                if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
                        return -1;
 
                if (check_oob) {
-                       if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize,
-                                       &retlen, buf) < 0)
-                               return -1;
-                       if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0)
+                       if (memcmpb(buf + SECTORSIZE, 0xff, nftl->mbd.mtd->oobsize) != 0)
                                return -1;
                }
                address += SECTORSIZE;
@@ -282,7 +294,6 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int
  * Return: 0 when succeed, -1 on error.
  *
  *  ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
- *        2. UnitSizeFactor != 0xFF
  */
 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
 {
@@ -312,11 +323,10 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
        MTD_ERASE(nftl->mbd.mtd, instr);
 
        if (instr->state == MTD_ERASE_FAILED) {
-               /* could not format, FixMe: We should update the BadUnitTable 
-                  both in memory and on disk */
                printk("Error while formatting block %d\n", block);
-               return -1;
-       } else {
+               goto fail;
+       }
+
                /* increase and write Wear-Leveling info */
                nb_erases = le32_to_cpu(uci.WearInfo);
                nb_erases++;
@@ -329,14 +339,18 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
                 * FixMe:  is this check really necessary ? since we have check the
                 *         return code after the erase operation. */
                if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
-                       return -1;
+                       goto fail;
 
                uci.WearInfo = le32_to_cpu(nb_erases);
                if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
                                 &retlen, (char *)&uci) < 0)
-                       return -1;
+                       goto fail;
                return 0;
-       }
+fail:
+       /* could not format, update the bad block table (caller is responsible
+          for setting the ReplUnitTable to BLOCK_RESERVED on failure) */
+       nftl->mbd.mtd->block_markbad(nftl->mbd.mtd, instr->addr);
+       return -1;
 }
 
 /* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct.
@@ -441,8 +455,7 @@ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
 
                printk("Formatting block %d\n", block);
                if (NFTL_formatblock(nftl, block) < 0) {
-                       /* cannot format !!!! Mark it as Bad Unit,
-                          FixMe: update the BadUnitTable on disk */
+                       /* cannot format !!!! Mark it as Bad Unit */
                        nftl->ReplUnitTable[block] = BLOCK_RESERVED;
                } else {
                        nftl->ReplUnitTable[block] = BLOCK_FREE;
index 3e27999..626ad36 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: redboot.c,v 1.11 2003/05/21 10:39:26 dwmw2 Exp $
+ * $Id: redboot.c,v 1.13 2004/04/01 10:17:40 gthomas Exp $
  *
  * Parse RedBoot-style Flash Image System (FIS) tables and
  * produce a Linux partition array to match.
@@ -48,21 +48,24 @@ static int parse_redboot_partitions(struct mtd_info *master,
        char *names;
        char *nullname;
        int namelen = 0;
+       int nulllen = 0;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
        static char nullstring[] = "unallocated";
+#endif
 
-       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       buf = kmalloc(master->erasesize, GFP_KERNEL);
 
        if (!buf)
                return -ENOMEM;
 
        /* Read the start of the last erase block */
        ret = master->read(master, master->size - master->erasesize,
-                          PAGE_SIZE, &retlen, (void *)buf);
+                          master->erasesize, &retlen, (void *)buf);
 
        if (ret)
                goto out;
 
-       if (retlen != PAGE_SIZE) {
+       if (retlen != master->erasesize) {
                ret = -EIO;
                goto out;
        }
@@ -80,7 +83,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
                goto out;
        }
 
-       for (i = 0; i < PAGE_SIZE / sizeof(struct fis_image_desc); i++) {
+       for (i = 0; i < master->erasesize / sizeof(struct fis_image_desc); i++) {
                struct fis_list *new_fl, **prev;
 
                if (buf[i].name[0] == 0xff)
@@ -112,48 +115,69 @@ static int parse_redboot_partitions(struct mtd_info *master,
 
                nrparts++;
        }
-       if (fl->img->flash_base)
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+       if (fl->img->flash_base) {
                nrparts++;
+               nulllen = sizeof(nullstring);
+       }
 
        for (tmp_fl = fl; tmp_fl->next; tmp_fl = tmp_fl->next) {
-               if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base)
+               if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize <= tmp_fl->next->img->flash_base) {
                        nrparts++;
+                       nulllen = sizeof(nullstring);
+               }
        }
-       parts = kmalloc(sizeof(*parts)*nrparts + sizeof(nullstring) + namelen, GFP_KERNEL);
+#endif
+       parts = kmalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
 
        if (!parts) {
                ret = -ENOMEM;
                goto out;
        }
 
-       memset(parts, 0, sizeof(*parts)*nrparts + namelen);
+       memset(parts, 0, sizeof(*parts)*nrparts + nulllen + namelen);
 
-       /* FIXME: Include nullname only if it's used */
        nullname = (char *)&parts[nrparts];
-       sprintf(nullname, nullstring);
-       names = nullname + sizeof(nullstring);
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+       if (nulllen > 0) {
+               strcpy(nullname, nullstring);
+       }
+#endif
+       names = nullname + nulllen;
 
        i=0;
 
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
        if (fl->img->flash_base) {
               parts[0].name = nullname;
               parts[0].size = fl->img->flash_base;
               parts[0].offset = 0;
+               i++;
        }
+#endif
        for ( ; i<nrparts; i++) {
                parts[i].size = fl->img->size;
                parts[i].offset = fl->img->flash_base;
                parts[i].name = names;
 
                strcpy(names, fl->img->name);
+#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
+               if (!memcmp(names, "RedBoot", 8) ||
+                               !memcmp(names, "RedBoot config", 15) ||
+                               !memcmp(names, "FIS directory", 14)) {
+                       parts[i].mask_flags = MTD_WRITEABLE;
+               }
+#endif
                names += strlen(names)+1;
 
-               if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize < fl->next->img->flash_base) {
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+               if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
                        i++;
                        parts[i].offset = parts[i-1].size + parts[i-1].offset;
                        parts[i].size = fl->next->img->flash_base - parts[i].offset;
                        parts[i].name = nullname;
                }
+#endif
                tmp_fl = fl;
                fl = fl->next;
                kfree(tmp_fl);
index c73345b..d67975b 100644 (file)
@@ -2130,6 +2130,17 @@ config TIGON3
          To compile this driver as a module, choose M here: the module
          will be called tg3.  This is recommended.
 
+config GIANFAR
+       tristate "Gianfar Ethernet"
+       depends on 85xx
+       help
+         This driver supports the Gigabit TSEC on the MPC85xx 
+         family of chips, and the FEC on the 8540
+
+config GFAR_NAPI
+       bool "NAPI Support"
+       depends on GIANFAR
+
 endmenu
 
 #
index 3a7b01d..76d3af5 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_BONDING) += bonding/
+obj-$(CONFIG_GIANFAR) += gianfar.o gianfar_ethtool.o gianfar_phy.o
 
 #
 # link order important here
index 070031d..30bc80a 100644 (file)
@@ -337,6 +337,20 @@ config SERIAL_UART00_CONSOLE
          your boot loader (lilo or loadlin) about how to pass options to the
          kernel at boot time.)
 
+config SERIAL_MPSC
+       bool "Marvell MPSC serial port support"
+       depends on PPC32 && MV64X60
+       select SERIAL_CORE
+       help
+         Say Y here if you want to use the Marvell MPSC serial controller.
+
+config SERIAL_MPSC_CONSOLE
+       bool "Support for console on Marvell MPSC serial port"
+       depends on SERIAL_MPSC
+       select SERIAL_CORE_CONSOLE
+       help
+         Say Y here if you want to support a serial console on a Marvell MPSC.
+
 config SERIAL_PXA
        bool "PXA serial port support"
        depends on ARM && ARCH_PXA
index 5780ae7..f7d3577 100644 (file)
@@ -4,6 +4,8 @@
 #  $Id: Makefile,v 1.8 2002/07/21 21:32:30 rmk Exp $
 #
 
+obj-$(CONFIG_SERIAL_MPSC) += mpsc/
+
 serial-8250-y :=
 serial-8250-$(CONFIG_SERIAL_8250_ACPI) += 8250_acpi.o
 serial-8250-$(CONFIG_GSC) += 8250_gsc.o
index a4a93a0..2c35a14 100644 (file)
@@ -1097,17 +1097,15 @@ config JFFS_FS_VERBOSE
 
 config JFFS_PROC_FS
        bool "JFFS stats available in /proc filesystem"
-       depends on JFFS_FS && PROC
+       depends on JFFS_FS && PROC_FS
        help
          Enabling this option will cause statistics from mounted JFFS file systems
          to be made available to the user in the /proc/fs/jffs/ directory.
 
 config JFFS2_FS
        tristate "Journalling Flash File System v2 (JFFS2) support"
-       depends on MTD
        select CRC32
-       select ZLIB_INFLATE
-       select ZLIB_DEFLATE
+       depends on MTD
        help
          JFFS2 is the second generation of the Journalling Flash File System
          for use on diskless embedded devices. It provides improved wear
@@ -1151,6 +1149,82 @@ config JFFS2_FS_NAND
          Say 'N' unless you have NAND flash and you are willing to test and
          develop JFFS2 support for it.
 
+config JFFS2_COMPRESSION_OPTIONS
+       bool "Advanced compression options for JFFS2"
+       default n
+       help
+         Enabling this option allows you to explicitly choose which
+         compression modules, if any, are enabled in JFFS2. Removing
+         compressors and mean you cannot read existing file systems,
+         and enabling experimental compressors can mean that you
+         write a file system which cannot be read by a standard kernel.
+
+         If unsure, you should _definitely_ say 'N'.
+
+config JFFS2_ZLIB
+       bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS
+       select ZLIB_INFLATE
+       select ZLIB_DEFLATE
+       depends on JFFS2_FS
+       default y
+        help
+          Zlib is designed to be a free, general-purpose, legally unencumbered,
+          lossless data-compression library for use on virtually any computer 
+          hardware and operating system. See http://www.gzip.org/zlib/ for
+          further information.
+          
+          Say 'Y' if unsure.
+
+config JFFS2_RTIME
+       bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS
+       depends on JFFS2_FS
+       default y
+        help
+          Rtime does manage to recompress already-compressed data. Say 'Y' if unsure.
+
+config JFFS2_RUBIN
+       bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS
+       depends on JFFS2_FS
+       default n
+        help
+          RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure.
+
+choice
+        prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS
+        default JFFS2_CMODE_PRIORITY
+        depends on JFFS2_FS
+        help
+          You can set here the default compression mode of JFFS2 from 
+          the avaiable compression modes. Don't touch if unsure.
+
+config JFFS2_CMODE_NONE
+        bool "no compression"
+        help
+          Uses no compression.
+
+config JFFS2_CMODE_PRIORITY
+        bool "priority"
+        help
+          Tries the compressors in a predefinied order and chooses the first 
+          successful one.
+
+config JFFS2_CMODE_SIZE
+        bool "size (EXPERIMENTAL)"
+        help
+          Tries all compressors and chooses the one which has the smallest 
+          result.
+
+endchoice
+
+config JFFS2_PROC
+       bool "JFFS2 proc interface support" if JFFS2_COMPRESSION_OPTIONS
+       depends on JFFS2_FS && PROC_FS
+       default n
+        help
+          You can read some statistics and set the compression mode and
+          compressor priorities with this interface.
+
+
 config CRAMFS
        tristate "Compressed ROM file system support"
        select ZLIB_INFLATE
index 1a47874..73ee110 100644 (file)
@@ -1,15 +1,18 @@
 #
-# Makefile for the linux Journalling Flash FileSystem (JFFS) routines.
+# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
 #
-# $Id: Makefile,v 1.34 2002/03/08 11:27:59 dwmw2 Exp $
+# $Id: Makefile.common,v 1.5 2004/07/15 16:06:41 dwmw2 Exp $
 #
 
 obj-$(CONFIG_JFFS2_FS) += jffs2.o
 
-jffs2-y        := compr.o compr_rubin.o compr_rtime.o compr_zlib.o
-jffs2-y        += dir.o file.o ioctl.o nodelist.o malloc.o
+jffs2-y        := compr.o dir.o file.o ioctl.o nodelist.o malloc.o
 jffs2-y        += read.o nodemgmt.o readinode.o write.o scan.o gc.o
 jffs2-y        += symlink.o build.o erase.o background.o fs.o writev.o
 jffs2-y        += super.o
 
 jffs2-$(CONFIG_JFFS2_FS_NAND)  += wbuf.o
+jffs2-$(CONFIG_JFFS2_RUBIN)    += compr_rubin.o
+jffs2-$(CONFIG_JFFS2_RTIME)    += compr_rtime.o
+jffs2-$(CONFIG_JFFS2_ZLIB)     += compr_zlib.o
+jffs2-$(CONFIG_JFFS2_PROC)     += proc.o
index 6212310..ac59ee3 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: background.c,v 1.44 2003/10/08 13:29:55 dwmw2 Exp $
+ * $Id: background.c,v 1.49 2004/07/13 08:56:40 dwmw2 Exp $
  *
  */
 
 
 
 static int jffs2_garbage_collect_thread(void *);
-static int thread_should_wake(struct jffs2_sb_info *c);
 
 void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
 {
        spin_lock(&c->erase_completion_lock);
-        if (c->gc_task && thread_should_wake(c))
+        if (c->gc_task && jffs2_thread_should_wake(c))
                 send_sig(SIGHUP, c->gc_task, 1);
        spin_unlock(&c->erase_completion_lock);
 }
@@ -84,11 +83,11 @@ static int jffs2_garbage_collect_thread(void *_c)
        for (;;) {
                allow_signal(SIGHUP);
 
-               if (!thread_should_wake(c)) {
+               if (!jffs2_thread_should_wake(c)) {
                        set_current_state (TASK_INTERRUPTIBLE);
                        D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n"));
-                       /* Yes, there's a race here; we checked thread_should_wake() before
-                          setting current->state to TASK_INTERRUPTIBLE. But it doesn't
+                       /* Yes, there's a race here; we checked jffs2_thread_should_wake()
+                          before setting current->state to TASK_INTERRUPTIBLE. But it doesn't
                           matter - We don't care if we miss a wakeup, because the GC thread
                           is only an optimisation anyway. */
                        schedule();
@@ -144,34 +143,3 @@ static int jffs2_garbage_collect_thread(void *_c)
        spin_unlock(&c->erase_completion_lock);
        complete_and_exit(&c->gc_thread_exit, 0);
 }
-
-static int thread_should_wake(struct jffs2_sb_info *c)
-{
-       int ret = 0;
-       uint32_t dirty;
-
-       if (c->unchecked_size) {
-               D1(printk(KERN_DEBUG "thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
-                         c->unchecked_size, c->checked_ino));
-               return 1;
-       }
-
-       /* dirty_size contains blocks on erase_pending_list
-        * those blocks are counted in c->nr_erasing_blocks.
-        * If one block is actually erased, it is not longer counted as dirty_space
-        * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
-        * with c->nr_erasing_blocks * c->sector_size again.
-        * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
-        * This helps us to force gc and pick eventually a clean block to spread the load.
-        */
-       dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
-
-       if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && 
-                       (dirty > c->nospc_dirty_size)) 
-               ret = 1;
-
-       D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", 
-                 c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
-
-       return ret;
-}
index c05f64b..9b6e1d8 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: build.c,v 1.52 2003/10/09 00:38:38 dwmw2 Exp $
+ * $Id: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $
  *
  */
 
@@ -16,8 +16,7 @@
 #include <linux/slab.h>
 #include "nodelist.h"
 
-int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
-int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *);
+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **);
 
 static inline struct jffs2_inode_cache *
 first_inode_chain(int *i, struct jffs2_sb_info *c)
@@ -44,6 +43,41 @@ next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c)
             ic;                                        \
             ic = next_inode(&i, ic, (c)))
 
+
+static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+{
+       struct jffs2_full_dirent *fd;
+
+       D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino));
+
+       /* For each child, increase nlink */
+       for(fd = ic->scan_dents; fd; fd = fd->next) {
+               struct jffs2_inode_cache *child_ic;
+               if (!fd->ino)
+                       continue;
+
+               /* XXX: Can get high latency here with huge directories */
+
+               child_ic = jffs2_get_ino_cache(c, fd->ino);
+               if (!child_ic) {
+                       printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
+                                 fd->name, fd->ino, ic->ino);
+                       continue;
+               }
+
+               if (child_ic->nlink++ && fd->type == DT_DIR) {
+                       printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
+                       if (fd->ino == 1 && ic->ino == 1) {
+                               printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
+                               printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
+                       }
+                       /* What do we do about it? */
+               }
+               D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
+               /* Can't free them. We might need them in pass 2 */
+       }
+}
+
 /* Scan plan:
  - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
  - Scan directory tree from top down, setting nlink in inocaches
@@ -54,6 +88,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        int ret;
        int i;
        struct jffs2_inode_cache *ic;
+       struct jffs2_full_dirent *dead_fds = NULL;
 
        /* First, scan the medium and build all the inode caches with
           lists of physical nodes */
@@ -71,47 +106,51 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        /* 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));
-               ret = jffs2_build_inode_pass1(c, ic);
-               if (ret) {
-                       D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
-                       return ret;
+
+               D1(BUG_ON(ic->ino > c->highest_ino));
+
+               if (ic->scan_dents) {
+                       jffs2_build_inode_pass1(c, ic);
+                       cond_resched();
                }
-               cond_resched();
        }
        D1(printk(KERN_DEBUG "Pass 1 complete\n"));
-       D1(jffs2_dump_block_lists(c));
 
        /* Next, scan for inodes with nlink == 0 and remove them. If
           they were directories, then decrement the nlink of their
           children too, and repeat the scan. As that's going to be
           a fairly uncommon occurrence, it's not so evil to do it this
           way. Recursion bad. */
-       do { 
-               D1(printk(KERN_DEBUG "Pass 2 (re)starting\n"));
-               ret = 0;
-               for_each_inode(i, c, ic) {
-                       D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
-                       if (ic->nlink)
-                               continue;
+       D1(printk(KERN_DEBUG "Pass 2 starting\n"));
+
+       for_each_inode(i, c, ic) {
+               D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes));
+               if (ic->nlink)
+                       continue;
                        
-                       /* XXX: Can get high latency here. Move the cond_resched() from the end of the loop? */
+               jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
+               cond_resched();
+       } 
 
-                       ret = jffs2_build_remove_unlinked_inode(c, ic);
-                       if (ret)
-                               break;
-               /* -EAGAIN means the inode's nlink was zero, so we deleted it,
-                  and furthermore that it had children and their nlink has now
-                  gone to zero too. So we have to restart the scan. */
-               } 
-               D1(jffs2_dump_block_lists(c));
+       D1(printk(KERN_DEBUG "Pass 2a starting\n"));
 
-               cond_resched();
-       
-       } while(ret == -EAGAIN);
+       while (dead_fds) {
+               struct jffs2_inode_cache *ic;
+               struct jffs2_full_dirent *fd = dead_fds;
+
+               dead_fds = fd->next;
+
+               ic = jffs2_get_ino_cache(c, fd->ino);
+               D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic));
+
+               if (ic)
+                       jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
+               jffs2_free_full_dirent(fd);
+       }
 
        D1(printk(KERN_DEBUG "Pass 2 complete\n"));
        
-       /* Finally, we can scan again and free the dirent nodes and scan_info structs */
+       /* Finally, we can scan again and free the dirent structs */
        for_each_inode(i, c, ic) {
                struct jffs2_full_dirent *fd;
                D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
@@ -133,49 +172,10 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
        return ret;
 }
 
-int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
-{
-       struct jffs2_full_dirent *fd;
-
-       D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
-
-       if (ic->ino > c->highest_ino)
-               c->highest_ino = ic->ino;
-
-       /* For each child, increase nlink */
-       for(fd=ic->scan_dents; fd; fd = fd->next) {
-               struct jffs2_inode_cache *child_ic;
-               if (!fd->ino)
-                       continue;
-               
-               /* XXX: Can get high latency here with huge directories */
-
-               child_ic = jffs2_get_ino_cache(c, fd->ino);
-               if (!child_ic) {
-                       printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
-                                 fd->name, fd->ino, ic->ino);
-                       continue;
-               }
-
-               if (child_ic->nlink++ && fd->type == DT_DIR) {
-                       printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
-                       if (fd->ino == 1 && ic->ino == 1) {
-                               printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
-                               printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
-                       }
-                       /* What do we do about it? */
-               }
-               D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
-               /* Can't free them. We might need them in pass 2 */
-       }
-       return 0;
-}
-
-int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds)
 {
        struct jffs2_raw_node_ref *raw;
        struct jffs2_full_dirent *fd;
-       int ret = 0;
 
        D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
        
@@ -214,18 +214,29 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
                                jffs2_free_full_dirent(fd);
                                continue;
                        }
-                       jffs2_free_full_dirent(fd);
+
+                       /* Reduce nlink of the child. If it's now zero, stick it on the 
+                          dead_fds list to be cleaned up later. Else just free the fd */
+
                        child_ic->nlink--;
+                       
+                       if (!child_ic->nlink) {
+                               D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n",
+                                         fd->ino, fd->name));
+                               fd->next = *dead_fds;
+                               *dead_fds = fd;
+                       } else {
+                               D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
+                                         fd->ino, fd->name, child_ic->nlink));
+                               jffs2_free_full_dirent(fd);
+                       }
                }
-               ret = -EAGAIN;
        }
 
        /*
           We don't delete the inocache from the hash list and free it yet. 
           The erase code will do that, when all the nodes are completely gone.
        */
-
-       return ret;
 }
 
 static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c)
index 471ec55..9e5138a 100644 (file)
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
- *
  * Created by Arjan van de Ven <arjanv@redhat.com>
  *
+ * Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
+ *                    University of Szeged, Hungary
+ *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr.c,v 1.27 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr.c,v 1.41 2004/06/24 09:51:38 havasi Exp $
  *
  */
 
-#if defined(__KERNEL__) || defined (__ECOS)
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#else 
-#define KERN_DEBUG
-#define KERN_NOTICE
-#define KERN_WARNING
-#define printk printf
-#include <stdio.h>
-#include <stdint.h>
-#include <errno.h>
-#endif
+#include "compr.h"
+
+static spinlock_t jffs2_compressor_list_lock = SPIN_LOCK_UNLOCKED;
+
+/* Available compressors are on this list */
+static LIST_HEAD(jffs2_compressor_list);
+
+/* Actual compression mode */
+static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
 
-#include <linux/jffs2.h>
+void jffs2_set_compression_mode(int mode) 
+{
+        jffs2_compression_mode = mode;
+}
 
-int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
-int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
-void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
+int jffs2_get_compression_mode(void)
+{
+        return jffs2_compression_mode;
+}
 
+/* Statistics for blocks stored without compression */
+static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
 
 /* jffs2_compress:
  * @data: Pointer to uncompressed data
- * @cdata: Pointer to buffer for compressed data
+ * @cdata: Pointer to returned pointer to buffer for compressed data
  * @datalen: On entry, holds the amount of data available for compression.
  *     On exit, expected to hold the amount of data actually compressed.
  * @cdatalen: On entry, holds the amount of space available for compressed
  *     data. On exit, expected to hold the actual size of the compressed
  *     data.
  *
- * Returns: Byte to be stored with data indicating compression type used.
+ * Returns: Lower byte to be stored with data indicating compression type used.
  * Zero is used to show that the data could not be compressed - the 
  * compressed version was actually larger than the original.
+ * Upper byte will be used later. (soon)
  *
  * If the cdata buffer isn't large enough to hold all the uncompressed data,
  * jffs2_compress should compress as much as will fit, and should set 
  * *datalen accordingly to show the amount of data which were compressed.
  */
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, 
-                   uint32_t *datalen, uint32_t *cdatalen)
+uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                            unsigned char *data_in, unsigned char **cpage_out, 
+                            uint32_t *datalen, uint32_t *cdatalen)
 {
-       int ret;
+       int ret = JFFS2_COMPR_NONE;
+        int compr_ret;
+        struct jffs2_compressor *this, *best=NULL;
+        unsigned char *output_buf = NULL, *tmp_buf;
+        uint32_t orig_slen, orig_dlen;
+        uint32_t best_slen=0, best_dlen=0;
 
-       ret = jffs2_zlib_compress(data_in, cpage_out, datalen, cdatalen);
-       if (!ret) {
-               return JFFS2_COMPR_ZLIB;
-       }
-#if 0 /* Disabled 23/9/1. With zlib it hardly ever gets a look in */
-       ret = jffs2_dynrubin_compress(data_in, cpage_out, datalen, cdatalen);
-       if (!ret) {
-               return JFFS2_COMPR_DYNRUBIN;
-       }
-#endif
-#if 0 /* Disabled 26/2/1. Obsoleted by dynrubin */
-       ret = jffs2_rubinmips_compress(data_in, cpage_out, datalen, cdatalen);
-       if (!ret) {
-               return JFFS2_COMPR_RUBINMIPS;
-       }
-#endif
-       /* rtime does manage to recompress already-compressed data */
-       ret = jffs2_rtime_compress(data_in, cpage_out, datalen, cdatalen);
-       if (!ret) {
-               return JFFS2_COMPR_RTIME;
-       }
-#if 0
-       /* We don't need to copy. Let the caller special-case the COMPR_NONE case. */
-       /* If we get here, no compression is going to work */
-       /* But we might want to use the fragmentation part -- Arjan */
-       memcpy(cpage_out,data_in,min(*datalen,*cdatalen));
-       if (*datalen > *cdatalen)
-               *datalen = *cdatalen;
-#endif         
-       return JFFS2_COMPR_NONE; /* We failed to compress */
+        switch (jffs2_compression_mode) {
+        case JFFS2_COMPR_MODE_NONE:
+                break;
+        case JFFS2_COMPR_MODE_PRIORITY:
+                output_buf = kmalloc(*cdatalen,GFP_KERNEL);
+                if (!output_buf) {
+                        printk(KERN_WARNING "JFFS2: No memory for compressor allocation. Compression failed.\n");
+                        goto out;
+                }
+                orig_slen = *datalen;
+                orig_dlen = *cdatalen;
+                spin_lock(&jffs2_compressor_list_lock);
+                list_for_each_entry(this, &jffs2_compressor_list, list) {
+                        /* Skip decompress-only backwards-compatibility and disabled modules */
+                        if ((!this->compress)||(this->disabled))
+                                continue;
 
+                        this->usecount++;
+                        spin_unlock(&jffs2_compressor_list_lock);
+                        *datalen  = orig_slen;
+                        *cdatalen = orig_dlen;
+                        compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL);
+                        spin_lock(&jffs2_compressor_list_lock);
+                        this->usecount--;
+                        if (!compr_ret) {
+                                ret = this->compr;
+                                this->stat_compr_blocks++;
+                                this->stat_compr_orig_size += *datalen;
+                                this->stat_compr_new_size  += *cdatalen;
+                                break;
+                        }
+                }
+                spin_unlock(&jffs2_compressor_list_lock);
+                if (ret == JFFS2_COMPR_NONE) kfree(output_buf);
+                break;
+        case JFFS2_COMPR_MODE_SIZE:
+                orig_slen = *datalen;
+                orig_dlen = *cdatalen;
+                spin_lock(&jffs2_compressor_list_lock);
+                list_for_each_entry(this, &jffs2_compressor_list, list) {
+                        /* Skip decompress-only backwards-compatibility and disabled modules */
+                        if ((!this->compress)||(this->disabled))
+                                continue;
+                        /* Allocating memory for output buffer if necessary */
+                        if ((this->compr_buf_size<orig_dlen)&&(this->compr_buf)) {
+                                spin_unlock(&jffs2_compressor_list_lock);
+                                kfree(this->compr_buf);
+                                spin_lock(&jffs2_compressor_list_lock);
+                                this->compr_buf_size=0;
+                                this->compr_buf=NULL;
+                        }
+                        if (!this->compr_buf) {
+                                spin_unlock(&jffs2_compressor_list_lock);
+                                tmp_buf = kmalloc(orig_dlen,GFP_KERNEL);
+                                spin_lock(&jffs2_compressor_list_lock);
+                                if (!tmp_buf) {
+                                        printk(KERN_WARNING "JFFS2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
+                                        continue;
+                                }
+                                else {
+                                        this->compr_buf = tmp_buf;
+                                        this->compr_buf_size = orig_dlen;
+                                }
+                        }
+                        this->usecount++;
+                        spin_unlock(&jffs2_compressor_list_lock);
+                        *datalen  = orig_slen;
+                        *cdatalen = orig_dlen;
+                        compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL);
+                        spin_lock(&jffs2_compressor_list_lock);
+                        this->usecount--;
+                        if (!compr_ret) {
+                                if ((!best_dlen)||(best_dlen>*cdatalen)) {
+                                        best_dlen = *cdatalen;
+                                        best_slen = *datalen;
+                                        best = this;
+                                }
+                        }
+                }
+                if (best_dlen) {
+                        *cdatalen = best_dlen;
+                        *datalen  = best_slen;
+                        output_buf = best->compr_buf;
+                        best->compr_buf = NULL;
+                        best->compr_buf_size = 0;
+                        best->stat_compr_blocks++;
+                        best->stat_compr_orig_size += best_slen;
+                        best->stat_compr_new_size  += best_dlen;
+                        ret = best->compr;
+                }
+                spin_unlock(&jffs2_compressor_list_lock);
+                break;
+        default:
+                printk(KERN_ERR "JFFS2: unknow compression mode.\n");
+        }
+ out:
+        if (ret == JFFS2_COMPR_NONE) {
+               *cpage_out = data_in;
+               *datalen = *cdatalen;
+                none_stat_compr_blocks++;
+                none_stat_compr_size += *datalen;
+        }
+        else {
+                *cpage_out = output_buf;
+        }
+       return ret;
 }
 
-
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, 
+int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                    uint16_t comprtype, unsigned char *cdata_in, 
                     unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
 {
-       switch (comprtype) {
+        struct jffs2_compressor *this;
+        int ret;
+
+       switch (comprtype & 0xff) {
        case JFFS2_COMPR_NONE:
                /* This should be special-cased elsewhere, but we might as well deal with it */
                memcpy(data_out, cdata_in, datalen);
+                none_stat_decompr_blocks++;
                break;
-
        case JFFS2_COMPR_ZERO:
                memset(data_out, 0, datalen);
                break;
+       default:
+                spin_lock(&jffs2_compressor_list_lock);
+                list_for_each_entry(this, &jffs2_compressor_list, list) {
+                        if (comprtype == this->compr) {
+                                this->usecount++;
+                                spin_unlock(&jffs2_compressor_list_lock);
+                                ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL);
+                                spin_lock(&jffs2_compressor_list_lock);
+                                if (ret) {
+                                        printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret);
+                                }
+                                else {
+                                        this->stat_decompr_blocks++;
+                                }
+                                this->usecount--;
+                                spin_unlock(&jffs2_compressor_list_lock);
+                                return ret;
+                        }
+                }
+               printk(KERN_WARNING "JFFS2 compression type 0x%02x not avaiable.\n", comprtype);
+                spin_unlock(&jffs2_compressor_list_lock);
+               return -EIO;
+       }
+       return 0;
+}
 
-       case JFFS2_COMPR_ZLIB:
-               jffs2_zlib_decompress(cdata_in, data_out, cdatalen, datalen);
-               break;
+int jffs2_register_compressor(struct jffs2_compressor *comp)
+{
+        struct jffs2_compressor *this;
 
-       case JFFS2_COMPR_RTIME:
-               jffs2_rtime_decompress(cdata_in, data_out, cdatalen, datalen);
-               break;
+        if (!comp->name) {
+                printk(KERN_WARNING "NULL compressor name at registering JFFS2 compressor. Failed.\n");
+                return -1;
+        }
+        comp->compr_buf_size=0;
+        comp->compr_buf=NULL;
+        comp->usecount=0;
+        comp->stat_compr_orig_size=0;
+        comp->stat_compr_new_size=0;
+        comp->stat_compr_blocks=0;
+        comp->stat_decompr_blocks=0;
+        D1(printk(KERN_DEBUG "Registering JFFS2 compressor \"%s\"\n", comp->name));
+
+        spin_lock(&jffs2_compressor_list_lock);
+
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                if (this->priority < comp->priority) {
+                        list_add(&comp->list, this->list.prev);
+                        goto out;
+                }
+        }
+        list_add_tail(&comp->list, &jffs2_compressor_list);
+out:
+        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+        })
+
+        spin_unlock(&jffs2_compressor_list_lock);
+
+        return 0;
+}
+
+int jffs2_unregister_compressor(struct jffs2_compressor *comp)
+{
+        D2(struct jffs2_compressor *this;)
+
+        D1(printk(KERN_DEBUG "Unregistering JFFS2 compressor \"%s\"\n", comp->name));
+
+        spin_lock(&jffs2_compressor_list_lock);
+
+        if (comp->usecount) {
+                spin_unlock(&jffs2_compressor_list_lock);
+                printk(KERN_WARNING "JFFS2: Compressor modul is in use. Unregister failed.\n");
+                return -1;
+        }
+        list_del(&comp->list);
+
+        D2(list_for_each_entry(this, &jffs2_compressor_list, list) {
+                printk(KERN_DEBUG "Compressor \"%s\", prio %d\n", this->name, this->priority);
+        })
+        spin_unlock(&jffs2_compressor_list_lock);
+        return 0;
+}
+
+#ifdef CONFIG_JFFS2_PROC
+
+#define JFFS2_STAT_BUF_SIZE 16000
+
+char *jffs2_list_compressors(void)
+{
+        struct jffs2_compressor *this;
+        char *buf, *act_buf;
+
+        act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                act_buf += sprintf(act_buf, "%10s priority:%d ", this->name, this->priority);
+                if ((this->disabled)||(!this->compress))
+                        act_buf += sprintf(act_buf,"disabled");
+                else
+                        act_buf += sprintf(act_buf,"enabled");
+                act_buf += sprintf(act_buf,"\n");
+        }
+        return buf;
+}
+
+char *jffs2_stats(void)
+{
+        struct jffs2_compressor *this;
+        char *buf, *act_buf;
+
+        act_buf = buf = kmalloc(JFFS2_STAT_BUF_SIZE,GFP_KERNEL);
+
+        act_buf += sprintf(act_buf,"JFFS2 compressor statistics:\n");
+        act_buf += sprintf(act_buf,"%10s   ","none");
+        act_buf += sprintf(act_buf,"compr: %d blocks (%d)  decompr: %d blocks\n", none_stat_compr_blocks, 
+                           none_stat_compr_size, none_stat_decompr_blocks);
+        spin_lock(&jffs2_compressor_list_lock);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                act_buf += sprintf(act_buf,"%10s ",this->name);
+                if ((this->disabled)||(!this->compress))
+                        act_buf += sprintf(act_buf,"- ");
+                else
+                        act_buf += sprintf(act_buf,"+ ");
+                act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d)  decompr: %d blocks ", this->stat_compr_blocks, 
+                                   this->stat_compr_new_size, this->stat_compr_orig_size, 
+                                   this->stat_decompr_blocks);
+                act_buf += sprintf(act_buf,"\n");
+        }
+        spin_unlock(&jffs2_compressor_list_lock);
+
+        return buf;
+}
+
+char *jffs2_get_compression_mode_name(void) 
+{
+        switch (jffs2_compression_mode) {
+        case JFFS2_COMPR_MODE_NONE:
+                return "none";
+        case JFFS2_COMPR_MODE_PRIORITY:
+                return "priority";
+        case JFFS2_COMPR_MODE_SIZE:
+                return "size";
+        }
+        return "unkown";
+}
+
+int jffs2_set_compression_mode_name(const char *name) 
+{
+        if (!strcmp("none",name)) {
+                jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+                return 0;
+        }
+        if (!strcmp("priority",name)) {
+                jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
+                return 0;
+        }
+        if (!strcmp("size",name)) {
+                jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+                return 0;
+        }
+        return 1;
+}
+
+static int jffs2_compressor_Xable(const char *name, int disabled)
+{
+        struct jffs2_compressor *this;
+        spin_lock(&jffs2_compressor_list_lock);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                if (!strcmp(this->name, name)) {
+                        this->disabled = disabled;
+                        spin_unlock(&jffs2_compressor_list_lock);
+                        return 0;                        
+                }
+        }
+        spin_unlock(&jffs2_compressor_list_lock);
+        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);
+        return 1;
+}
+
+int jffs2_enable_compressor_name(const char *name)
+{
+        return jffs2_compressor_Xable(name, 0);
+}
+
+int jffs2_disable_compressor_name(const char *name)
+{
+        return jffs2_compressor_Xable(name, 1);
+}
+
+int jffs2_set_compressor_priority(const char *name, int priority)
+{
+        struct jffs2_compressor *this,*comp;
+        spin_lock(&jffs2_compressor_list_lock);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                if (!strcmp(this->name, name)) {
+                        this->priority = priority;
+                        comp = this;
+                        goto reinsert;
+                }
+        }
+        spin_unlock(&jffs2_compressor_list_lock);
+        printk(KERN_WARNING "JFFS2: compressor %s not found.\n",name);        
+        return 1;
+reinsert:
+        /* list is sorted in the order of priority, so if
+           we change it we have to reinsert it into the
+           good place */
+        list_del(&comp->list);
+        list_for_each_entry(this, &jffs2_compressor_list, list) {
+                if (this->priority < comp->priority) {
+                        list_add(&comp->list, this->list.prev);
+                        spin_unlock(&jffs2_compressor_list_lock);
+                        return 0;
+                }
+        }
+        list_add_tail(&comp->list, &jffs2_compressor_list);
+        spin_unlock(&jffs2_compressor_list_lock);
+        return 0;
+}
 
-       case JFFS2_COMPR_RUBINMIPS:
-#if 0 /* Disabled 23/9/1 */
-               jffs2_rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
-#else
-               printk(KERN_WARNING "JFFS2: Rubinmips compression encountered but support not compiled in!\n");
 #endif
-               break;
-       case JFFS2_COMPR_DYNRUBIN:
-#if 1 /* Phase this one out */
-               jffs2_dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
+
+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
+{
+        if (orig != comprbuf)
+                kfree(comprbuf);
+}
+
+int jffs2_compressors_init(void) 
+{
+/* Registering compressors */
+#ifdef CONFIG_JFFS2_ZLIB
+        jffs2_zlib_init();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+        jffs2_rtime_init();
+#endif
+#ifdef CONFIG_JFFS2_RUBIN
+        jffs2_rubinmips_init();
+        jffs2_dynrubin_init();
+#endif
+#ifdef CONFIG_JFFS2_LZARI
+        jffs2_lzari_init();
+#endif
+#ifdef CONFIG_JFFS2_LZO
+        jffs2_lzo_init();
+#endif
+/* Setting default compression mode */
+#ifdef CONFIG_JFFS2_CMODE_NONE
+        jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
+        D1(printk(KERN_INFO "JFFS2: default compression mode: none\n");)
 #else
-               printk(KERN_WARNING "JFFS2: Dynrubin compression encountered but support not compiled in!\n");
+#ifdef CONFIG_JFFS2_CMODE_SIZE
+        jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
+        D1(printk(KERN_INFO "JFFS2: default compression mode: size\n");)
+#else
+        D1(printk(KERN_INFO "JFFS2: default compression mode: priority\n");)
 #endif
-               break;
+#endif
+        return 0;
+}
 
-       default:
-               printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype);
-               return -EIO;
-       }
-       return 0;
+int jffs2_compressors_exit(void) 
+{
+/* Unregistering compressors */
+#ifdef CONFIG_JFFS2_LZO
+        jffs2_lzo_exit();
+#endif
+#ifdef CONFIG_JFFS2_LZARI
+        jffs2_lzari_exit();
+#endif
+#ifdef CONFIG_JFFS2_RUBIN
+        jffs2_dynrubin_exit();
+        jffs2_rubinmips_exit();
+#endif
+#ifdef CONFIG_JFFS2_RTIME
+        jffs2_rtime_exit();
+#endif
+#ifdef CONFIG_JFFS2_ZLIB
+        jffs2_zlib_exit();
+#endif
+        return 0;
 }
index a72ce67..3bfe277 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_rtime.c,v 1.11 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr_rtime.c,v 1.14 2004/06/23 16:34:40 havasi Exp $
  *
  *
  * Very simple lz77-ish encoder.
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/string.h> 
+#include <linux/jffs2.h> 
+#include "compr.h"
 
 /* _compress returns the compressed size, -1 if bigger */
 int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, 
-                  uint32_t *sourcelen, uint32_t *dstlen)
+                  uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
        short positions[256];
        int outpos = 0;
@@ -67,8 +69,8 @@ int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
 }                 
 
 
-void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
-                     uint32_t srclen, uint32_t destlen)
+int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
+                     uint32_t srclen, uint32_t destlen, void *model)
 {
        short positions[256];
        int outpos = 0;
@@ -98,7 +100,29 @@ void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
                                outpos+=repeat;         
                        }
                }
-       }               
+       }
+        return 0;
 }                 
 
+static struct jffs2_compressor jffs2_rtime_comp = {
+    .priority = JFFS2_RTIME_PRIORITY,
+    .name = "rtime",
+    .compr = JFFS2_COMPR_RTIME,
+    .compress = &jffs2_rtime_compress,
+    .decompress = &jffs2_rtime_decompress,
+#ifdef JFFS2_RTIME_DISABLED
+    .disabled = 1,
+#else
+    .disabled = 0,
+#endif
+};
+
+int jffs2_rtime_init(void)
+{
+    return jffs2_register_compressor(&jffs2_rtime_comp);
+}
 
+void jffs2_rtime_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_rtime_comp);
+}
index be8e8d5..450d662 100644 (file)
@@ -7,17 +7,17 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_rubin.c,v 1.17 2002/05/20 14:56:37 dwmw2 Exp $
+ * $Id: compr_rubin.c,v 1.20 2004/06/23 16:34:40 havasi Exp $
  *
  */
 
  
 #include <linux/string.h>
 #include <linux/types.h>
+#include <linux/jffs2.h>
 #include "compr_rubin.h"
 #include "histo_mips.h"
-
-
+#include "compr.h"
 
 static void init_rubin(struct rubin_state *rs, int div, int *bits)
 {      
@@ -223,13 +223,13 @@ static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
 #if 0
 /* _compress returns the compressed size, -1 if bigger */
 int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, 
-                  uint32_t *sourcelen, uint32_t *dstlen)
+                  uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
        return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
 }
 #endif
 int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, 
-                  uint32_t *sourcelen, uint32_t *dstlen)
+                  uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
        int bits[8];
        unsigned char histo[256];
@@ -306,14 +306,15 @@ static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata
 }                 
 
 
-void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, 
-                  uint32_t sourcelen, uint32_t dstlen)
+int jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, 
+                  uint32_t sourcelen, uint32_t dstlen, void *model)
 {
        rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
+        return 0;
 }
 
-void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, 
-                  uint32_t sourcelen, uint32_t dstlen)
+int jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, 
+                  uint32_t sourcelen, uint32_t dstlen, void *model)
 {
        int bits[8];
        int c;
@@ -322,4 +323,51 @@ void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
                bits[c] = data_in[c];
 
        rubin_do_decompress(256, bits, data_in+8, cpage_out, sourcelen-8, dstlen);
+        return 0;
+}
+
+static struct jffs2_compressor jffs2_rubinmips_comp = {
+    .priority = JFFS2_RUBINMIPS_PRIORITY,
+    .name = "rubinmips",
+    .compr = JFFS2_COMPR_DYNRUBIN,
+    .compress = NULL, /*&jffs2_rubinmips_compress,*/
+    .decompress = &jffs2_rubinmips_decompress,
+#ifdef JFFS2_RUBINMIPS_DISABLED
+    .disabled = 1,
+#else
+    .disabled = 0,
+#endif
+};
+
+int jffs2_rubinmips_init(void)
+{
+    return jffs2_register_compressor(&jffs2_rubinmips_comp);
+}
+
+void jffs2_rubinmips_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_rubinmips_comp);
+}
+
+static struct jffs2_compressor jffs2_dynrubin_comp = {
+    .priority = JFFS2_DYNRUBIN_PRIORITY,
+    .name = "dynrubin",
+    .compr = JFFS2_COMPR_RUBINMIPS,
+    .compress = jffs2_dynrubin_compress,
+    .decompress = &jffs2_dynrubin_decompress,
+#ifdef JFFS2_DYNRUBIN_DISABLED
+    .disabled = 1,
+#else
+    .disabled = 0,
+#endif
+};
+
+int jffs2_dynrubin_init(void)
+{
+    return jffs2_register_compressor(&jffs2_dynrubin_comp);
+}
+
+void jffs2_dynrubin_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_dynrubin_comp);
 }
index c05e65f..f3b0bc9 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: compr_zlib.c,v 1.24 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.28 2004/06/23 16:34:40 havasi Exp $
  *
  */
 
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/zlib.h>
 #include <linux/zutil.h>
 #include <asm/semaphore.h>
 #include "nodelist.h"
+#include "compr.h"
 
        /* Plan: call deflate() with avail_in == *sourcelen, 
                avail_out = *dstlen - 12 and flush == Z_FINISH. 
@@ -39,7 +38,10 @@ static DECLARE_MUTEX(inflate_sem);
 static z_stream inf_strm, def_strm;
 
 #ifdef __KERNEL__ /* Linux-only */
-int __init jffs2_zlib_init(void)
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+
+static int __init alloc_workspaces(void)
 {
        def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
        if (!def_strm.workspace) {
@@ -57,15 +59,18 @@ int __init jffs2_zlib_init(void)
        return 0;
 }
 
-void jffs2_zlib_exit(void)
+static void free_workspaces(void)
 {
        vfree(def_strm.workspace);
        vfree(inf_strm.workspace);
 }
+#else
+#define alloc_workspaces() (0)
+#define free_workspaces() do { } while(0)
 #endif /* __KERNEL__ */
 
 int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, 
-                  uint32_t *sourcelen, uint32_t *dstlen)
+                  uint32_t *sourcelen, uint32_t *dstlen, void *model)
 {
        int ret;
 
@@ -130,8 +135,8 @@ int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
        return ret;
 }
 
-void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
-                     uint32_t srclen, uint32_t destlen)
+int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+                     uint32_t srclen, uint32_t destlen, void *model)
 {
        int ret;
        int wbits = MAX_WBITS;
@@ -165,7 +170,7 @@ void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
        if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) {
                printk(KERN_WARNING "inflateInit failed\n");
                up(&inflate_sem);
-               return;
+               return 1;
        }
 
        while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK)
@@ -175,4 +180,39 @@ void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
        }
        zlib_inflateEnd(&inf_strm);
        up(&inflate_sem);
+        return 0;
+}
+
+static struct jffs2_compressor jffs2_zlib_comp = {
+    .priority = JFFS2_ZLIB_PRIORITY,
+    .name = "zlib",
+    .compr = JFFS2_COMPR_ZLIB,
+    .compress = &jffs2_zlib_compress,
+    .decompress = &jffs2_zlib_decompress,
+#ifdef JFFS2_ZLIB_DISABLED
+    .disabled = 1,
+#else
+    .disabled = 0,
+#endif
+};
+
+int __init jffs2_zlib_init(void)
+{
+    int ret;
+
+    ret = alloc_workspaces();
+    if (ret)
+        return ret;
+
+    ret = jffs2_register_compressor(&jffs2_zlib_comp);
+    if (ret)
+        free_workspaces();
+
+    return ret;
+}
+
+void jffs2_zlib_exit(void)
+{
+    jffs2_unregister_compressor(&jffs2_zlib_comp);
+    free_workspaces();
 }
index f7a9409..4856f36 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: erase.c,v 1.53 2003/10/08 17:22:54 dwmw2 Exp $
+ * $Id: erase.c,v 1.60 2004/06/30 17:26:15 dbrown Exp $
  *
  */
 
@@ -28,7 +28,7 @@ struct erase_priv_struct {
 #ifndef __ECOS
 static void jffs2_erase_callback(struct erase_info *);
 #endif
-static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
 static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
@@ -36,6 +36,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
 void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
        int ret;
+       uint32_t bad_offset;
 #ifdef __ECOS
        ret = jffs2_flash_erase(c, jeb);
        if (!ret) {
@@ -65,18 +66,16 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
        instr->len = c->sector_size;
        instr->callback = jffs2_erase_callback;
        instr->priv = (unsigned long)(&instr[1]);
+       instr->fail_addr = 0xffffffff;
        
        ((struct erase_priv_struct *)instr->priv)->jeb = jeb;
        ((struct erase_priv_struct *)instr->priv)->c = c;
 
-       /* NAND , read out the fail counter, if possible */
-       if (!jffs2_can_mark_obsolete(c)) 
-               jffs2_nand_read_failcnt(c,jeb);
-               
        ret = c->mtd->erase(c->mtd, instr);
        if (!ret)
                return;
 
+       bad_offset = instr->fail_addr;
        kfree(instr);
 #endif /* __ECOS */
 
@@ -98,10 +97,10 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
        else
                printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
 
-       jffs2_erase_failed(c, jeb);
+       jffs2_erase_failed(c, jeb, bad_offset);
 }
 
-void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count)
 {
        struct jffs2_eraseblock *jeb;
 
@@ -118,6 +117,11 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
                        spin_unlock(&c->erase_completion_lock);
                        jffs2_mark_erased_block(c, jeb);
 
+                       if (!--count) {
+                               D1(printk(KERN_DEBUG "Count reached. jffs2_erase_pending_blocks leaving\n"));
+                               goto done;
+                       }
+
                } else if (!list_empty(&c->erase_pending_list)) {
                        jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
                        D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
@@ -144,6 +148,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
        }
 
        spin_unlock(&c->erase_completion_lock);
+ done:
        D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
 
        up(&c->erase_free_sem);
@@ -160,16 +165,34 @@ static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblo
        jffs2_erase_pending_trigger(c);
 }
 
-static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
 {
-        spin_lock(&c->erase_completion_lock);
-        c->erasing_size -= c->sector_size;
-        c->bad_size += c->sector_size;
-        list_del(&jeb->list);
-        list_add(&jeb->list, &c->bad_list);
-        c->nr_erasing_blocks--;
-        spin_unlock(&c->erase_completion_lock);
-        wake_up(&c->erase_wait);
+       /* For NAND, if the failure did not occur at the device level for a
+          specific physical page, don't bother updating the bad block table. */
+       if (jffs2_cleanmarker_oob(c) && (bad_offset != 0xffffffff)) {
+               /* We had a device-level failure to erase.  Let's see if we've
+                  failed too many times. */
+               if (!jffs2_write_nand_badblock(c, jeb, bad_offset)) {
+                       /* We'd like to give this block another try. */
+                       spin_lock(&c->erase_completion_lock);
+                       list_del(&jeb->list);
+                       list_add(&jeb->list, &c->erase_pending_list);
+                       c->erasing_size -= c->sector_size;
+                       c->dirty_size += c->sector_size;
+                       jeb->dirty_size = c->sector_size;
+                       spin_unlock(&c->erase_completion_lock);
+                       return;
+               }
+       }
+
+       spin_lock(&c->erase_completion_lock);
+       c->erasing_size -= c->sector_size;
+       c->bad_size += c->sector_size;
+       list_del(&jeb->list);
+       list_add(&jeb->list, &c->bad_list);
+       c->nr_erasing_blocks--;
+       spin_unlock(&c->erase_completion_lock);
+       wake_up(&c->erase_wait);
 }       
 
 #ifndef __ECOS
@@ -179,7 +202,7 @@ static void jffs2_erase_callback(struct erase_info *instr)
 
        if(instr->state != MTD_ERASE_DONE) {
                printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state);
-               jffs2_erase_failed(priv->c, priv->jeb);
+               jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
        } else {
                jffs2_erase_succeeded(priv->c, priv->jeb);
        }       
@@ -277,17 +300,13 @@ static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_erase
        jeb->last_node = NULL;
 }
 
-void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
-{
-       OFNI_BS_2SFFJ(c)->s_dirt = 1;
-}
-
 static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
        struct jffs2_raw_node_ref *marker_ref = NULL;
        unsigned char *ebuf;
        size_t retlen;
        int ret;
+       uint32_t bad_offset;
 
        if (!jffs2_cleanmarker_oob(c)) {
                marker_ref = jffs2_alloc_raw_node_ref();
@@ -312,6 +331,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                        uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
                        int i;
 
+                       bad_offset = ofs;
+
                        ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
                        if (ret) {
                                printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
@@ -325,22 +346,21 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                                /* It's OK. We know it's properly aligned */
                                unsigned long datum = *(unsigned long *)(&ebuf[i]);
                                if (datum + 1) {
-                                       printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i);
+                                       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))
                                                jffs2_free_raw_node_ref(marker_ref);
-                                       else 
-                                               jffs2_write_nand_badblock( c ,jeb );
                                        kfree(ebuf);
                                bad2:
                                        spin_lock(&c->erase_completion_lock);
-                                       c->erasing_size -= c->sector_size;
-                                       c->bad_size += c->sector_size;
-
-                                       list_add_tail(&jeb->list, &c->bad_list);
-                                       c->nr_erasing_blocks--;
+                                       /* Stick it on a list (any list) so
+                                          erase_failed can take it right off
+                                          again.  Silly, but shouldn't happen
+                                          often. */
+                                       list_add(&jeb->list, &c->erasing_list);
                                        spin_unlock(&c->erase_completion_lock);
-                                       wake_up(&c->erase_wait);
+                                       jffs2_erase_failed(c, jeb, bad_offset);
                                        return;
                                }
                        }
@@ -349,7 +369,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                }
                kfree(ebuf);
        }
-                                       
+
+       bad_offset = jeb->offset;
+
        /* Write the erase complete marker */   
        D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
        if (jffs2_cleanmarker_oob(c)) {
@@ -370,29 +392,30 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
                        .totlen =       cpu_to_je32(c->cleanmarker_size)
                };
 
-               marker.hdr_crc = cpu_to_je32(crc32(0, &marker, je32_to_cpu(marker.totlen) - 4));
+               marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
 
-               ret = jffs2_flash_write(c, jeb->offset, je32_to_cpu(marker.totlen), &retlen, (char *)&marker);
+               /* We only write the header; the rest was noise or padding anyway */
+               ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
                if (ret) {
                        printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
                               jeb->offset, ret);
                        goto bad2;
                }
-               if (retlen != je32_to_cpu(marker.totlen)) {
+               if (retlen != sizeof(marker)) {
                        printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %zd\n",
-                              jeb->offset, je32_to_cpu(marker.totlen), retlen);
+                              jeb->offset, sizeof(marker), retlen);
                        goto bad2;
                }
 
                marker_ref->next_in_ino = NULL;
                marker_ref->next_phys = NULL;
                marker_ref->flash_offset = jeb->offset | REF_NORMAL;
-               marker_ref->totlen = PAD(je32_to_cpu(marker.totlen));
+               marker_ref->__totlen = c->cleanmarker_size;
                        
                jeb->first_node = jeb->last_node = marker_ref;
                        
-               jeb->free_size = c->sector_size - marker_ref->totlen;
-               jeb->used_size = marker_ref->totlen;
+               jeb->free_size = c->sector_size - c->cleanmarker_size;
+               jeb->used_size = c->cleanmarker_size;
                jeb->dirty_size = 0;
                jeb->wasted_size = 0;
        }
index 8b3f8e7..4b14101 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: file.c,v 1.96 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: file.c,v 1.98 2004/03/19 16:41:09 dwmw2 Exp $
  *
  */
 
@@ -72,7 +72,7 @@ int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
        unsigned char *pg_buf;
        int ret;
 
-       D1(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
+       D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
 
        if (!PageLocked(pg))
                 PAGE_BUG(pg);
@@ -93,7 +93,7 @@ int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
        flush_dcache_page(pg);
        kunmap(pg);
 
-       D1(printk(KERN_DEBUG "readpage finished\n"));
+       D2(printk(KERN_DEBUG "readpage finished\n"));
        return 0;
 }
 
@@ -207,6 +207,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
        struct jffs2_raw_inode *ri;
+       unsigned aligned_start = start & ~3;
        int ret = 0;
        uint32_t writtenlen = 0;
 
@@ -240,9 +241,9 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
           hurt to do it again. The alternative is ifdefs, which are ugly. */
        kmap(pg);
 
-       ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + start,
-                                     (pg->index << PAGE_CACHE_SHIFT) + start,
-                                     end - start, &writtenlen);
+       ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start,
+                                     (pg->index << PAGE_CACHE_SHIFT) + aligned_start,
+                                     end - aligned_start, &writtenlen);
 
        kunmap(pg);
 
@@ -250,6 +251,12 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
                /* There was an error writing. */
                SetPageError(pg);
        }
+       
+       /* Adjust writtenlen for the padding we did, so we don't confuse our caller */
+       if (writtenlen < (start&3))
+               writtenlen = 0;
+       else
+               writtenlen -= (start&3);
 
        if (writtenlen) {
                if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) {
index 1f9e578..76d7279 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: fs.c,v 1.32 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: fs.c,v 1.46 2004/07/13 08:56:54 dwmw2 Exp $
  *
  */
 
@@ -58,7 +58,7 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
                mdata = kmalloc(f->metadata->size, GFP_USER);
                if (!mdata)
                        return -ENOMEM;
-               ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen);
+               ret = jffs2_read_dnode(c, f, f->metadata, mdata, 0, mdatalen);
                if (ret) {
                        kfree(mdata);
                        return ret;
@@ -145,10 +145,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
 
        old_metadata = f->metadata;
 
-       if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
-               vmtruncate(inode, iattr->ia_size);
+       if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
                jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
-       }
 
        if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
                jffs2_add_full_dnode_to_inode(c, f, new_metadata);
@@ -166,6 +164,14 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
        up(&f->sem);
        jffs2_complete_reservation(c);
 
+       /* We have to do the vmtruncate() without f->sem held, since
+          some pages may be locked and waiting for it in readpage(). 
+          We are protected from a simultaneous write() extending i_size
+          back past iattr->ia_size, because do_truncate() holds the
+          generic inode semaphore. */
+       if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size)
+               vmtruncate(inode, iattr->ia_size);
+
        return 0;
 }
 
@@ -287,7 +293,7 @@ void jffs2_read_inode (struct inode *inode)
        case S_IFCHR:
                /* Read the device numbers from the media */
                D1(printk(KERN_DEBUG "Reading device numbers from flash\n"));
-               if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
+               if (jffs2_read_dnode(c, f, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) {
                        /* Eep */
                        printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino);
                        up(&f->sem);
@@ -317,7 +323,7 @@ void jffs2_dirty_inode(struct inode *inode)
        struct iattr iattr;
 
        if (!(inode->i_state & I_DIRTY_DATASYNC)) {
-               D1(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
+               D2(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino));
                return;
        }
 
@@ -343,9 +349,14 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data)
 
        /* We stop if it was running, then restart if it needs to.
           This also catches the case where it was stopped and this
-          is just a remount to restart it */
-       if (!(sb->s_flags & MS_RDONLY))
+          is just a remount to restart it.
+          Flush the writebuffer, if neccecary, else we loose it */
+       if (!(sb->s_flags & MS_RDONLY)) {
                jffs2_stop_garbage_collect_thread(c);
+               down(&c->alloc_sem);
+               jffs2_flush_wbuf_pad(c);
+               up(&c->alloc_sem);
+       }       
 
        if (!(*flags & MS_RDONLY))
                jffs2_start_garbage_collect_thread(c);
@@ -365,7 +376,7 @@ void jffs2_write_super (struct super_block *sb)
 
        D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
        jffs2_garbage_collect_trigger(c);
-       jffs2_erase_pending_blocks(c);
+       jffs2_erase_pending_blocks(c, 0);
        jffs2_flush_wbuf_gc(c, 0);
 }
 
@@ -437,17 +448,35 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
 
        c = JFFS2_SB_INFO(sb);
 
+#ifndef CONFIG_JFFS2_FS_NAND
+       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;
+       }
+#endif
+
        c->flash_size = c->mtd->size;
 
        /* 
         * Check, if we have to concatenate physical blocks to larger virtual blocks
         * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation)
         */
-       blocks = c->flash_size / c->mtd->erasesize;
-       while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024))
+       c->sector_size = c->mtd->erasesize; 
+       blocks = c->flash_size / c->sector_size;
+       while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
                blocks >>= 1;
+               c->sector_size <<= 1;
+       }       
        
-       c->sector_size = c->flash_size / blocks;
+       /*
+        * Size alignment check
+        */
+       if ((c->sector_size * blocks) != c->flash_size) {
+               c->flash_size = c->sector_size * blocks;                
+               printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n",
+                       c->flash_size / 1024);
+       }
+
        if (c->sector_size != c->mtd->erasesize)
                printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", 
                        c->mtd->erasesize / 1024, c->sector_size / 1024);
@@ -460,12 +489,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
        c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
        /* Joern -- stick alignment for weird 8-byte-page flash here */
 
-       if (jffs2_cleanmarker_oob(c)) {
-               /* NAND (or other bizarre) flash... do setup accordingly */
-               ret = jffs2_nand_flash_setup(c);
-               if (ret)
-                       return ret;
-       }
+       /* NAND (or other bizarre) flash... do setup accordingly */
+       ret = jffs2_flash_setup(c);
+       if (ret)
+               return ret;
 
        c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
        if (!c->inocache_list) {
@@ -510,7 +537,126 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
  out_inohash:
        kfree(c->inocache_list);
  out_wbuf:
-       jffs2_nand_flash_cleanup(c);
+       jffs2_flash_cleanup(c);
+
+       return ret;
+}
+
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+                                  struct jffs2_inode_info *f)
+{
+       iput(OFNI_EDONI_2SFFJ(f));
+}
+
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+                                                    int inum, int nlink)
+{
+       struct inode *inode;
+       struct jffs2_inode_cache *ic;
+       if (!nlink) {
+               /* The inode has zero nlink but its nodes weren't yet marked
+                  obsolete. This has to be because we're still waiting for 
+                  the final (close() and) iput() to happen.
+
+                  There's a possibility that the final iput() could have 
+                  happened while we were contemplating. In order to ensure
+                  that we don't cause a new read_inode() (which would fail)
+                  for the inode in question, we use ilookup() in this case
+                  instead of iget().
+
+                  The nlink can't _become_ zero at this point because we're 
+                  holding the alloc_sem, and jffs2_do_unlink() would also
+                  need that while decrementing nlink on any inode.
+               */
+               inode = ilookup(OFNI_BS_2SFFJ(c), inum);
+               if (!inode) {
+                       D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
+                                 inum));
+
+                       spin_lock(&c->inocache_lock);
+                       ic = jffs2_get_ino_cache(c, inum);
+                       if (!ic) {
+                               D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
+                               spin_unlock(&c->inocache_lock);
+                               return NULL;
+                       }
+                       if (ic->state != INO_STATE_CHECKEDABSENT) {
+                               /* Wait for progress. Don't just loop */
+                               D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
+                                         ic->ino, ic->state));
+                               sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+                       } else {
+                               spin_unlock(&c->inocache_lock);
+                       }
+
+                       return NULL;
+               }
+       } else {
+               /* Inode has links to it still; they're not going away because
+                  jffs2_do_unlink() would need the alloc_sem and we have it.
+                  Just iget() it, and if read_inode() is necessary that's OK.
+               */
+               inode = iget(OFNI_BS_2SFFJ(c), inum);
+               if (!inode)
+                       return ERR_PTR(-ENOMEM);
+       }
+       if (is_bad_inode(inode)) {
+               printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
+                      inum, nlink);
+               /* NB. This will happen again. We need to do something appropriate here. */
+               iput(inode);
+               return ERR_PTR(-EIO);
+       }
+
+       return JFFS2_INODE_INFO(inode);
+}
+
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
+                                  struct jffs2_inode_info *f, 
+                                  unsigned long offset,
+                                  unsigned long *priv)
+{
+       struct inode *inode = OFNI_EDONI_2SFFJ(f);
+       struct page *pg;
+
+       pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, 
+                            (void *)jffs2_do_readpage_unlock, inode);
+       if (IS_ERR(pg))
+               return (void *)pg;
+       
+       *priv = (unsigned long)pg;
+       return kmap(pg);
+}
+
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+                          unsigned char *ptr,
+                          unsigned long *priv)
+{
+       struct page *pg = (void *)*priv;
+
+       kunmap(pg);
+       page_cache_release(pg);
+}
+
+int jffs2_flash_setup(struct jffs2_sb_info *c) {
+       int ret = 0;
+       
+       if (jffs2_cleanmarker_oob(c)) {
+               /* NAND flash... do setup accordingly */
+               ret = jffs2_nand_flash_setup(c);
+               if (ret)
+                       return ret;
+       }
 
+       /* add setups for other bizarre flashes here... */
        return ret;
 }
+
+void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
+
+       if (jffs2_cleanmarker_oob(c)) {
+               jffs2_nand_flash_cleanup(c);
+       }
+
+       /* add cleanups for other bizarre flashes here... */
+}
index 1cc6bfc..f4d16ad 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: gc.c,v 1.114 2003/10/09 13:53:35 dwmw2 Exp $
+ * $Id: gc.c,v 1.136 2004/05/27 19:06:09 gleixner Exp $
  *
  */
 
@@ -19,6 +19,7 @@
 #include <linux/compiler.h>
 #include <linux/stat.h>
 #include "nodelist.h"
+#include "compr.h"
 
 static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 
                                          struct jffs2_inode_cache *ic,
@@ -36,7 +37,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                                       struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
                                       uint32_t start, uint32_t end);
 static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_eraseblock *jeb,
-                              struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic);
+                              struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f);
 
 /* Called with erase_completion_lock held */
 static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
@@ -80,7 +81,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
                nextlist = &c->erasable_list;
        } else {
                /* Eep. All were empty */
-               printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n");
+               D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"));
                return NULL;
        }
 
@@ -112,11 +113,11 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
  */
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 {
+       struct jffs2_inode_info *f;
        struct jffs2_inode_cache *ic;
        struct jffs2_eraseblock *jeb;
        struct jffs2_raw_node_ref *raw;
-       uint32_t inum;
-       int ret = 0;
+       int ret = 0, inum, nlink;
 
        if (down_interruptible(&c->alloc_sem))
                return -EINTR;
@@ -186,7 +187,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                ic->state = INO_STATE_CHECKING;
                spin_unlock(&c->inocache_lock);
 
-               D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino));
+               D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%u\n", ic->ino));
 
                ret = jffs2_do_crccheck_inode(c, ic);
                if (ret)
@@ -204,7 +205,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                jeb = jffs2_find_gc_block(c);
 
        if (!jeb) {
-               printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n");
+               D1 (printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"));
                spin_unlock(&c->erase_completion_lock);
                up(&c->alloc_sem);
                return -EIO;
@@ -223,17 +224,21 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                        
        while(ref_obsolete(raw)) {
                D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
-               jeb->gc_node = raw = raw->next_phys;
-               if (!raw) {
+               raw = raw->next_phys;
+               if (unlikely(!raw)) {
                        printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
                        printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", 
                               jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size);
+                       jeb->gc_node = raw;
                        spin_unlock(&c->erase_completion_lock);
                        up(&c->alloc_sem);
                        BUG();
                }
        }
+       jeb->gc_node = raw;
+
        D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw)));
+
        if (!raw->next_in_ino) {
                /* Inode-less node. Clean marker, snapshot or something like that */
                /* FIXME: If it's something that needs to be copied, including something
@@ -243,13 +248,17 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                up(&c->alloc_sem);
                goto eraseit_lock;
        }
-                                                    
-       inum = jffs2_raw_ref_to_inum(raw);
-       D1(printk(KERN_DEBUG "Inode number is #%u\n", inum));
+
+       ic = jffs2_raw_ref_to_ic(raw);
+
+       /* We need to hold the inocache. Either the erase_completion_lock or
+          the inocache_lock are sufficient; we trade down since the inocache_lock 
+          causes less contention. */
+       spin_lock(&c->inocache_lock);
 
        spin_unlock(&c->erase_completion_lock);
 
-       D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), inum));
+       D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino));
 
        /* Three possibilities:
           1. Inode is already in-core. We must iget it and do proper
@@ -259,11 +268,6 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
           3. Inode is not in-core, node is not pristine. We must iget()
              and take the slow path.
        */
-       spin_lock(&c->inocache_lock);
-       ic = jffs2_get_ino_cache(c, inum);
-
-       /* This should never fail unless I'm particularly stupid.
-          So we don't check before dereferencing it */
 
        switch(ic->state) {
        case INO_STATE_CHECKEDABSENT:
@@ -275,28 +279,28 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                        ic->state = INO_STATE_GC;
                else {
                        D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", 
-                                 inum));
+                                 ic->ino));
                }
                break;
 
        case INO_STATE_PRESENT:
-       case INO_STATE_UNCHECKED:
-               /* It's in-core or hasn't been checked. GC must iget() it. */
+               /* It's in-core. GC must iget() it. */
                break;
 
+       case INO_STATE_UNCHECKED:
        case INO_STATE_CHECKING:
+       case INO_STATE_GC:
                /* Should never happen. We should have finished checking
-                  by the time we actually start doing any GC. */
+                  by the time we actually start doing any GC, and since 
+                  we're holding the alloc_sem, no other garbage collection 
+                  can happen.
+               */
+               printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n",
+                      ic->ino, ic->state);
+               up(&c->alloc_sem);
+               spin_unlock(&c->inocache_lock);
                BUG();
 
-       
-       case INO_STATE_GC:
-               /* Should never happen. We are holding the alloc_sem, 
-                  no other garbage collection can happen. Note that we
-                  do depend on this later when deciding to do a simple
-                  node copy */
-               BUG();
-                        
        case INO_STATE_READING:
                /* Someone's currently trying to read it. We must wait for
                   them to finish and then go through the full iget() route
@@ -306,7 +310,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
 
                up(&c->alloc_sem);
                D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n",
-                         inum, ic->state));
+                         ic->ino, ic->state));
                sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
                /* And because we dropped the alloc_sem we must start again from the 
                   beginning. Ponder chance of livelock here -- we're returning success
@@ -319,27 +323,50 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
                   A: Small enough that I don't care :) 
                */
                return 0;
-
        }
 
-       spin_unlock(&c->inocache_lock);
-
        /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the
           node intact, and we don't have to muck about with the fragtree etc. 
           because we know it's not in-core. If it _was_ in-core, we go through
           all the iget() crap anyway */
 
        if (ic->state == INO_STATE_GC) {
+               spin_unlock(&c->inocache_lock);
+
                ret = jffs2_garbage_collect_pristine(c, ic, raw);
-               jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT);
 
-               if (ret != -EBADFD)
+               spin_lock(&c->inocache_lock);
+               ic->state = INO_STATE_CHECKEDABSENT;
+               wake_up(&c->inocache_wq);
+
+               if (ret != -EBADFD) {
+                       spin_unlock(&c->inocache_lock);
                        goto release_sem;
+               }
 
-               /* Fall through if it wanted us to */
+               /* Fall through if it wanted us to, with inocache_lock held */
        }
 
-       ret = jffs2_garbage_collect_live(c, jeb, raw, ic);
+       /* Prevent the fairly unlikely race where the gcblock is
+          entirely obsoleted by the final close of a file which had
+          the only valid nodes in the block, followed by erasure,
+          followed by freeing of the ic because the erased block(s)
+          held _all_ the nodes of that inode.... never been seen but
+          it's vaguely possible. */
+
+       inum = ic->ino;
+       nlink = ic->nlink;
+       spin_unlock(&c->inocache_lock);
+
+       f = jffs2_gc_fetch_inode(c, inum, nlink);
+       if (IS_ERR(f))
+               return PTR_ERR(f);
+       if (!f)
+               return 0;
+
+       ret = jffs2_garbage_collect_live(c, jeb, raw, f);
+
+       jffs2_gc_release_inode(c, f);
 
  release_sem:
        up(&c->alloc_sem);
@@ -362,38 +389,35 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
        return ret;
 }
 
-
 static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_eraseblock *jeb,
-                              struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic)
+                                     struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f)
 {
-       struct jffs2_inode_info *f;
        struct jffs2_node_frag *frag;
        struct jffs2_full_dnode *fn = NULL;
        struct jffs2_full_dirent *fd;
        uint32_t start = 0, end = 0, nrfrags = 0;
-       struct inode *inode;
        int ret = 0;
 
-       inode = iget(OFNI_BS_2SFFJ(c), ic->ino);
-       if (is_bad_inode(inode)) {
-               printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino);
-               /* NB. This will happen again. We need to do something appropriate here. */
-               up(&c->alloc_sem);
-               iput(inode);
-               return -EIO;
-       }
-
-       f = JFFS2_INODE_INFO(inode);
        down(&f->sem);
 
        /* Now we have the lock for this inode. Check that it's still the one at the head
           of the list. */
 
+       spin_lock(&c->erase_completion_lock);
+
+       if (c->gcblock != jeb) {
+               spin_unlock(&c->erase_completion_lock);
+               D1(printk(KERN_DEBUG "GC block is no longer gcblock. Restart\n"));
+               goto upnout;
+       }
        if (ref_obsolete(raw)) {
+               spin_unlock(&c->erase_completion_lock);
                D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n"));
                /* They'll call again */
                goto upnout;
        }
+       spin_unlock(&c->erase_completion_lock);
+
        /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */
        if (f->metadata && f->metadata->raw == raw) {
                fn = f->metadata;
@@ -406,30 +430,6 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_era
                if (frag->node && frag->node->raw == raw) {
                        fn = frag->node;
                        end = frag->ofs + frag->size;
-#if 1 /* Temporary debugging sanity checks, till we're ready to _trust_ the REF_PRISTINE flag stuff */ 
-                       if (!nrfrags && ref_flags(fn->raw) == REF_PRISTINE) {
-                               if (fn->frags > 1) {
-                                       printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(raw), fn->frags);
-                                       mark_ref_normal(raw);
-                               }
-                               /* A hole node which isn't multi-page should be garbage-collected
-                                  and merged anyway, so we just check for the frag size here,
-                                  rather than mucking around with actually reading the node
-                                  and checking the compression type, which is the real way
-                                  to tell a hole node. */
-                               if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE) {
-                                       printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
-                                              ref_offset(raw));
-                                       mark_ref_normal(raw);
-                               }
-
-                               if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE) {
-                                       printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
-                                              ref_offset(raw), frag->ofs, frag->ofs+frag->size);
-                                       mark_ref_normal(raw);
-                               }
-                       }
-#endif
                        if (!nrfrags++)
                                start = frag->ofs;
                        if (nrfrags == frag->node->frags)
@@ -438,10 +438,10 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_era
        }
        if (fn) {
                if (ref_flags(raw) == REF_PRISTINE) {
-                       ret = jffs2_garbage_collect_pristine(c, ic, raw);
+                       ret = jffs2_garbage_collect_pristine(c, f->inocache, raw);
                        if (!ret) {
                                /* Urgh. Return it sensibly. */
-                               frag->node->raw = ic->nodes;
+                               frag->node->raw = f->inocache->nodes;
                        }       
                        if (ret != -EBADFD)
                                goto upnout;
@@ -478,7 +478,6 @@ static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_era
        }
  upnout:
        up(&f->sem);
-       iput(inode);
 
        return ret;
 }
@@ -492,30 +491,32 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
        size_t retlen;
        int ret;
        uint32_t phys_ofs, alloclen;
-       uint32_t crc;
+       uint32_t crc, rawlen;
        int retried = 0;
 
        D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));
 
+       rawlen = ref_totlen(c, c->gcblock, raw);
+
        /* Ask for a small amount of space (or the totlen if smaller) because we
           don't want to force wastage of the end of a block if splitting would
           work. */
-       ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, raw->totlen),
-                                    &phys_ofs, &alloclen);
+       ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, 
+                                             rawlen), &phys_ofs, &alloclen);
        if (ret)
                return ret;
 
-       if (alloclen < raw->totlen) {
+       if (alloclen < rawlen) {
                /* Doesn't fit untouched. We'll go the old route and split it */
                return -EBADFD;
        }
 
-       node = kmalloc(raw->totlen, GFP_KERNEL);
+       node = kmalloc(rawlen, GFP_KERNEL);
        if (!node)
                return -ENOMEM;
 
-       ret = jffs2_flash_read(c, ref_offset(raw), raw->totlen, &retlen, (char *)node);
-       if (!ret && retlen != raw->totlen)
+       ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node);
+       if (!ret && retlen != rawlen)
                ret = -EIO;
        if (ret)
                goto out_node;
@@ -578,14 +579,14 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
        /* OK, all the CRCs are good; this node can just be copied as-is. */
  retry:
        nraw->flash_offset = phys_ofs;
-       nraw->totlen = raw->totlen;
+       nraw->__totlen = rawlen;
        nraw->next_phys = NULL;
 
-       ret = jffs2_flash_write(c, phys_ofs, raw->totlen, &retlen, (char *)node);
+       ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node);
 
-       if (ret || (retlen != raw->totlen)) {
+       if (ret || (retlen != rawlen)) {
                printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
-                       raw->totlen, phys_ofs, ret, retlen);
+                       rawlen, phys_ofs, ret, retlen);
                if (retlen) {
                         /* Doesn't belong to any inode */
                        nraw->next_in_ino = NULL;
@@ -609,7 +610,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
                        ACCT_SANITY_CHECK(c,jeb);
                        D1(ACCT_PARANOIA_CHECK(jeb));
 
-                       ret = jffs2_reserve_space_gc(c, raw->totlen, &phys_ofs, &dummy);
+                       ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy);
 
                        if (!ret) {
                                D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
@@ -674,7 +675,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
                        printk(KERN_WARNING "kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n");
                        return -ENOMEM;
                }
-               ret = jffs2_read_dnode(c, fn, mdata, 0, mdatalen);
+               ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen);
                if (ret) {
                        printk(KERN_WARNING "read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", ret);
                        kfree(mdata);
@@ -779,13 +780,17 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
           delete a 'real' dirent with the same name that's still
           somewhere else on the flash. */
        if (!jffs2_can_mark_obsolete(c)) {
-               struct jffs2_raw_dirent rd;
+               struct jffs2_raw_dirent *rd;
                struct jffs2_raw_node_ref *raw;
                int ret;
                size_t retlen;
                int name_len = strlen(fd->name);
                uint32_t name_crc = crc32(0, fd->name, name_len);
-               char *namebuf = NULL;
+               uint32_t rawlen = ref_totlen(c, jeb, fd->raw);
+
+               rd = kmalloc(rawlen, GFP_KERNEL);
+               if (!rd)
+                       return -ENOMEM;
 
                /* Prevent the erase code from nicking the obsolete node refs while
                   we're looking at them. I really don't like this extra lock but
@@ -793,91 +798,66 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
                down(&c->erase_free_sem);
 
                for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
+
                        /* We only care about obsolete ones */
                        if (!(ref_obsolete(raw)))
                                continue;
 
+                       /* Any dirent with the same name is going to have the same length... */
+                       if (ref_totlen(c, NULL, raw) != rawlen)
+                               continue;
+
                        /* 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)))
                                continue;
 
-                       /* This is an obsolete node belonging to the same directory */
-                       ret = jffs2_flash_read(c, ref_offset(raw), sizeof(struct jffs2_unknown_node), &retlen, (char *)&rd);
+                       D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
+
+                       /* This is an obsolete node belonging to the same directory, and it's of the right
+                          length. We need to take a closer look...*/
+                       ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd);
                        if (ret) {
-                               printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading header from obsolete node at %08x\n", ret, ref_offset(raw));
+                               printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading obsolete node at %08x\n", ret, ref_offset(raw));
                                /* If we can't read it, we don't need to continue to obsolete it. Continue */
                                continue;
                        }
-                       if (retlen != sizeof(struct jffs2_unknown_node)) {
+                       if (retlen != rawlen) {
                                printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n",
-                                      retlen, sizeof(struct jffs2_unknown_node), ref_offset(raw));
+                                      retlen, rawlen, ref_offset(raw));
                                continue;
                        }
-                       if (je16_to_cpu(rd.nodetype) != JFFS2_NODETYPE_DIRENT ||
-                           PAD(je32_to_cpu(rd.totlen)) != PAD(sizeof(rd) + name_len))
-                               continue;
 
-                       /* OK, it's a dirent node, it's the right length. We have to take a 
-                          closer look at it... */
-                       ret = jffs2_flash_read(c, ref_offset(raw), sizeof(rd), &retlen, (char *)&rd);
-                       if (ret) {
-                               printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading from obsolete node at %08x\n", ret, ref_offset(raw));
-                               /* If we can't read it, we don't need to continune to obsolete it. Continue */
+                       if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT)
                                continue;
-                       }
-                       if (retlen != sizeof(rd)) {
-                               printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading from obsolete node at %08x\n",
-                                      retlen, sizeof(rd), ref_offset(raw));
-                               continue;
-                       }
 
                        /* If the name CRC doesn't match, skip */
-                       if (je32_to_cpu(rd.name_crc) != name_crc)
+                       if (je32_to_cpu(rd->name_crc) != name_crc)
                                continue;
+
                        /* If the name length doesn't match, or it's another deletion dirent, skip */
-                       if (rd.nsize != name_len || !je32_to_cpu(rd.ino))
+                       if (rd->nsize != name_len || !je32_to_cpu(rd->ino))
                                continue;
 
                        /* OK, check the actual name now */
-                       if (!namebuf) {
-                               namebuf = kmalloc(name_len + 1, GFP_KERNEL);
-                               if (!namebuf) {
-                                       up(&c->erase_free_sem);
-                                       return -ENOMEM;
-                               }
-                       }
-                       /* We read the extra byte before it so it's a word-aligned read */
-                       ret = jffs2_flash_read(c, (ref_offset(raw))+sizeof(rd)-1, name_len+1, &retlen, namebuf);
-                       if (ret) {
-                               printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading name from obsolete node at %08x\n", ret, ref_offset(raw));
-                               /* If we can't read it, we don't need to continune to obsolete it. Continue */
-                               continue;
-                       }
-                       if (retlen != name_len+1) {
-                               printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %d) reading name from obsolete node at %08x\n",
-                                      retlen, name_len+1, ref_offset(raw));
-                               continue;
-                       }
-                       if (memcmp(namebuf+1, fd->name, name_len))
+                       if (memcmp(rd->name, fd->name, name_len))
                                continue;
 
                        /* OK. The name really does match. There really is still an older node on
                           the flash which our deletion dirent obsoletes. So we have to write out
                           a new deletion dirent to replace it */
-                       
-                       if (namebuf)
-                               kfree(namebuf);
-
                        up(&c->erase_free_sem);
+
+                       D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",
+                                 ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)));
+                       kfree(rd);
+
                        return jffs2_garbage_collect_dirent(c, jeb, f, fd);
                }
 
                up(&c->erase_free_sem);
-
-               if (namebuf) 
-                       kfree(namebuf);
+               kfree(rd);
        }
 
        /* No need for it any more. Just mark it obsolete and remove it from the list */
@@ -1008,6 +988,9 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
                       je32_to_cpu(ri.ino));
        });
 
+       /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */
+       mark_ref_normal(new_fn->raw);
+
        for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); 
             frag; frag = frag_next(frag)) {
                if (frag->ofs > fn->size + fn->ofs)
@@ -1042,10 +1025,9 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
        uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;      
        int ret = 0;
        unsigned char *comprbuf = NULL, *writebuf;
-       struct page *pg;
+       unsigned long pg;
        unsigned char *pg_ptr;
-       /* FIXME: */ struct inode *inode = OFNI_EDONI_2SFFJ(f);
-
        memset(&ri, 0, sizeof(ri));
 
        D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",
@@ -1184,23 +1166,18 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
         *    page OK. We'll actually write it out again in commit_write, which is a little
         *    suboptimal, but at least we're correct.
         */
-#ifdef __ECOS
-       pg = read_cache_page(start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-#else
-       pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-#endif
-       if (IS_ERR(pg)) {
-               printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg));
-               return PTR_ERR(pg);
+       pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
+
+       if (IS_ERR(pg_ptr)) {
+               printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr));
+               return PTR_ERR(pg_ptr);
        }
-       pg_ptr = (char *)kmap(pg);
-       comprbuf = kmalloc(end - start, GFP_KERNEL);
 
        offset = start;
        while(offset < orig_end) {
                uint32_t datalen;
                uint32_t cdatalen;
-               char comprtype = JFFS2_COMPR_NONE;
+               uint16_t comprtype = JFFS2_COMPR_NONE;
 
                ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
 
@@ -1214,14 +1191,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
 
                writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
 
-               if (comprbuf) {
-                       comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen);
-               }
-               if (comprtype) {
-                       writebuf = comprbuf;
-               } else {
-                       datalen = cdatalen;
-               }
+               comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen);
+
                ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
                ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
                ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen);
@@ -1239,11 +1210,14 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                ri.offset = cpu_to_je32(offset);
                ri.csize = cpu_to_je32(cdatalen);
                ri.dsize = cpu_to_je32(datalen);
-               ri.compr = comprtype;
+               ri.compr = comprtype & 0xff;
+               ri.usercompr = (comprtype >> 8) & 0xff;
                ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
-               ri.data_crc = cpu_to_je32(crc32(0, writebuf, cdatalen));
+               ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
        
-               new_fn = jffs2_write_dnode(c, f, &ri, writebuf, cdatalen, phys_ofs, ALLOC_GC);
+               new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC);
+
+               jffs2_free_comprbuf(comprbuf, writebuf);
 
                if (IS_ERR(new_fn)) {
                        printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));
@@ -1258,12 +1232,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
                        f->metadata = NULL;
                }
        }
-       if (comprbuf) kfree(comprbuf);
 
-       kunmap(pg);
-       /* XXX: Does the page get freed automatically? */
-       /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */
-       page_cache_release(pg);
+       jffs2_gc_release_page(c, pg_ptr, &pg);
        return ret;
 }
 
index 1c0bebc..1f8fb48 100644 (file)
@@ -1,13 +1,13 @@
 /*
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
  *
  * Created by David Woodhouse <dwmw2@redhat.com>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: ioctl.c,v 1.7 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: ioctl.c,v 1.8 2003/10/28 16:16:28 dwmw2 Exp $
  *
  */
 
@@ -18,6 +18,6 @@ int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
 {
        /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which
           will include compression support etc. */
-       return -EINVAL;
+       return -ENOTTY;
 }
        
index d81680f..b0bbe8a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: malloc.c,v 1.25 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: malloc.c,v 1.27 2003/10/28 17:14:58 dwmw2 Exp $
  *
  */
 
index 6c94c36..b359f8a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.c,v 1.80 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.86 2003/10/31 15:37:51 dwmw2 Exp $
  *
  */
 
@@ -58,7 +58,7 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new
 /* Put a new tmp_dnode_info into the list, keeping the list in 
    order of increasing version
 */
-void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
+static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
 {
        struct jffs2_tmp_dnode_info **prev = list;
        
@@ -133,7 +133,9 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
                cond_resched();
 
                /* FIXME: point() */
-               err = jffs2_flash_read(c, (ref_offset(ref)), min_t(uint32_t, ref->totlen, sizeof(node)), &retlen, (void *)&node);
+               err = jffs2_flash_read(c, (ref_offset(ref)), 
+                                      min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
+                                      &retlen, (void *)&node);
                if (err) {
                        printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
                        goto free_out;
@@ -141,7 +143,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
                        
 
                        /* Check we've managed to read at least the common node header */
-               if (retlen < min_t(uint32_t, ref->totlen, sizeof(node.u))) {
+               if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) {
                        printk(KERN_WARNING "short read in get_inode_nodes()\n");
                        err = -EIO;
                        goto free_out;
@@ -246,7 +248,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
 
                        /* If we've never checked the CRCs on this node, check them now. */
                        if (ref_flags(ref) == REF_UNCHECKED) {
-                               uint32_t crc;
+                               uint32_t crc, len;
                                struct jffs2_eraseblock *jeb;
 
                                crc = crc32(0, &node, sizeof(node.i)-8);
@@ -321,10 +323,12 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
                                /* Mark the node as having been checked and fix the accounting accordingly */
                                spin_lock(&c->erase_completion_lock);
                                jeb = &c->blocks[ref->flash_offset / c->sector_size];
-                               jeb->used_size += ref->totlen;
-                               jeb->unchecked_size -= ref->totlen;
-                               c->used_size += ref->totlen;
-                               c->unchecked_size -= ref->totlen;
+                               len = ref_totlen(c, jeb, ref);
+
+                               jeb->used_size += len;
+                               jeb->unchecked_size -= len;
+                               c->used_size += len;
+                               c->unchecked_size -= len;
 
                                /* If node covers at least a whole page, or if it starts at the 
                                   beginning of a page and runs to the end of the file, or if 
@@ -377,6 +381,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
                default:
                        if (ref_flags(ref) == REF_UNCHECKED) {
                                struct jffs2_eraseblock *jeb;
+                               uint32_t len;
 
                                printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n",
                                       je16_to_cpu(node.u.nodetype), ref_offset(ref));
@@ -384,10 +389,12 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
                                /* Mark the node as having been checked and fix the accounting accordingly */
                                spin_lock(&c->erase_completion_lock);
                                jeb = &c->blocks[ref->flash_offset / c->sector_size];
-                               jeb->used_size += ref->totlen;
-                               jeb->unchecked_size -= ref->totlen;
-                               c->used_size += ref->totlen;
-                               c->unchecked_size -= ref->totlen;
+                               len = ref_totlen(c, jeb, ref);
+
+                               jeb->used_size += len;
+                               jeb->unchecked_size -= len;
+                               c->used_size += len;
+                               c->unchecked_size -= len;
 
                                mark_ref_normal(ref);
                                spin_unlock(&c->erase_completion_lock);
@@ -631,6 +638,8 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
 
                jffs2_free_node_frag(frag);
                frag = parent;
+
+               cond_resched();
        }
 }
 
index d36f29a..cea0c13 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodelist.h,v 1.104 2003/10/08 11:45:11 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.119 2004/05/26 12:28:12 gleixner Exp $
  *
  */
 
 #define D2(x)
 #endif
 
+#define JFFS2_NATIVE_ENDIAN
+
+/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
+   whatever OS we're actually running on here too. */
+
+#if defined(JFFS2_NATIVE_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){x})
+#define cpu_to_je32(x) ((jint32_t){x})
+#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
+
+#define je16_to_cpu(x) ((x).v16)
+#define je32_to_cpu(x) ((x).v32)
+#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
+#elif defined(JFFS2_BIG_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
+#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
+#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
+
+#define je16_to_cpu(x) (be16_to_cpu(x.v16))
+#define je32_to_cpu(x) (be32_to_cpu(x.v32))
+#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
+#elif defined(JFFS2_LITTLE_ENDIAN)
+#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
+#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
+#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
+
+#define je16_to_cpu(x) (le16_to_cpu(x.v16))
+#define je32_to_cpu(x) (le32_to_cpu(x.v32))
+#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
+#else 
+#error wibble
+#endif
+
 /*
   This is all we need to keep in-core for each raw node during normal
   operation. As and when we do read_inode on a particular inode, we can
@@ -59,13 +92,12 @@ struct jffs2_raw_node_ref
                word so you know when you've got there :) */
        struct jffs2_raw_node_ref *next_phys;
        uint32_t flash_offset;
-       uint32_t totlen;
-       
+       uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */
+};
+
         /* flash_offset & 3 always has to be zero, because nodes are
           always aligned at 4 bytes. So we have a couple of extra bits
-          to play with. So we set the least significant bit to 1 to
-          signify that the node is obsoleted by later nodes.
-       */
+          to play with, which indicate the node's status; see below: */ 
 #define REF_UNCHECKED  0       /* We haven't yet checked the CRC or built its inode */
 #define REF_OBSOLETE   1       /* Obsolete, can be completely ignored */
 #define REF_PRISTINE   2       /* Completely clean. GC without looking */
@@ -74,7 +106,6 @@ struct jffs2_raw_node_ref
 #define ref_offset(ref)                ((ref)->flash_offset & ~3)
 #define ref_obsolete(ref)      (((ref)->flash_offset & 3) == REF_OBSOLETE)
 #define mark_ref_normal(ref)    do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
-};
 
 /* 
    Used for keeping track of deletion nodes &c, which can only be marked
@@ -246,9 +277,9 @@ static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb)
                                BUG(); \
                        } \
                        if (ref_flags(ref2) == REF_UNCHECKED) \
-                               my_unchecked_size += ref2->totlen; \
+                               my_unchecked_size += ref_totlen(c, jeb, ref2); \
                        else if (!ref_obsolete(ref2)) \
-                               my_used_size += ref2->totlen; \
+                               my_used_size += ref_totlen(c, jeb, ref2); \
                        if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \
                                printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \
                                       ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \
@@ -268,6 +299,57 @@ static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb)
                } \
        } while(0)
 
+/* Calculate totlen from surrounding nodes or eraseblock */
+static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
+                                   struct jffs2_eraseblock *jeb,
+                                   struct jffs2_raw_node_ref *ref)
+{
+       uint32_t ref_end;
+       
+       if (ref->next_phys)
+               ref_end = ref_offset(ref->next_phys);
+       else {
+               if (!jeb)
+                       jeb = &c->blocks[ref->flash_offset / c->sector_size];
+
+               /* Last node in block. Use free_space */
+               BUG_ON(ref != jeb->last_node);
+               ref_end = jeb->offset + c->sector_size - jeb->free_size;
+       }
+       return ref_end - ref_offset(ref);
+}
+
+static inline uint32_t ref_totlen(struct jffs2_sb_info *c,
+                                 struct jffs2_eraseblock *jeb,
+                                 struct jffs2_raw_node_ref *ref)
+{
+       uint32_t ret;
+
+       D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
+               printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
+                      jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
+               BUG();
+       })
+
+#if 1
+       ret = ref->__totlen;
+#else
+       /* This doesn't actually work yet */
+       ret = __ref_totlen(c, jeb, ref);
+       if (ret != ref->__totlen) {
+               printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
+                      ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
+                      ret, ref->__totlen);
+               if (!jeb)
+                       jeb = &c->blocks[ref->flash_offset / c->sector_size];
+               paranoia_failed_dump(jeb);
+               BUG();
+       }
+#endif
+       return ret;
+}
+
+
 #define ALLOC_NORMAL   0       /* Normal allocation */
 #define ALLOC_DELETION 1       /* Deletion node. Best to allow it */
 #define ALLOC_GC       2       /* Space requested for GC. Give it or die */
@@ -281,13 +363,13 @@ static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb)
 
 #define PAD(x) (((x)+3)&~3)
 
-static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw)
+static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw)
 {
        while(raw->next_in_ino) {
                raw = raw->next_in_ino;
        }
 
-       return ((struct jffs2_inode_cache *)raw)->ino;
+       return ((struct jffs2_inode_cache *)raw);
 }
 
 static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
@@ -311,7 +393,6 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
 /* nodelist.c */
 D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
 void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
-void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list);
 int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
                          struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
                          uint32_t *highest_version, uint32_t *latest_mctime,
@@ -330,6 +411,7 @@ struct rb_node *rb_prev(struct rb_node *);
 void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
 
 /* nodemgmt.c */
+int jffs2_thread_should_wake(struct jffs2_sb_info *c);
 int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
 int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
 int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
@@ -383,18 +465,13 @@ void jffs2_free_inode_cache(struct jffs2_inode_cache *);
 int jffs2_garbage_collect_pass(struct jffs2_sb_info *c);
 
 /* read.c */
-int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len);
+int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                    struct jffs2_full_dnode *fd, unsigned char *buf,
+                    int ofs, int len);
 int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                           unsigned char *buf, uint32_t offset, uint32_t len);
 char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
 
-
-/* compr.c */
-unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, 
-                            uint32_t *datalen, uint32_t *cdatalen);
-int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, 
-                    unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
-
 /* scan.c */
 int jffs2_scan_medium(struct jffs2_sb_info *c);
 void jffs2_rotate_lists(struct jffs2_sb_info *c);
@@ -404,8 +481,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c);
 
 /* erase.c */
 void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-void jffs2_erase_pending_blocks(struct jffs2_sb_info *c);
-void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
 
 #ifdef CONFIG_JFFS2_FS_NAND
 /* wbuf.c */
@@ -413,11 +489,6 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
 int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
 int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 #endif
 
-/* compr_zlib.c */
-int jffs2_zlib_init(void);
-void jffs2_zlib_exit(void);
-
 #endif /* __JFFS2_NODELIST_H__ */
index 980de2e..5043d1a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: nodemgmt.c,v 1.102 2003/10/08 17:21:19 dwmw2 Exp $
+ * $Id: nodemgmt.c,v 1.107 2003/11/26 15:30:58 dwmw2 Exp $
  *
  */
 
@@ -209,8 +209,6 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, ui
 
                if (list_empty(&c->free_list)) {
 
-                       DECLARE_WAITQUEUE(wait, current);
-                       
                        if (!c->nr_erasing_blocks && 
                            !list_empty(&c->erasable_list)) {
                                struct jffs2_eraseblock *ejeb;
@@ -243,30 +241,12 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, ui
                                       list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
                                return -ENOSPC;
                        }
-                       /* Make sure this can't deadlock. Someone has to start the erases
-                          of erase_pending blocks */
-#ifdef __ECOS
-                       /* In eCos, we don't have a handy kernel thread doing the erases for
-                          us. We do them ourselves right now. */
-                       jffs2_erase_pending_blocks(c);
-#else
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       add_wait_queue(&c->erase_wait, &wait);
-                       D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", 
-                                 c->nr_erasing_blocks, list_empty(&c->erasable_list)?"yes":"no",
-                                 list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"));
-                       if (!list_empty(&c->erase_pending_list)) {
-                               D1(printk(KERN_DEBUG "Triggering pending erases\n"));
-                               jffs2_erase_pending_trigger(c);
-                       }
+
                        spin_unlock(&c->erase_completion_lock);
-                       schedule();
-                       remove_wait_queue(&c->erase_wait, &wait);
+                       /* Don't wait for it; just erase one right now */
+                       jffs2_erase_pending_blocks(c, 1);
                        spin_lock(&c->erase_completion_lock);
-                       if (signal_pending(current)) {
-                               return -EINTR;
-                       }
-#endif
+
                        /* An erase may have failed, decreasing the
                           amount of free space available. So we must
                           restart from the beginning */
@@ -321,9 +301,11 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, ui
 int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new)
 {
        struct jffs2_eraseblock *jeb;
-       uint32_t len = new->totlen;
+       uint32_t len;
 
        jeb = &c->blocks[new->flash_offset / c->sector_size];
+       len = ref_totlen(c, jeb, new);
+
        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)) {
@@ -420,31 +402,31 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
        spin_lock(&c->erase_completion_lock);
 
        if (ref_flags(ref) == REF_UNCHECKED) {
-               D1(if (unlikely(jeb->unchecked_size < ref->totlen)) {
+               D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) {
                        printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
-                              ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
+                              ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
                        BUG();
                })
-               D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref->totlen));
-               jeb->unchecked_size -= ref->totlen;
-               c->unchecked_size -= ref->totlen;
+               D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
+               jeb->unchecked_size -= ref_totlen(c, jeb, ref);
+               c->unchecked_size -= ref_totlen(c, jeb, ref);
        } else {
-               D1(if (unlikely(jeb->used_size < ref->totlen)) {
+               D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) {
                        printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
-                              ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
+                              ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size);
                        BUG();
                })
-               D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref->totlen));
-               jeb->used_size -= ref->totlen;
-               c->used_size -= ref->totlen;
+               D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref)));
+               jeb->used_size -= ref_totlen(c, jeb, ref);
+               c->used_size -= ref_totlen(c, jeb, ref);
        }
 
        // Take care, that wasted size is taken into concern
-       if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) {
+       if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
                D1(printk("Dirtying\n"));
-               addedsize = ref->totlen;
-               jeb->dirty_size += ref->totlen;
-               c->dirty_size += ref->totlen;
+               addedsize = ref_totlen(c, jeb, ref);
+               jeb->dirty_size += ref_totlen(c, jeb, ref);
+               c->dirty_size += ref_totlen(c, jeb, ref);
 
                /* Convert wasted space to dirty, if not a bad block */
                if (jeb->wasted_size) {
@@ -465,8 +447,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
        } else {
                D1(printk("Wasting\n"));
                addedsize = 0;
-               jeb->wasted_size += ref->totlen;
-               c->wasted_size += ref->totlen;  
+               jeb->wasted_size += ref_totlen(c, jeb, ref);
+               c->wasted_size += ref_totlen(c, jeb, ref);      
        }
        ref->flash_offset = ref_offset(ref) | REF_OBSOLETE;
        
@@ -497,30 +479,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                if (jffs2_wbuf_dirty(c)) {
                        D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n"));
                        list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list);
-#if 0 /* This check was added to allow us to find places where we added nodes to the lists
-        after dropping the alloc_sem, and it did that just fine. But it also caused us to
-        lock the alloc_sem in other places, like clear_inode(), when we wouldn't otherwise
-        have needed to. So I suspect it's outlived its usefulness. Thomas? */
-
-                       /* We've changed the rules slightly. After
-                          writing a node you now mustn't drop the
-                          alloc_sem before you've finished all the
-                          list management - this is so that when we
-                          get here, we know that no other nodes have
-                          been written, and the above check on wbuf
-                          is valid - wbuf_len is nonzero IFF the node
-                          which obsoletes this node is still in the
-                          wbuf.
-
-                          So we BUG() if that new rule is broken, to
-                          make sure we catch it and fix it.
-                       */
-                       if (!down_trylock(&c->alloc_sem)) {
-                               up(&c->alloc_sem);
-                               printk(KERN_CRIT "jffs2_mark_node_obsolete() called with wbuf active but alloc_sem not locked!\n");
-                               BUG();
-                       }
-#endif
                } else {
                        if (jiffies & 127) {
                                /* Most of the time, we just erase it immediately. Otherwise we
@@ -572,12 +530,12 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
                printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen);
                return;
        }
-       if (PAD(je32_to_cpu(n.totlen)) != PAD(ref->totlen)) {
-               printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref->totlen);
+       if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) {
+               printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref));
                return;
        }
        if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
-               D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
+               D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
                return;
        }
        /* XXX FIXME: This is ugly now */
@@ -750,3 +708,34 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
        }
 }
 #endif /* CONFIG_JFFS2_FS_DEBUG */
+
+int jffs2_thread_should_wake(struct jffs2_sb_info *c)
+{
+       int ret = 0;
+       uint32_t dirty;
+
+       if (c->unchecked_size) {
+               D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
+                         c->unchecked_size, c->checked_ino));
+               return 1;
+       }
+
+       /* dirty_size contains blocks on erase_pending_list
+        * those blocks are counted in c->nr_erasing_blocks.
+        * If one block is actually erased, it is not longer counted as dirty_space
+        * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
+        * with c->nr_erasing_blocks * c->sector_size again.
+        * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
+        * This helps us to force gc and pick eventually a clean block to spread the load.
+        */
+       dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
+
+       if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && 
+                       (dirty > c->nospc_dirty_size)) 
+               ret = 1;
+
+       D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", 
+                 c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
+
+       return ret;
+}
index 11f3a5a..9a7e01c 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: os-linux.h,v 1.37 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.47 2004/07/14 13:20:23 dwmw2 Exp $
  *
  */
 
@@ -23,6 +23,9 @@
 #define kstatfs statfs
 #endif
 
+struct kstatfs;
+struct kvec;
+
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
 #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
 #define OFNI_EDONI_2SFFJ(f)  (&(f)->vfs_inode)
 #define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
 #endif
 
-/* Hmmm. P'raps generic code should only ever see versions of signal
-   functions which do the locking automatically? */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40) && !defined(__rh_config_h__)
-#define current_sig_lock current->sigmask_lock
-#else
-#define current_sig_lock current->sighand->siglock
-#endif
-
 #define sleep_on_spinunlock(wq, s)                             \
        do {                                                    \
                DECLARE_WAITQUEUE(__wait, current);             \
@@ -113,8 +108,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 #define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
 #define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
-#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
-#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
+#define jffs2_write_nand_badblock(c,jeb,bad_offset) (1)
 #define jffs2_nand_flash_setup(c) (0)
 #define jffs2_nand_flash_cleanup(c) do {} while(0)
 #define jffs2_wbuf_dirty(c) (0)
@@ -130,9 +124,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
 #define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
 #define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len)
-struct kstatfs;
 
-struct kvec;
 /* wbuf.c */
 int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino);
 int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
@@ -140,13 +132,19 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
 int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
 int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
 int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
-int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
 void jffs2_wbuf_timeout(unsigned long data);
 void jffs2_wbuf_process(void *data);
 int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
 void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
 #endif /* NAND */
 
+/* erase.c */
+static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
+{
+       OFNI_BS_2SFFJ(c)->s_dirt = 1;
+}
+
 /* background.c */
 int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
 void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
@@ -184,13 +182,26 @@ int jffs2_statfs (struct super_block *, struct kstatfs *);
 void jffs2_write_super (struct super_block *);
 int jffs2_remount_fs (struct super_block *, int *, char *);
 int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+                           struct jffs2_inode_info *f);
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+                                             int inum, int nlink);
+
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, 
+                                  struct jffs2_inode_info *f, 
+                                  unsigned long offset,
+                                  unsigned long *priv);
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+                          unsigned char *pg,
+                          unsigned long *priv);
+int jffs2_flash_setup(struct jffs2_sb_info *c);
+void jffs2_flash_cleanup(struct jffs2_sb_info *c);
+     
 
 /* writev.c */
 int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, 
                       unsigned long count, loff_t to, size_t *retlen);
 
-/* super.c */
-
 
 #endif /* __JFFS2_OS_LINUX_H__ */
 
index adeeeb1..3737595 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: read.c,v 1.34 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: read.c,v 1.36 2004/05/25 11:12:32 havasi Exp $
  *
  */
 
 #include <linux/mtd/mtd.h>
 #include <linux/compiler.h>
 #include "nodelist.h"
+#include "compr.h"
 
-int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len)
+int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+                    struct jffs2_full_dnode *fd, unsigned char *buf,
+                    int ofs, int len)
 {
        struct jffs2_raw_inode *ri;
        size_t readlen;
@@ -127,7 +130,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
        if (ri->compr != JFFS2_COMPR_NONE) {
                D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
                          je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); 
-               ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
+               ret = jffs2_decompress(c, f, ri->compr | (ri->usercompr << 8), readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
                if (ret) {
                        printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
                        goto out_decomprbuf;
@@ -195,7 +198,7 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                        D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n",
                                  frag->ofs+fragofs, frag->ofs+fragofs+readlen,
                                  ref_offset(frag->node->raw), ref_flags(frag->node->raw)));
-                       ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
+                       ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
                        D2(printk(KERN_DEBUG "node read done\n"));
                        if (ret) {
                                D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret));
@@ -231,7 +234,7 @@ char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
        }
        buf[f->metadata->size]=0;
 
-       ret = jffs2_read_dnode(c, f->metadata, buf, 0, f->metadata->size);
+       ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size);
 
        up(&f->sem);
 
index ea4bbf7..54a5d1a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: readinode.c,v 1.107 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: readinode.c,v 1.113 2003/11/03 13:20:33 dwmw2 Exp $
  *
  */
 
@@ -56,6 +56,66 @@ void jffs2_print_frag_list(struct jffs2_inode_info *f)
                printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
        }
 }
+
+static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f)
+{
+       struct jffs2_node_frag *frag;
+       int bitched = 0;
+
+       for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
+
+               struct jffs2_full_dnode *fn = frag->node;
+               if (!fn || !fn->raw)
+                       continue;
+
+               if (ref_flags(fn->raw) == REF_PRISTINE) {
+
+                       if (fn->frags > 1) {
+                               printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags);
+                               bitched = 1;
+                       }
+                       /* A hole node which isn't multi-page should be garbage-collected
+                          and merged anyway, so we just check for the frag size here,
+                          rather than mucking around with actually reading the node
+                          and checking the compression type, which is the real way
+                          to tell a hole node. */
+                       if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) {
+                               printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
+                                      ref_offset(fn->raw));
+                               bitched = 1;
+                       }
+
+                       if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) {
+                               printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
+                                      ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size);
+                               bitched = 1;
+                       }
+               }
+       }
+       
+       if (bitched) {
+               struct jffs2_node_frag *thisfrag;
+
+               printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino);
+               thisfrag = frag_first(&f->fragtree);
+               while (thisfrag) {
+                       if (!thisfrag->node) {
+                               printk("Frag @0x%x-0x%x; node-less hole\n",
+                                      thisfrag->ofs, thisfrag->size + thisfrag->ofs);
+                       } else if (!thisfrag->node->raw) {
+                               printk("Frag @0x%x-0x%x; raw-less hole\n",
+                                      thisfrag->ofs, thisfrag->size + thisfrag->ofs);
+                       } else {
+                               printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n",
+                                      thisfrag->ofs, thisfrag->size + thisfrag->ofs,
+                                      ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw),
+                                      thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size);
+                       }
+                       thisfrag = frag_next(thisfrag);
+               }
+       }
+       return bitched;
+}
 #endif /* D1 */
 
 static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
@@ -130,6 +190,11 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
                                mark_ref_normal(next->node->raw);
                }
        }
+       D2(if (jffs2_sanitycheck_fragtree(f)) {
+                  printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n",
+                         fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag);
+                  return 0;
+          })
        D2(jffs2_print_frag_list(f));
        return 0;
 }
@@ -384,6 +449,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                }
        }
        spin_unlock(&c->inocache_lock);
+
        if (!f->inocache && ino == 1) {
                /* Special case - no root inode on medium */
                f->inocache = jffs2_alloc_inode_cache();
@@ -460,7 +526,7 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                fn = tn->fn;
 
                if (f->metadata) {
-                       if (tn->version > mdata_ver) {
+                       if (likely(tn->version >= mdata_ver)) {
                                D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw)));
                                jffs2_mark_node_obsolete(c, f->metadata->raw);
                                jffs2_free_full_dnode(f->metadata);
@@ -468,10 +534,13 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                                
                                mdata_ver = 0;
                        } else {
-                               D1(printk(KERN_DEBUG "Er. New metadata at 0x%08x with ver %d is actually older than previous %d\n",
-                                      ref_offset(f->metadata->raw), tn->version, mdata_ver));
+                               /* This should never happen. */
+                               printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n",
+                                         ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw));
                                jffs2_mark_node_obsolete(c, fn->raw);
                                jffs2_free_full_dnode(fn);
+                               /* Fill in latest_node from the metadata, not this one we're about to free... */
+                               fn = f->metadata;
                                goto next_tn;
                        }
                }
@@ -488,6 +557,8 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
                tn_list = tn->next;
                jffs2_free_tmp_dnode_info(tn);
        }
+       D1(jffs2_sanitycheck_fragtree(f));
+
        if (!fn) {
                /* No data nodes for this inode. */
                if (f->inocache->ino != 1) {
@@ -594,24 +665,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
 void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
 {
        struct jffs2_full_dirent *fd, *fds;
-       /* I don't think we care about the potential race due to reading this
-          without f->sem. It can never get undeleted. */
-       int deleted = f->inocache && !f->inocache->nlink;
-
-       /* If it's a deleted inode, grab the alloc_sem. This prevents
-          jffs2_garbage_collect_pass() from deciding that it wants to
-          garbage collect one of the nodes we're just about to mark 
-          obsolete -- by the time we drop alloc_sem and return, all
-          the nodes are marked obsolete, and jffs2_g_c_pass() won't
-          call iget() for the inode in question.
-
-          We also used to do this to keep the temporary BUG() in 
-          jffs2_mark_node_obsolete() from triggering. 
-       */
-       if(deleted)
-               down(&c->alloc_sem);
+       int deleted;
 
        down(&f->sem);
+       deleted = f->inocache && !f->inocache->nlink;
 
        if (f->metadata) {
                if (deleted)
@@ -633,7 +690,4 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
                jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
 
        up(&f->sem);
-
-       if(deleted)
-               up(&c->alloc_sem);
 }
index 6e59cad..67a1d1b 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: scan.c,v 1.104 2003/10/11 14:52:48 dwmw2 Exp $
+ * $Id: scan.c,v 1.110 2004/06/17 17:15:31 gleixner Exp $
  *
  */
 #include <linux/kernel.h>
@@ -285,8 +285,6 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
        uint32_t hdr_crc, buf_ofs, buf_len;
        int err;
        int noise = 0;
-       int wasempty = 0;
-       uint32_t empty_start = 0;
 #ifdef CONFIG_JFFS2_FS_NAND
        int cleanmarkerfound = 0;
 #endif
@@ -339,8 +337,6 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
                        switch (ret) {
                        case 0:         return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
                        case 1:         return BLK_STATE_ALLDIRTY;
-                       case 2:         return BLK_STATE_BADBLOCK; /* case 2/3 are paranoia checks */
-                       case 3:         return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
                        default:        return ret;
                        }
                }
@@ -359,6 +355,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
 
        noise = 10;
 
+scan_more:     
        while(ofs < jeb->offset + c->sector_size) {
 
                D1(ACCT_PARANOIA_CHECK(jeb));
@@ -398,42 +395,52 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
                node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
 
                if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
-                       uint32_t inbuf_ofs = ofs - buf_ofs + 4;
-                       uint32_t scanend;
+                       uint32_t inbuf_ofs;
+                       uint32_t empty_start;
 
                        empty_start = ofs;
                        ofs += 4;
 
-                       /* If scanning empty space after only a cleanmarker, don't
-                          bother scanning the whole block */
-                       if (unlikely(empty_start == jeb->offset + c->cleanmarker_size &&
-                                    jeb->offset + EMPTY_SCAN_SIZE < buf_ofs + buf_len))
-                               scanend = jeb->offset + EMPTY_SCAN_SIZE - buf_ofs;
-                       else
-                               scanend = buf_len;
-
                        D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
-                       while (inbuf_ofs < scanend) {
-                               if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)
-                                       goto emptyends;
+               more_empty:
+                       inbuf_ofs = ofs - buf_ofs;
+                       while (inbuf_ofs < buf_len) {
+                               if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) {
+                                       printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
+                                              empty_start, ofs);
+                                       DIRTY_SPACE(ofs-empty_start);
+                                       goto scan_more;
+                               }
 
                                inbuf_ofs+=4;
                                ofs += 4;
                        }
                        /* Ran off end. */
-                       D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs));
+                       D1(printk(KERN_DEBUG "Empty flash to end of buffer at 0x%08x\n", ofs));
 
-                       if (buf_ofs == jeb->offset &&  jeb->used_size == PAD(c->cleanmarker_size) && 
-                           c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size)
+                       /* 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));
                                return BLK_STATE_CLEANMARKER;
-                       wasempty = 1;
-                       continue;
-               } else if (wasempty) {
-               emptyends:
-                       printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs);
-                       DIRTY_SPACE(ofs-empty_start);
-                       wasempty = 0;
-                       continue;
+                       }
+
+                       /* See how much more there is to read in this eraseblock... */
+                       buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
+                       if (!buf_len) {
+                               /* No more to read. Break out of main loop without marking 
+                                  this range of empty space as dirty (because it's not) */
+                               D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
+                                         empty_start));
+                               break;
+                       }
+                       D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
+                       err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
+                       if (err)
+                               return err;
+                       buf_ofs = ofs;
+                       goto more_empty;
                }
 
                if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
@@ -554,7 +561,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
                                marker_ref->next_in_ino = NULL;
                                marker_ref->next_phys = NULL;
                                marker_ref->flash_offset = ofs | REF_NORMAL;
-                               marker_ref->totlen = c->cleanmarker_size;
+                               marker_ref->__totlen = c->cleanmarker_size;
                                jeb->first_node = jeb->last_node = marker_ref;
                             
                                USED_SPACE(PAD(c->cleanmarker_size));
@@ -610,7 +617,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
        }
 
        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_in_ino) )
                return BLK_STATE_CLEANMARKER;
                
        /* move blocks with max 4 byte dirty space to cleanlist */      
@@ -634,6 +641,9 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
        if (ic)
                return ic;
 
+       if (ino > c->highest_ino)
+               c->highest_ino = ino;
+
        ic = jffs2_alloc_inode_cache();
        if (!ic) {
                printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of inode cache failed\n");
@@ -645,7 +655,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
        ic->nodes = (void *)ic;
        jffs2_add_ino_cache(c, ic);
        if (ino == 1)
-               ic->nlink=1;
+               ic->nlink = 1;
        return ic;
 }
 
@@ -698,7 +708,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
        /* Wheee. It worked */
 
        raw->flash_offset = ofs | REF_UNCHECKED;
-       raw->totlen = PAD(je32_to_cpu(ri->totlen));
+       raw->__totlen = PAD(je32_to_cpu(ri->totlen));
        raw->next_phys = NULL;
        raw->next_in_ino = ic->nodes;
 
@@ -775,7 +785,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
                return -ENOMEM;
        }
        
-       raw->totlen = PAD(je32_to_cpu(rd->totlen));
+       raw->__totlen = PAD(je32_to_cpu(rd->totlen));
        raw->flash_offset = ofs | REF_PRISTINE;
        raw->next_phys = NULL;
        raw->next_in_ino = ic->nodes;
index b657c55..23dad47 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: super.c,v 1.90 2003/10/11 11:47:23 dwmw2 Exp $
+ * $Id: super.c,v 1.96 2004/07/13 08:57:30 dwmw2 Exp $
  *
  */
 
@@ -24,6 +24,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/ctype.h>
 #include <linux/namei.h>
+#include "compr.h"
 #include "nodelist.h"
 
 static void jffs2_put_super(struct super_block *);
@@ -266,7 +267,7 @@ static void jffs2_put_super (struct super_block *sb)
        jffs2_free_ino_caches(c);
        jffs2_free_raw_node_refs(c);
        kfree(c->blocks);
-       jffs2_nand_flash_cleanup(c);
+       jffs2_flash_cleanup(c);
        kfree(c->inocache_list);
        if (c->mtd->sync)
                c->mtd->sync(c->mtd);
@@ -294,7 +295,7 @@ static int __init init_jffs2_fs(void)
        int ret;
 
        printk(KERN_INFO "JFFS2 version 2.2."
-#ifdef CONFIG_FS_JFFS2_NAND
+#ifdef CONFIG_JFFS2_FS_NAND
               " (NAND)"
 #endif
               " (C) 2001-2003 Red Hat, Inc.\n");
@@ -307,15 +308,22 @@ static int __init init_jffs2_fs(void)
                printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
                return -ENOMEM;
        }
-       ret = jffs2_zlib_init();
+#ifdef CONFIG_JFFS2_PROC
+       ret = jffs2_proc_init();
        if (ret) {
-               printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n");
+               printk(KERN_ERR "JFFS2 error: Failed to initialise proc interface\n");
+               goto out;
+       }
+#endif
+       ret = jffs2_compressors_init();
+       if (ret) {
+               printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
                goto out;
        }
        ret = jffs2_create_slab_caches();
        if (ret) {
                printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
-               goto out_zlib;
+               goto out_compressors;
        }
        ret = register_filesystem(&jffs2_fs_type);
        if (ret) {
@@ -326,8 +334,11 @@ static int __init init_jffs2_fs(void)
 
  out_slab:
        jffs2_destroy_slab_caches();
- out_zlib:
-       jffs2_zlib_exit();
+ out_compressors:
+       jffs2_compressors_exit();
+#ifdef CONFIG_JFFS2_PROC
+        jffs2_proc_exit();
+#endif
  out:
        return ret;
 }
@@ -336,7 +347,10 @@ static void __exit exit_jffs2_fs(void)
 {
        unregister_filesystem(&jffs2_fs_type);
        jffs2_destroy_slab_caches();
-       jffs2_zlib_exit();
+       jffs2_compressors_exit();
+#ifdef CONFIG_JFFS2_PROC
+        jffs2_proc_exit();
+#endif
        kmem_cache_destroy(jffs2_inode_cachep);
 }
 
index d0adaf6..958cafb 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: symlink.c,v 1.12 2003/10/04 08:33:07 dwmw2 Exp $
+ * $Id: symlink.c,v 1.13 2004/07/13 08:59:04 dwmw2 Exp $
  *
  */
 
index 956f98d..2470eef 100644 (file)
@@ -2,12 +2,14 @@
  * JFFS2 -- Journalling Flash File System, Version 2.
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de>
  *
  * Created by David Woodhouse <dwmw2@redhat.com>
+ * Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: wbuf.c,v 1.53 2003/10/11 11:46:09 dwmw2 Exp $
+ * $Id: wbuf.c,v 1.70 2004/07/13 08:58:25 dwmw2 Exp $
  *
  */
 
@@ -27,7 +29,7 @@ static unsigned char *brokenbuf;
 #endif
 
 /* max. erase failures before we mark a block bad */
-#define MAX_ERASE_FAILURES     5
+#define MAX_ERASE_FAILURES     2
 
 /* two seconds timeout for timed wbuf-flushing */
 #define WBUF_FLUSH_TIMEOUT     2 * HZ
@@ -179,10 +181,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
        first_raw = &jeb->first_node;
        while (*first_raw && 
               (ref_obsolete(*first_raw) ||
-               (ref_offset(*first_raw) + (*first_raw)->totlen) < c->wbuf_ofs)) {
+               (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) {
                D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
                          ref_offset(*first_raw), ref_flags(*first_raw),
-                         (ref_offset(*first_raw) + (*first_raw)->totlen),
+                         (ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)),
                          c->wbuf_ofs));
                first_raw = &(*first_raw)->next_phys;
        }
@@ -195,13 +197,13 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
        }
 
        start = ref_offset(*first_raw);
-       end = ref_offset(*first_raw) + (*first_raw)->totlen;
+       end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw);
 
        /* Find the last node to be recovered */
        raw = first_raw;
        while ((*raw)) {
                if (!ref_obsolete(*raw))
-                       end = ref_offset(*raw) + (*raw)->totlen;
+                       end = ref_offset(*raw) + ref_totlen(c, jeb, *raw);
 
                raw = &(*raw)->next_phys;
        }
@@ -295,7 +297,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
                                        return;
 
                                raw2->flash_offset = ofs | REF_OBSOLETE;
-                               raw2->totlen = (*first_raw)->totlen;
+                               raw2->__totlen = ref_totlen(c, jeb, *first_raw);
                                raw2->next_phys = NULL;
                                raw2->next_in_ino = NULL;
 
@@ -336,24 +338,26 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
 
        raw = first_raw;
        while (*raw) {
+               uint32_t rawlen = ref_totlen(c, jeb, *raw);
+
                D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
-                         (*raw)->totlen, ref_offset(*raw), ref_flags(*raw), ofs));
+                         rawlen, ref_offset(*raw), ref_flags(*raw), ofs));
 
                if (ref_obsolete(*raw)) {
                        /* Shouldn't really happen much */
-                       new_jeb->dirty_size += (*raw)->totlen;
-                       new_jeb->free_size -= (*raw)->totlen;
-                       c->dirty_size += (*raw)->totlen;
+                       new_jeb->dirty_size += rawlen;
+                       new_jeb->free_size -= rawlen;
+                       c->dirty_size += rawlen;
                } else {
-                       new_jeb->used_size += (*raw)->totlen;
-                       new_jeb->free_size -= (*raw)->totlen;
-                       jeb->dirty_size += (*raw)->totlen;
-                       jeb->used_size  -= (*raw)->totlen;
-                       c->dirty_size += (*raw)->totlen;
+                       new_jeb->used_size += rawlen;
+                       new_jeb->free_size -= rawlen;
+                       jeb->dirty_size += rawlen;
+                       jeb->used_size  -= rawlen;
+                       c->dirty_size += rawlen;
                }
-               c->free_size -= (*raw)->totlen;
+               c->free_size -= rawlen;
                (*raw)->flash_offset = ofs | ref_flags(*raw);
-               ofs += (*raw)->totlen;
+               ofs += rawlen;
                new_jeb->last_node = *raw;
 
                raw = &(*raw)->next_phys;
@@ -422,6 +426,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
                        padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
                        padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
                        padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
+               } else {
+                       /* Pad with JFFS2_DIRTY_BITMASK */
+                       memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);
                }
        }
        /* else jffs2_flash_writev has actually filled in the rest of the
@@ -454,31 +461,34 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
                return ret; 
        }
 
-       /* Adjusting free size of next block only, if it's called from fsync ! */
-       if (pad == 2) {
-               D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of c->nextblock\n"));
-               spin_lock(&c->erase_completion_lock);
-               if (!c->nextblock)
-                       BUG();
+       spin_lock(&c->erase_completion_lock);
+
+       /* Adjust free size of the block if we padded. */
+       if (pad) {
+               struct jffs2_eraseblock *jeb;
+
+               jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
+
+               D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
+                         (jeb==c->nextblock)?"next":"", jeb->offset));
+
                /* wbuf_pagesize - wbuf_len is the amount of space that's to be 
                   padded. If there is less free space in the block than that,
                   something screwed up */
-               if (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
+               if (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
                        printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
                               c->wbuf_ofs, c->wbuf_len, c->wbuf_pagesize-c->wbuf_len);
                        printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
-                              c->nextblock->offset, c->nextblock->free_size);
+                              jeb->offset, jeb->free_size);
                        BUG();
                }
-               c->nextblock->free_size -= (c->wbuf_pagesize - c->wbuf_len);
+               jeb->free_size -= (c->wbuf_pagesize - c->wbuf_len);
                c->free_size -= (c->wbuf_pagesize - c->wbuf_len);
-               c->nextblock->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
+               jeb->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
                c->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
-               spin_unlock(&c->erase_completion_lock);
        }
 
        /* Stick any now-obsoleted blocks on the erase_pending_list */
-       spin_lock(&c->erase_completion_lock);
        jffs2_refile_wbuf_blocks(c);
        jffs2_clear_wbuf_ino_list(c);
        spin_unlock(&c->erase_completion_lock);
@@ -512,8 +522,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
        old_wbuf_ofs = c->wbuf_ofs;
        old_wbuf_len = c->wbuf_len;
 
-       while (old_wbuf_len &&
-              old_wbuf_ofs == c->wbuf_ofs) {
+       if (c->unchecked_size) {
+               /* GC won't make any progress for a while */
+               D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
+               ret = __jffs2_flush_wbuf(c, 2);
+       } else while (old_wbuf_len &&
+                     old_wbuf_ofs == c->wbuf_ofs) {
 
                up(&c->alloc_sem);
 
@@ -835,9 +849,8 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
        size_t  retlen;
        int     oob_size;
 
-       oob_size = c->mtd->oobsize;
-
        /* allocate a buffer for all oob data in this sector */
+       oob_size = c->mtd->oobsize;
        len = 4 * oob_size;
        buf = kmalloc(len, GFP_KERNEL);
        if (!buf) {
@@ -861,35 +874,23 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
                goto out;
        }
        
-       /* Special check for first two pages */
-       for (page = 0; page < 2 * oob_size; page += oob_size) {
-               /* Check for bad block marker */
-               if (buf[page+c->badblock_pos] != 0xff) {
-                       D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Bad or failed block at %08x\n",jeb->offset));
-                       /* Return 2 for bad and 3 for failed block 
-                          bad goes to list_bad and failed to list_erase */
-                       ret = (!page) ? 2 : 3;
+       /* Special check for first page */
+       for(i = 0; i < oob_size ; i++) {
+               /* Yeah, we know about the cleanmarker. */
+               if (mode && i >= c->fsdata_pos && 
+                   i < c->fsdata_pos + c->fsdata_len)
+                       continue;
+
+               if (buf[i] != 0xFF) {
+                       D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
+                                 buf[page+i], page+i, jeb->offset));
+                       ret = 1; 
                        goto out;
                }
-               for(i = 0; i < oob_size ; i++) {
-                       /* Yeah, we know about the cleanmarker. */
-                       if (mode && i >= c->fsdata_pos && 
-                           i < c->fsdata_pos+c->fsdata_len)
-                               continue;
-
-                       if (buf[page+i] != 0xFF) {
-                               D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n",
-                                         buf[page+i], page+i, jeb->offset));
-                               ret = 1; 
-                               goto out;
-                       }
-               }
-               /* only the first page can contain a cleanmarker !*/
-               mode = 0;
-       }       
+       }
 
        /* we know, we are aligned :) */        
-       for (; page < len; page += sizeof(long)) {
+       for (page = oob_size; page < len; page += sizeof(long)) {
                unsigned long dat = *(unsigned long *)(&buf[page]);
                if(dat != -1) {
                        ret = 1; 
@@ -912,7 +913,7 @@ out:
 int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
 {
        struct jffs2_unknown_node n;
-       unsigned char buf[32];
+       unsigned char buf[2 * NAND_MAX_OOBSIZE];
        unsigned char *p;
        int ret, i, cnt, retval = 0;
        size_t retlen, offset;
@@ -923,6 +924,11 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo
 
        /* Loop through the physical blocks */
        for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) {
+               /* Check first if the block is bad. */
+               if (c->mtd->block_isbad (c->mtd, offset)) {
+                       D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset));
+                       return 2;
+               }
                /*
                   *    We read oob data from page 0 and 1 of the block.
                   *    page 0 contains cleanmarker and badblock info
@@ -939,19 +945,6 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo
                        return -EIO;
                }
 
-               /* Check for bad block marker */
-               if (buf[c->badblock_pos] != 0xff) {
-                       D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x (has %02x %02x in badblock_pos %d\n",
-                                   jeb->offset, buf[c->badblock_pos],  buf[c->badblock_pos + oob_size], c->badblock_pos));
-                       return 2;
-               }
-
-               /* Check for failure counter in the second page */
-               if (buf[c->badblock_pos + oob_size] != 0xff) {
-                       D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[c->badblock_pos + oob_size]));
-                       return 3;
-               }
-
                /* Check cleanmarker only on the first physical block */
                if (!cnt) {
                        n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
@@ -1002,136 +995,100 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
 }
 
 /* 
- * We try to get the failure count of this block.
- */
-int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) {
-
-       unsigned char buf[16];
-       int     ret;
-       size_t  retlen;
-       int     oob_size;
-
-       oob_size = c->mtd->oobsize;
-       
-       ret = c->mtd->read_oob(c->mtd, jeb->offset + c->mtd->oobblock, oob_size , &retlen, buf);
-       
-       if (ret) {
-               D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB failed %d for block at %08x\n", ret, jeb->offset));
-               return ret;
-       }
-
-       if (retlen < oob_size) {
-               D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset));
-               return -EIO;
-       }
-
-       jeb->bad_count =  buf[c->badblock_pos]; 
-       return 0;
-}
-
-/* 
- * On NAND we try to mark this block bad. We try to write how often
- * the block was erased and mark it finaly bad, if the count
- * is > MAX_ERASE_FAILURES. We read this information on mount !
- * jeb->bad_count contains the count before this erase.
+ * On NAND we try to mark this block bad. If the block was erased more
+ * than MAX_ERASE_FAILURES we mark it finaly bad.
  * Don't care about failures. This block remains on the erase-pending
  * or badblock list as long as nobody manipulates the flash with
  * a bootloader or something like that.
  */
 
-int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset)
 {
-       unsigned char buf = 0x0;
        int     ret;
-       size_t  retlen;
 
        /* if the count is < max, we try to write the counter to the 2nd page oob area */
-       if( ++jeb->bad_count < MAX_ERASE_FAILURES) {
-               buf = (unsigned char)jeb->bad_count;
-               c->badblock_pos += c->mtd->oobblock;
-       }
-       
-       ret = jffs2_flash_write_oob(c, jeb->offset + c->badblock_pos, 1, &retlen, &buf);
+       if( ++jeb->bad_count < MAX_ERASE_FAILURES)
+               return 0;
+
+       if (!c->mtd->block_markbad)
+               return 1; // What else can we do?
+
+       D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", bad_offset));
+       ret = c->mtd->block_markbad(c->mtd, bad_offset);
        
        if (ret) {
                D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));
                return ret;
        }
-       if (retlen != 1) {
-               D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %zd not 1\n", jeb->offset, retlen));
-               return ret;
-       }
-       return 0;
+       return 1;
 }
 
-#define JFFS2_OOB_ECCPOS0              0
-#define JFFS2_OOB_ECCPOS1              1
-#define JFFS2_OOB_ECCPOS2              2
-#define JFFS2_OOB_ECCPOS3              3
-#define JFFS2_OOB_ECCPOS4              6
-#define JFFS2_OOB_ECCPOS5              7
-
-#define NAND_JFFS2_OOB8_FSDAPOS                6
-#define NAND_JFFS2_OOB16_FSDAPOS       8
-#define NAND_JFFS2_OOB8_FSDALEN                2
 #define NAND_JFFS2_OOB16_FSDALEN       8
 
-static struct nand_oobinfo jffs2_oobinfo_swecc = {
-       .useecc = 1,
-       .eccpos = {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2,
-                  JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
-};
-
 static struct nand_oobinfo jffs2_oobinfo_docecc = {
-       .useecc = 1,
+       .useecc = MTD_NANDECC_PLACE,
+       .eccbytes = 6,
        .eccpos = {0,1,2,3,4,5}
 };
 
 
-
-int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c)
 {
+       struct nand_oobinfo *oinfo = &c->mtd->oobinfo;
+
+       /* Do this only, if we have an oob buffer */
+       if (!c->mtd->oobsize)
+               return 0;
+       
        /* Cleanmarker is out-of-band, so inline size zero */
        c->cleanmarker_size = 0;
 
-       /* Initialise write buffer */
-       c->wbuf_pagesize = c->mtd->oobblock;
-       c->wbuf_ofs = 0xFFFFFFFF;
-
-       /* FIXME: If we had a generic way of describing the hardware's
-          use of OOB area, we could perhaps make this generic too. */
-       switch(c->mtd->ecctype) {
-       case MTD_ECC_SW:
-               D1(printk(KERN_DEBUG "JFFS2 using software ECC\n"));
-               c->oobinfo = &jffs2_oobinfo_swecc;
-               if (c->mtd->oobsize == 8) {
-                       c->fsdata_pos = NAND_JFFS2_OOB8_FSDAPOS;
-                       c->fsdata_len = NAND_JFFS2_OOB8_FSDALEN;
-               } else {
-                       c->fsdata_pos = NAND_JFFS2_OOB16_FSDAPOS;
+       /* Should we use autoplacement ? */
+       if (oinfo && oinfo->useecc == MTD_NANDECC_AUTOPLACE) {
+               D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n"));
+               /* Get the position of the free bytes */
+               if (!oinfo->oobfree[0][0]) {
+                       printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep. Autoplacement selected and no empty space in oob\n");
+                       return -ENOSPC;
+               }
+               c->fsdata_pos = oinfo->oobfree[0][0];
+               c->fsdata_len = oinfo->oobfree[0][1];
+               if (c->fsdata_len > 8)
+                       c->fsdata_len = 8;
+       } else {
+               /* This is just a legacy fallback and should go away soon */
+               switch(c->mtd->ecctype) {
+               case MTD_ECC_RS_DiskOnChip:
+                       printk(KERN_WARNING "JFFS2 using DiskOnChip hardware ECC without autoplacement. Fix it!\n");
+                       c->oobinfo = &jffs2_oobinfo_docecc;
+                       c->fsdata_pos = 6;
                        c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
+                       c->badblock_pos = 15;
+                       break;
+       
+               default:
+                       D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n"));
+                       return -EINVAL;
                }
-               c->badblock_pos = NAND_BADBLOCK_POS;
-               break;
-
-       case MTD_ECC_RS_DiskOnChip:
-               D1(printk(KERN_DEBUG "JFFS2 using DiskOnChip hardware ECC\n"));
-               c->oobinfo = &jffs2_oobinfo_docecc;
-               c->fsdata_pos = 6;
-               c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN;
-               c->badblock_pos = 15;
-               break;
-
-       default:
-               printk("JFFS2 doesn't yet know how to handle ECC type %d\n",
-                      c->mtd->ecctype);
-               return -EINVAL;
        }
+       return 0;
+}
 
+int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
+{
+       int res;
+
+       /* Initialise write buffer */
+       c->wbuf_pagesize = c->mtd->oobblock;
+       c->wbuf_ofs = 0xFFFFFFFF;
+
+       
        c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
        if (!c->wbuf)
                return -ENOMEM;
 
+       res = jffs2_nand_set_oobinfo(c);
+
 #ifdef BREAKME
        if (!brokenbuf)
                brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
@@ -1141,7 +1098,7 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c)
        }
        memset(brokenbuf, 0xdb, c->wbuf_pagesize);
 #endif
-       return 0;
+       return res;
 }
 
 void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
index 11c7610..1253c48 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: write.c,v 1.75 2003/10/08 11:45:11 dwmw2 Exp $
+ * $Id: write.c,v 1.85 2004/07/13 08:58:25 dwmw2 Exp $
  *
  */
 
@@ -18,6 +18,7 @@
 #include <linux/pagemap.h>
 #include <linux/mtd/mtd.h>
 #include "nodelist.h"
+#include "compr.h"
 
 
 int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
@@ -31,7 +32,6 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
 
        memset(ic, 0, sizeof(*ic));
 
-       init_MUTEX_LOCKED(&f->sem);
        f->inocache = ic;
        f->inocache->nlink = 1;
        f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
@@ -133,7 +133,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
        fn->raw = raw;
 
        raw->flash_offset = flash_ofs;
-       raw->totlen = PAD(sizeof(*ri)+datalen);
+       raw->__totlen = PAD(sizeof(*ri)+datalen);
        raw->next_phys = NULL;
 
        ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
@@ -275,11 +275,11 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
        fd->raw = raw;
 
        raw->flash_offset = flash_ofs;
-       raw->totlen = PAD(sizeof(*rd)+namelen);
+       raw->__totlen = PAD(sizeof(*rd)+namelen);
        raw->next_phys = NULL;
 
        ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
-                                (alloc_mode==ALLOC_GC)?0:fd->ino);
+                                (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
        if (ret || (retlen != sizeof(*rd) + namelen)) {
                printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", 
                               sizeof(*rd)+namelen, flash_ofs, ret, retlen);
@@ -359,7 +359,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
        while(writelen) {
                struct jffs2_full_dnode *fn;
                unsigned char *comprbuf = NULL;
-               unsigned char comprtype = JFFS2_COMPR_NONE;
+               uint16_t comprtype = JFFS2_COMPR_NONE;
                uint32_t phys_ofs, alloclen;
                uint32_t datalen, cdatalen;
                int retried = 0;
@@ -373,24 +373,10 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                        break;
                }
                down(&f->sem);
-               datalen = writelen;
-               cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), writelen);
+               datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
+               cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
 
-               comprbuf = kmalloc(cdatalen, GFP_KERNEL);
-               if (comprbuf) {
-                       comprtype = jffs2_compress(buf, comprbuf, &datalen, &cdatalen);
-               }
-               if (comprtype == JFFS2_COMPR_NONE) {
-                       /* Either compression failed, or the allocation of comprbuf failed */
-                       if (comprbuf)
-                               kfree(comprbuf);
-                       comprbuf = buf;
-                       datalen = cdatalen;
-               }
-               /* Now comprbuf points to the data to be written, be it compressed or not.
-                  comprtype holds the compression type, and comprtype == JFFS2_COMPR_NONE means
-                  that the comprbuf doesn't need to be kfree()d. 
-               */
+               comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
 
                ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
                ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
@@ -403,14 +389,14 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
                ri->offset = cpu_to_je32(offset);
                ri->csize = cpu_to_je32(cdatalen);
                ri->dsize = cpu_to_je32(datalen);
-               ri->compr = comprtype;
+               ri->compr = comprtype & 0xff;
+               ri->usercompr = (comprtype >> 8 ) & 0xff;
                ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
                ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
 
                fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY);
 
-               if (comprtype != JFFS2_COMPR_NONE)
-                       kfree(comprbuf);
+               jffs2_free_comprbuf(comprbuf, buf);
 
                if (IS_ERR(fn)) {
                        ret = PTR_ERR(fn);
@@ -559,48 +545,75 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
        uint32_t alloclen, phys_ofs;
        int ret;
 
-       rd = jffs2_alloc_raw_dirent();
-       if (!rd)
-               return -ENOMEM;
+       if (1 /* alternative branch needs testing */ || 
+           !jffs2_can_mark_obsolete(c)) {
+               /* We can't mark stuff obsolete on the medium. We need to write a deletion dirent */
 
-       ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
-       if (ret) {
+               rd = jffs2_alloc_raw_dirent();
+               if (!rd)
+                       return -ENOMEM;
+
+               ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION);
+               if (ret) {
+                       jffs2_free_raw_dirent(rd);
+                       return ret;
+               }
+
+               down(&dir_f->sem);
+
+               /* Build a deletion node */
+               rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+               rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
+               rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
+               rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
+               
+               rd->pino = cpu_to_je32(dir_f->inocache->ino);
+               rd->version = cpu_to_je32(++dir_f->highest_version);
+               rd->ino = cpu_to_je32(0);
+               rd->mctime = cpu_to_je32(get_seconds());
+               rd->nsize = namelen;
+               rd->type = DT_UNKNOWN;
+               rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
+               rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
+
+               fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
+               
                jffs2_free_raw_dirent(rd);
-               return ret;
-       }
 
-       down(&dir_f->sem);
+               if (IS_ERR(fd)) {
+                       jffs2_complete_reservation(c);
+                       up(&dir_f->sem);
+                       return PTR_ERR(fd);
+               }
 
-       /* Build a deletion node */
-       rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
-       rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
-       rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
-       rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
+               /* File it. This will mark the old one obsolete. */
+               jffs2_add_fd_to_list(c, fd, &dir_f->dents);
+               up(&dir_f->sem);
+       } else {
+               struct jffs2_full_dirent **prev = &dir_f->dents;
+               uint32_t nhash = full_name_hash(name, namelen);
 
-       rd->pino = cpu_to_je32(dir_f->inocache->ino);
-       rd->version = cpu_to_je32(++dir_f->highest_version);
-       rd->ino = cpu_to_je32(0);
-       rd->mctime = cpu_to_je32(get_seconds());
-       rd->nsize = namelen;
-       rd->type = DT_UNKNOWN;
-       rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
-       rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
+               down(&dir_f->sem);
 
-       fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION);
-       
-       jffs2_free_raw_dirent(rd);
+               while ((*prev) && (*prev)->nhash <= nhash) {
+                       if ((*prev)->nhash == nhash && 
+                           !memcmp((*prev)->name, name, namelen) &&
+                           !(*prev)->name[namelen]) {
+                               struct jffs2_full_dirent *this = *prev;
 
-       if (IS_ERR(fd)) {
-               jffs2_complete_reservation(c);
+                               D1(printk(KERN_DEBUG "Marking old dirent node (ino #%u) @%08x obsolete\n",
+                                         this->ino, ref_offset(this->raw)));
+
+                               *prev = this->next;
+                               jffs2_mark_node_obsolete(c, (this->raw));
+                               jffs2_free_full_dirent(this);
+                               break;
+                       }
+                       prev = &((*prev)->next);
+               }
                up(&dir_f->sem);
-               return PTR_ERR(fd);
        }
 
-       /* File it. This will mark the old one obsolete. */
-       jffs2_add_fd_to_list(c, fd, &dir_f->dents);
-
-       up(&dir_f->sem);
-       
        /* dead_f is NULL if this was a rename not a real unlink */
        /* Also catch the !f->inocache case, where there was a dirent
           pointing to an inode which didn't exist. */
index c88bf73..7e46e95 100644 (file)
@@ -7,7 +7,7 @@
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: writev.c,v 1.4 2003/10/04 08:33:07 dwmw2 Exp $
+ * $Id: writev.c,v 1.5 2004/07/13 08:58:25 dwmw2 Exp $
  *
  */
 
index 5d4ad8a..666796c 100644 (file)
@@ -25,6 +25,7 @@
 #define        OCP_VENDOR_ARM          0x0004
 #define OCP_VENDOR_FREESCALE   0x1057
 #define OCP_VENDOR_IBM         0x1014
+#define OCP_VENDOR_MARVELL     0x11ab
 #define OCP_VENDOR_MOTOROLA    OCP_VENDOR_FREESCALE
 #define        OCP_VENDOR_XILINX       0x10ee
 #define        OCP_VENDOR_UNKNOWN      0xFFFF
@@ -42,6 +43,9 @@
 #define OCP_FUNC_16550         0x0031
 #define OCP_FUNC_IIC           0x0032
 #define OCP_FUNC_USB           0x0033
+#define        OCP_FUNC_MPSC           0x0034
+#define        OCP_FUNC_COMM_MPSC      0x0035
+#define        OCP_FUNC_SDMA           0x0036
 
 /* Memory devices 0x0090 - 0x009F */
 #define OCP_FUNC_MAL           0x0090
 #define OCP_FUNC_PERFMON       0x00D2  /* Performance Monitor */
 #define OCP_FUNC_RGMII         0x00D3
 #define OCP_FUNC_TAH           0x00D4
+#define        OCP_FUNC_I2C            0x00D5  /* I2C Controller */
+#define        OCP_FUNC_BRG            0x00D6  /* Baud Rate Generator */
+#define        OCP_FUNC_PIC            0x00D7  /* Programmable Interrupt Controller */
 
 /* Network 0x0200 - 0x02FF */
 #define OCP_FUNC_EMAC          0x0200
-#define OCP_FUNC_GFAR          0x0201  /* TSEC & FEC */
+#define OCP_FUNC_ENET          0x0201  /* TSEC & FEC */
+#define        OCP_FUNC_COMM_EMAC      0x0202
+#define OCP_FUNC_GFAR          0x0203  /* TSEC & FEC */
 
 /* Bridge devices 0xE00 - 0xEFF */
 #define OCP_FUNC_OPB           0x0E00
+#define        OCP_FUNC_HB             0x0E01  /* Host bridge */
 
 #define OCP_FUNC_UNKNOWN       0xFFFF
index 310206e..c77cfb4 100644 (file)
@@ -10,6 +10,8 @@
 
 #if defined(CONFIG_EV64260)
 #include <platforms/ev64260.h>
+#elif defined(CONFIG_DMV182)
+#include <platforms/dmv182_serial.h>
 #elif defined(CONFIG_GEMINI)
 #include <platforms/gemini_serial.h>
 #elif defined(CONFIG_POWERPMC250)
index cd51da3..7109aa6 100644 (file)
@@ -252,6 +252,11 @@ static inline int __next_cpu(int n, const cpumask_t *srcp, int nbits)
        [0 ... BITS_TO_LONGS(NR_CPUS)-1] =  0UL                         \
 } })
 
+#define CPU_MASK_CPU0                                                  \
+((cpumask_t) { {                                                       \
+       [0] =  1UL                                                      \
+} })
+
 #define cpus_addr(src) ((src).bits)
 
 #define cpumask_scnprintf(buf, len, src) \
index e1a49dc..162f06e 100644 (file)
@@ -8,7 +8,7 @@
  * For licensing information, see the file 'LICENCE' in the 
  * jffs2 directory.
  *
- * $Id: jffs2.h,v 1.31 2003/10/04 08:33:05 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.33 2004/05/25 11:31:55 havasi Exp $
  *
  */
 
@@ -43,6 +43,8 @@
 #define JFFS2_COMPR_COPY       0x04
 #define JFFS2_COMPR_DYNRUBIN   0x05
 #define JFFS2_COMPR_ZLIB       0x06
+#define JFFS2_COMPR_LZO         0x07
+#define JFFS2_COMPR_LZARI       0x08
 /* Compatibility flags. */
 #define JFFS2_COMPAT_MASK 0xc000      /* What do to if an unknown nodetype is found */
 #define JFFS2_NODE_ACCURATE 0x2000
@@ -87,39 +89,6 @@ typedef struct {
        uint16_t v16;
 } __attribute__((packed)) jint16_t;
 
-#define JFFS2_NATIVE_ENDIAN
-
-/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from
-   whatever OS we're actually running on here too. */
-
-#if defined(JFFS2_NATIVE_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){x})
-#define cpu_to_je32(x) ((jint32_t){x})
-#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)})
-
-#define je16_to_cpu(x) ((x).v16)
-#define je32_to_cpu(x) ((x).v32)
-#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m))
-#elif defined(JFFS2_BIG_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
-#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
-#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))})
-
-#define je16_to_cpu(x) (be16_to_cpu(x.v16))
-#define je32_to_cpu(x) (be32_to_cpu(x.v32))
-#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m)))
-#elif defined(JFFS2_LITTLE_ENDIAN)
-#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
-#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
-#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))})
-
-#define je16_to_cpu(x) (le16_to_cpu(x.v16))
-#define je32_to_cpu(x) (le32_to_cpu(x.v32))
-#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m)))
-#else 
-#error wibble
-#endif
-
 struct jffs2_unknown_node
 {
        /* All start like this */
index db91aa6..14743de 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_i.h,v 1.15 2002/11/12 09:42:49 dwmw2 Exp $ */
+/* $Id: jffs2_fs_i.h,v 1.16 2003/01/09 14:03:21 dwmw2 Exp $ */
 
 #ifndef _JFFS2_FS_I
 #define _JFFS2_FS_I
@@ -36,9 +36,11 @@ struct jffs2_inode_info {
 
        uint16_t flags;
        uint8_t usercompr;
+#if !defined (__ECOS)
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
        struct inode vfs_inode;
 #endif
+#endif
 };
 
 #endif /* _JFFS2_FS_I */
index b646a48..acbd719 100644 (file)
@@ -69,6 +69,7 @@
 /* defines only for the constants which don't work well as enums */
 #define ATA_TAG_POISON         0xfafbfcfdU
 
+#undef PORT_UNKNOWN
 enum {
        /* various global constants */
        LIBATA_MAX_PRD          = ATA_MAX_PRD / 2,
index fa32bf2..1278162 100644 (file)
@@ -1,7 +1,7 @@
 
 /* Common Flash Interface structures 
  * See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.35 2003/05/28 15:37:32 dwmw2 Exp $
+ * $Id: cfi.h,v 1.44 2004/07/13 22:32:52 dwmw2 Exp $
  */
 
 #ifndef __MTD_CFI_H__
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/flashchip.h>
+#include <linux/mtd/map.h>
 #include <linux/mtd/cfi_endian.h>
 
-/*
- * You can optimize the code size and performance by defining only 
- * the geometry(ies) available on your hardware.
- * CFIDEV_INTERLEAVE_n, where  represents the interleave (number of chips to fill the bus width)
- * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes)
- *
- * By default, all (known) geometries are supported.
- */
-
-#ifndef CONFIG_MTD_CFI_GEOMETRY
-
-/* The default case - support all but 64-bit, which has
-   a performance penalty */
-
-#define CFIDEV_INTERLEAVE_1 (1)
-#define CFIDEV_INTERLEAVE_2 (2)
-#define CFIDEV_INTERLEAVE_4 (4)
-
-#define CFIDEV_BUSWIDTH_1 (1)
-#define CFIDEV_BUSWIDTH_2 (2)
-#define CFIDEV_BUSWIDTH_4 (4)
-
-typedef __u32 cfi_word;
-
-#else
-
-/* Explicitly configured buswidth/interleave support */
-
 #ifdef CONFIG_MTD_CFI_I1
-#define CFIDEV_INTERLEAVE_1 (1)
-#endif
-#ifdef CONFIG_MTD_CFI_I2
-#define CFIDEV_INTERLEAVE_2 (2)
-#endif
-#ifdef CONFIG_MTD_CFI_I4
-#define CFIDEV_INTERLEAVE_4 (4)
-#endif
-#ifdef CONFIG_MTD_CFI_I8
-#define CFIDEV_INTERLEAVE_8 (8)
-#endif
-
-#ifdef CONFIG_MTD_CFI_B1
-#define CFIDEV_BUSWIDTH_1 (1)
-#endif
-#ifdef CONFIG_MTD_CFI_B2
-#define CFIDEV_BUSWIDTH_2 (2)
-#endif
-#ifdef CONFIG_MTD_CFI_B4
-#define CFIDEV_BUSWIDTH_4 (4)
-#endif
-#ifdef CONFIG_MTD_CFI_B8
-#define CFIDEV_BUSWIDTH_8 (8)
-#endif
-
-/* pick the largest necessary */
-#ifdef CONFIG_MTD_CFI_B8
-typedef __u64 cfi_word;
-
-/* This only works if asm/io.h is included first */
-#ifndef __raw_readll
-#define __raw_readll(addr)     (*(volatile __u64 *)(addr))
-#endif
-#ifndef __raw_writell
-#define __raw_writell(v, addr) (*(volatile __u64 *)(addr) = (v))
-#endif
-#define CFI_WORD_64
-#else  /* CONFIG_MTD_CFI_B8 */
-/* All others can use 32-bits. It's probably more efficient than
-   the smaller types anyway */
-typedef __u32 cfi_word;
-#endif /* CONFIG_MTD_CFI_B8 */
-
-#endif
-
-/*
- * The following macros are used to select the code to execute:
- *   cfi_buswidth_is_*()
- *   cfi_interleave_is_*()
- *   [where * is either 1, 2, 4, or 8]
- * Those macros should be used with 'if' statements.  If only one of few
- * geometry arrangements are selected, they expand to constants thus allowing
- * the compiler (most of them being 0) to optimize away all the unneeded code,
- * while still validating the syntax (which is not possible with embedded 
- * #if ... #endif constructs).
- * The exception to this is the 64-bit versions, which need an extension
- * to the cfi_word type, and cause compiler warnings about shifts being
- * out of range.
- */
-
-#ifdef CFIDEV_INTERLEAVE_1
-# ifdef CFIDEV_INTERLEAVE
-#  undef CFIDEV_INTERLEAVE
-#  define CFIDEV_INTERLEAVE (cfi->interleave)
-# else
-#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_1
-# endif
-# define cfi_interleave_is_1() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_1)
+#define cfi_interleave(cfi) 1
+#define cfi_interleave_is_1(cfi) (cfi_interleave(cfi) == 1)
 #else
-# define cfi_interleave_is_1() (0)
+#define cfi_interleave_is_1(cfi) (0)
 #endif
 
-#ifdef CFIDEV_INTERLEAVE_2
-# ifdef CFIDEV_INTERLEAVE
-#  undef CFIDEV_INTERLEAVE
-#  define CFIDEV_INTERLEAVE (cfi->interleave)
+#ifdef CONFIG_MTD_CFI_I2
+# ifdef cfi_interleave
+#  undef cfi_interleave
+#  define cfi_interleave(cfi) ((cfi)->interleave)
 # else
-#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_2
+#  define cfi_interleave(cfi) 2
 # endif
-# define cfi_interleave_is_2() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_2)
+#define cfi_interleave_is_2(cfi) (cfi_interleave(cfi) == 2)
 #else
-# define cfi_interleave_is_2() (0)
+#define cfi_interleave_is_2(cfi) (0)
 #endif
 
-#ifdef CFIDEV_INTERLEAVE_4
-# ifdef CFIDEV_INTERLEAVE
-#  undef CFIDEV_INTERLEAVE
-#  define CFIDEV_INTERLEAVE (cfi->interleave)
+#ifdef CONFIG_MTD_CFI_I4
+# ifdef cfi_interleave
+#  undef cfi_interleave
+#  define cfi_interleave(cfi) ((cfi)->interleave)
 # else
-#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_4
+#  define cfi_interleave(cfi) 4
 # endif
-# define cfi_interleave_is_4() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_4)
+#define cfi_interleave_is_4(cfi) (cfi_interleave(cfi) == 4)
 #else
-# define cfi_interleave_is_4() (0)
+#define cfi_interleave_is_4(cfi) (0)
 #endif
 
-#ifdef CFIDEV_INTERLEAVE_8
-# ifdef CFIDEV_INTERLEAVE
-#  undef CFIDEV_INTERLEAVE
-#  define CFIDEV_INTERLEAVE (cfi->interleave)
+#ifdef CONFIG_MTD_CFI_I8
+# ifdef cfi_interleave
+#  undef cfi_interleave
+#  define cfi_interleave(cfi) ((cfi)->interleave)
 # else
-#  define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8
+#  define cfi_interleave(cfi) 8
 # endif
-# define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8)
+#define cfi_interleave_is_8(cfi) (cfi_interleave(cfi) == 8)
 #else
-# define cfi_interleave_is_8() (0)
+#define cfi_interleave_is_8(cfi) (0)
 #endif
 
-#ifndef CFIDEV_INTERLEAVE
-#error You must define at least one interleave to support!
+static inline int cfi_interleave_supported(int i)
+{
+       switch (i) {
+#ifdef CONFIG_MTD_CFI_I1
+       case 1:
 #endif
-
-#ifdef CFIDEV_BUSWIDTH_1
-# ifdef CFIDEV_BUSWIDTH
-#  undef CFIDEV_BUSWIDTH
-#  define CFIDEV_BUSWIDTH (map->buswidth)
-# else
-#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_1
-# endif
-# define cfi_buswidth_is_1() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_1)
-#else
-# define cfi_buswidth_is_1() (0)
+#ifdef CONFIG_MTD_CFI_I2
+       case 2:
 #endif
-
-#ifdef CFIDEV_BUSWIDTH_2
-# ifdef CFIDEV_BUSWIDTH
-#  undef CFIDEV_BUSWIDTH
-#  define CFIDEV_BUSWIDTH (map->buswidth)
-# else
-#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_2
-# endif
-# define cfi_buswidth_is_2() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_2)
-#else
-# define cfi_buswidth_is_2() (0)
+#ifdef CONFIG_MTD_CFI_I4
+       case 4:
 #endif
-
-#ifdef CFIDEV_BUSWIDTH_4
-# ifdef CFIDEV_BUSWIDTH
-#  undef CFIDEV_BUSWIDTH
-#  define CFIDEV_BUSWIDTH (map->buswidth)
-# else
-#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_4
-# endif
-# define cfi_buswidth_is_4() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_4)
-#else
-# define cfi_buswidth_is_4() (0)
+#ifdef CONFIG_MTD_CFI_I8
+       case 8:
 #endif
+               return 1;
 
-#ifdef CFIDEV_BUSWIDTH_8
-# ifdef CFIDEV_BUSWIDTH
-#  undef CFIDEV_BUSWIDTH
-#  define CFIDEV_BUSWIDTH (map->buswidth)
-# else
-#  define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8
-# endif
-# define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8)
-#else
-# define cfi_buswidth_is_8() (0)
-#endif
+       default:
+               return 0;
+       }
+}
 
-#ifndef CFIDEV_BUSWIDTH
-#error You must define at least one bus width to support!
-#endif
 
 /* NB: these values must represents the number of bytes needed to meet the 
  *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes. 
@@ -223,64 +97,84 @@ typedef __u32 cfi_word;
 
 /* Basic Query Structure */
 struct cfi_ident {
-  __u8  qry[3];
-  __u16 P_ID;
-  __u16 P_ADR;
-  __u16 A_ID;
-  __u16 A_ADR;
-  __u8  VccMin;
-  __u8  VccMax;
-  __u8  VppMin;
-  __u8  VppMax;
-  __u8  WordWriteTimeoutTyp;
-  __u8  BufWriteTimeoutTyp;
-  __u8  BlockEraseTimeoutTyp;
-  __u8  ChipEraseTimeoutTyp;
-  __u8  WordWriteTimeoutMax;
-  __u8  BufWriteTimeoutMax;
-  __u8  BlockEraseTimeoutMax;
-  __u8  ChipEraseTimeoutMax;
-  __u8  DevSize;
-  __u16 InterfaceDesc;
-  __u16 MaxBufWriteSize;
-  __u8  NumEraseRegions;
-  __u32 EraseRegionInfo[0]; /* Not host ordered */
+       uint8_t  qry[3];
+       uint16_t P_ID;
+       uint16_t P_ADR;
+       uint16_t A_ID;
+       uint16_t A_ADR;
+       uint8_t  VccMin;
+       uint8_t  VccMax;
+       uint8_t  VppMin;
+       uint8_t  VppMax;
+       uint8_t  WordWriteTimeoutTyp;
+       uint8_t  BufWriteTimeoutTyp;
+       uint8_t  BlockEraseTimeoutTyp;
+       uint8_t  ChipEraseTimeoutTyp;
+       uint8_t  WordWriteTimeoutMax;
+       uint8_t  BufWriteTimeoutMax;
+       uint8_t  BlockEraseTimeoutMax;
+       uint8_t  ChipEraseTimeoutMax;
+       uint8_t  DevSize;
+       uint16_t InterfaceDesc;
+       uint16_t MaxBufWriteSize;
+       uint8_t  NumEraseRegions;
+       uint32_t EraseRegionInfo[0]; /* Not host ordered */
 } __attribute__((packed));
 
 /* Extended Query Structure for both PRI and ALT */
 
 struct cfi_extquery {
-  __u8  pri[3];
-  __u8  MajorVersion;
-  __u8  MinorVersion;
+       uint8_t  pri[3];
+       uint8_t  MajorVersion;
+       uint8_t  MinorVersion;
 } __attribute__((packed));
 
 /* Vendor-Specific PRI for Intel/Sharp Extended Command Set (0x0001) */
 
 struct cfi_pri_intelext {
-  __u8  pri[3];
-  __u8  MajorVersion;
-  __u8  MinorVersion;
-  __u32 FeatureSupport;
-  __u8  SuspendCmdSupport;
-  __u16 BlkStatusRegMask;
-  __u8  VccOptimal;
-  __u8  VppOptimal;
-  __u8  NumProtectionFields;
-  __u16 ProtRegAddr;
-  __u8  FactProtRegSize;
-  __u8  UserProtRegSize;
+       uint8_t  pri[3];
+       uint8_t  MajorVersion;
+       uint8_t  MinorVersion;
+       uint32_t FeatureSupport; /* if bit 31 is set then an additional uint32_t feature
+                                   block follows - FIXME - not currently supported */
+       uint8_t  SuspendCmdSupport;
+       uint16_t BlkStatusRegMask;
+       uint8_t  VccOptimal;
+       uint8_t  VppOptimal;
+       uint8_t  NumProtectionFields;
+       uint16_t ProtRegAddr;
+       uint8_t  FactProtRegSize;
+       uint8_t  UserProtRegSize;
+} __attribute__((packed));
+
+/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */
+
+struct cfi_pri_amdstd {
+       uint8_t  pri[3];
+       uint8_t  MajorVersion;
+       uint8_t  MinorVersion;
+       uint8_t  SiliconRevision; /* bits 1-0: Address Sensitive Unlock */
+       uint8_t  EraseSuspend;
+       uint8_t  BlkProt;
+       uint8_t  TmpBlkUnprotect;
+       uint8_t  BlkProtUnprot;
+       uint8_t  SimultaneousOps;
+       uint8_t  BurstMode;
+       uint8_t  PageMode;
+       uint8_t  VppMin;
+       uint8_t  VppMax;
+       uint8_t  TopBottom;
 } __attribute__((packed));
 
 struct cfi_pri_query {
-  __u8  NumFields;
-  __u32 ProtField[1]; /* Not host ordered */
+       uint8_t  NumFields;
+       uint32_t ProtField[1]; /* Not host ordered */
 } __attribute__((packed));
 
 struct cfi_bri_query {
-  __u8  PageModeReadCap;
-  __u8  NumFields;
-  __u32 ConfField[1]; /* Not host ordered */
+       uint8_t  PageModeReadCap;
+       uint8_t  NumFields;
+       uint32_t ConfField[1]; /* Not host ordered */
 } __attribute__((packed));
 
 #define P_ID_NONE 0
@@ -288,8 +182,10 @@ struct cfi_bri_query {
 #define P_ID_AMD_STD 2
 #define P_ID_INTEL_STD 3
 #define P_ID_AMD_EXT 4
+#define P_ID_ST_ADV 32
 #define P_ID_MITSUBISHI_STD 256
 #define P_ID_MITSUBISHI_EXT 257
+#define P_ID_SST_PAGE 258
 #define P_ID_RESERVED 65535
 
 
@@ -297,14 +193,13 @@ struct cfi_bri_query {
 #define CFI_MODE_JEDEC 0
 
 struct cfi_private {
-       __u16 cmdset;
+       uint16_t cmdset;
        void *cmdset_priv;
        int interleave;
        int device_type;
        int cfi_mode;           /* Are we a JEDEC device pretending to be CFI? */
        int addr_unlock1;
        int addr_unlock2;
-       int fast_prog;
        struct mtd_info *(*cmdset_setup)(struct map_info *);
        struct cfi_ident *cfiq; /* For now only one. We insist that all devs
                                  must be of the same type. */
@@ -315,107 +210,81 @@ struct cfi_private {
        struct flchip chips[0];  /* per-chip data structure for each chip */
 };
 
-#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */
-
 /*
  * Returns the command address according to the given geometry.
  */
-static inline __u32 cfi_build_cmd_addr(__u32 cmd_ofs, int interleave, int type)
+static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int type)
 {
        return (cmd_ofs * type) * interleave;
 }
 
 /*
- * Transforms the CFI command for the given geometry (bus width & interleave.
+ * Transforms the CFI command for the given geometry (bus width & interleave).
+ * It looks too long to be inline, but in the common case it should almost all
+ * get optimised away. 
  */
-static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
 {
-       cfi_word val = 0;
-
-       if (cfi_buswidth_is_1()) {
-               /* 1 x8 device */
-               val = cmd;
-       } else if (cfi_buswidth_is_2()) {
-               if (cfi_interleave_is_1()) {
-                       /* 1 x16 device in x16 mode */
-                       val = cpu_to_cfi16(cmd);
-               } else if (cfi_interleave_is_2()) {
-                       /* 2 (x8, x16 or x32) devices in x8 mode */
-                       val = cpu_to_cfi16((cmd << 8) | cmd);
-               }
-       } else if (cfi_buswidth_is_4()) {
-               if (cfi_interleave_is_1()) {
-                       /* 1 x32 device in x32 mode */
-                       val = cpu_to_cfi32(cmd);
-               } else if (cfi_interleave_is_2()) {
-                       /* 2 x16 device in x16 mode */
-                       val = cpu_to_cfi32((cmd << 16) | cmd);
-               } else if (cfi_interleave_is_4()) {
-                       /* 4 (x8, x16 or x32) devices in x8 mode */
-                       val = (cmd << 16) | cmd;
-                       val = cpu_to_cfi32((val << 8) | val);
-               }
-#ifdef CFI_WORD_64
-       } else if (cfi_buswidth_is_8()) {
-               if (cfi_interleave_is_1()) {
-                       /* 1 x64 device in x64 mode */
-                       val = cpu_to_cfi64(cmd);
-               } else if (cfi_interleave_is_2()) {
-                       /* 2 x32 device in x32 mode */
-                       val = cmd;
-                       val = cpu_to_cfi64((val << 32) | val);
-               } else if (cfi_interleave_is_4()) {
-                       /* 4 (x16, x32 or x64) devices in x16 mode */
-                       val = (cmd << 16) | cmd;
-                       val = cpu_to_cfi64((val << 32) | val);
-               } else if (cfi_interleave_is_8()) {
-                       /* 8 (x8, x16 or x32) devices in x8 mode */
-                       val = (cmd << 8) | cmd;
-                       val = (val << 16) | val;
-                       val = (val << 32) | val;
-                       val = cpu_to_cfi64(val);
-               }
-#endif /* CFI_WORD_64 */
-       }
-       return val;
-}
-#define CMD(x)  cfi_build_cmd((x), map, cfi)
-
-/*
- * Read a value according to the bus width.
- */
-
-static inline cfi_word cfi_read(struct map_info *map, __u32 addr)
-{
-       if (cfi_buswidth_is_1()) {
-               return map_read8(map, addr);
-       } else if (cfi_buswidth_is_2()) {
-               return map_read16(map, addr);
-       } else if (cfi_buswidth_is_4()) {
-               return map_read32(map, addr);
-       } else if (cfi_buswidth_is_8()) {
-               return map_read64(map, addr);
+       map_word val = { {0} };
+       int wordwidth, words_per_bus, chip_mode, chips_per_word;
+       unsigned long onecmd;
+       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 {
-               return 0;
+               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);
+
+       /* First, determine what the bit-pattern should be for a single
+          device, according to chip mode and endianness... */
+       switch (chip_mode) {
+       default: BUG();
+       case 1:
+               onecmd = cmd;
+               break;
+       case 2:
+               onecmd = cpu_to_cfi16(cmd);
+               break;
+       case 4:
+               onecmd = cpu_to_cfi32(cmd);
+               break;
        }
-}
 
-/*
- * Write a value according to the bus width.
- */
+       /* Now replicate it across the size of an unsigned long, or 
+          just to the bus width as appropriate */
+       switch (chips_per_word) {
+       default: BUG();
+#if BITS_PER_LONG >= 64
+       case 8:
+               onecmd |= (onecmd << (chip_mode * 32));
+#endif
+       case 4:
+               onecmd |= (onecmd << (chip_mode * 16));
+       case 2:
+               onecmd |= (onecmd << (chip_mode * 8));
+       case 1:
+               ;
+       }
 
-static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
-{
-       if (cfi_buswidth_is_1()) {
-               map_write8(map, val, addr);
-       } else if (cfi_buswidth_is_2()) {
-               map_write16(map, val, addr);
-       } else if (cfi_buswidth_is_4()) {
-               map_write32(map, val, addr);
-       } else if (cfi_buswidth_is_8()) {
-               map_write64(map, val, addr);
+       /* And finally, for the multi-word case, replicate it 
+          in all words in the structure */
+       for (i=0; i < words_per_bus; i++) {
+               val.x[i] = onecmd;
        }
+
+       return val;
 }
+#define CMD(x)  cfi_build_cmd((x), map, cfi)
 
 /*
  * Sends a CFI command to a bank of flash for the given geometry.
@@ -424,35 +293,36 @@ static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr)
  * If prev_val is non-null, it will be set to the value at the command address,
  * before the command was written.
  */
-static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base,
+static inline uint32_t cfi_send_gen_cmd(u_char cmd, uint32_t cmd_addr, uint32_t base,
                                struct map_info *map, struct cfi_private *cfi,
-                               int type, cfi_word *prev_val)
+                               int type, map_word *prev_val)
 {
-       cfi_word val;
-       __u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type);
+       map_word val;
+       uint32_t addr = base + cfi_build_cmd_addr(cmd_addr, cfi_interleave(cfi), type);
 
        val = cfi_build_cmd(cmd, map, cfi);
 
        if (prev_val)
-               *prev_val = cfi_read(map, addr);
+               *prev_val = map_read(map, addr);
 
-       cfi_write(map, val, addr);
+       map_write(map, val, addr);
 
        return addr - base;
 }
 
-static inline __u8 cfi_read_query(struct map_info *map, __u32 addr)
+static inline uint8_t cfi_read_query(struct map_info *map, uint32_t addr)
 {
-       if (cfi_buswidth_is_1()) {
-               return map_read8(map, addr);
-       } else if (cfi_buswidth_is_2()) {
-               return cfi16_to_cpu(map_read16(map, addr));
-       } else if (cfi_buswidth_is_4()) {
-               return cfi32_to_cpu(map_read32(map, addr));
-       } else if (cfi_buswidth_is_8()) {
-               return cfi64_to_cpu(map_read64(map, addr));
+       map_word val = map_read(map, addr);
+
+       if (map_bankwidth_is_1(map)) {
+               return val.x[0];
+       } else if (map_bankwidth_is_2(map)) {
+               return cfi16_to_cpu(val.x[0]);
        } else {
-               return 0;
+               /* No point in a 64-bit byteswap since that would just be
+                  swapping the responses from different chips, and we are
+                  only interested in one chip (a representative sample) */
+               return cfi32_to_cpu(val.x[0]);
        }
 }
 
@@ -480,4 +350,19 @@ static inline void cfi_spin_unlock(spinlock_t *mutex)
        spin_unlock_bh(mutex);
 }
 
+struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size,
+                            const char* name);
+
+struct cfi_fixup {
+       uint16_t mfr;
+       uint16_t id;
+       void (*fixup)(struct map_info *map, void* param);
+       void* param;
+};
+
+#define CFI_MFR_ANY 0xffff
+#define CFI_ID_ANY  0xffff
+
+void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups);
+
 #endif /* __MTD_CFI_H__ */
index 64465a9..0fd8f49 100644 (file)
@@ -1,13 +1,21 @@
-
-/* Linux driver for Disk-On-Chip 2000       */
-/* (c) 1999 Machine Vision Holdings, Inc.   */
-/* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: doc2000.h,v 1.17 2003/06/12 01:20:46 gerg Exp $ */
+/* 
+ * Linux driver for Disk-On-Chip devices
+ *
+ * Copyright (C) 1999 Machine Vision Holdings, Inc.   
+ * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org>
+ * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com>
+ * Copyright (C) 2002-2003 SnapGear Inc
+ *
+ * $Id: doc2000.h,v 1.22 2003/11/05 10:51:36 dwmw2 Exp $ 
+ *
+ * Released under GPL
+ */
 
 #ifndef __MTD_DOC2000_H__
 #define __MTD_DOC2000_H__
 
 #include <linux/mtd/mtd.h>
+#include <asm/semaphore.h>
 
 #define DoC_Sig1 0
 #define DoC_Sig2 1
  * Others use readb/writeb 
  */
 #if defined(__arm__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2))))
-#define WriteDOC_(d, adr, reg)  do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
+#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
+#define WriteDOC_(d, adr, reg)  do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
 #define DOC_IOREMAP_LEN 0x8000
 #elif defined(__ppc__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1))))
-#define WriteDOC_(d, adr, reg)  do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
+#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
+#define WriteDOC_(d, adr, reg)  do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
 #define DOC_IOREMAP_LEN 0x4000
 #else
 #define ReadDOC_(adr, reg)      readb(((unsigned long)adr) + (reg))
 #define DOC_MODE_MDWREN        0x04
 
 #define DOC_ChipID_Doc2k       0x20
+#define DOC_ChipID_Doc2kTSOP   0x21    /* internal number for MTD */
 #define DOC_ChipID_DocMil      0x30
 #define DOC_ChipID_DocMilPlus32        0x40
 #define DOC_ChipID_DocMilPlus16        0x41
@@ -147,10 +156,10 @@ struct Nand {
 #define MAX_FLOORS 4
 #define MAX_CHIPS 4
 
-#define MAX_FLOORS_MIL 4
+#define MAX_FLOORS_MIL 1
 #define MAX_CHIPS_MIL 1
 
-#define MAX_FLOORS_MPLUS 1
+#define MAX_FLOORS_MPLUS 2
 #define MAX_CHIPS_MPLUS 1
 
 #define ADDR_COLUMN 1
@@ -161,7 +170,7 @@ struct DiskOnChip {
        unsigned long physadr;
        unsigned long virtadr;
        unsigned long totlen;
-       char ChipID; /* Type of DiskOnChip */
+       unsigned char ChipID; /* Type of DiskOnChip */
        int ioreg;
        
        unsigned long mfr; /* Flash IDs - only one type of flash per device */
index 7e042bf..c3ac4df 100644 (file)
@@ -6,7 +6,7 @@
  *
  * (C) 2000 Red Hat. GPLd.
  *
- * $Id: flashchip.h,v 1.9 2003/04/30 11:15:22 dwmw2 Exp $
+ * $Id: flashchip.h,v 1.14 2004/06/15 16:44:59 nico Exp $
  *
  */
 
@@ -43,7 +43,8 @@ typedef enum {
 
 
 /* NOTE: confusingly, this can be used to refer to more than one chip at a time, 
-   if they're interleaved. */
+   if they're interleaved.  This can even refer to individual partitions on
+   the same physical chip when present. */
 
 struct flchip {
        unsigned long start; /* Offset within the map */
@@ -61,6 +62,7 @@ struct flchip {
 
        int write_suspended:1;
        int erase_suspended:1;
+       unsigned long in_progress_block_addr;
 
        spinlock_t *mutex;
        spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */
@@ -69,8 +71,17 @@ struct flchip {
        int word_write_time;
        int buffer_write_time;
        int erase_time;
+
+       void *priv;
 };
 
+/* This is used to handle contention on write/erase operations
+   between partitions of the same physical chip. */
+struct flchip_shared {
+       spinlock_t lock;
+       struct flchip *writing;
+       struct flchip *erasing;
+};
 
 
 #endif /* __MTD_FLASHCHIP_H__ */
index ae017ef..3678459 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ftl.h,v 1.5 2001/06/02 20:35:51 dwmw2 Exp $
+ * $Id: ftl.h,v 1.6 2003/01/24 13:20:04 dwmw2 Exp $
  * 
  * Derived from (and probably identical to):
  * ftl.h 1.7 1999/10/25 20:23:17
index 43c3a08..2d66b33 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * (C) 2001, 2001 Red Hat, Inc.
  * GPL'd
- * $Id: gen_probe.h,v 1.1 2001/09/02 18:50:13 dwmw2 Exp $
+ * $Id: gen_probe.h,v 1.2 2003/11/08 00:51:21 dsaxena Exp $
  */
 
 #ifndef __LINUX_MTD_GEN_PROBE_H__
 #include <linux/mtd/flashchip.h>
 #include <linux/mtd/map.h> 
 #include <linux/mtd/cfi.h>
+#include <asm/bitops.h>
 
 struct chip_probe {
        char *name;
        int (*probe_chip)(struct map_info *map, __u32 base,
-                         struct flchip *chips, struct cfi_private *cfi);
-
+                         unsigned long *chip_map, struct cfi_private *cfi);
 };
 
 struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp);
index 5cc052d..b52c8cb 100644 (file)
  *
  *     (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
  *
- *     $Id: inftl.h,v 1.3 2003/05/23 11:35:34 dwmw2 Exp $
+ *     $Id: inftl.h,v 1.6 2004/06/30 14:49:00 dbrown Exp $
  */
 
 #ifndef __MTD_INFTL_H__
 #define __MTD_INFTL_H__
 
+#ifndef __KERNEL__
+#error This is a kernel header. Perhaps include nftl-user.h instead?
+#endif
+
 #include <linux/mtd/blktrans.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nftl.h>
 
-#define        OSAK_VERSION    0x5120
-#define        PERCENTUSED     98
-
-#define        SECTORSIZE      512
+#include <mtd/inftl-user.h>
 
 #ifndef INFTL_MAJOR
-#define INFTL_MAJOR 93 /* FIXME */
+#define INFTL_MAJOR 94
 #endif
 #define INFTL_PARTN_BITS 4
 
-/* Block Control Information */
-
-struct inftl_bci {
-       __u8 ECCsig[6];
-       __u8 Status;
-       __u8 Status1;
-} __attribute__((packed));
-
-struct inftl_unithead1 {
-       __u16 virtualUnitNo;
-       __u16 prevUnitNo;
-       __u8 ANAC;
-       __u8 NACs;
-       __u8 parityPerField;
-       __u8 discarded;
-} __attribute__((packed));
-
-struct inftl_unithead2 {
-       __u8 parityPerField;
-       __u8 ANAC;
-       __u16 prevUnitNo;
-       __u16 virtualUnitNo;
-       __u8 NACs;
-       __u8 discarded;
-} __attribute__((packed));
-
-struct inftl_unittail {
-       __u8 Reserved[4];
-       __u16 EraseMark;
-       __u16 EraseMark1;
-} __attribute__((packed));
-
-union inftl_uci {
-       struct inftl_unithead1 a;
-       struct inftl_unithead2 b;
-       struct inftl_unittail c;
-};
-
-struct inftl_oob {
-       struct inftl_bci b;
-       union inftl_uci u;
-};
-
-
-/* INFTL Media Header */
-
-struct INFTLPartition {
-       __u32 virtualUnits;
-       __u32 firstUnit;
-       __u32 lastUnit;
-       __u32 flags;
-       __u32 spareUnits;
-       __u32 Reserved0;
-       __u32 Reserved1;
-} __attribute__((packed));
-
-struct INFTLMediaHeader {
-       char bootRecordID[8];
-       __u32 NoOfBootImageBlocks;
-       __u32 NoOfBinaryPartitions;
-       __u32 NoOfBDTLPartitions;
-       __u32 BlockMultiplierBits;
-       __u32 FormatFlags;
-       __u32 OsakVersion;
-       __u32 PercentUsed;
-       struct INFTLPartition Partitions[4];
-} __attribute__((packed));
-
-/* Partition flag types */
-#define        INFTL_BINARY    0x20000000
-#define        INFTL_BDTL      0x40000000
-#define        INFTL_LAST      0x80000000
-
-
 #ifdef __KERNEL__
 
 struct INFTLrecord {
        struct mtd_blktrans_dev mbd;
-       __u16 MediaUnit, SpareMediaUnit;
+       __u16 MediaUnit;
        __u32 EraseSize;
        struct INFTLMediaHeader MediaHdr;
        int usecount;
@@ -119,6 +46,7 @@ struct INFTLrecord {
         unsigned int nb_blocks;                /* number of physical blocks */
         unsigned int nb_boot_blocks;   /* number of blocks used by the bios */
         struct erase_info instr;
+        struct nand_oobinfo oobinfo;
 };
 
 int INFTL_mount(struct INFTLrecord *s);
index 0c933f9..ed41dae 100644 (file)
@@ -1,6 +1,6 @@
 
 /* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.34 2003/05/28 12:42:22 dwmw2 Exp $ */
+/* $Id: map.h,v 1.43 2004/07/14 13:30:27 dwmw2 Exp $ */
 
 #ifndef __LINUX_MTD_MAP_H__
 #define __LINUX_MTD_MAP_H__
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/list.h>
+#include <asm/unaligned.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/bug.h>
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
+#define map_bankwidth(map) 1
+#define map_bankwidth_is_1(map) (map_bankwidth(map) == 1)
+#define map_bankwidth_is_large(map) (0)
+#define map_words(map) (1)
+#define MAX_MAP_BANKWIDTH 1
+#else
+#define map_bankwidth_is_1(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
+# ifdef map_bankwidth
+#  undef map_bankwidth
+#  define map_bankwidth(map) ((map)->bankwidth)
+# else
+#  define map_bankwidth(map) 2
+#  define map_bankwidth_is_large(map) (0)
+#  define map_words(map) (1)
+# endif
+#define map_bankwidth_is_2(map) (map_bankwidth(map) == 2)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 2
+#else
+#define map_bankwidth_is_2(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
+# ifdef map_bankwidth
+#  undef map_bankwidth
+#  define map_bankwidth(map) ((map)->bankwidth)
+# else
+#  define map_bankwidth(map) 4
+#  define map_bankwidth_is_large(map) (0)
+#  define map_words(map) (1)
+# endif
+#define map_bankwidth_is_4(map) (map_bankwidth(map) == 4)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 4
+#else
+#define map_bankwidth_is_4(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
+# ifdef map_bankwidth
+#  undef map_bankwidth
+#  define map_bankwidth(map) ((map)->bankwidth)
+#  if BITS_PER_LONG < 64
+#   undef map_bankwidth_is_large
+#   define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
+#   undef map_words
+#   define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+#  endif
+# else
+#  define map_bankwidth(map) 8
+#  define map_bankwidth_is_large(map) (BITS_PER_LONG < 64)
+#  define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# endif
+#define map_bankwidth_is_8(map) (map_bankwidth(map) == 8)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 8
+#else
+#define map_bankwidth_is_8(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
+# ifdef map_bankwidth
+#  undef map_bankwidth
+#  define map_bankwidth(map) ((map)->bankwidth)
+#  undef map_bankwidth_is_large
+#  define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
+#  undef map_words
+#  define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# else
+#  define map_bankwidth(map) 16
+#  define map_bankwidth_is_large(map) (1)
+#  define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# endif
+#define map_bankwidth_is_16(map) (map_bankwidth(map) == 16)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 16
+#else
+#define map_bankwidth_is_16(map) (0)
+#endif
+
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
+# ifdef map_bankwidth
+#  undef map_bankwidth
+#  define map_bankwidth(map) ((map)->bankwidth)
+#  undef map_bankwidth_is_large
+#  define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8)
+#  undef map_words
+#  define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# else
+#  define map_bankwidth(map) 32
+#  define map_bankwidth_is_large(map) (1)
+#  define map_words(map) (map_bankwidth(map) / sizeof(unsigned long))
+# endif
+#define map_bankwidth_is_32(map) (map_bankwidth(map) == 32)
+#undef MAX_MAP_BANKWIDTH
+#define MAX_MAP_BANKWIDTH 32
+#else
+#define map_bankwidth_is_32(map) (0)
+#endif
+
+#ifndef map_bankwidth
+#error "No bus width supported. What's the point?"
+#endif
+
+static inline int map_bankwidth_supported(int w)
+{
+       switch (w) {
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1
+       case 1:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2
+       case 2:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4
+       case 4:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
+       case 8:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16
+       case 16:
+#endif
+#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32
+       case 32:
+#endif
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
+#define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG )
+
+typedef union {
+       unsigned long x[MAX_MAP_LONGS];
+} map_word;
 
 /* The map stuff is very simple. You fill in your struct map_info with
    a handful of routines for accessing the device, making sure they handle
    paging etc. correctly if your device needs it. Then you pass it off
-   to a chip driver which deals with a mapped device - generally either
-   do_cfi_probe() or do_ram_probe(), either of which will return a 
-   struct mtd_info if they liked what they saw. At which point, you
-   fill in the mtd->module with your own module address, and register 
-   it.
+   to a chip probe routine -- either JEDEC or CFI probe or both -- via
+   do_map_probe(). If a chip is recognised, the probe code will invoke the
+   appropriate chip driver (if present) and return a struct mtd_info.
+   At which point, you fill in the mtd->module with your own module 
+   address, and register it with the MTD core code. Or you could partition
+   it and register the partitions instead, or keep it for your own private
+   use; whatever.
    
    The mtd->priv field will point to the struct map_info, and any further
    private data required by the chip driver is linked from the 
@@ -36,28 +182,29 @@ struct map_info {
        unsigned long virt;
        void *cached;
 
-       int buswidth; /* in octets */
+       int bankwidth; /* in octets. This isn't necessarily the width
+                      of actual bus cycles -- it's the repeat interval
+                     in bytes, before you are talking to the first chip again.
+                     */
 
 #ifdef CONFIG_MTD_COMPLEX_MAPPINGS
-       u8 (*read8)(struct map_info *, unsigned long);
-       u16 (*read16)(struct map_info *, unsigned long);
-       u32 (*read32)(struct map_info *, unsigned long);  
-       u64 (*read64)(struct map_info *, unsigned long);  
-       /* If it returned a 'long' I'd call it readl.
-        * It doesn't.
-        * I won't.
-        * dwmw2 */
-       
+       map_word (*read)(struct map_info *, unsigned long);
        void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
-       void (*write8)(struct map_info *, u8, unsigned long);
-       void (*write16)(struct map_info *, u16, unsigned long);
-       void (*write32)(struct map_info *, u32, unsigned long);
-       void (*write64)(struct map_info *, u64, unsigned long);
+
+       void (*write)(struct map_info *, const map_word, unsigned long);
        void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
 
        /* We can perhaps put in 'point' and 'unpoint' methods, if we really
           want to enable XIP for non-linear mappings. Not yet though. */
 #endif
+       /* It's possible for the map driver to use cached memory in its
+          copy_from implementation (and _only_ with copy_from).  However,
+          when the chip driver knows some flash area has changed contents,
+          it will signal it to the map driver through this routine to let
+          the map driver invalidate the corresponding cache as needed.
+          If there is no cache to care about this can be set to NULL. */
+       void (*inval_cache)(struct map_info *, unsigned long, ssize_t);
+
        /* set_vpp() must handle being reentered -- enable, enable, disable 
           must leave it enabled. */
        void (*set_vpp)(struct map_info *, int);
@@ -85,86 +232,173 @@ void map_destroy(struct mtd_info *mtd);
 #define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
 #define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
 
-#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
-#define map_read8(map, ofs) (map)->read8(map, ofs)
-#define map_read16(map, ofs) (map)->read16(map, ofs)
-#define map_read32(map, ofs) (map)->read32(map, ofs)
-#define map_read64(map, ofs) (map)->read64(map, ofs)
-#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
-#define map_write8(map, datum, ofs) (map)->write8(map, datum, ofs)
-#define map_write16(map, datum, ofs) (map)->write16(map, datum, ofs)
-#define map_write32(map, datum, ofs) (map)->write32(map, datum, ofs)
-#define map_write64(map, datum, ofs) (map)->write64(map, datum, ofs)
-#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
+#define INVALIDATE_CACHED_RANGE(map, from, size) \
+       do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
 
-extern void simple_map_init(struct map_info *);
-#define map_is_linear(map) (map->phys != NO_XIP)
 
-#else
-static inline u8 map_read8(struct map_info *map, unsigned long ofs)
+static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
 {
-       return __raw_readb(map->virt + ofs);
+       int i;
+       for (i=0; i<map_words(map); i++) {
+               if (val1.x[i] != val2.x[i])
+                       return 0;
+       }
+       return 1;
 }
 
-static inline u16 map_read16(struct map_info *map, unsigned long ofs)
+static inline map_word map_word_and(struct map_info *map, map_word val1, map_word val2)
 {
-       return __raw_readw(map->virt + ofs);
+       map_word r;
+       int i;
+
+       for (i=0; i<map_words(map); i++) {
+               r.x[i] = val1.x[i] & val2.x[i];
+       }
+       return r;
 }
 
-static inline u32 map_read32(struct map_info *map, unsigned long ofs)
+static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
 {
-       return __raw_readl(map->virt + ofs);
+       map_word r;
+       int i;
+
+       for (i=0; i<map_words(map); i++) {
+               r.x[i] = val1.x[i] | val2.x[i];
+       }
+       return r;
 }
+#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
 
-static inline u64 map_read64(struct map_info *map, unsigned long ofs)
+static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
 {
-#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
-       BUG();
+       int i;
+
+       for (i=0; i<map_words(map); i++) {
+               if (val1.x[i] & val2.x[i])
+                       return 1;
+       }
        return 0;
-#else
-       return __raw_readll(map->virt + ofs);
-#endif
 }
 
-static inline void map_write8(struct map_info *map, u8 datum, unsigned long ofs)
+static inline map_word map_word_load(struct map_info *map, const void *ptr)
 {
-       __raw_writeb(datum, map->virt + ofs);
-       mb();
+       map_word r;
+
+       if (map_bankwidth_is_1(map))
+               r.x[0] = *(unsigned char *)ptr;
+       else if (map_bankwidth_is_2(map))
+               r.x[0] = get_unaligned((uint16_t *)ptr);
+       else if (map_bankwidth_is_4(map))
+               r.x[0] = get_unaligned((uint32_t *)ptr);
+#if BITS_PER_LONG >= 64
+       else if (map_bankwidth_is_8(map))
+               r.x[0] = get_unaligned((uint64_t *)ptr);
+#endif
+       else if (map_bankwidth_is_large(map))
+               memcpy(r.x, ptr, map->bankwidth);
+
+       return r;
 }
 
-static inline void map_write16(struct map_info *map, u16 datum, unsigned long ofs)
+static inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len)
 {
-       __raw_writew(datum, map->virt + ofs);
-       mb();
+       int i;
+
+       if (map_bankwidth_is_large(map)) {
+               char *dest = (char *)&orig;
+               memcpy(dest+start, buf, len);
+       } else {
+               for (i=start; i < start+len; i++) {
+                       int bitpos;
+#ifdef __LITTLE_ENDIAN
+                       bitpos = i*8;
+#else /* __BIG_ENDIAN */
+                       bitpos = (map_bankwidth(map)-1-i)*8;
+#endif
+                       orig.x[0] &= ~(0xff << bitpos);
+                       orig.x[0] |= buf[i] << bitpos;
+               }
+       }
+       return orig;
 }
 
-static inline void map_write32(struct map_info *map, u32 datum, unsigned long ofs)
+static inline map_word map_word_ff(struct map_info *map)
 {
-       __raw_writel(datum, map->virt + ofs);
-       mb();
+       map_word r;
+       int i;
+
+       for (i=0; i<map_words(map); i++) {
+               r.x[i] = ~0UL;
+       }
+       return r;
+}
+static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
+{
+       map_word r;
+
+       if (map_bankwidth_is_1(map))
+               r.x[0] = __raw_readb(map->virt + ofs);
+       else if (map_bankwidth_is_2(map))
+               r.x[0] = __raw_readw(map->virt + ofs);
+       else if (map_bankwidth_is_4(map))
+               r.x[0] = __raw_readl(map->virt + ofs);
+#if BITS_PER_LONG >= 64
+       else if (map_bankwidth_is_8(map))
+               r.x[0] = __raw_readq(map->virt + ofs);
+#endif
+       else if (map_bankwidth_is_large(map))
+               memcpy_fromio(r.x, map->virt+ofs, map->bankwidth);
+
+       return r;
 }
 
-static inline void map_write64(struct map_info *map, u64 datum, unsigned long ofs)
+static inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
 {
-#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */
-       BUG();
-#else
-       __raw_writell(datum, map->virt + ofs);
+       if (map_bankwidth_is_1(map))
+               __raw_writeb(datum.x[0], map->virt + ofs);
+       else if (map_bankwidth_is_2(map))
+               __raw_writew(datum.x[0], map->virt + ofs);
+       else if (map_bankwidth_is_4(map))
+               __raw_writel(datum.x[0], map->virt + ofs);
+#if BITS_PER_LONG >= 64
+       else if (map_bankwidth_is_8(map))
+               __raw_writeq(datum.x[0], map->virt + ofs);
+#endif
+       else if (map_bankwidth_is_large(map))
+               memcpy_toio(map->virt+ofs, datum.x, map->bankwidth);
        mb();
-#endif /* CFI_B8 */
 }
 
-static inline void map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
 {
-       memcpy_fromio(to, map->virt + from, len);
+       if (map->cached)
+               memcpy(to, (char *)map->cached + from, len);
+       else
+               memcpy_fromio(to, map->virt + from, len);
 }
 
-static inline void map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
 {
        memcpy_toio(map->virt + to, from, len);
 }
 
-#define simple_map_init(map) do { } while (0)
+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS
+#define map_read(map, ofs) (map)->read(map, ofs)
+#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len)
+#define map_write(map, datum, ofs) (map)->write(map, datum, ofs)
+#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len)
+
+extern void simple_map_init(struct map_info *);
+#define map_is_linear(map) (map->phys != NO_XIP)
+
+#else
+#define map_read(map, ofs) inline_map_read(map, ofs)
+#define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len)
+#define map_write(map, datum, ofs) inline_map_write(map, datum, ofs)
+#define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len)
+
+
+#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth))
 #define map_is_linear(map) (1)
 
 #endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
index 2f0e43d..fd7b15d 100644 (file)
@@ -1,10 +1,17 @@
-
-/* $Id: mtd.h,v 1.45 2003/05/20 21:56:40 dwmw2 Exp $ */
+/* 
+ * $Id: mtd.h,v 1.54 2004/07/15 01:13:12 dwmw2 Exp $
+ *
+ * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
+ *
+ * Released under GPL
+ */
 
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
 
-#ifdef __KERNEL__
+#ifndef __KERNEL__
+#error This is a kernel header. Perhaps include mtd-user.h instead?
+#endif
 
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/uio.h>
 
-#endif /* __KERNEL__ */
-
-struct erase_info_user {
-       u_int32_t start;
-       u_int32_t length;
-};
-
-struct mtd_oob_buf {
-       u_int32_t start;
-       u_int32_t length;
-       unsigned char __user *ptr;
-};
+#include <mtd/mtd-abi.h>
 
 #define MTD_CHAR_MAJOR 90
 #define MTD_BLOCK_MAJOR 31
 #define MAX_MTD_DEVICES 16
 
-
-
-#define MTD_ABSENT             0
-#define MTD_RAM                        1
-#define MTD_ROM                        2
-#define MTD_NORFLASH           3
-#define MTD_NANDFLASH          4
-#define MTD_PEROM              5
-#define MTD_OTHER              14
-#define MTD_UNKNOWN            15
-
-
-
-#define MTD_CLEAR_BITS         1       // Bits can be cleared (flash)
-#define MTD_SET_BITS           2       // Bits can be set
-#define MTD_ERASEABLE          4       // Has an erase function
-#define MTD_WRITEB_WRITEABLE   8       // Direct IO is possible
-#define MTD_VOLATILE           16      // Set for RAMs
-#define MTD_XIP                        32      // eXecute-In-Place possible
-#define MTD_OOB                        64      // Out-of-band data (NAND flash)
-#define MTD_ECC                        128     // Device capable of automatic ECC
-
-// Some common devices / combinations of capabilities
-#define MTD_CAP_ROM            0
-#define MTD_CAP_RAM            (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE)
-#define MTD_CAP_NORFLASH        (MTD_CLEAR_BITS|MTD_ERASEABLE)
-#define MTD_CAP_NANDFLASH       (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB)
-#define MTD_WRITEABLE          (MTD_CLEAR_BITS|MTD_SET_BITS)
-
-
-// Types of automatic ECC/Checksum available
-#define MTD_ECC_NONE           0       // No automatic ECC available
-#define MTD_ECC_RS_DiskOnChip  1       // Automatic ECC on DiskOnChip
-#define MTD_ECC_SW             2       // SW ECC for Toshiba & Samsung devices
-
-struct mtd_info_user {
-       u_char type;
-       u_int32_t flags;
-       u_int32_t size;  // Total size of the MTD
-       u_int32_t erasesize;
-       u_int32_t oobblock;  // Size of OOB blocks (e.g. 512)
-       u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
-       u_int32_t ecctype;
-       u_int32_t eccsize;
-};
-
-struct region_info_user {
-       u_int32_t offset;               /* At which this region starts, 
-                                        * from the beginning of the MTD */
-       u_int32_t erasesize;            /* For this region */
-       u_int32_t numblocks;            /* Number of blocks in this region */
-       u_int32_t regionindex;
-};
-
-#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)
-#define MEMREADOOB              _IOWR('M', 4, struct mtd_oob_buf)
-#define MEMLOCK                 _IOW('M', 5, struct erase_info_user)
-#define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
-#define MEMGETREGIONCOUNT      _IOR('M', 7, int)
-#define MEMGETREGIONINFO       _IOWR('M', 8, struct region_info_user)
-#define MEMSETOOBSEL           _IOW('M', 9, struct nand_oobinfo)
-
-struct nand_oobinfo {
-       int     useecc;
-       int     eccpos[6];      
-};
-
-
-#ifndef __KERNEL__
-
-typedef struct mtd_info_user mtd_info_t;
-typedef struct erase_info_user erase_info_t;
-typedef struct region_info_user region_info_t;
-typedef struct nand_oobinfo nand_oobinfo_t;
-
-       /* User-space ioctl definitions */
-
-#else /* __KERNEL__ */
-
-
 #define MTD_ERASE_PENDING              0x01
 #define MTD_ERASING            0x02
 #define MTD_ERASE_SUSPEND      0x04
 #define MTD_ERASE_DONE          0x08
 #define MTD_ERASE_FAILED        0x10
 
+/* If the erase fails, fail_addr might indicate exactly which block failed.  If
+   fail_addr = 0xffffffff, the failure was not at the device level or was not
+   specific to any particular block. */
 struct erase_info {
        struct mtd_info *mtd;
        u_int32_t addr;
        u_int32_t len;
+       u_int32_t fail_addr;
        u_long time;
        u_long retries;
        u_int dev;
@@ -150,6 +68,7 @@ struct mtd_info {
 
        u_int32_t oobblock;  // Size of OOB blocks (e.g. 512)
        u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
+       u_int32_t oobavail;  // Number of bytes in OOB area available for fs 
        u_int32_t ecctype;
        u_int32_t eccsize;
        
@@ -223,6 +142,10 @@ struct mtd_info {
        int (*suspend) (struct mtd_info *mtd);
        void (*resume) (struct mtd_info *mtd);
 
+       /* Bad block management functions */
+       int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
+       int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
+
        void *priv;
 
        struct module *owner;
@@ -288,6 +211,4 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
 
 #endif /* CONFIG_MTD_DEBUG */
 
-#endif /* __KERNEL__ */
-
 #endif /* __MTD_MTD_H__ */
index 88d48a2..7de9f8d 100644 (file)
@@ -5,7 +5,7 @@
  *                     Steven J. Hill <sjhill@realitydiluted.com>
  *                    Thomas Gleixner <tglx@linutronix.de>
  *
- * $Id: nand.h,v 1.25 2003/05/21 15:15:02 dwmw2 Exp $
+ * $Id: nand.h,v 1.63 2004/07/07 16:29:43 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
  *                     NAND_YAFFS_OOB
  *  11-25-2002 tglx    Added Manufacturer code FUJITSU, NATIONAL
  *                     Split manufacturer and device ID structures 
+ *
+ *  02-08-2004 tglx    added option field to nand structure for chip anomalities
+ *  05-25-2004 tglx    added bad block table support, ST-MICRO manufacturer id
+ *                     update of nand_chip structure description
  */
 #ifndef __LINUX_MTD_NAND_H
 #define __LINUX_MTD_NAND_H
 #include <linux/config.h>
 #include <linux/wait.h>
 #include <linux/spinlock.h>
+#include <linux/mtd/mtd.h>
 
 struct mtd_info;
-/*
- * Searches for a NAND device
+/* Scan and identify a NAND device */
+extern int nand_scan (struct mtd_info *mtd, int max_chips);
+/* Free resources held by the NAND device */
+extern void nand_release (struct mtd_info *mtd);
+
+/* Read raw data from the device without ECC */
+extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen);
+
+
+/* The maximum number of NAND chips in an array */
+#define NAND_MAX_CHIPS         8
+
+/* This constant declares the max. oobsize / page, which
+ * is supported now. If you add a chip with bigger oobsize/page
+ * adjust this accordingly.
  */
-extern int nand_scan (struct mtd_info *mtd);
+#define NAND_MAX_OOBSIZE       64
 
 /*
  * Constants for hardware specific CLE/ALE/NCE function
 */
+/* Select the chip by setting nCE to low */
 #define NAND_CTL_SETNCE        1
+/* Deselect the chip by setting nCE to high */
 #define NAND_CTL_CLRNCE                2
+/* Select the command latch by setting CLE to high */
 #define NAND_CTL_SETCLE                3
+/* Deselect the command latch by setting CLE to low */
 #define NAND_CTL_CLRCLE                4
+/* Select the address latch by setting ALE to high */
 #define NAND_CTL_SETALE                5
+/* Deselect the address latch by setting ALE to low */
 #define NAND_CTL_CLRALE                6
+/* Set write protection by setting WP to high. Not used! */
+#define NAND_CTL_SETWP         7
+/* Clear write protection by setting WP to low. Not used! */
+#define NAND_CTL_CLRWP         8
 
 /*
  * Standard NAND flash commands
@@ -77,35 +105,102 @@ extern int nand_scan (struct mtd_info *mtd);
 #define NAND_CMD_READOOB       0x50
 #define NAND_CMD_ERASE1                0x60
 #define NAND_CMD_STATUS                0x70
+#define NAND_CMD_STATUS_MULTI  0x71
 #define NAND_CMD_SEQIN         0x80
 #define NAND_CMD_READID                0x90
 #define NAND_CMD_ERASE2                0xd0
 #define NAND_CMD_RESET         0xff
 
+/* Extended commands for large page devices */
+#define NAND_CMD_READSTART     0x30
+#define NAND_CMD_CACHEDPROG    0x15
+
+/* Status bits */
+#define NAND_STATUS_FAIL       0x01
+#define NAND_STATUS_FAIL_N1    0x02
+#define NAND_STATUS_TRUE_READY 0x20
+#define NAND_STATUS_READY      0x40
+#define NAND_STATUS_WP         0x80
+
 /* 
  * Constants for ECC_MODES
- *
- * NONE:       No ECC
- * SOFT:       Software ECC 3 byte ECC per 256 Byte data
- * HW3_256:    Hardware ECC 3 byte ECC per 256 Byte data
- * HW3_512:    Hardware ECC 3 byte ECC per 512 Byte data
- *
- *
-*/
+ */
+
+/* No ECC. Usage is not recommended ! */
 #define NAND_ECC_NONE          0
+/* Software ECC 3 byte ECC per 256 Byte data */
 #define NAND_ECC_SOFT          1
+/* Hardware ECC 3 byte ECC per 256 Byte data */
 #define NAND_ECC_HW3_256       2
+/* Hardware ECC 3 byte ECC per 512 Byte data */
 #define NAND_ECC_HW3_512       3
+/* Hardware ECC 3 byte ECC per 512 Byte data */
 #define NAND_ECC_HW6_512       4
-#define NAND_ECC_DISKONCHIP    5
+/* Hardware ECC 8 byte ECC per 512 Byte data */
+#define NAND_ECC_HW8_512       6
 
 /*
  * Constants for Hardware ECC
 */
+/* Reset Hardware ECC for read */
 #define NAND_ECC_READ          0
+/* Reset Hardware ECC for write */
 #define NAND_ECC_WRITE         1
-       
+/* Enable Hardware ECC before syndrom is read back from flash */
+#define NAND_ECC_READSYN       2
+
+/* Option constants for bizarre disfunctionality and real
+*  features
+*/
+/* Chip can not auto increment pages */
+#define NAND_NO_AUTOINCR       0x00000001
+/* Buswitdh is 16 bit */
+#define NAND_BUSWIDTH_16       0x00000002
+/* Device supports partial programming without padding */
+#define NAND_NO_PADDING                0x00000004
+/* Chip has cache program function */
+#define NAND_CACHEPRG          0x00000008
+/* Chip has copy back function */
+#define NAND_COPYBACK          0x00000010
+/* AND Chip which has 4 banks and a confusing page / block 
+ * assignment. See Renesas datasheet for further information */
+#define NAND_IS_AND            0x00000020
+/* Chip has a array of 4 pages which can be read without
+ * additional ready /busy waits */
+#define NAND_4PAGE_ARRAY       0x00000040 
+
+/* Options valid for Samsung large page devices */
+#define NAND_SAMSUNG_LP_OPTIONS \
+       (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK)
+
+/* Macros to identify the above */
+#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR))
+#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING))
+#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
+#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
+
+/* Mask to zero out the chip options, which come from the id table */
+#define NAND_CHIPOPTIONS_MSK   (0x0000ffff & ~NAND_NO_AUTOINCR)
+
+/* Non chip related options */
+/* Use a flash based bad block table. This option is passed to the
+ * default bad block table function. */
+#define NAND_USE_FLASH_BBT     0x00010000
+/* The hw ecc generator provides a syndrome instead a ecc value on read 
+ * This can only work if we have the ecc bytes directly behind the 
+ * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
+#define NAND_HWECC_SYNDROME    0x00020000
+
+
+/* Options set by nand scan */
+/* Nand scan has allocated oob_buf */
+#define NAND_OOBBUF_ALLOC      0x40000000
+/* Nand scan has allocated data_buf */
+#define NAND_DATABUF_ALLOC     0x80000000
+
+
 /*
+ * nand_state_t - chip states
  * Enumeration for NAND flash chip state
  */
 typedef enum {
@@ -113,71 +208,116 @@ typedef enum {
        FL_READING,
        FL_WRITING,
        FL_ERASING,
-       FL_SYNCING
+       FL_SYNCING,
+       FL_CACHEDPRG,
 } nand_state_t;
 
 
-/*
- * NAND Private Flash Chip Data
- *
- * Structure overview:
- *
- *  IO_ADDR_R - address to read the 8 I/O lines of the flash device 
- *
- *  IO_ADDR_W - address to write the 8 I/O lines of the flash device 
- *
- *  hwcontrol - hardwarespecific function for accesing control-lines
- *
- *  dev_ready - hardwarespecific function for accesing device ready/busy line
- *
- *  waitfunc - hardwarespecific function for wait on ready
- *
- *  calculate_ecc - function for ecc calculation or readback from ecc hardware
- *
- *  correct_data - function for ecc correction, matching to ecc generator (sw/hw)
- *
- *  enable_hwecc - function to enable (reset) hardware ecc generator
- *
- *  eccmod - mode of ecc: see constants
- *
- *  eccsize - databytes used per ecc-calculation
- *
- *  chip_delay - chip dependent delay for transfering data from array to read regs (tR)
- *
- *  chip_lock - spinlock used to protect access to this structure
- *
- *  wq - wait queue to sleep on if a NAND operation is in progress
- *
- *  state - give the current state of the NAND device
- *
- *  page_shift - number of address bits in a page (column address bits)
- *
- *  data_buf - data buffer passed to/from MTD user modules
- *
- *  data_cache - data cache for redundant page access and shadow for
- *              ECC failure
- *
- *  cache_page - number of last valid page in page_cache 
+/**
+ * struct nand_chip - NAND Private Flash Chip Data
+ * @IO_ADDR_R:         [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device 
+ * @IO_ADDR_W:         [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device 
+ * @read_byte:         [REPLACEABLE] read one byte from the chip
+ * @write_byte:                [REPLACEABLE] write one byte to the chip
+ * @read_word:         [REPLACEABLE] read one word from the chip
+ * @write_word:                [REPLACEABLE] write one word to the chip
+ * @write_buf:         [REPLACEABLE] write data from the buffer to the chip
+ * @read_buf:          [REPLACEABLE] read data from the chip into the buffer
+ * @verify_buf:                [REPLACEABLE] verify buffer contents against the chip data
+ * @select_chip:       [REPLACEABLE] select chip nr
+ * @block_bad:         [REPLACEABLE] check, if the block is bad
+ * @block_markbad:     [REPLACEABLE] mark the block bad
+ * @hwcontrol:         [BOARDSPECIFIC] hardwarespecific function for accesing control-lines
+ * @dev_ready:         [BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line
+ *                     If set to NULL no access to ready/busy is available and the ready/busy information
+ *                     is read from the chip status register
+ * @cmdfunc:           [REPLACEABLE] hardwarespecific function for writing commands to the chip
+ * @waitfunc:          [REPLACEABLE] hardwarespecific function for wait on ready
+ * @calculate_ecc:     [REPLACEABLE] function for ecc calculation or readback from ecc hardware
+ * @correct_data:      [REPLACEABLE] function for ecc correction, matching to ecc generator (sw/hw)
+ * @enable_hwecc:      [BOARDSPECIFIC] function to enable (reset) hardware ecc generator. Must only
+ *                     be provided if a hardware ECC is available
+ * @erase_cmd:         [INTERN] erase command write function, selectable due to AND support
+ * @scan_bbt:          [REPLACEABLE] function to scan bad block table
+ * @eccmode:           [BOARDSPECIFIC] mode of ecc, see defines 
+ * @eccsize:           [INTERN] databytes used per ecc-calculation
+ * @eccsteps:          [INTERN] number of ecc calculation steps per page
+ * @chip_delay:                [BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR)
+ * @chip_lock:         [INTERN] spinlock used to protect access to this structure and the chip
+ * @wq:                        [INTERN] wait queue to sleep on if a NAND operation is in progress
+ * @state:             [INTERN] the current state of the NAND device
+ * @page_shift:                [INTERN] number of address bits in a page (column address bits)
+ * @phys_erase_shift:  [INTERN] number of address bits in a physical eraseblock
+ * @bbt_erase_shift:   [INTERN] number of address bits in a bbt entry
+ * @chip_shift:                [INTERN] number of address bits in one chip
+ * @data_buf:          [INTERN] internal buffer for one page + oob 
+ * @oob_buf:           [INTERN] oob buffer for one eraseblock
+ * @oobdirty:          [INTERN] indicates that oob_buf must be reinitialized
+ * @data_poi:          [INTERN] pointer to a data buffer
+ * @options:           [BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about
+ *                     special functionality. See the defines for further explanation
+ * @badblockpos:       [INTERN] position of the bad block marker in the oob area
+ * @numchips:          [INTERN] number of physical chips
+ * @chipsize:          [INTERN] the size of one chip for multichip arrays
+ * @pagemask:          [INTERN] page number mask = number of (pages / chip) - 1
+ * @pagebuf:           [INTERN] holds the pagenumber which is currently in data_buf
+ * @autooob:           [REPLACEABLE] the default (auto)placement scheme
+ * @bbt:               [INTERN] bad block table pointer
+ * @bbt_td:            [REPLACEABLE] bad block table descriptor for flash lookup
+ * @bbt_md:            [REPLACEABLE] bad block table mirror descriptor
+ * @priv:              [OPTIONAL] pointer to private chip date
  */
 struct nand_chip {
        unsigned long   IO_ADDR_R;
        unsigned long   IO_ADDR_W;
-       void            (*hwcontrol)(int cmd);
-       int             (*dev_ready)(void);
+       
+       u_char          (*read_byte)(struct mtd_info *mtd);
+       void            (*write_byte)(struct mtd_info *mtd, u_char byte);
+       u16             (*read_word)(struct mtd_info *mtd);
+       void            (*write_word)(struct mtd_info *mtd, u16 word);
+       
+       void            (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len);
+       void            (*read_buf)(struct mtd_info *mtd, u_char *buf, int len);
+       int             (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len);
+       void            (*select_chip)(struct mtd_info *mtd, int chip);
+       int             (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip);
+       int             (*block_markbad)(struct mtd_info *mtd, loff_t ofs);
+       void            (*hwcontrol)(struct mtd_info *mtd, int cmd);
+       int             (*dev_ready)(struct mtd_info *mtd);
        void            (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
        int             (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
-       void            (*calculate_ecc)(const u_char *dat, u_char *ecc_code);
-       int             (*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-       void            (*enable_hwecc)(int mode);
+       int             (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
+       int             (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+       void            (*enable_hwecc)(struct mtd_info *mtd, int mode);
+       void            (*erase_cmd)(struct mtd_info *mtd, int page);
+       int             (*scan_bbt)(struct mtd_info *mtd);
        int             eccmode;
        int             eccsize;
+       int             eccsteps;
        int             chip_delay;
-       spinlock_t      chip_lock;
+       spinlock_t      chip_lock;
        wait_queue_head_t wq;
        nand_state_t    state;
        int             page_shift;
+       int             phys_erase_shift;
+       int             bbt_erase_shift;
+       int             chip_shift;
        u_char          *data_buf;
+       u_char          *oob_buf;
+       int             oobdirty;
        u_char          *data_poi;
+       unsigned int    options;
+       int             badblockpos;
+       int             numchips;
+       unsigned long   chipsize;
+       int             pagemask;
+       int             pagebuf;
+       struct nand_oobinfo     *autooob;
+       uint8_t         *bbt;
+       struct nand_bbt_descr   *bbt_td;
+       struct nand_bbt_descr   *bbt_md;
+       void            *priv;
 };
 
 /*
@@ -187,46 +327,35 @@ struct nand_chip {
 #define NAND_MFR_SAMSUNG       0xec
 #define NAND_MFR_FUJITSU       0x04
 #define NAND_MFR_NATIONAL      0x8f
+#define NAND_MFR_RENESAS       0x07
+#define NAND_MFR_STMICRO       0x20
 
-/*
- * NAND Flash Device ID Structure
- *
- * Structure overview:
- *
- *  name - Identify the device type
- *
- *  id -  device ID code
- *
- *  chipshift - total number of address bits for the device which
- *              is used to calculate address offsets and the total
- *              number of bytes the device is capable of.
- *
- *  page256 - denotes if flash device has 256 byte pages or not.
- *
- *  pageadrlen - number of bytes minus one needed to hold the
- *               complete address into the flash array. Keep in
- *               mind that when a read or write is done to a
- *               specific address, the address is input serially
- *               8 bits at a time. This structure member is used
- *               by the read/write routines as a loop index for
- *               shifting the address out 8 bits at a time.
- *
- *  erasesize - size of an erase block in the flash device.
+/**
+ * struct nand_flash_dev - NAND Flash Device ID Structure
+ *
+ * @name:      Identify the device type
+ * @id:        device ID code
+ * @pagesize:          Pagesize in bytes. Either 256 or 512 or 0
+ *             If the pagesize is 0, then the real pagesize 
+ *             and the eraseize are determined from the
+ *             extended id bytes in the chip
+ * @erasesize:         Size of an erase block in the flash device.
+ * @chipsize:          Total chipsize in Mega Bytes
+ * @options:   Bitfield to store chip relevant options
  */
 struct nand_flash_dev {
-       char * name;
+       char *name;
        int id;
-       int chipshift;
+       unsigned long pagesize;
+       unsigned long chipsize;
        unsigned long erasesize;
-       char page256;
+       unsigned long options;
 };
 
-/*
- * NAND Flash Manufacturer ID Structure
- *
- *  name - Manufacturer name
- *
- *  id - manufacturer ID code of device.
+/**
+ * struct nand_manufacturers - NAND Flash Manufacturer ID Structure
+ * @name:      Manufacturer name
+ * @id:        manufacturer ID code of device.
 */
 struct nand_manufacturers {
        int id;
@@ -236,9 +365,85 @@ struct nand_manufacturers {
 extern struct nand_flash_dev nand_flash_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 
+/** 
+ * struct nand_bbt_descr - bad block table descriptor
+ * @options:   options for this descriptor
+ * @pages:     the page(s) where we find the bbt, used with option BBT_ABSPAGE
+ *             when bbt is searched, then we store the found bbts pages here.
+ *             Its an array and supports up to 8 chips now
+ * @offs:      offset of the pattern in the oob area of the page
+ * @veroffs:   offset of the bbt version counter in the oob are of the page
+ * @version:   version read from the bbt page during scan
+ * @len:       length of the pattern, if 0 no pattern check is performed
+ * @maxblocks: maximum number of blocks to search for a bbt. This number of
+ *             blocks is reserved at the end of the device where the tables are 
+ *             written.
+ * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than
+ *              bad) block in the stored bbt
+ * @pattern:   pattern to identify bad block table or factory marked good / 
+ *             bad blocks, can be NULL, if len = 0
+ *
+ * Descriptor for the bad block table marker and the descriptor for the 
+ * pattern which identifies good and bad blocks. The assumption is made
+ * that the pattern and the version count are always located in the oob area
+ * of the first block.
+ */
+struct nand_bbt_descr {
+       int     options;
+       int     pages[NAND_MAX_CHIPS];
+       int     offs;
+       int     veroffs;
+       uint8_t version[NAND_MAX_CHIPS];
+       int     len;
+       int     maxblocks;
+       int     reserved_block_code;
+       uint8_t *pattern;
+};
+
+/* Options for the bad block table descriptors */
+
+/* The number of bits used per block in the bbt on the device */
+#define NAND_BBT_NRBITS_MSK    0x0000000F
+#define NAND_BBT_1BIT          0x00000001
+#define NAND_BBT_2BIT          0x00000002
+#define NAND_BBT_4BIT          0x00000004
+#define NAND_BBT_8BIT          0x00000008
+/* The bad block table is in the last good block of the device */
+#define        NAND_BBT_LASTBLOCK      0x00000010
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_ABSPAGE       0x00000020
+/* The bbt is at the given page, else we must scan for the bbt */
+#define NAND_BBT_SEARCH                0x00000040
+/* bbt is stored per chip on multichip devices */
+#define NAND_BBT_PERCHIP       0x00000080
+/* bbt has a version counter at offset veroffs */
+#define NAND_BBT_VERSION       0x00000100
+/* Create a bbt if none axists */
+#define NAND_BBT_CREATE                0x00000200
+/* Search good / bad pattern through all pages of a block */
+#define NAND_BBT_SCANALLPAGES  0x00000400
+/* Scan block empty during good / bad block scan */
+#define NAND_BBT_SCANEMPTY     0x00000800
+/* Write bbt if neccecary */
+#define NAND_BBT_WRITE         0x00001000
+/* Read and write back block contents when writing bbt */
+#define NAND_BBT_SAVECONTENT   0x00002000
+/* Search good / bad pattern on the first and the second page */
+#define NAND_BBT_SCAN2NDPAGE   0x00004000
+
+/* The maximum number of blocks to scan for a bbt */
+#define NAND_BBT_SCAN_MAXBLOCKS        4
+
+extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd);
+extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
+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);
+
 /*
 * Constants for oob configuration
 */
-#define NAND_BADBLOCK_POS              5
+#define NAND_SMALL_BADBLOCK_POS                5
+#define NAND_LARGE_BADBLOCK_POS                0
 
 #endif /* __LINUX_MTD_NAND_H */
index c3b493c..12c5bc3 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
  *
- * $Id: nand_ecc.h,v 1.2 2003/02/20 13:34:20 sjhill Exp $
+ * $Id: nand_ecc.h,v 1.4 2004/06/17 02:35:02 dbrown 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
  * This file is the header for the ECC algorithm.
  */
 
-/*
- * Creates non-inverted ECC code from line parity
- */
-void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code);
+#ifndef __MTD_NAND_ECC_H__
+#define __MTD_NAND_ECC_H__
+
+struct mtd_info;
 
 /*
  * Calculate 3 byte ECC code for 256 byte block
  */
-void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
+int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
 
 /*
  * Detect and correct a 1 bit error for 256 byte block
  */
-int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+
+#endif /* __MTD_NAND_ECC_H__ */
index fd57ffd..d35d2c2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nftl.h,v 1.13 2003/05/23 11:25:02 dwmw2 Exp $
+ * $Id: nftl.h,v 1.16 2004/06/30 14:49:00 dbrown Exp $
  *
  * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
  */
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/blktrans.h>
 
-/* Block Control Information */
-
-struct nftl_bci {
-       unsigned char ECCSig[6];
-       __u8 Status;
-       __u8 Status1;
-}__attribute__((packed));
-
-/* Unit Control Information */
-
-struct nftl_uci0 {
-       __u16 VirtUnitNum;
-       __u16 ReplUnitNum;
-       __u16 SpareVirtUnitNum;
-       __u16 SpareReplUnitNum;
-} __attribute__((packed));
-
-struct nftl_uci1 {
-       __u32 WearInfo;
-       __u16 EraseMark;
-       __u16 EraseMark1;
-} __attribute__((packed));
-
-struct nftl_uci2 {
-        __u16 FoldMark;
-        __u16 FoldMark1;
-       __u32 unused;
-} __attribute__((packed));
-
-union nftl_uci {
-       struct nftl_uci0 a;
-       struct nftl_uci1 b;
-       struct nftl_uci2 c;
-};
-
-struct nftl_oob {
-       struct nftl_bci b;
-       union nftl_uci u;
-};
-
-/* NFTL Media Header */
-
-struct NFTLMediaHeader {
-       char DataOrgID[6];
-       __u16 NumEraseUnits;
-       __u16 FirstPhysicalEUN;
-       __u32 FormattedSize;
-       unsigned char UnitSizeFactor;
-} __attribute__((packed));
-
-#define MAX_ERASE_ZONES (8192 - 512)
-
-#define ERASE_MARK 0x3c69
-#define SECTOR_FREE 0xff
-#define SECTOR_USED 0x55
-#define SECTOR_IGNORE 0x11
-#define SECTOR_DELETED 0x00
-
-#define FOLD_MARK_IN_PROGRESS 0x5555
-
-#define ZONE_GOOD 0xff
-#define ZONE_BAD_ORIGINAL 0
-#define ZONE_BAD_MARKED 7
-
-#ifdef __KERNEL__
+#include <mtd/nftl-user.h>
 
 /* these info are used in ReplUnitTable */
 #define BLOCK_NIL          0xffff /* last block of a chain */
@@ -101,6 +37,7 @@ struct NFTLrecord {
         unsigned int nb_blocks;                /* number of physical blocks */
         unsigned int nb_boot_blocks;   /* number of blocks used by the bios */
         struct erase_info instr;
+       struct nand_oobinfo oobinfo;
 };
 
 int NFTL_mount(struct NFTLrecord *s);
@@ -114,6 +51,4 @@ int NFTL_formatblock(struct NFTLrecord *s, int block);
 #define MAX_SECTORS_PER_UNIT 64
 #define NFTL_PARTN_BITS 4
 
-#endif /* __KERNEL__ */
-
 #endif /* __MTD_NFTL_H__ */
index 5c5f877..100ea79 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: partitions.h,v 1.14 2003/05/20 21:56:29 dwmw2 Exp $
+ * $Id: partitions.h,v 1.15 2003/07/09 11:15:43 dwmw2 Exp $
  */
 
 #ifndef MTD_PARTITIONS_H
@@ -50,7 +50,7 @@ struct mtd_partition {
 #define MTDPART_SIZ_FULL       (0)
 
 
-int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);
+int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
 int del_mtd_partitions(struct mtd_info *);
 
 /*
index 93f7492..2307f11 100644 (file)
@@ -130,6 +130,13 @@ struct rs_multiport_struct {
  * reason (mips != alpha!)
  */
 #define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
+#elif defined(CONFIG_SBC8560)
+/*
+ * WindRiver did something similarly broken on their SBC8560 board. The
+ * UART tristates its IRQ output while OUT2 is clear, but they pulled
+ * the interrupt line _up_ instead of down, so if we register the IRQ
+ * while the UART is in that state, we die in an IRQ storm. */
+#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
 #else
 #define ALPHA_KLUDGE_MCR 0
 #endif
index 1ad3753..4e57b45 100644 (file)
@@ -86,6 +86,9 @@
 /* PPC CPM type number */
 #define PORT_CPM        58
 
+/* Marvell MPSC for PPC & MIPS */
+#define PORT_MPSC      59
+
 #ifdef __KERNEL__
 
 #include <linux/config.h>
index 58c9b3c..f0e5fc7 100644 (file)
@@ -337,7 +337,6 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long
        struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
        struct page *page = NULL;
        swp_entry_t *entry;
-       static const swp_entry_t unswapped = { 0 };
 
        if (sgp != SGP_WRITE &&
            ((loff_t) index << PAGE_CACHE_SHIFT) >= i_size_read(inode))
@@ -345,7 +344,7 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long
 
        while (!(entry = shmem_swp_entry(info, index, &page))) {
                if (sgp == SGP_READ)
-                       return (swp_entry_t *) &unswapped;
+                       return shmem_swp_map(ZERO_PAGE(0));
                /*
                 * Test free_blocks against 1 not 0, since we have 1 data
                 * page (and perhaps indirect index pages) yet to allocate: