Merge to Fedora kernel-2.6.7-1.494 and VServer 1.9.1.12. Fix some previous merge...
authorMark Huang <mlhuang@cs.princeton.edu>
Fri, 30 Jul 2004 14:12:45 +0000 (14:12 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Fri, 30 Jul 2004 14:12:45 +0000 (14:12 +0000)
262 files changed:
CREDITS
Documentation/vm/hugetlbpage.txt
Makefile
arch/alpha/kernel/entry.S
arch/alpha/kernel/process.c
arch/alpha/kernel/signal.c
arch/ia64/kernel/entry.S
arch/ia64/mm/fault.c
arch/mips/kernel/syscall.c
arch/mips/kernel/sysirix.c
arch/ppc/Kconfig
arch/ppc/boot/common/misc-common.c
arch/ppc/boot/simple/Makefile
arch/ppc/boot/simple/gt64260_tty.c [deleted file]
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/kernel/syscalls.c
arch/ppc/platforms/Makefile
arch/ppc/platforms/ev64260.h
arch/ppc/platforms/ev64260_setup.c [deleted file]
arch/ppc/syslib/Makefile
arch/ppc/syslib/gt64260_pic.c
arch/ppc/syslib/open_pic.c
arch/ppc64/kernel/sys_ppc32.c
arch/sparc/kernel/sys_sparc.c
arch/sparc64/kernel/sys_sparc.c
arch/um/drivers/stdio_console.c
arch/um/include/sysdep-i386/checksum.h
arch/um/kernel/syscall_kern.c
arch/um/sys-i386/Makefile
arch/x86_64/ia32/ia32entry.S
arch/x86_64/ia32/sys_ia32.c
arch/x86_64/kernel/sys_x86_64.c
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/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.c [deleted file]
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/Makefile
fs/attr.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/exec.c
fs/ext2/balloc.c
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/xattr.c
fs/ext3/balloc.c
fs/ext3/ialloc.c
fs/ext3/inode.c
fs/ext3/ioctl.c
fs/ext3/super.c
fs/ext3/xattr.c
fs/inode.c
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
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/nfs3xdr.c
fs/nfs/nfsroot.c
fs/nfs/proc.c
fs/nfsd/auth.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsxdr.c
fs/nfsd/vfs.c
fs/open.c
fs/proc/array.c
fs/proc/base.c
fs/reiserfs/super.c
fs/stat.c
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/linux-2.6/xfs_vnode.c
include/asm-generic/tlb.h
include/asm-ppc/gt64260.h [deleted file]
include/asm-ppc/gt64260_defs.h [deleted file]
include/asm-ppc/ocp_ids.h
include/asm-ppc/serial.h
include/asm-um/mmu_context.h
include/asm-x86_64/unistd.h
include/linux/binfmts.h
include/linux/cpumask.h
include/linux/ext3_fs.h
include/linux/fs.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/nfs_mount.h
include/linux/ninline.h [deleted file]
include/linux/reiserfs_fs_sb.h
include/linux/serialP.h
include/linux/serial_core.h
include/linux/stat.h
include/linux/tcp.h
include/linux/vinline.h [deleted file]
include/net/route.h
include/net/sock.h
init/Kconfig
init/main.c
ipc/util.c
kernel/exit.c
kernel/fork.c
kernel/sched.c
kernel/sys.c
kernel/vserver/context.c
kernel/vserver/dlimit.c
kernel/vserver/network.c
mm/memory.c
mm/mlock.c
mm/mmap.c
mm/mremap.c
mm/shmem.c
mm/swapfile.c
net/core/dev.c
net/core/sock.c
net/ipv4/af_inet.c
net/ipv4/icmp.c
net/ipv4/raw.c
net/ipv4/tcp.c
net/ipv4/tcp_minisocks.c
net/sunrpc/auth.c
net/sunrpc/auth_unix.c
net/unix/af_unix.c
scripts/reference_init.pl

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 47a7121..61ae09f 100644 (file)
@@ -91,12 +91,9 @@ A regular chown, chgrp and chmod commands (with right permissions) could be
 used to change the file attributes on hugetlbfs.
 
 Also, it is important to note that no such mount command is required if the
-applications are going to use only shmat/shmget system calls.  Users who
-wish to use hugetlb page via shared memory segment should be a member of
-a supplementary group and system admin needs to configure that gid into
-/proc/sys/vm/hugetlb_shm_group.  It is possible for same or different
-applications to use any combination of mmaps and shm* calls.  Though the
-mount of filesystem will be required for using mmaps.
+applications are going to use only shmat/shmget system calls.  It is possible
+for same or different applications to use any combination of mmaps and shm*
+calls.  Though the mount of filesystem will be required for using mmaps.
 
 /* Example of using hugepage in user application using Sys V shared memory
  * system calls.  In this example, app is requesting memory of size 256MB that
index 6d0ffee..824a4db 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 7
-EXTRAVERSION = -1.492-ckrm.E15-vs1.9.1
+EXTRAVERSION = -1.494-ckrm.E15-vs1.9.1.12
 NAME=Zonked Quokka
 
 # *DOCUMENTATION*
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 52576c3..0b24641 100644 (file)
@@ -1526,7 +1526,7 @@ sys_call_table:
        data8 sys_mq_notify
        data8 sys_mq_getsetattr
        data8 sys_ni_syscall                    // reserved for kexec_load
-       data8 sys_ni_syscall
+       data8 sys_vserver
        data8 sys_ni_syscall                    // 1270
        data8 sys_ni_syscall
        data8 sys_ni_syscall
index 20d11f4..8e63f14 100644 (file)
@@ -34,9 +34,12 @@ expand_backing_store (struct vm_area_struct *vma, unsigned long address)
 
        grow = PAGE_SIZE >> PAGE_SHIFT;
        if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur
-           || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur))
+           || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) >
+               current->rlim[RLIMIT_AS].rlim_cur))
                return -ENOMEM;
-       if (!vx_vmpages_avail(vma->vm_mm, grow)
+       if (!vx_vmpages_avail(vma->vm_mm, grow) ||
+               ((vma->vm_flags & VM_LOCKED) &&
+               !vx_vmlocked_avail(vma->vm_mm, grow)))
                return -ENOMEM;
        vma->vm_end += PAGE_SIZE;
        // vma->vm_mm->total_vm += grow;
index f996749..8cc462d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
+#include <linux/vs_cvirt.h>
 
 #include <asm/branch.h>
 #include <asm/cachectl.h>
index 8a0a046..e82b61f 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/socket.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/vs_cvirt.h>
 
 #include <asm/ptrace.h>
 #include <asm/page.h>
index da5c9e5..b95d133 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)
diff --git a/arch/ppc/boot/simple/gt64260_tty.c b/arch/ppc/boot/simple/gt64260_tty.c
deleted file mode 100644 (file)
index e5d1483..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * arch/ppc/boot/simple/gt64260_tty.c
- *
- * Bootloader version of the embedded MPSC/UART driver for the GT64260[A].
- * Note: Due to 64260A errata, DMA will be used for UART input (via SDMA).
- *
- * Author: Mark A. 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.
- */
-
-/* This code assumes that the data cache has been disabled (L1, L2, L3). */
-
-#include <linux/config.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <asm/serial.h>
-#include <asm/gt64260_defs.h>
-
-extern void udelay(long);
-static void stop_dma(int chan);
-
-static u32     gt64260_base = EV64260_BRIDGE_REG_BASE; /* base addr of 64260 */
-
-inline unsigned
-gt64260_in_le32(volatile unsigned *addr)
-{
-       unsigned ret;
-
-       __asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
-                                    "r" (addr), "m" (*addr));
-       return ret;
-}
-
-inline void
-gt64260_out_le32(volatile unsigned *addr, int val)
-{
-       __asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
-                                    "r" (val), "r" (addr));
-}
-
-#define GT64260_REG_READ(offs)                                         \
-       (gt64260_in_le32((volatile uint *)(gt64260_base + (offs))))
-#define GT64260_REG_WRITE(offs, d)                                     \
-        (gt64260_out_le32((volatile uint *)(gt64260_base + (offs)), (int)(d)))
-
-
-static struct {
-       u32     sdc;
-       u32     sdcm;
-       u32     rx_desc;
-       u32     rx_buf_ptr;
-       u32     scrdp;
-       u32     tx_desc;
-       u32     sctdp;
-       u32     sftdp;
-} sdma_regs;
-
-#define        SDMA_REGS_INIT(chan) {                                          \
-       sdma_regs.sdc        = GT64260_SDMA_##chan##_SDC;               \
-       sdma_regs.sdcm       = GT64260_SDMA_##chan##_SDCM;              \
-       sdma_regs.rx_desc    = GT64260_SDMA_##chan##_RX_DESC;           \
-       sdma_regs.rx_buf_ptr = GT64260_SDMA_##chan##_RX_BUF_PTR;        \
-       sdma_regs.scrdp      = GT64260_SDMA_##chan##_SCRDP;             \
-       sdma_regs.tx_desc    = GT64260_SDMA_##chan##_TX_DESC;           \
-       sdma_regs.sctdp      = GT64260_SDMA_##chan##_SCTDP;             \
-       sdma_regs.sftdp      = GT64260_SDMA_##chan##_SFTDP;             \
-}
-
-typedef struct {
-       volatile u16 bufsize;
-       volatile u16 bytecnt;
-       volatile u32 cmd_stat;
-       volatile u32 next_desc_ptr;
-       volatile u32 buffer;
-} gt64260_rx_desc_t;
-
-typedef struct {
-       volatile u16 bytecnt;
-       volatile u16 shadow;
-       volatile u32 cmd_stat;
-       volatile u32 next_desc_ptr;
-       volatile u32 buffer;
-} gt64260_tx_desc_t;
-
-#define        MAX_RESET_WAIT  10000
-#define        MAX_TX_WAIT     10000
-
-#define        RX_NUM_DESC     2
-#define        TX_NUM_DESC     2
-
-#define        RX_BUF_SIZE     16
-#define        TX_BUF_SIZE     16
-
-static gt64260_rx_desc_t rd[RX_NUM_DESC] __attribute__ ((aligned(32)));
-static gt64260_tx_desc_t td[TX_NUM_DESC] __attribute__ ((aligned(32)));
-
-static char rx_buf[RX_NUM_DESC * RX_BUF_SIZE] __attribute__ ((aligned(32)));
-static char tx_buf[TX_NUM_DESC * TX_BUF_SIZE] __attribute__ ((aligned(32)));
-
-static int cur_rd = 0;
-static int cur_td = 0;
-
-
-#define        RX_INIT_RDP(rdp) {                                              \
-       (rdp)->bufsize = 2;                                             \
-       (rdp)->bytecnt = 0;                                             \
-       (rdp)->cmd_stat = GT64260_SDMA_DESC_CMDSTAT_L |                 \
-                         GT64260_SDMA_DESC_CMDSTAT_F |                 \
-                         GT64260_SDMA_DESC_CMDSTAT_O;                  \
-}
-
-unsigned long
-serial_init(int chan, void *ignored)
-{
-       u32     mpsc_adjust, sdma_adjust, brg_bcr;
-       int     i;
-
-       stop_dma(0);
-       stop_dma(1);
-
-       if (chan != 1) {
-               chan = 0;  /* default to chan 0 if anything but 1 */
-               mpsc_adjust = 0;
-               sdma_adjust = 0;
-               brg_bcr = GT64260_BRG_0_BCR;
-               SDMA_REGS_INIT(0);
-       }
-       else {
-               mpsc_adjust = 0x1000;
-               sdma_adjust = 0x2000;
-               brg_bcr = GT64260_BRG_1_BCR;
-               SDMA_REGS_INIT(1);
-       }
-
-       /* Set up ring buffers */
-       for (i=0; i<RX_NUM_DESC; i++) {
-               RX_INIT_RDP(&rd[i]);
-               rd[i].buffer = (u32)&rx_buf[i * RX_BUF_SIZE];
-               rd[i].next_desc_ptr = (u32)&rd[i+1];
-       }
-       rd[RX_NUM_DESC - 1].next_desc_ptr = (u32)&rd[0];
-
-       for (i=0; i<TX_NUM_DESC; i++) {
-               td[i].bytecnt = 0;
-               td[i].shadow = 0;
-               td[i].buffer = (u32)&tx_buf[i * TX_BUF_SIZE];
-               td[i].cmd_stat = GT64260_SDMA_DESC_CMDSTAT_F |
-                                GT64260_SDMA_DESC_CMDSTAT_L;
-               td[i].next_desc_ptr = (u32)&td[i+1];
-       }
-       td[TX_NUM_DESC - 1].next_desc_ptr = (u32)&td[0];
-
-       /* Set MPSC Routing */
-        GT64260_REG_WRITE(GT64260_MPSC_MRR, 0x3ffffe38);
-        GT64260_REG_WRITE(GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
-
-       /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */
-        GT64260_REG_WRITE(GT64260_MPSC_RCRR, 0x00000100);
-        GT64260_REG_WRITE(GT64260_MPSC_TCRR, 0x00000100);
-
-       /* clear pending interrupts */
-        GT64260_REG_WRITE(GT64260_SDMA_INTR_MASK, 0);
-
-       GT64260_REG_WRITE(GT64260_SDMA_0_SCRDP + sdma_adjust, &rd[0]);
-       GT64260_REG_WRITE(GT64260_SDMA_0_SCTDP + sdma_adjust,
-               &td[TX_NUM_DESC - 1]);
-       GT64260_REG_WRITE(GT64260_SDMA_0_SFTDP + sdma_adjust,
-               &td[TX_NUM_DESC - 1]);
-
-       GT64260_REG_WRITE(GT64260_SDMA_0_SDC + sdma_adjust,
-                         GT64260_SDMA_SDC_RFT | GT64260_SDMA_SDC_SFM |
-                         GT64260_SDMA_SDC_BLMR | GT64260_SDMA_SDC_BLMT |
-                         (3 << 12));
-
-       /* Set BRG to generate proper baud rate */
-       GT64260_REG_WRITE(brg_bcr, ((8 << 18) | (1 << 16) | 36));
-
-       /* Put MPSC into UART mode, no null modem, 16x clock mode */
-       GT64260_REG_WRITE(GT64260_MPSC_0_MMCRL + mpsc_adjust, 0x000004c4);
-       GT64260_REG_WRITE(GT64260_MPSC_0_MMCRH + mpsc_adjust, 0x04400400);
-
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_1 + mpsc_adjust, 0);
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_9 + mpsc_adjust, 0);
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_10 + mpsc_adjust, 0);
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_3 + mpsc_adjust, 4);
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_4 + mpsc_adjust, 0);
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_5 + mpsc_adjust, 0);
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_6 + mpsc_adjust, 0);
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_7 + mpsc_adjust, 0);
-        GT64260_REG_WRITE(GT64260_MPSC_0_CHR_8 + mpsc_adjust, 0);
-
-       /* 8 data bits, 1 stop bit */
-       GT64260_REG_WRITE(GT64260_MPSC_0_MPCR + mpsc_adjust, (3 << 12));
-
-       GT64260_REG_WRITE(GT64260_SDMA_0_SDCM + sdma_adjust,
-               GT64260_SDMA_SDCM_ERD);
-
-       GT64260_REG_WRITE(GT64260_MPSC_0_CHR_2 + sdma_adjust,
-               GT64260_MPSC_UART_CR_EH);
-
-       udelay(100);
-
-       return (ulong)chan;
-}
-
-static void
-stop_dma(int chan)
-{
-       u32     sdma_sdcm = GT64260_SDMA_0_SDCM;
-       int     i;
-
-       if (chan == 1) {
-               sdma_sdcm = GT64260_SDMA_1_SDCM;
-       }
-
-       /* Abort SDMA Rx, Tx */
-       GT64260_REG_WRITE(sdma_sdcm,
-               GT64260_SDMA_SDCM_AR | GT64260_SDMA_SDCM_STD);
-
-       for (i=0; i<MAX_RESET_WAIT; i++) {
-               if ((GT64260_REG_READ(sdma_sdcm) & (GT64260_SDMA_SDCM_AR |
-                                       GT64260_SDMA_SDCM_AT)) == 0) break;
-               udelay(100);
-       }
-
-       return;
-}
-
-static int
-wait_for_ownership(void)
-{
-       int     i;
-
-       for (i=0; i<MAX_TX_WAIT; i++) {
-               if ((GT64260_REG_READ(sdma_regs.sdcm) &
-                                       GT64260_SDMA_SDCM_TXD) == 0) break;
-               udelay(1000);
-       }
-
-       return (i < MAX_TX_WAIT);
-}
-
-void
-serial_putc(unsigned long com_port, unsigned char c)
-{
-       gt64260_tx_desc_t       *tdp;
-
-       if (wait_for_ownership() == 0) return;
-
-       tdp = &td[cur_td];
-       if (++cur_td >= TX_NUM_DESC) cur_td = 0;
-
-       *(unchar *)(tdp->buffer ^ 7) = c;
-       tdp->bytecnt = 1;
-       tdp->shadow = 1;
-       tdp->cmd_stat = GT64260_SDMA_DESC_CMDSTAT_L |
-               GT64260_SDMA_DESC_CMDSTAT_F | GT64260_SDMA_DESC_CMDSTAT_O;
-
-       GT64260_REG_WRITE(sdma_regs.sctdp, tdp);
-       GT64260_REG_WRITE(sdma_regs.sftdp, tdp);
-       GT64260_REG_WRITE(sdma_regs.sdcm,
-               GT64260_REG_READ(sdma_regs.sdcm) | GT64260_SDMA_SDCM_TXD);
-
-       return;
-}
-
-unsigned char
-serial_getc(unsigned long com_port)
-{
-       gt64260_rx_desc_t       *rdp;
-       unchar                  c = '\0';
-
-       rdp = &rd[cur_rd];
-
-       if ((rdp->cmd_stat & (GT64260_SDMA_DESC_CMDSTAT_O |
-                             GT64260_SDMA_DESC_CMDSTAT_ES)) == 0) {
-               c = *(unchar *)(rdp->buffer ^ 7);
-               RX_INIT_RDP(rdp);
-               if (++cur_rd >= RX_NUM_DESC) cur_rd = 0;
-       }
-
-       return c;
-}
-
-int
-serial_tstc(unsigned long com_port)
-{
-       gt64260_rx_desc_t       *rdp;
-       int                     loop_count = 0;
-       int                     rc = 0;
-
-       rdp = &rd[cur_rd];
-
-       /* Go thru rcv desc's until empty looking for one with data (no error)*/
-       while (((rdp->cmd_stat & GT64260_SDMA_DESC_CMDSTAT_O) == 0) &&
-              (loop_count++ < RX_NUM_DESC)) {
-
-               /* If there was an error, reinit the desc & continue */
-               if ((rdp->cmd_stat & GT64260_SDMA_DESC_CMDSTAT_ES) != 0) {
-                       RX_INIT_RDP(rdp);
-                       if (++cur_rd >= RX_NUM_DESC) cur_rd = 0;
-                       rdp = (gt64260_rx_desc_t *)rdp->next_desc_ptr;
-               }
-               else {
-                       rc = 1;
-                       break;
-               }
-       }
-
-       return rc;
-}
-
-void
-serial_close(unsigned long com_port)
-{
-       stop_dma(com_port);
-       return;
-}
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 d33e635..cbc9596 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/utsname.h>
 #include <linux/file.h>
 #include <linux/unistd.h>
+#include <linux/vs_cvirt.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
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 */
diff --git a/arch/ppc/platforms/ev64260_setup.c b/arch/ppc/platforms/ev64260_setup.c
deleted file mode 100644 (file)
index a5b75f5..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * arch/ppc/platforms/ev64260_setup.c
- *
- * Board setup routines for the Marvell/Galileo EV-64260-BP Evaluation Board.
- *
- * Author: Mark A. 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.
- */
-
-/*
- * The EV-64260-BP port is the result of hard work from many people from
- * many companies.  In particular, employees of Marvell/Galileo, Mission
- * Critical Linux, Xyterra, and MontaVista Software were heavily involved.
- */
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/ide.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-#if    !defined(CONFIG_GT64260_CONSOLE)
-#include <linux/serial.h>
-#endif
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/time.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/smp.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-#include <asm/gt64260.h>
-#include <platforms/ev64260.h>
-
-
-extern char cmd_line[];
-unsigned long ev64260_find_end_of_memory(void);
-
-TODC_ALLOC();
-
-/*
- * Marvell/Galileo EV-64260-BP Evaluation Board PCI interrupt routing.
- */
-static int __init
-ev64260_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-       struct pci_controller   *hose = pci_bus_to_hose(dev->bus->number);
-
-       if (hose->index == 0) {
-               static char pci_irq_table[][4] =
-               /*
-                *      PCI IDSEL/INTPIN->INTLINE
-                *         A   B   C   D
-                */
-               {
-                       { 91, 0, 0, 0 },        /* IDSEL 7 - PCI bus 0 */
-                       { 91, 0, 0, 0 },        /* IDSEL 8 - PCI bus 0 */
-               };
-
-               const long min_idsel = 7, max_idsel = 8, irqs_per_slot = 4;
-               return PCI_IRQ_TABLE_LOOKUP;
-       }
-       else {
-               static char pci_irq_table[][4] =
-               /*
-                *      PCI IDSEL/INTPIN->INTLINE
-                *         A   B   C   D
-                */
-               {
-                       { 93, 0, 0, 0 },        /* IDSEL 7 - PCI bus 1 */
-                       { 93, 0, 0, 0 },        /* IDSEL 8 - PCI bus 1 */
-               };
-
-               const long min_idsel = 7, max_idsel = 8, irqs_per_slot = 4;
-               return PCI_IRQ_TABLE_LOOKUP;
-       }
-}
-
-static void __init
-ev64260_setup_bridge(void)
-{
-       gt64260_bridge_info_t           info;
-       int                             window;
-
-       GT64260_BRIDGE_INFO_DEFAULT(&info, ev64260_find_end_of_memory());
-
-       /* Lookup PCI host bridges */
-       if (gt64260_find_bridges(EV64260_BRIDGE_REG_BASE,
-                                &info,
-                                ev64260_map_irq)) {
-               printk("Bridge initialization failed.\n");
-       }
-
-       /*
-        * Enabling of PCI internal-vs-external arbitration
-        * is a platform- and errata-dependent decision.
-        */
-       if(gt64260_revision == GT64260)  {
-               /* FEr#35 */
-               gt_clr_bits(GT64260_PCI_0_ARBITER_CNTL, (1<<31));
-               gt_clr_bits(GT64260_PCI_1_ARBITER_CNTL, (1<<31));
-       } else if( gt64260_revision == GT64260A )  {
-               gt_set_bits(GT64260_PCI_0_ARBITER_CNTL, (1<<31));
-               gt_set_bits(GT64260_PCI_1_ARBITER_CNTL, (1<<31));
-               /* Make external GPP interrupts level sensitive */
-               gt_set_bits(GT64260_COMM_ARBITER_CNTL, (1<<10));
-               /* Doc Change 9: > 100 MHz so must be set */
-               gt_set_bits(GT64260_CPU_CONFIG, (1<<23));
-       }
-
-       gt_set_bits(GT64260_CPU_MASTER_CNTL, (1<<9)); /* Only 1 cpu */
-
-       /* SCS windows not disabled above, disable all but SCS 0 */
-       for (window=1; window<GT64260_CPU_SCS_DECODE_WINDOWS; window++) {
-               gt64260_cpu_scs_set_window(window, 0, 0);
-       }
-
-       /* Set up windows to RTC/TODC and DUART on device module (CS 1 & 2) */
-       gt64260_cpu_cs_set_window(1, EV64260_TODC_BASE, EV64260_TODC_LEN);
-       gt64260_cpu_cs_set_window(2, EV64260_UART_BASE, EV64260_UART_LEN);
-
-       /*
-        * The EV-64260-BP uses several Multi-Purpose Pins (MPP) on the 64260
-        * bridge as interrupt inputs (via the General Purpose Ports (GPP)
-        * register).  Need to route the MPP inputs to the GPP and set the
-        * polarity correctly.
-        *
-        * In MPP Control 2 Register
-        *   MPP 21 -> GPP 21 (DUART channel A intr)
-        *   MPP 22 -> GPP 22 (DUART channel B intr)
-        *
-        * In MPP Control 3 Register
-        *   MPP 27 -> GPP 27 (PCI 0 INTA)
-        *   MPP 29 -> GPP 29 (PCI 1 INTA)
-        */
-       gt_clr_bits(GT64260_MPP_CNTL_2,
-                              ((1<<20) | (1<<21) | (1<<22) | (1<<23) |
-                               (1<<24) | (1<<25) | (1<<26) | (1<<27)));
-
-       gt_clr_bits(GT64260_MPP_CNTL_3,
-                              ((1<<12) | (1<<13) | (1<<14) | (1<<15) |
-                               (1<<20) | (1<<21) | (1<<22) | (1<<23)));
-
-       gt_write(GT64260_GPP_LEVEL_CNTL, 0x000002c6);
-
-       /* DUART & PCI interrupts are active low */
-       gt_set_bits(GT64260_GPP_LEVEL_CNTL,
-                            ((1<<21) | (1<<22) | (1<<27) | (1<<29)));
-
-       /* Clear any pending interrupts for these inputs and enable them. */
-       gt_write(GT64260_GPP_INTR_CAUSE,
-                         ~((1<<21) | (1<<22) | (1<<27) | (1<<29)));
-       gt_set_bits(GT64260_GPP_INTR_MASK,
-                            ((1<<21) | (1<<22)| (1<<27) | (1<<29)));
-       gt_set_bits(GT64260_IC_CPU_INTR_MASK_HI, ((1<<26) | (1<<27)));
-
-       /* Set MPSC Multiplex RMII */
-       /* NOTE: ethernet driver modifies bit 0 and 1 */
-       gt_write(GT64260_MPP_SERIAL_PORTS_MULTIPLEX, 0x00001102);
-
-       return;
-}
-
-
-static void __init
-ev64260_setup_arch(void)
-{
-#if    !defined(CONFIG_GT64260_CONSOLE)
-       struct serial_struct    serial_req;
-#endif
-
-       if ( ppc_md.progress )
-               ppc_md.progress("ev64260_setup_arch: enter", 0);
-
-       loops_per_jiffy = 50000000 / HZ;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start)
-               ROOT_DEV = Root_RAM0;
-       else
-#endif
-#ifdef CONFIG_ROOT_NFS
-               ROOT_DEV = Root_NFS;
-#else
-               ROOT_DEV = Root_SDA2;
-#endif
-
-       if ( ppc_md.progress )
-               ppc_md.progress("ev64260_setup_arch: find_bridges", 0);
-
-       /*
-        * Set up the L2CR register.
-        * L2 cache was invalidated by bootloader.
-        */
-       switch (PVR_VER(mfspr(PVR))) {
-               case PVR_VER(PVR_750):
-                       _set_L2CR(0xfd100000);
-                       break;
-               case PVR_VER(PVR_7400):
-               case PVR_VER(PVR_7410):
-                       _set_L2CR(0xcd100000);
-                       break;
-               /* case PVR_VER(PVR_7450): */
-                       /* XXXX WHAT VALUE?? FIXME */
-                       break;
-       }
-
-       ev64260_setup_bridge();
-
-       TODC_INIT(TODC_TYPE_DS1501, 0, 0, ioremap(EV64260_TODC_BASE,0x20), 8);
-
-#if    !defined(CONFIG_GT64260_CONSOLE)
-       memset(&serial_req, 0, sizeof(serial_req));
-       serial_req.line = 0;
-       serial_req.baud_base = BASE_BAUD;
-       serial_req.port = 0;
-       serial_req.irq = 85;
-       serial_req.flags = STD_COM_FLAGS;
-       serial_req.io_type = SERIAL_IO_MEM;
-       serial_req.iomem_base = ioremap(EV64260_SERIAL_0, 0x20);
-       serial_req.iomem_reg_shift = 2;
-
-       if (early_serial_setup(&serial_req) != 0) {
-               printk("Early serial init of port 0 failed\n");
-       }
-
-       /* Assume early_serial_setup() doesn't modify serial_req */
-       serial_req.line = 1;
-       serial_req.port = 1;
-       serial_req.irq = 86;
-       serial_req.iomem_base = ioremap(EV64260_SERIAL_1, 0x20);
-
-       if (early_serial_setup(&serial_req) != 0) {
-               printk("Early serial init of port 1 failed\n");
-       }
-#endif
-
-       printk("Marvell/Galileo EV-64260-BP Evaluation Board\n");
-       printk("EV-64260-BP port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
-
-       if ( ppc_md.progress )
-               ppc_md.progress("ev64260_setup_arch: exit", 0);
-
-       return;
-}
-
-static void __init
-ev64260_init_irq(void)
-{
-       gt64260_init_irq();
-
-       if(gt64260_revision != GT64260)  {
-               /* XXXX Kludge--need to fix gt64260_init_irq() interface */
-               /* Mark PCI intrs level sensitive */
-               irq_desc[91].status |= IRQ_LEVEL;
-               irq_desc[93].status |= IRQ_LEVEL;
-       }
-}
-
-unsigned long __init
-ev64260_find_end_of_memory(void)
-{
-       return 32*1024*1024;    /* XXXX FIXME */
-}
-
-static void
-ev64260_reset_board(void)
-{
-       local_irq_disable();
-
-       /* Set exception prefix high - to the firmware */
-       _nmask_and_or_msr(0, MSR_IP);
-
-       /* XXX FIXME */
-       printk("XXXX **** trying to reset board ****\n");
-       return;
-}
-
-static void
-ev64260_restart(char *cmd)
-{
-       volatile ulong  i = 10000000;
-
-       ev64260_reset_board();
-
-       while (i-- > 0);
-       panic("restart failed\n");
-}
-
-static void
-ev64260_halt(void)
-{
-       local_irq_disable();
-       while (1);
-       /* NOTREACHED */
-}
-
-static void
-ev64260_power_off(void)
-{
-       ev64260_halt();
-       /* NOTREACHED */
-}
-
-static int
-ev64260_show_cpuinfo(struct seq_file *m)
-{
-       uint pvid;
-
-       pvid = mfspr(PVR);
-       seq_printf(m, "vendor\t\t: Marvell/Galileo\n");
-       seq_printf(m, "machine\t\t: EV-64260-BP\n");
-       seq_printf(m, "PVID\t\t: 0x%x, vendor: %s\n",
-                       pvid, (pvid & (1<<15) ? "IBM" : "Motorola"));
-
-       return 0;
-}
-
-/* DS1501 RTC has too much variation to use RTC for calibration */
-static void __init
-ev64260_calibrate_decr(void)
-{
-       ulong freq;
-
-       freq = 100000000 / 4;
-
-       printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-              freq/1000000, freq%1000000);
-
-       tb_ticks_per_jiffy = freq / HZ;
-       tb_to_us = mulhwu_scale_factor(freq, 1000000);
-
-       return;
-}
-
-#if defined(CONFIG_SERIAL_TEXT_DEBUG)
-/*
- * Set BAT 3 to map 0xf0000000 to end of physical memory space.
- */
-static __inline__ void
-ev64260_set_bat(void)
-{
-       unsigned long   bat3u, bat3l;
-       static int      mapping_set = 0;
-
-       if (!mapping_set) {
-
-               __asm__ __volatile__(
-               " lis %0,0xf000\n \
-                 ori %1,%0,0x002a\n \
-                 ori %0,%0,0x1ffe\n \
-                 mtspr 0x21e,%0\n \
-                 mtspr 0x21f,%1\n \
-                 isync\n \
-                 sync "
-               : "=r" (bat3u), "=r" (bat3l));
-
-               mapping_set = 1;
-       }
-
-       return;
-}
-
-#if !defined(CONFIG_GT64260_CONSOLE)
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <asm/serial.h>
-
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
-       SERIAL_PORT_DFNS        /* Defined in <asm/serial.h> */
-};
-
-static void
-ev64260_16550_progress(char *s, unsigned short hex)
-{
-       volatile char c;
-       volatile unsigned long com_port;
-       u16 shift;
-
-       com_port = rs_table[0].port;
-       shift = rs_table[0].iomem_reg_shift;
-
-       while ((c = *s++) != 0) {
-               while ((*((volatile unsigned char *)com_port +
-                               (UART_LSR << shift)) & UART_LSR_THRE) == 0)
-                               ;
-               *(volatile unsigned char *)com_port = c;
-
-               if (c == '\n') {
-                       while ((*((volatile unsigned char *)com_port +
-                               (UART_LSR << shift)) & UART_LSR_THRE) == 0)
-                                       ;
-                       *(volatile unsigned char *)com_port = '\r';
-               }
-       }
-
-       /* Move to next line on */
-       while ((*((volatile unsigned char *)com_port +
-               (UART_LSR << shift)) & UART_LSR_THRE) == 0)
-                       ;
-       *(volatile unsigned char *)com_port = '\n';
-       while ((*((volatile unsigned char *)com_port +
-               (UART_LSR << shift)) & UART_LSR_THRE) == 0)
-                       ;
-       *(volatile unsigned char *)com_port = '\r';
-
-       return;
-}
-#endif /* !CONFIG_GT64260_CONSOLE */
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-             unsigned long r6, unsigned long r7)
-{
-       parse_bootinfo(find_bootinfo());
-
-       isa_mem_base = 0;
-
-       ppc_md.setup_arch = ev64260_setup_arch;
-       ppc_md.show_cpuinfo = ev64260_show_cpuinfo;
-       ppc_md.irq_canonicalize = NULL;
-       ppc_md.init_IRQ = ev64260_init_irq;
-       ppc_md.get_irq = gt64260_get_irq;
-       ppc_md.init = NULL;
-
-       ppc_md.restart = ev64260_restart;
-       ppc_md.power_off = ev64260_power_off;
-       ppc_md.halt = ev64260_halt;
-
-       ppc_md.find_end_of_memory = ev64260_find_end_of_memory;
-
-       ppc_md.time_init = todc_time_init;
-       ppc_md.set_rtc_time = todc_set_rtc_time;
-       ppc_md.get_rtc_time = todc_get_rtc_time;
-       ppc_md.calibrate_decr = ev64260_calibrate_decr;
-
-       ppc_md.nvram_read_val = todc_direct_read_val;
-       ppc_md.nvram_write_val = todc_direct_write_val;
-
-       ppc_md.heartbeat = NULL;
-       ppc_md.heartbeat_reset = 0;
-       ppc_md.heartbeat_count = 0;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-       ev64260_set_bat();
-#ifdef CONFIG_GT64260_CONSOLE
-       gt64260_base = EV64260_BRIDGE_REG_BASE;
-       ppc_md.progress = gt64260_mpsc_progress; /* embedded UART */
-#else
-       ppc_md.progress = ev64260_16550_progress; /* Dev module DUART */
-#endif
-#else  /* !CONFIG_SERIAL_TEXT_DEBUG */
-       ppc_md.progress = NULL;
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-
-       return;
-}
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 1fdb3ff..376dc4a 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/ptrace.h>
 #include <linux/aio_abi.h>
 #include <linux/elf.h>
+#include <linux/vs_cvirt.h>
 
 #include <net/scm.h>
 #include <net/sock.h>
index 86950ea..16745a2 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/utsname.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/vs_cvirt.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
index b14265a..50d889f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/syscalls.h>
 #include <linux/ipc.h>
 #include <linux/personality.h>
+#include <linux/vs_cvirt.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
index 7159367..94b4d55 100644 (file)
@@ -191,8 +191,8 @@ int stdio_init(void)
 
 late_initcall(stdio_init);
 
-static void console_write(struct console *console, const char *string, 
-                         unsigned len)
+static void stdio_console_write(struct console *console, const char *string, 
+                               unsigned len)
 {
        struct line *line = &vts[console->index];
 
@@ -203,22 +203,22 @@ static void console_write(struct console *console, const char *string,
                up(&line->sem);
 }
 
-static struct tty_driver *console_device(struct console *c, int *index)
+static struct tty_driver *stdio_console_device(struct console *c, int *index)
 {
        *index = c->index;
        return console_driver;
 }
 
-static int console_setup(struct console *co, char *options)
+static int stdio_console_setup(struct console *co, char *options)
 {
        return(0);
 }
 
 static struct console stdiocons = {
        name:           "tty",
-       write:          console_write,
-       device:         console_device,
-       setup:          console_setup,
+       write:          stdio_console_write,
+       device:         stdio_console_device,
+       setup:          stdio_console_setup,
        flags:          CON_PRINTBUFFER,
        index:          -1,
 };
index d1ca652..0694eaa 100644 (file)
@@ -6,6 +6,7 @@
 #define __UM_SYSDEP_CHECKSUM_H
 
 #include "linux/string.h"
+#include "linux/in6.h"
 
 /*
  * computes the checksum of a memory block at buff, length len,
index 801e66e..cec6e63 100644 (file)
@@ -15,6 +15,8 @@
 #include "linux/unistd.h"
 #include "linux/slab.h"
 #include "linux/utime.h"
+#include <linux/vs_cvirt.h>
+
 #include "asm/mman.h"
 #include "asm/uaccess.h"
 #include "asm/ipc.h"
index c9c539f..47f9044 100644 (file)
@@ -1,5 +1,5 @@
 obj-y = bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o ptrace_user.o \
-       semaphore.o sigcontext.o syscalls.o sysrq.o time.o
+       semaphore.o bitops.o sigcontext.o syscalls.o sysrq.o time.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 obj-$(CONFIG_MODULES) += module.o
@@ -7,7 +7,7 @@ obj-$(CONFIG_MODULES) += module.o
 USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
 USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
 
-SYMLINKS = semaphore.c highmem.c module.c
+SYMLINKS = semaphore.c highmem.c module.c bitops.c
 SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
 
 clean-files := $(SYMLINKS)
@@ -15,6 +15,7 @@ clean-files := $(SYMLINKS)
 semaphore.c-dir = kernel
 highmem.c-dir = mm
 module.c-dir = kernel
+bitops.c-dir = lib
 
 define make_link
        -rm -f $1
index 0a2fb66..805e980 100644 (file)
@@ -578,7 +578,7 @@ ia32_sys_call_table:
        .quad sys_tgkill                /* 270 */
        .quad compat_sys_utimes
        .quad sys32_fadvise64_64
-       .quad quiet_ni_syscall  /* sys_vserver */
+       .quad sys_vserver
        .quad sys_mbind
        .quad compat_get_mempolicy      /* 275 */
        .quad sys_set_mempolicy
index 08a60e5..282695a 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/ptrace.h>
 #include <linux/highuid.h>
 #include <linux/vmalloc.h>
+#include <linux/vs_cvirt.h>
 #include <asm/mman.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
index a2c5b03..3feb337 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/file.h>
 #include <linux/utsname.h>
 #include <linux/personality.h>
+#include <linux/vs_cvirt.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
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 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";
diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c
deleted file mode 100644 (file)
index 63244bf..0000000
+++ /dev/null
@@ -1,1397 +0,0 @@
-/*
- *  drivers/mtd/nand.c
- *
- *  Overview:
- *   This is the generic MTD driver for NAND flash devices. It should be
- *   capable of working with almost all NAND chips currently available.
- *   
- *     Additional technical information is available on
- *     http://www.linux-mtd.infradead.org/tech/nand.html
- *     
- *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
- *               2002 Thomas Gleixner (tglx@linutronix.de)
- *
- *  10-29-2001  Thomas Gleixner (tglx@linutronix.de)
- *             - Changed nand_chip structure for controlline function to
- *             support different hardware structures (Access to
- *             controllines ALE,CLE,NCE via hardware specific function. 
- *             - exit out of "failed erase block" changed, to avoid
- *             driver hangup
- *             - init_waitqueue_head added in function nand_scan !!
- *
- *  01-30-2002  Thomas Gleixner (tglx@linutronix.de)
- *             change in nand_writev to block invalid vecs entries
- *
- *  02-11-2002  Thomas Gleixner (tglx@linutronix.de)
- *             - major rewrite to avoid duplicated code
- *               common nand_write_page function  
- *               common get_chip function 
- *             - added oob_config structure for out of band layouts
- *             - write_oob changed for partial programming
- *             - read cache for faster access for subsequent reads
- *             from the same page.
- *             - support for different read/write address
- *             - support for device ready/busy line
- *             - read oob for more than one page enabled
- *
- *  02-27-2002 Thomas Gleixner (tglx@linutronix.de)
- *             - command-delay can be programmed
- *             - fixed exit from erase with callback-function enabled
- *
- *  03-21-2002  Thomas Gleixner (tglx@linutronix.de)
- *             - DEBUG improvements provided by Elizabeth Clarke 
- *             (eclarke@aminocom.com)
- *             - added zero check for this->chip_delay
- *
- *  04-03-2002  Thomas Gleixner (tglx@linutronix.de)
- *             - added added hw-driver supplied command and wait functions
- *             - changed blocking for erase (erase suspend enabled)
- *             - check pointers before accessing flash provided by
- *             John Hall (john.hall@optionexist.co.uk)
- *
- *  04-09-2002  Thomas Gleixner (tglx@linutronix.de)
- *             - nand_wait repaired
- *
- *  04-28-2002  Thomas Gleixner (tglx@linutronix.de)   
- *             - OOB config defines moved to nand.h 
- *
- *  08-01-2002  Thomas Gleixner (tglx@linutronix.de)   
- *             - changed my mailaddress, added pointer to tech/nand.html
- *
- *  08-07-2002         Thomas Gleixner (tglx@linutronix.de)
- *             forced bad block location to byte 5 of OOB, even if
- *             CONFIG_MTD_NAND_ECC_JFFS2 is not set, to prevent
- *             erase /dev/mtdX from erasing bad blocks and destroying
- *             bad block info
- *
- *  08-10-2002         Thomas Gleixner (tglx@linutronix.de)
- *             Fixed writing tail of data. Thanks to Alice Hennessy
- *             <ahennessy@mvista.com>.
- *
- *  08-10-2002         Thomas Gleixner (tglx@linutronix.de)
- *             nand_read_ecc and nand_write_page restructured to support
- *             hardware ECC. Thanks to Steven Hein (ssh@sgi.com)
- *             for basic implementation and suggestions.
- *             3 new pointers in nand_chip structure:
- *             calculate_ecc, correct_data, enabled_hwecc                                       
- *             forcing all hw-drivers to support page cache
- *             eccvalid_pos is now mandatory
- *
- *  08-17-2002 tglx: fixed signed/unsigned missmatch in write.c
- *             Thanks to Ken Offer <koffer@arlut.utexas.edu>   
- *
- *  08-29-2002  tglx: use buffered read/write only for non pagealigned 
- *             access, speed up the aligned path by using the fs-buffer
- *             reset chip removed from nand_select(), implicit done
- *             only, when erase is interrupted
- *             waitfuntion use yield, instead of schedule_timeout
- *             support for 6byte/512byte hardware ECC
- *             read_ecc, write_ecc extended for different oob-layout
- *             selections: Implemented NAND_NONE_OOB, NAND_JFFS2_OOB,
- *             NAND_YAFFS_OOB. fs-driver gives one of these constants
- *             to select the oob-layout fitting the filesystem.
- *             oobdata can be read together with the raw data, when
- *             the fs-driver supplies a big enough buffer.
- *             size = 12 * number of pages to read (256B pagesize)
- *                    24 * number of pages to read (512B pagesize)
- *             the buffer contains 8/16 byte oobdata and 4/8 byte
- *             returncode from calculate_ecc
- *             oobdata can be given from filesystem to program them
- *             in one go together with the raw data. ECC codes are
- *             filled in at the place selected by oobsel.
- *
- *  09-04-2002  tglx: fixed write_verify (John Hall (john.hall@optionexist.co.uk))
- *
- *  11-11-2002  tglx: fixed debug output in nand_write_page 
- *             (John Hall (john.hall@optionexist.co.uk))
- *
- *  11-25-2002  tglx: Moved device ID/ manufacturer ID from nand_ids.h
- *             Splitted device ID and manufacturer ID table. 
- *             Removed CONFIG_MTD_NAND_ECC, as it defaults to ECC_NONE for
- *             mtd->read / mtd->write and is controllable by the fs driver
- *             for mtd->read_ecc / mtd->write_ecc
- *             some minor cleanups
- *
- *  12-05-2002  tglx: Dave Ellis (DGE@sixnetio) provided the fix for
- *             WRITE_VERIFY long time ago. Thanks for remembering me.  
- *
- *  02-14-2003  tglx: Reject non page aligned writes   
- *             Fixed ecc select in nand_write_page to match semantics. 
- *
- *  02-18-2003 tglx: Changed oobsel to pointer. Added a default oob-selector
- *                     
- *  02-18-2003 tglx: Implemented oobsel again. Now it uses a pointer to
- +             a structure, which will be supplied by a filesystem driver
- *             If NULL is given, then the defaults (none or defaults
- *             supplied by ioctl (MEMSETOOBSEL) are used.
- *             For partitions the partition defaults are used (mtdpart.c)
- *
- *  06-04-2003  tglx: fix compile errors and fix write verify problem for
- *             some chips, which need either a delay between the readback
- *             and the next write command or have the CE removed. The
- *             CE disable/enable is much faster than a 20us delay and
- *             it should work on all available chips.
- *     
- * $Id: nand.c,v 1.46 2003/06/04 17:10:36 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
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/compatmac.h>
-#include <linux/interrupt.h>
-#include <asm/io.h>
-
-/*
- * Macros for low-level register control
- */
-#define nand_select()  this->hwcontrol(NAND_CTL_SETNCE);
-#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE);
-
-/*
- * NAND low-level MTD interface functions
- */
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
-static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-                         size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel);
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf);
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf);
-static int nand_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 *oobsel);
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf);
-static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs,
-                       unsigned long count, loff_t to, size_t * retlen);
-static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
-                       unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
-static int nand_erase (struct mtd_info *mtd, struct erase_info *instr);
-static void nand_sync (struct mtd_info *mtd);
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,  struct nand_oobinfo *oobsel);
-
-
-/*
- * Send command to NAND device
- */
-static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-{
-       register struct nand_chip *this = mtd->priv;
-       register unsigned long NAND_IO_ADDR = this->IO_ADDR_W;
-
-       /* Begin command latch cycle */
-       this->hwcontrol (NAND_CTL_SETCLE);
-       /*
-        * Write out the command to the device.
-        */
-       if (command != NAND_CMD_SEQIN)
-               writeb (command, NAND_IO_ADDR);
-       else {
-               if (mtd->oobblock == 256 && column >= 256) {
-                       column -= 256;
-                       writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
-                       writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
-               } else if (mtd->oobblock == 512 && column >= 256) {
-                       if (column < 512) {
-                               column -= 256;
-                               writeb (NAND_CMD_READ1, NAND_IO_ADDR);
-                               writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
-                       } else {
-                               column -= 512;
-                               writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
-                               writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
-                       }
-               } else {
-                       writeb (NAND_CMD_READ0, NAND_IO_ADDR);
-                       writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
-               }
-       }
-
-       /* Set ALE and clear CLE to start address cycle */
-       this->hwcontrol (NAND_CTL_CLRCLE);
-
-       if (column != -1 || page_addr != -1) {
-               this->hwcontrol (NAND_CTL_SETALE);
-
-               /* Serially input address */
-               if (column != -1)
-                       writeb (column, NAND_IO_ADDR);
-               if (page_addr != -1) {
-                       writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
-                       writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
-                       /* One more address cycle for higher density devices */
-                       if (mtd->size & 0x0c000000) 
-                               writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR);
-               }
-               /* Latch in address */
-               this->hwcontrol (NAND_CTL_CLRALE);
-       }
-       
-       /* 
-        * program and erase have their own busy handlers 
-        * status and sequential in needs no delay
-       */
-       switch (command) {
-                       
-       case NAND_CMD_PAGEPROG:
-       case NAND_CMD_ERASE1:
-       case NAND_CMD_ERASE2:
-       case NAND_CMD_SEQIN:
-       case NAND_CMD_STATUS:
-               return;
-
-       case NAND_CMD_RESET:
-               if (this->dev_ready)    
-                       break;
-               this->hwcontrol (NAND_CTL_SETCLE);
-               writeb (NAND_CMD_STATUS, NAND_IO_ADDR);
-               this->hwcontrol (NAND_CTL_CLRCLE);
-               while ( !(readb (this->IO_ADDR_R) & 0x40));
-               return;
-
-       /* This applies to read commands */     
-       default:
-               /* 
-                * If we don't have access to the busy pin, we apply the given
-                * command delay
-               */
-               if (!this->dev_ready) {
-                       udelay (this->chip_delay);
-                       return;
-               }       
-       }
-       
-       /* wait until command is processed */
-       while (!this->dev_ready());
-}
-
-/*
- *     Get chip for selected access
- */
-static inline void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state)
-{
-
-       DECLARE_WAITQUEUE (wait, current);
-
-       /* 
-        * Grab the lock and see if the device is available 
-        * For erasing, we keep the spinlock until the
-        * erase command is written. 
-       */
-retry:
-       spin_lock_bh (&this->chip_lock);
-
-       if (this->state == FL_READY) {
-               this->state = new_state;
-               if (new_state != FL_ERASING)
-                       spin_unlock_bh (&this->chip_lock);
-               return;
-       }
-
-       if (this->state == FL_ERASING) {
-               if (new_state != FL_ERASING) {
-                       this->state = new_state;
-                       spin_unlock_bh (&this->chip_lock);
-                       nand_select (); /* select in any case */
-                       this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-                       return;
-               }
-       }
-
-       set_current_state (TASK_UNINTERRUPTIBLE);
-       add_wait_queue (&this->wq, &wait);
-       spin_unlock_bh (&this->chip_lock);
-       schedule ();
-       remove_wait_queue (&this->wq, &wait);
-       goto retry;
-}
-
-/*
- * Wait for command done. This applies to erase and program only
- * Erase can take up to 400ms and program up to 20ms according to 
- * general NAND and SmartMedia specs
- *
-*/
-static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
-{
-
-       unsigned long   timeo = jiffies;
-       int     status;
-       
-       if (state == FL_ERASING)
-                timeo += (HZ * 400) / 1000;
-       else
-                timeo += (HZ * 20) / 1000;
-
-       spin_lock_bh (&this->chip_lock);
-       this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-
-       while (time_before(jiffies, timeo)) {           
-               /* Check, if we were interrupted */
-               if (this->state != state) {
-                       spin_unlock_bh (&this->chip_lock);
-                       return 0;
-               }
-               if (this->dev_ready) {
-                       if (this->dev_ready ())
-                               break;
-               }
-               if (readb (this->IO_ADDR_R) & 0x40)
-                       break;
-                                               
-               spin_unlock_bh (&this->chip_lock);
-               yield ();
-               spin_lock_bh (&this->chip_lock);
-       }
-       status = (int) readb (this->IO_ADDR_R);
-       spin_unlock_bh (&this->chip_lock);
-
-       return status;
-}
-
-/*
- *     Nand_page_program function is used for write and writev !
- *     This function will always program a full page of data
- *     If you call it with a non page aligned buffer, you're lost :)
- */
-static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,  struct nand_oobinfo *oobsel)
-{
-       int     i, status;
-       u_char  ecc_code[6], *oob_data;
-       int     eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
-       int     *oob_config = oobsel->eccpos;
-       
-       /* pad oob area, if we have no oob buffer from fs-driver */
-       if (!oob_buf) {
-               oob_data = &this->data_buf[mtd->oobblock];
-               for (i = 0; i < mtd->oobsize; i++)
-                       oob_data[i] = 0xff;
-       } else 
-               oob_data = oob_buf;
-       
-       /* Send command to begin auto page programming */
-       this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
-
-       /* Write out complete page of data, take care of eccmode */
-       switch (eccmode) {
-       /* No ecc and software ecc 3/256, write all */
-       case NAND_ECC_NONE:
-               printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
-               for (i = 0; i < mtd->oobblock; i++) 
-                       writeb ( this->data_poi[i] , this->IO_ADDR_W);
-               break;
-       case NAND_ECC_SOFT:
-               this->calculate_ecc (&this->data_poi[0], &(ecc_code[0]));
-               for (i = 0; i < 3; i++)
-                       oob_data[oob_config[i]] = ecc_code[i];
-               /* Calculate and write the second ECC for 512 Byte page size */
-               if (mtd->oobblock == 512) {
-                       this->calculate_ecc (&this->data_poi[256], &(ecc_code[3]));
-                       for (i = 3; i < 6; i++)
-                               oob_data[oob_config[i]] = ecc_code[i];
-               } 
-               for (i = 0; i < mtd->oobblock; i++) 
-                       writeb ( this->data_poi[i] , this->IO_ADDR_W);
-               break;
-               
-       /* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */      
-       case NAND_ECC_HW3_256:          
-               this->enable_hwecc (NAND_ECC_WRITE);    /* enable hardware ecc logic for write */
-               for (i = 0; i < mtd->eccsize; i++) 
-                       writeb ( this->data_poi[i] , this->IO_ADDR_W);
-               
-               this->calculate_ecc (NULL, &(ecc_code[0]));
-               for (i = 0; i < 3; i++)
-                       oob_data[oob_config[i]] = ecc_code[i];
-                       
-               if (mtd->oobblock == 512) {
-                       this->enable_hwecc (NAND_ECC_WRITE);    /* enable hardware ecc logic for write*/
-                       for (i = mtd->eccsize; i < mtd->oobblock; i++) 
-                               writeb ( this->data_poi[i] , this->IO_ADDR_W);
-                       this->calculate_ecc (NULL, &(ecc_code[3]));
-                       for (i = 3; i < 6; i++)
-                               oob_data[oob_config[i]] = ecc_code[i];
-               }
-               break;
-                               
-       /* Hardware ecc 3 byte / 512 byte data, write full page */      
-       case NAND_ECC_HW3_512:  
-               this->enable_hwecc (NAND_ECC_WRITE);    /* enable hardware ecc logic */
-               for (i = 0; i < mtd->oobblock; i++) 
-                       writeb ( this->data_poi[i] , this->IO_ADDR_W);
-               this->calculate_ecc (NULL, &(ecc_code[0]));
-               for (i = 0; i < 3; i++)
-                       oob_data[oob_config[i]] = ecc_code[i];
-               break;
-
-       /* Hardware ecc 6 byte / 512 byte data, write full page */      
-       case NAND_ECC_HW6_512:  
-               this->enable_hwecc (NAND_ECC_WRITE);    /* enable hardware ecc logic */
-               for (i = 0; i < mtd->oobblock; i++) 
-                       writeb ( this->data_poi[i] , this->IO_ADDR_W);
-               this->calculate_ecc (NULL, &(ecc_code[0]));
-               for (i = 0; i < 6; i++)
-                       oob_data[oob_config[i]] = ecc_code[i];
-               break;
-               
-       default:
-               printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-               BUG();  
-       }       
-       
-       /* Write out OOB data */
-       for (i = 0; i <  mtd->oobsize; i++)
-               writeb ( oob_data[i] , this->IO_ADDR_W);
-
-       /* Send command to actually program the data */
-       this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
-       /* call wait ready function */
-       status = this->waitfunc (mtd, this, FL_WRITING);
-
-       /* See if device thinks it succeeded */
-       if (status & 0x01) {
-               DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
-               return -EIO;
-       }
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-       /*
-        * The NAND device assumes that it is always writing to
-        * a cleanly erased page. Hence, it performs its internal
-        * write verification only on bits that transitioned from
-        * 1 to 0. The device does NOT verify the whole page on a
-        * byte by byte basis. It is possible that the page was
-        * not completely erased or the page is becoming unusable
-        * due to wear. The read with ECC would catch the error
-        * later when the ECC page check fails, but we would rather
-        * catch it early in the page write stage. Better to write
-        * no data than invalid data.
-        */
-
-       /* Send command to read back the page */
-       this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
-       /* Loop through and verify the data */
-       for (i = 0; i < mtd->oobblock; i++) {
-               if (this->data_poi[i] != readb (this->IO_ADDR_R)) {
-                       DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
-                       return -EIO;
-               }
-       }
-
-       /* check, if we have a fs-supplied oob-buffer */
-       if (oob_buf) {
-               for (i = 0; i < mtd->oobsize; i++) {
-                       if (oob_data[i] != readb (this->IO_ADDR_R)) {
-                               DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
-                               return -EIO;
-                       }
-               }
-       } else {
-               if (eccmode != NAND_ECC_NONE) {
-                       int ecc_bytes = 0;
-
-                       switch (this->eccmode) {
-                       case NAND_ECC_SOFT:
-                       case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break;
-                       case NAND_ECC_HW3_512: ecc_bytes = 3; break;
-                       case NAND_ECC_HW6_512: ecc_bytes = 6; break;
-                       }
-
-                       for (i = 0; i < mtd->oobsize; i++)
-                               oob_data[i] = readb (this->IO_ADDR_R);
-
-                       for (i = 0; i < ecc_bytes; i++) {
-                               if (oob_data[oob_config[i]] != ecc_code[i]) {
-                                       DEBUG (MTD_DEBUG_LEVEL0,
-                                              "%s: Failed ECC write "
-                                      "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
-                               return -EIO;
-                               }
-                       }
-               }
-       }
-       /* 
-        * Terminate the read command. This is faster than sending a reset command or 
-        * applying a 20us delay before issuing the next programm sequence.
-        * This is not a problem for all chips, but I have found a bunch of them.
-        */
-       nand_deselect();
-       nand_select();
-#endif
-       return 0;
-}
-
-/*
-*      Use NAND read ECC
-*/
-static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
-{
-       return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL));
-}                         
-
-
-/*
- * NAND read with ECC
- */
-static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-                         size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
-{
-       int j, col, page, end, ecc;
-       int erase_state = 0;
-       int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
-       struct nand_chip *this = mtd->priv;
-       u_char *data_poi, *oob_data = oob_buf;
-       u_char ecc_calc[6];
-       u_char ecc_code[6];
-       int     eccmode;
-       int     *oob_config;
-
-       // use chip default if zero
-       if (oobsel == NULL)
-               oobsel = &mtd->oobinfo;
-               
-       eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
-       oob_config = oobsel->eccpos;
-
-       DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
-
-       /* Do not allow reads past end of device */
-       if ((from + len) > mtd->size) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
-               *retlen = 0;
-               return -EINVAL;
-       }
-
-       /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd ,FL_READING, &erase_state);
-
-       /* Select the NAND device */
-       nand_select ();
-
-       /* First we calculate the starting page */
-       page = from >> this->page_shift;
-
-       /* Get raw starting column */
-       col = from & (mtd->oobblock - 1);
-
-       end = mtd->oobblock;
-       ecc = mtd->eccsize;
-
-       /* Send the read command */
-       this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
-       
-       /* Loop until all data read */
-       while (read < len) {
-               
-               /* If we have consequent page reads, apply delay or wait for ready/busy pin */
-               if (read) {
-                       if (!this->dev_ready) 
-                               udelay (this->chip_delay);
-                       else
-                               while (!this->dev_ready());     
-               }
-
-               /* 
-                * If the read is not page aligned, we have to read into data buffer
-                * due to ecc, else we read into return buffer direct
-                */
-               if (!col && (len - read) >= end)  
-                       data_poi = &buf[read];
-               else 
-                       data_poi = this->data_buf;
-
-               /* get oob area, if we have no oob buffer from fs-driver */
-               if (!oob_buf) {
-                       oob_data = &this->data_buf[end];
-                       oob = 0;
-               }       
-                       
-               j = 0;
-               switch (eccmode) {
-               case NAND_ECC_NONE:     /* No ECC, Read in a page */            
-                       printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");
-                       while (j < end)
-                               data_poi[j++] = readb (this->IO_ADDR_R);
-                       break;
-                       
-               case NAND_ECC_SOFT:     /* Software ECC 3/256: Read in a page + oob data */
-                       while (j < end)
-                               data_poi[j++] = readb (this->IO_ADDR_R);
-                       this->calculate_ecc (&data_poi[0], &ecc_calc[0]);
-                       if (mtd->oobblock == 512)
-                               this->calculate_ecc (&data_poi[256], &ecc_calc[3]);
-                       break;  
-                       
-               case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */
-                       this->enable_hwecc (NAND_ECC_READ);     
-                       while (j < ecc)
-                               data_poi[j++] = readb (this->IO_ADDR_R);
-                       this->calculate_ecc (&data_poi[0], &ecc_calc[0]);       /* read from hardware */
-                       
-                       if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */
-                               this->enable_hwecc (NAND_ECC_READ);     
-                               while (j < end)
-                                       data_poi[j++] = readb (this->IO_ADDR_R);
-                               this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */
-                       }                                       
-                       break;                                          
-                               
-               case NAND_ECC_HW3_512:  
-               case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page  */
-                       this->enable_hwecc (NAND_ECC_READ);     
-                       while (j < end)
-                               data_poi[j++] = readb (this->IO_ADDR_R);
-                       this->calculate_ecc (&data_poi[0], &ecc_calc[0]);       /* read from hardware */
-                       break;
-
-               default:
-                       printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-                       BUG();  
-               }
-
-               /* read oobdata */
-               for (j = 0; j <  mtd->oobsize; j++) 
-                       oob_data[oob + j] = readb (this->IO_ADDR_R);
-               
-               /* Skip ECC, if not active */
-               if (eccmode == NAND_ECC_NONE)
-                       goto readdata;  
-               
-               /* Pick the ECC bytes out of the oob data */
-               for (j = 0; j < 6; j++)
-                       ecc_code[j] = oob_data[oob + oob_config[j]];
-
-               /* correct data, if neccecary */
-               ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]);
-               /* check, if we have a fs supplied oob-buffer */
-               if (oob_buf) { 
-                       oob += mtd->oobsize;
-                       *((int *)&oob_data[oob]) = ecc_status;
-                       oob += sizeof(int);
-               }
-               if (ecc_status == -1) { 
-                       DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
-                       ecc_failed++;
-               }
-               
-               if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) {
-                       ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]);
-                       if (oob_buf) {
-                               *((int *)&oob_data[oob]) = ecc_status;
-                               oob += sizeof(int);
-                       }
-                       if (ecc_status == -1) {
-                               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
-                               ecc_failed++;
-                       }
-               }
-readdata:
-               if (col || (len - read) < end) { 
-                       for (j = col; j < end && read < len; j++)
-                               buf[read++] = data_poi[j];
-               } else          
-                       read += mtd->oobblock;
-               /* For subsequent reads align to page boundary. */
-               col = 0;
-               /* Increment page address */
-               page++;
-       }
-
-       /* De-select the NAND device */
-       nand_deselect ();
-
-       /* Wake up anyone waiting on the device */
-       spin_lock_bh (&this->chip_lock);
-       this->state = FL_READY;
-       wake_up (&this->wq);
-       spin_unlock_bh (&this->chip_lock);
-
-       /*
-        * Return success, if no ECC failures, else -EIO
-        * fs driver will take care of that, because
-        * retlen == desired len and result == -EIO
-        */
-       *retlen = read;
-       return ecc_failed ? -EIO : 0;
-}
-
-/*
- * NAND read out-of-band
- */
-static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
-{
-       int i, col, page;
-       int erase_state = 0;
-       struct nand_chip *this = mtd->priv;
-
-       DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
-
-       /* Shift to get page */
-       page = ((int) from) >> this->page_shift;
-
-       /* Mask to get column */
-       col = from & 0x0f;
-
-       /* Initialize return length value */
-       *retlen = 0;
-
-       /* Do not allow reads past end of device */
-       if ((from + len) > mtd->size) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");
-               *retlen = 0;
-               return -EINVAL;
-       }
-
-       /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd , FL_READING, &erase_state);
-
-       /* Select the NAND device */
-       nand_select ();
-
-       /* Send the read command */
-       this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);
-       /* 
-        * Read the data, if we read more than one page
-        * oob data, let the device transfer the data !
-        */
-       for (i = 0; i < len; i++) {
-               buf[i] = readb (this->IO_ADDR_R);
-               if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1))
-                       udelay (this->chip_delay);
-       }
-       /* De-select the NAND device */
-       nand_deselect ();
-
-       /* Wake up anyone waiting on the device */
-       spin_lock_bh (&this->chip_lock);
-       this->state = FL_READY;
-       wake_up (&this->wq);
-       spin_unlock_bh (&this->chip_lock);
-
-       /* Return happy */
-       *retlen = len;
-       return 0;
-}
-
-#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
-
-/*
-*      Use NAND write ECC
-*/
-static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
-{
-       return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));
-}                         
-/*
- * NAND write with ECC
- */
-static int nand_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 *oobsel)
-{
-       int page, ret = 0, oob = 0, written = 0;
-       struct nand_chip *this = mtd->priv;
-
-       DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
-
-       /* Do not allow write past end of device */
-       if ((to + len) > mtd->size) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");
-               return -EINVAL;
-       }
-
-       /* reject writes, which are not page aligned */ 
-       if (NOTALIGNED (to) || NOTALIGNED(len)) {
-               printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
-               return -EINVAL;
-       }
-
-       // if oobsel is NULL, use chip defaults
-       if (oobsel == NULL) 
-               oobsel = &mtd->oobinfo;         
-
-       /* Shift to get page */
-       page = ((int) to) >> this->page_shift;
-
-       /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd, FL_WRITING, NULL);
-
-       /* Select the NAND device */
-       nand_select ();
-
-       /* Check the WP bit */
-       this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-       if (!(readb (this->IO_ADDR_R) & 0x80)) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");
-               ret = -EIO;
-               goto out;
-       }
-
-       /* Loop until all data is written */
-       while (written < len) {
-               int cnt = mtd->oobblock;
-               this->data_poi = (u_char*) &buf[written];
-               /* We use the same function for write and writev */
-               if (eccbuf) {
-                       ret = nand_write_page (mtd, this, page, &eccbuf[oob], oobsel);
-                       oob += mtd->oobsize;
-               } else 
-                       ret = nand_write_page (mtd, this, page, NULL, oobsel);  
-               
-               if (ret)
-                       goto out;
-
-               /* Update written bytes count */
-               written += cnt;
-               /* Increment page address */
-               page++;
-       }
-
-out:
-       /* De-select the NAND device */
-       nand_deselect ();
-
-       /* Wake up anyone waiting on the device */
-       spin_lock_bh (&this->chip_lock);
-       this->state = FL_READY;
-       wake_up (&this->wq);
-       spin_unlock_bh (&this->chip_lock);
-
-       *retlen = written;
-       return ret;
-}
-
-/*
- * NAND write out-of-band
- */
-static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf)
-{
-       int i, column, page, status, ret = 0;
-       struct nand_chip *this = mtd->priv;
-
-       DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
-
-       /* Shift to get page */
-       page = ((int) to) >> this->page_shift;
-
-       /* Mask to get column */
-       column = to & 0x1f;
-
-       /* Initialize return length value */
-       *retlen = 0;
-
-       /* Do not allow write past end of page */
-       if ((column + len) > mtd->oobsize) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");
-               return -EINVAL;
-       }
-
-       /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd, FL_WRITING, NULL);
-
-       /* Select the NAND device */
-       nand_select ();
-
-       /* Check the WP bit */
-       this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-       if (!(readb (this->IO_ADDR_R) & 0x80)) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");
-               ret = -EIO;
-               goto out;
-       }
-
-       /* Write out desired data */
-       this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);
-       /* prepad 0xff for partial programming */
-       for (i = 0; i < column; i++)
-               writeb (0xff, this->IO_ADDR_W);
-       /* write data */
-       for (i = 0; i < len; i++)
-               writeb (buf[i], this->IO_ADDR_W);       
-       /* postpad 0xff for partial programming */
-       for (i = len + column; i < mtd->oobsize; i++)
-               writeb (0xff, this->IO_ADDR_W);
-
-       /* Send command to program the OOB data */
-       this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
-
-       status = this->waitfunc (mtd, this, FL_WRITING);
-
-       /* See if device thinks it succeeded */
-       if (status & 0x01) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
-               ret = -EIO;
-               goto out;
-       }
-       /* Return happy */
-       *retlen = len;
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-       /* Send command to read back the data */
-       this->cmdfunc (mtd, NAND_CMD_READOOB, column, page);
-
-       /* Loop through and verify the data */
-       for (i = 0; i < len; i++) {
-               if (buf[i] != readb (this->IO_ADDR_R)) {
-                       DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
-                       ret = -EIO;
-                       goto out;
-               }
-       }
-#endif
-
-out:
-       /* De-select the NAND device */
-       nand_deselect ();
-
-       /* Wake up anyone waiting on the device */
-       spin_lock_bh (&this->chip_lock);
-       this->state = FL_READY;
-       wake_up (&this->wq);
-       spin_unlock_bh (&this->chip_lock);
-
-       return ret;
-}
-
-
-/*
- * NAND write with kvec
- */
-static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, 
-               loff_t to, size_t * retlen)
-{
-       return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL));    
-}
-
-static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, 
-               loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel)
-{
-       int i, page, len, total_len, ret = 0, written = 0;
-       struct nand_chip *this = mtd->priv;
-
-       /* Calculate total length of data */
-       total_len = 0;
-       for (i = 0; i < count; i++)
-               total_len += (int) vecs[i].iov_len;
-
-       DEBUG (MTD_DEBUG_LEVEL3,
-              "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);
-
-       /* Do not allow write past end of page */
-       if ((to + total_len) > mtd->size) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n");
-               return -EINVAL;
-       }
-
-       /* reject writes, which are not page aligned */ 
-       if (NOTALIGNED (to) || NOTALIGNED(total_len)) {
-               printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");
-               return -EINVAL;
-       }
-
-       // if oobsel is NULL, use chip defaults
-       if (oobsel == NULL) 
-               oobsel = &mtd->oobinfo;         
-
-       /* Shift to get page */
-       page = ((int) to) >> this->page_shift;
-
-       /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd, FL_WRITING, NULL);
-
-       /* Select the NAND device */
-       nand_select ();
-
-       /* Check the WP bit */
-       this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-       if (!(readb (this->IO_ADDR_R) & 0x80)) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n");
-               ret = -EIO;
-               goto out;
-       }
-
-       /* Loop until all kvec' data has been written */
-       len = 0;
-       while (count) {
-               /* 
-                *  Check, if the tuple gives us not enough data for a 
-                *  full page write. Then we can use the iov direct, 
-                *  else we have to copy into data_buf.         
-                */
-               if ((vecs->iov_len - len) >= mtd->oobblock) {
-                       this->data_poi = vecs->iov_base;
-                       this->data_poi += len;
-                       len += mtd->oobblock; 
-                       /* Check, if we have to switch to the next tuple */
-                       if (len >= (int) vecs->iov_len) {
-                               vecs++;
-                               len = 0;
-                               count--;
-                       }
-               } else {
-                       /*
-                        * Read data out of each tuple until we have a full page
-                        * to write or we've read all the tuples.
-                       */
-                       int cnt = 0;
-                       while ((cnt < mtd->oobblock) && count) {
-                               if (vecs->iov_base != NULL && vecs->iov_len) {
-                                       this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++];
-                               }
-                               /* Check, if we have to switch to the next tuple */
-                               if (len >= (int) vecs->iov_len) {
-                                       vecs++;
-                                       len = 0;
-                                       count--;
-                               }
-                       }       
-                       this->data_poi = this->data_buf;        
-               }
-               
-               /* We use the same function for write and writev !) */
-               ret = nand_write_page (mtd, this, page, NULL, oobsel);
-               if (ret)
-                       goto out;
-
-               /* Update written bytes count */
-               written += mtd->oobblock;
-
-               /* Increment page address */
-               page++;
-       }
-
-out:
-       /* De-select the NAND device */
-       nand_deselect ();
-
-       /* Wake up anyone waiting on the device */
-       spin_lock_bh (&this->chip_lock);
-       this->state = FL_READY;
-       wake_up (&this->wq);
-       spin_unlock_bh (&this->chip_lock);
-
-       *retlen = written;
-       return ret;
-}
-
-/*
- * NAND erase a block
- */
-static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
-{
-       int page, len, status, pages_per_block, ret;
-       struct nand_chip *this = mtd->priv;
-       DECLARE_WAITQUEUE (wait, current);
-
-       DEBUG (MTD_DEBUG_LEVEL3,
-              "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
-
-       /* Start address must align on block boundary */
-       if (instr->addr & (mtd->erasesize - 1)) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
-               return -EINVAL;
-       }
-
-       /* Length must align on block boundary */
-       if (instr->len & (mtd->erasesize - 1)) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
-               return -EINVAL;
-       }
-
-       /* Do not allow erase past end of device */
-       if ((instr->len + instr->addr) > mtd->size) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
-               return -EINVAL;
-       }
-
-       /* Grab the lock and see if the device is available */
-       nand_get_chip (this, mtd, FL_ERASING, NULL);
-
-       /* Shift to get first page */
-       page = (int) (instr->addr >> this->page_shift);
-
-       /* Calculate pages in each block */
-       pages_per_block = mtd->erasesize / mtd->oobblock;
-
-       /* Select the NAND device */
-       nand_select ();
-
-       /* Check the WP bit */
-       this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-       if (!(readb (this->IO_ADDR_R) & 0x80)) {
-               DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
-               instr->state = MTD_ERASE_FAILED;
-               goto erase_exit;
-       }
-
-       /* Loop through the pages */
-       len = instr->len;
-
-       instr->state = MTD_ERASING;
-
-       while (len) {
-               /* Check if we have a bad block, we do not erase bad blocks ! */
-               this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page);
-               if (readb (this->IO_ADDR_R) != 0xff) {
-                       printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page);
-                       instr->state = MTD_ERASE_FAILED;
-                       goto erase_exit;
-               }
-
-               /* Send commands to erase a page */
-               this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
-               this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
-
-               spin_unlock_bh (&this->chip_lock);
-               status = this->waitfunc (mtd, this, FL_ERASING);
-
-               /* Get spinlock, in case we exit */
-               spin_lock_bh (&this->chip_lock);
-               /* See if block erase succeeded */
-               if (status & 0x01) {
-                       DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
-                       instr->state = MTD_ERASE_FAILED;
-                       goto erase_exit;
-               }
-               
-               /* Check, if we were interupted */
-               if (this->state == FL_ERASING) {
-                       /* Increment page address and decrement length */
-                       len -= mtd->erasesize;
-                       page += pages_per_block;
-               }
-               /* Release the spin lock */
-               spin_unlock_bh (&this->chip_lock);
-erase_retry:
-               spin_lock_bh (&this->chip_lock);
-               /* Check the state and sleep if it changed */
-               if (this->state == FL_ERASING || this->state == FL_READY) {
-                       /* Select the NAND device again, if we were interrupted */
-                       this->state = FL_ERASING;
-                       nand_select ();
-                       continue;
-               } else {
-                       set_current_state (TASK_UNINTERRUPTIBLE);
-                       add_wait_queue (&this->wq, &wait);
-                       spin_unlock_bh (&this->chip_lock);
-                       schedule ();
-                       remove_wait_queue (&this->wq, &wait);
-                       goto erase_retry;
-               }
-       }
-       instr->state = MTD_ERASE_DONE;
-
-erase_exit:
-       /* De-select the NAND device */
-       nand_deselect ();
-       spin_unlock_bh (&this->chip_lock);
-
-       ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
-       /* Do call back function */
-       if (!ret && instr->callback)
-               instr->callback (instr);
-
-       /* The device is ready */
-       spin_lock_bh (&this->chip_lock);
-       this->state = FL_READY;
-       spin_unlock_bh (&this->chip_lock);
-
-       /* Return more or less happy */
-       return ret;
-}
-
-/*
- * NAND sync
- */
-static void nand_sync (struct mtd_info *mtd)
-{
-       struct nand_chip *this = mtd->priv;
-       DECLARE_WAITQUEUE (wait, current);
-
-       DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");
-
-retry:
-       /* Grab the spinlock */
-       spin_lock_bh (&this->chip_lock);
-
-       /* See what's going on */
-       switch (this->state) {
-       case FL_READY:
-       case FL_SYNCING:
-               this->state = FL_SYNCING;
-               spin_unlock_bh (&this->chip_lock);
-               break;
-
-       default:
-               /* Not an idle state */
-               add_wait_queue (&this->wq, &wait);
-               spin_unlock_bh (&this->chip_lock);
-               schedule ();
-
-               remove_wait_queue (&this->wq, &wait);
-               goto retry;
-       }
-
-       /* Lock the device */
-       spin_lock_bh (&this->chip_lock);
-
-       /* Set the device to be ready again */
-       if (this->state == FL_SYNCING) {
-               this->state = FL_READY;
-               wake_up (&this->wq);
-       }
-
-       /* Unlock the device */
-       spin_unlock_bh (&this->chip_lock);
-}
-
-/*
- * Scan for the NAND device
- */
-int nand_scan (struct mtd_info *mtd)
-{
-       int i, nand_maf_id, nand_dev_id;
-       struct nand_chip *this = mtd->priv;
-
-       /* check for proper chip_delay setup, set 20us if not */
-       if (!this->chip_delay)
-               this->chip_delay = 20;
-
-       /* check, if a user supplied command function given */
-       if (this->cmdfunc == NULL)
-               this->cmdfunc = nand_command;
-
-       /* check, if a user supplied wait function given */
-       if (this->waitfunc == NULL)
-               this->waitfunc = nand_wait;
-
-       /* Select the device */
-       nand_select ();
-
-       /* Send the command for reading device ID */
-       this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
-
-       /* Read manufacturer and device IDs */
-       nand_maf_id = readb (this->IO_ADDR_R);
-       nand_dev_id = readb (this->IO_ADDR_R);
-
-       /* Print and store flash device information */
-       for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-               if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) {
-                       mtd->name = nand_flash_ids[i].name;
-                       mtd->erasesize = nand_flash_ids[i].erasesize;
-                       mtd->size = (1 << nand_flash_ids[i].chipshift);
-                       mtd->eccsize = 256;
-                       if (nand_flash_ids[i].page256) {
-                               mtd->oobblock = 256;
-                               mtd->oobsize = 8;
-                               this->page_shift = 8;
-                       } else {
-                               mtd->oobblock = 512;
-                               mtd->oobsize = 16;
-                               this->page_shift = 9;
-                       }
-                       /* Try to identify manufacturer */
-                       for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
-                               if (nand_manuf_ids[i].id == nand_maf_id)
-                                       break;
-                       }       
-                       printk (KERN_INFO "NAND device: Manufacture ID:"
-                               " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-                               nand_manuf_ids[i].name , mtd->name);
-                       break;
-               }
-       }
-
-       /* 
-        * check ECC mode, default to software
-        * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize
-        * fallback to software ECC 
-       */
-       this->eccsize = 256;    /* set default eccsize */       
-
-       switch (this->eccmode) {
-
-       case NAND_ECC_HW3_512: 
-               if (mtd->oobblock == 256) {
-                       printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n");
-                       this->eccmode = NAND_ECC_SOFT;
-                       this->calculate_ecc = nand_calculate_ecc;
-                       this->correct_data = nand_correct_data;
-                       break;          
-               } else 
-                       this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
-
-       case NAND_ECC_HW3_256:
-               if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
-                       break;
-               printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
-               BUG();  
-
-       case NAND_ECC_NONE: 
-               printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
-               this->eccmode = NAND_ECC_NONE;
-               break;
-
-       case NAND_ECC_SOFT:     
-               this->calculate_ecc = nand_calculate_ecc;
-               this->correct_data = nand_correct_data;
-               break;
-
-       default:
-               printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-               BUG();  
-       }       
-       
-       /* Initialize state, waitqueue and spinlock */
-       this->state = FL_READY;
-       init_waitqueue_head (&this->wq);
-       spin_lock_init (&this->chip_lock);
-
-       /* De-select the device */
-       nand_deselect ();
-
-       /* Print warning message for no device */
-       if (!mtd->size) {
-               printk (KERN_WARNING "No NAND device found!!!\n");
-               return 1;
-       }
-
-       /* Fill in remaining MTD driver data */
-       mtd->type = MTD_NANDFLASH;
-       mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;
-       mtd->ecctype = MTD_ECC_SW;
-       mtd->erase = nand_erase;
-       mtd->point = NULL;
-       mtd->unpoint = NULL;
-       mtd->read = nand_read;
-       mtd->write = nand_write;
-       mtd->read_ecc = nand_read_ecc;
-       mtd->write_ecc = nand_write_ecc;
-       mtd->read_oob = nand_read_oob;
-       mtd->write_oob = nand_write_oob;
-       mtd->readv = NULL;
-       mtd->writev = nand_writev;
-       mtd->writev_ecc = nand_writev_ecc;
-       mtd->sync = nand_sync;
-       mtd->lock = NULL;
-       mtd->unlock = NULL;
-       mtd->suspend = NULL;
-       mtd->resume = NULL;
-       mtd->owner = THIS_MODULE;
-
-       /* Return happy */
-       return 0;
-}
-
-EXPORT_SYMBOL (nand_scan);
-
-MODULE_LICENSE ("GPL");
-MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
-MODULE_DESCRIPTION ("Generic NAND flash driver code");
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 f80d5ce..e9ce544 100644 (file)
@@ -1147,17 +1147,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
@@ -1201,6 +1199,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 8abcedf..e39e43f 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_EXT2_FS)         += ext2/
 obj-$(CONFIG_CRAMFS)           += cramfs/
 obj-$(CONFIG_RAMFS)            += ramfs/
 obj-$(CONFIG_HUGETLBFS)                += hugetlbfs/
+obj-$(CONFIG_RELAYFS_FS)       += relayfs/
 obj-$(CONFIG_CODA_FS)          += coda/
 obj-$(CONFIG_MINIX_FS)         += minix/
 obj-$(CONFIG_FAT_FS)           += fat/
index 290ed82..d215302 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -104,6 +104,8 @@ int inode_setattr(struct inode * inode, struct iattr * attr)
                inode->i_uid = attr->ia_uid;
        if (ia_valid & ATTR_GID)
                inode->i_gid = attr->ia_gid;
+       if (ia_valid & ATTR_XID)
+               inode->i_xid = attr->ia_xid;
        if (ia_valid & ATTR_ATIME)
                inode->i_atime = attr->ia_atime;
        if (ia_valid & ATTR_MTIME)
@@ -134,6 +136,8 @@ int setattr_mask(unsigned int ia_valid)
                dn_mask |= DN_ATTRIB;
        if (ia_valid & ATTR_GID)
                dn_mask |= DN_ATTRIB;
+       if (ia_valid & ATTR_XID)
+               dn_mask |= DN_ATTRIB;
        if (ia_valid & ATTR_SIZE)
                dn_mask |= DN_MODIFY;
        /* both times implies a utime(s) call */
@@ -197,7 +201,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
                        error = security_inode_setattr(dentry, attr);
                if (!error) {
                        if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-                           (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
+                           (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) ||
+                           (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid))
                                error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
                        if (!error)
                                error = inode_setattr(inode, attr);
index 3389c4f..ee8feb0 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/binfmts.h>
 #include <linux/personality.h>
 #include <linux/init.h>
+#include <linux/vs_memory.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
index e7e288d..9e71db4 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/pagemap.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
-#include <linux/vs_memory.h>
 
 #include <asm/uaccess.h>
 #include <asm/param.h>
index d386912..6715972 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -47,7 +47,6 @@
 #include <linux/syscalls.h>
 #include <linux/rmap.h>
 #include <linux/ckrm.h>
-#include <linux/vs_memory.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
index f5a6b33..7b776af 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/quotaops.h>
 #include <linux/sched.h>
 #include <linux/buffer_head.h>
+#include <linux/vs_base.h>
+#include <linux/vs_dlimit.h>
 
 /*
  * balloc.c contains the blocks allocation and deallocation routines
@@ -108,6 +110,8 @@ static int reserve_blocks(struct super_block *sb, int count)
        free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
        root_blocks = le32_to_cpu(es->s_r_blocks_count);
 
+       DLIMIT_ADJUST_BLOCK(sb, vx_current_xid(), &free_blocks, &root_blocks);
+
        if (free_blocks < count)
                count = free_blocks;
 
@@ -258,6 +262,7 @@ do_more:
        }
 error_return:
        brelse(bitmap_bh);
+       DLIMIT_FREE_BLOCK(sb, inode->i_xid, freed);
        release_blocks(sb, freed);
        DQUOT_FREE_BLOCK(inode, freed);
 }
@@ -361,6 +366,10 @@ int ext2_new_block(struct inode *inode, unsigned long goal,
                *err = -ENOSPC;
                goto out_dquot;
        }
+       if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, es_alloc)) {
+               *err = -ENOSPC;
+               goto out_dlimit;
+       }
 
        ext2_debug ("goal=%lu.\n", goal);
 
@@ -508,6 +517,8 @@ got_block:
        *err = 0;
 out_release:
        group_release_blocks(sb, group_no, desc, gdp_bh, group_alloc);
+       DLIMIT_FREE_BLOCK(sb, inode->i_xid, es_alloc);
+out_dlimit:
        release_blocks(sb, es_alloc);
 out_dquot:
        DQUOT_FREE_BLOCK(inode, dq_alloc);
index 5aa6769..299ea3f 100644 (file)
@@ -18,6 +18,9 @@
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>
 #include <linux/random.h>
+#include <linux/vs_base.h>
+#include <linux/vs_dlimit.h>
+
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
@@ -124,6 +127,7 @@ void ext2_free_inode (struct inode * inode)
        if (!is_bad_inode(inode)) {
                /* Quota is already initialized in iput() */
                ext2_xattr_delete_inode(inode);
+               DLIMIT_FREE_INODE(sb, inode->i_xid);
                DQUOT_FREE_INODE(inode);
                DQUOT_DROP(inode);
        }
@@ -465,6 +469,10 @@ struct inode *ext2_new_inode(struct inode *dir, int mode)
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
+       if (DLIMIT_ALLOC_INODE(sb, inode->i_xid)) {
+               err = -ENOSPC;
+               goto fail_dlim;
+       }
        ei = EXT2_I(inode);
        sbi = EXT2_SB(sb);
        es = sbi->s_es;
@@ -621,12 +629,15 @@ got:
        return inode;
 
 fail2:
+       DLIMIT_FREE_INODE(sb, inode->i_xid);    
        inode->i_flags |= S_NOQUOTA;
        inode->i_nlink = 0;
        iput(inode);
        return ERR_PTR(err);
 
 fail:
+       DLIMIT_FREE_INODE(sb, inode->i_xid);    
+fail_dlim:
        make_bad_inode(inode);
        iput(inode);
        return ERR_PTR(err);
index a91a711..dfc0ca2 100644 (file)
@@ -1314,11 +1314,15 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
        if (error)
                return error;
        if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
-           (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
+           (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) ||
+           (iattr->ia_valid & ATTR_XID && iattr->ia_xid != inode->i_xid)) {
                error = DQUOT_TRANSFER(inode, iattr) ? -EDQUOT : 0;
                if (error)
                        return error;
        }
+       if (iattr->ia_valid & ATTR_ATTR_FLAG)
+               ext2_setattr_flags(inode, iattr->ia_attr_flags);
+
        error = inode_setattr(inode, iattr);
        if (!error && (iattr->ia_valid & ATTR_MODE))
                error = ext2_acl_chmod(inode);
index 85ee4e8..ab8308a 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/mbcache.h>
 #include <linux/quotaops.h>
 #include <linux/rwsem.h>
+#include <linux/vs_dlimit.h>
 #include "ext2.h"
 #include "xattr.h"
 #include "acl.h"
@@ -749,8 +750,12 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
                                   the inode.  */
                                ea_bdebug(new_bh, "reusing block");
 
+                               error = -ENOSPC;
+                               if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, 1))
+                                       goto cleanup;
                                error = -EDQUOT;
                                if (DQUOT_ALLOC_BLOCK(inode, 1)) {
+                                       DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
                                        unlock_buffer(new_bh);
                                        goto cleanup;
                                }
@@ -830,6 +835,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
                        /* Decrement the refcount only. */
                        HDR(old_bh)->h_refcount = cpu_to_le32(
                                le32_to_cpu(HDR(old_bh)->h_refcount) - 1);
+                       DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
                        DQUOT_FREE_BLOCK(inode, 1);
                        mark_buffer_dirty(old_bh);
                        ea_bdebug(old_bh, "refcount now=%d",
@@ -885,6 +891,7 @@ ext2_xattr_delete_inode(struct inode *inode)
                mark_buffer_dirty(bh);
                if (IS_SYNC(inode))
                        sync_dirty_buffer(bh);
+               DLIMIT_FREE_BLOCK(inode->i_sb, inode->i_xid, 1);
                DQUOT_FREE_BLOCK(inode, 1);
        }
        ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
index 4ebdcf4..556f9d9 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/ext3_jbd.h>
 #include <linux/quotaops.h>
 #include <linux/buffer_head.h>
+#include <linux/vs_dlimit.h>
 
 /*
  * balloc.c contains the blocks allocation and deallocation routines
@@ -275,8 +276,10 @@ do_more:
 error_return:
        brelse(bitmap_bh);
        ext3_std_error(sb, err);
-       if (dquot_freed_blocks)
+       if (dquot_freed_blocks) {
+               DLIMIT_FREE_BLOCK(sb, inode->i_xid, dquot_freed_blocks);
                DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
+       }
        return;
 }
 
@@ -465,12 +468,16 @@ fail:
        return -1;
 }
 
-static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
+static int ext3_has_free_blocks(struct super_block *sb)
 {
+       struct ext3_sb_info *sbi = EXT3_SB(sb);
        int free_blocks, root_blocks;
 
        free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
        root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
+
+       DLIMIT_ADJUST_BLOCK(sb, vx_current_xid(), &free_blocks, &root_blocks);
+
        if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
                sbi->s_resuid != current->fsuid &&
                (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
@@ -487,7 +494,7 @@ static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
  */
 int ext3_should_retry_alloc(struct super_block *sb, int *retries)
 {
-       if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3)
+       if (!ext3_has_free_blocks(sb) || (*retries)++ > 3)
                return 0;
 
        jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
@@ -537,12 +544,14 @@ ext3_new_block(handle_t *handle, struct inode *inode, unsigned long goal,
                *errp = -EDQUOT;
                return 0;
        }
+       if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, 1))
+               goto out_dlimit;
 
        sbi = EXT3_SB(sb);
        es = EXT3_SB(sb)->s_es;
        ext3_debug("goal=%lu.\n", goal);
 
-       if (!ext3_has_free_blocks(sbi)) {
+       if (!ext3_has_free_blocks(sb)) {
                *errp = -ENOSPC;
                goto out;
        }
@@ -697,6 +706,8 @@ allocated:
 io_error:
        *errp = -EIO;
 out:
+       DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
+out_dlimit:
        if (fatal) {
                *errp = fatal;
                ext3_std_error(sb, fatal);
@@ -704,8 +715,10 @@ out:
        /*
         * Undo the block allocation
         */
-       if (!performed_allocation)
+       if (!performed_allocation) {
+               DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
                DQUOT_FREE_BLOCK(inode, 1);
+       }
        brelse(bitmap_bh);
        return 0;
 }
index 624f0bb..0c21ea4 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/random.h>
+#include <linux/vs_dlimit.h>
 
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
@@ -124,6 +125,7 @@ void ext3_free_inode (handle_t *handle, struct inode * inode)
         */
        DQUOT_INIT(inode);
        ext3_xattr_delete_inode(handle, inode);
+       DLIMIT_FREE_INODE(sb, inode->i_xid);
        DQUOT_FREE_INODE(inode);
        DQUOT_DROP(inode);
 
@@ -444,6 +446,10 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode)
        inode = new_inode(sb);
        if (!inode)
                return ERR_PTR(-ENOMEM);
+       if (DLIMIT_ALLOC_INODE(sb, inode->i_xid)) {
+               err = -ENOSPC;
+               goto fail_dlim;
+       }
        ei = EXT3_I(inode);
 
        sbi = EXT3_SB(sb);
@@ -619,6 +625,8 @@ got:
        ext3_debug("allocating inode %lu\n", inode->i_ino);
        goto really_out;
 fail:
+       DLIMIT_FREE_INODE(sb, inode->i_xid);
+fail_dlim:
        ext3_std_error(sb, err);
 out:
        iput(inode);
@@ -628,6 +636,7 @@ really_out:
        return ret;
 
 fail2:
+       DLIMIT_FREE_INODE(sb, inode->i_xid);
        inode->i_flags |= S_NOQUOTA;
        inode->i_nlink = 0;
        iput(inode);
index dde5da1..66fccef 100644 (file)
@@ -2852,7 +2852,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
                return error;
 
        if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
-               (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+               (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) ||
+               (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid)) {
                handle_t *handle;
 
                /* (user+group)*(old+new) structure, inode write (sb,
@@ -2873,6 +2874,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
                        inode->i_uid = attr->ia_uid;
                if (attr->ia_valid & ATTR_GID)
                        inode->i_gid = attr->ia_gid;
+               if (attr->ia_valid & ATTR_XID)
+                       inode->i_xid = attr->ia_xid;
                error = ext3_mark_inode_dirty(handle, inode);
                ext3_journal_stop(handle);
        }
index dbe8a6f..7765ab0 100644 (file)
@@ -154,7 +154,6 @@ flags_err:
                        return ret;
                }
 #endif
-
 #if defined(CONFIG_VSERVER_LEGACY) && !defined(CONFIG_INOXID_NONE)
        case EXT3_IOC_SETXID: {
                handle_t *handle;
index 5d53601..e48747b 100644 (file)
@@ -587,7 +587,7 @@ enum {
        Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
        Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
        Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
-       Opt_tagxid, Opt_ignore, Opt_err, Opt_resize,
+       Opt_tagxid, Opt_ignore, Opt_err
 };
 
 static match_table_t tokens = {
index 163db30..b6c382c 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/mbcache.h>
 #include <linux/quotaops.h>
 #include <linux/rwsem.h>
+#include <linux/vs_dlimit.h>
 #include "xattr.h"
 #include "acl.h"
 
@@ -761,8 +762,12 @@ ext3_xattr_set_handle2(handle_t *handle, struct inode *inode,
                                   the inode. */
                                ea_bdebug(new_bh, "reusing block");
 
+                               error = -ENOSPC;
+                               if (DLIMIT_ALLOC_BLOCK(sb, inode->i_xid, 1))
+                                       goto cleanup;
                                error = -EDQUOT;
                                if (DQUOT_ALLOC_BLOCK(inode, 1)) {
+                                       DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
                                        unlock_buffer(new_bh);
                                        journal_release_buffer(handle, new_bh,
                                                               credits);
@@ -848,6 +853,7 @@ getblk_failed:
                        /* Decrement the refcount only. */
                        HDR(old_bh)->h_refcount = cpu_to_le32(
                                le32_to_cpu(HDR(old_bh)->h_refcount) - 1);
+                       DLIMIT_FREE_BLOCK(sb, inode->i_xid, 1);
                        DQUOT_FREE_BLOCK(inode, 1);
                        ext3_journal_dirty_metadata(handle, old_bh);
                        ea_bdebug(old_bh, "refcount now=%d",
@@ -939,6 +945,7 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
                ext3_journal_dirty_metadata(handle, bh);
                if (IS_SYNC(inode))
                        handle->h_sync = 1;
+               DLIMIT_FREE_BLOCK(inode->i_sb, inode->i_xid, 1);
                DQUOT_FREE_BLOCK(inode, 1);
        }
        ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
index 4ba56b2..207cc73 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pagemap.h>
 #include <linux/cdev.h>
 #include <linux/bootmem.h>
+#include <linux/vs_base.h>
 
 /*
  * This is needed for the following functions:
@@ -594,6 +595,7 @@ struct inode *new_inode(struct super_block *sb)
                list_add(&inode->i_list, &inode_in_use);
                inode->i_ino = ++last_ino;
                inode->i_state = 0;
+               inode->i_xid = vx_current_xid();
                spin_unlock(&inode_lock);
        }
        return inode;
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 f061e70..b3a950c 100644 (file)
@@ -1015,7 +1015,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
        int error;
        int open_flags = 0;
 
-       dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id, 
+       dfprintk(VFS, "NFS: create(%s/%ld, %s)\n", dir->i_sb->s_id,
                dir->i_ino, dentry->d_name.name);
 
        attr.ia_mode = mode;
@@ -1032,9 +1032,12 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
         */
        lock_kernel();
        nfs_begin_data_update(dir);
+       dfprintk(VFS, "NFS: attr %d.%d #%d\n", attr.ia_uid, attr.ia_gid, attr.ia_xid);
        inode = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, open_flags);
        nfs_end_data_update(dir);
        if (!IS_ERR(inode)) {
+               dfprintk(VFS, "NFS: inode=%p %d.%d #%d\n", inode,
+                       inode->i_uid, inode->i_gid, inode->i_xid);
                d_instantiate(dentry, inode);
                nfs_renew_times(dentry);
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
index 36f5abc..bf31dc3 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/mount.h>
 #include <linux/nfs_idmap.h>
 #include <linux/vfs.h>
+#include <linux/vserver/xid.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -130,6 +131,7 @@ nfs_delete_inode(struct inode * inode)
                printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
        }
 
+//     DLIMIT_FREE_INODE(inode->i_sb, inode->i_xid);
        clear_inode(inode);
 }
 
@@ -332,6 +334,9 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
        }
        server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
 
+       if (server->flags & NFS_MOUNT_TAGXID)
+               sb->s_flags |= MS_TAGXID;
+
        sb->s_maxbytes = fsinfo.maxfilesize;
        if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
                sb->s_maxbytes = MAX_LFS_FILESIZE; 
@@ -563,6 +568,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
                { NFS_MOUNT_NOAC, ",noac", "" },
                { NFS_MOUNT_NONLM, ",nolock", ",lock" },
                { NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
+               { NFS_MOUNT_TAGXID, ",tagxid", "" },
                { 0, NULL, NULL }
        };
        struct proc_nfs_info *nfs_infop;
@@ -694,6 +700,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
        if (inode->i_state & I_NEW) {
                struct nfs_inode *nfsi = NFS_I(inode);
 
+/*             if (DLIMIT_ALLOC_INODE(sb, inode->i_xid)) {
+                       err = -ENOSPC;
+                       goto fail_dlim;
+               }
+*/
                /* We set i_ino for the few things that still rely on it,
                 * such as stat(2) */
                inode->i_ino = hash;
@@ -728,8 +739,11 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
                        nfsi->change_attr = fattr->change_attr;
                inode->i_size = nfs_size_to_loff_t(fattr->size);
                inode->i_nlink = fattr->nlink;
-               inode->i_uid = fattr->uid;
-               inode->i_gid = fattr->gid;
+               inode->i_uid = INOXID_UID(fattr->uid, fattr->gid);
+               inode->i_gid = INOXID_GID(fattr->uid, fattr->gid);
+               if (inode->i_sb->s_flags & MS_TAGXID)
+                       inode->i_xid = INOXID_XID(fattr->uid, fattr->gid, 0);
+                                        /* maybe fattr->xid someday */
                if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
                        /*
                         * report the blocks in 512byte units
@@ -755,13 +769,19 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 
 out:
        return inode;
-
+/*
+fail_dlim:
+        make_bad_inode(inode);
+        iput(inode);
+       inode = NULL;
+*/
 out_no_inode:
        printk("nfs_fhget: iget failed\n");
        goto out;
 }
 
-#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET)
+#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_XID|ATTR_SIZE|\
+                        ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET)
 
 int
 nfs_setattr(struct dentry *dentry, struct iattr *attr)
@@ -801,6 +821,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
                        inode->i_uid = attr->ia_uid;
                if ((attr->ia_valid & ATTR_GID) != 0)
                        inode->i_gid = attr->ia_gid;
+               if ((attr->ia_valid & ATTR_XID) != 0)
+                       inode->i_xid = attr->ia_xid;
                if ((attr->ia_valid & ATTR_SIZE) != 0) {
                        inode->i_size = attr->ia_size;
                        vmtruncate(inode, attr->ia_size);
@@ -1067,6 +1089,9 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
        struct nfs_inode *nfsi = NFS_I(inode);
        loff_t cur_size, new_isize;
        int data_unstable;
+       uid_t uid;
+       gid_t gid;
+       xid_t xid = 0;
 
        /* Are we in the process of updating data on the server? */
        data_unstable = nfs_caches_unstable(inode);
@@ -1106,10 +1131,16 @@ int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
        } else if (S_ISREG(inode->i_mode) && new_isize > cur_size)
                        nfsi->flags |= NFS_INO_INVALID_ATTR;
 
+       uid = INOXID_UID(fattr->uid, fattr->gid);
+       gid = INOXID_GID(fattr->uid, fattr->gid);
+       if (inode->i_sb->s_flags & MS_TAGXID)
+               xid = INOXID_XID(fattr->uid, fattr->gid, 0);
+
        /* Have any file permissions changed? */
        if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
-                       || inode->i_uid != fattr->uid
-                       || inode->i_gid != fattr->gid)
+                       || inode->i_uid != uid
+                       || inode->i_gid != gid
+                       || inode->i_xid != xid)
                nfsi->flags |= NFS_INO_INVALID_ATTR;
 
        /* Has the link count changed? */
@@ -1143,6 +1174,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
        unsigned int    invalid = 0;
        loff_t          cur_isize;
        int data_unstable;
+       uid_t           uid;
+       gid_t           gid;
+       xid_t           xid = 0;
 
        dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
                        __FUNCTION__, inode->i_sb->s_id, inode->i_ino,
@@ -1225,9 +1259,15 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
        memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
        memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
 
+       uid = INOXID_UID(fattr->uid, fattr->gid);
+       gid = INOXID_GID(fattr->uid, fattr->gid);
+       if (inode->i_sb->s_flags & MS_TAGXID)
+               xid = INOXID_XID(fattr->uid, fattr->gid, 0);
+
        if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
-           inode->i_uid != fattr->uid ||
-           inode->i_gid != fattr->gid) {
+           inode->i_uid != uid ||
+           inode->i_gid != gid ||
+           inode->i_xid != xid) {
                struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
                if (*cred) {
                        put_rpccred(*cred);
@@ -1238,8 +1278,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
 
        inode->i_mode = fattr->mode;
        inode->i_nlink = fattr->nlink;
-       inode->i_uid = fattr->uid;
-       inode->i_gid = fattr->gid;
+       inode->i_uid = uid;
+       inode->i_gid = gid;
+       inode->i_xid = xid;
 
        if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
                /*
index 56ca3e9..4708e63 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/nfs.h>
 #include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
+#include <linux/vserver/xid.h>
 
 #define NFSDBG_FACILITY                NFSDBG_XDR
 
@@ -185,15 +186,15 @@ xdr_encode_sattr(u32 *p, struct iattr *attr)
        } else {
                *p++ = xdr_zero;
        }
-       if (attr->ia_valid & ATTR_UID) {
+       if (attr->ia_valid & ATTR_UID || attr->ia_valid & ATTR_XID) {
                *p++ = xdr_one;
-               *p++ = htonl(attr->ia_uid);
+               *p++ = htonl(XIDINO_UID(attr->ia_uid, attr->ia_xid));
        } else {
                *p++ = xdr_zero;
        }
-       if (attr->ia_valid & ATTR_GID) {
+       if (attr->ia_valid & ATTR_GID || attr->ia_valid & ATTR_XID) {
                *p++ = xdr_one;
-               *p++ = htonl(attr->ia_gid);
+               *p++ = htonl(XIDINO_GID(attr->ia_gid, attr->ia_xid));
        } else {
                *p++ = xdr_zero;
        }
index a561819..7db9747 100644 (file)
@@ -87,6 +87,7 @@
 #include <linux/root_dev.h>
 #include <net/ipconfig.h>
 #include <linux/parser.h>
+#include <linux/vs_cvirt.h>
 
 /* Define this to allow debugging output */
 #undef NFSROOT_DEBUG
@@ -124,7 +125,7 @@ enum {
        Opt_soft, Opt_hard, Opt_intr,
        Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, 
        Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
-       Opt_broken_suid,
+       Opt_broken_suid, Opt_tagxid,
        /* Error token */
        Opt_err
 };
@@ -160,6 +161,7 @@ static match_table_t __initdata tokens = {
        {Opt_tcp, "proto=tcp"},
        {Opt_tcp, "tcp"},
        {Opt_broken_suid, "broken_suid"},
+       {Opt_tagxid, "tagxid"},
        {Opt_err, NULL}
        
 };
@@ -271,6 +273,9 @@ static int __init root_nfs_parse(char *name, char *buf)
                        case Opt_broken_suid:
                                nfs_data.flags |= NFS_MOUNT_BROKEN_SUID;
                                break;
+                       case Opt_tagxid:
+                               nfs_data.flags |= NFS_MOUNT_TAGXID;
+                               break;
                        default : 
                                return 0;
                }
index 8dc6a98..171a34a 100644 (file)
@@ -244,6 +244,9 @@ nfs_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
        int                     status;
 
        fattr.valid = 0;
+       memset(&fattr, 0, sizeof(struct nfs_fattr));
+
+
        dprintk("NFS call  create %s\n", name->name);
        status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
        dprintk("NFS reply create: %d\n", status);
index cfe9ce8..05822ee 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcauth.h>
 #include <linux/nfsd/nfsd.h>
+#include <linux/vserver/xid.h>
 
 #define        CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
 
@@ -42,13 +43,15 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
        }
 
        if (cred->cr_uid != (uid_t) -1)
-               current->fsuid = cred->cr_uid;
+               current->fsuid = INOXID_UID(cred->cr_uid, cred->cr_gid);
        else
                current->fsuid = exp->ex_anon_uid;
        if (cred->cr_gid != (gid_t) -1)
-               current->fsgid = cred->cr_gid;
+               current->fsgid = INOXID_GID(cred->cr_uid, cred->cr_gid);
        else
                current->fsgid = exp->ex_anon_gid;
+       
+       current->xid = INOXID_XID(cred->cr_uid, cred->cr_gid, 0);
 
        if (!cred->cr_group_info)
                return -ENOMEM;
index f5df830..a45bd68 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/xdr3.h>
+#include <linux/vserver/xid.h>
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -176,8 +177,10 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
        *p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
        *p++ = htonl((u32) stat.mode);
        *p++ = htonl((u32) stat.nlink);
-       *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
-       *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
+       *p++ = htonl((u32) nfsd_ruid(rqstp,
+               XIDINO_UID(stat.uid, stat.xid)));
+       *p++ = htonl((u32) nfsd_rgid(rqstp,
+               XIDINO_GID(stat.gid, stat.xid)));
        if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
                p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
        } else {
index 2016b9c..41b6d12 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 #include <linux/nfsd_idmap.h>
+#include <linux/vserver/xid.h>
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -1560,14 +1561,16 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                WRITE32(stat.nlink);
        }
        if (bmval1 & FATTR4_WORD1_OWNER) {
-               status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen);
+               status = nfsd4_encode_user(rqstp,
+                       XIDINO_UID(stat.uid, stat.xid), &p, &buflen);
                if (status == nfserr_resource)
                        goto out_resource;
                if (status)
                        goto out;
        }
        if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
-               status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen);
+               status = nfsd4_encode_group(rqstp,
+                       XIDINO_GID(stat.gid, stat.xid), &p, &buflen);
                if (status == nfserr_resource)
                        goto out_resource;
                if (status)
index 1d582f7..6e230b5 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/xdr.h>
 #include <linux/mm.h>
+#include <linux/vserver/xid.h>
 
 #define NFSDDBG_FACILITY               NFSDDBG_XDR
 
@@ -160,8 +161,10 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
        *p++ = htonl(nfs_ftypes[type >> 12]);
        *p++ = htonl((u32) stat.mode);
        *p++ = htonl((u32) stat.nlink);
-       *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
-       *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
+       *p++ = htonl((u32) nfsd_ruid(rqstp,
+               XIDINO_UID(stat.uid, stat.xid)));
+       *p++ = htonl((u32) nfsd_rgid(rqstp,
+               XIDINO_GID(stat.gid, stat.xid)));
 
        if (S_ISLNK(type) && stat.size > NFS_MAXPATHLEN) {
                *p++ = htonl(NFS_MAXPATHLEN);
index a6a05c3..b5ebd40 100644 (file)
@@ -1516,6 +1516,7 @@ int
 nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
 {
        int err = fh_verify(rqstp, fhp, 0, MAY_NOP);
+
        if (!err && vfs_statfs(fhp->fh_dentry->d_inode->i_sb,stat))
                err = nfserr_io;
        return err;
@@ -1533,7 +1534,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
        if (acc == MAY_NOP)
                return 0;
 #if 0
-       dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
+       printk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",
                acc,
                (acc & MAY_READ)?       " read"  : "",
                (acc & MAY_WRITE)?      " write" : "",
@@ -1546,7 +1547,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
                IS_IMMUTABLE(inode)?    " immut" : "",
                IS_APPEND(inode)?       " append" : "",
                IS_RDONLY(inode)?       " ro" : "");
-       dprintk("      owner %d/%d user %d/%d\n",
+       printk("      owner %d/%d user %d/%d\n",
                inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
 
index 2f25b14..07f7124 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -44,6 +44,8 @@ int vfs_statfs(struct super_block *sb, struct kstatfs *buf)
                        if (retval == 0 && buf->f_frsize == 0)
                                buf->f_frsize = buf->f_bsize;
                }
+               if (!vx_check(0, VX_ADMIN|VX_WATCH))
+                       vx_vsi_statfs(sb, buf);
        }
        return retval;
 }
@@ -914,6 +916,7 @@ static inline void __put_unused_fd(struct files_struct *files, unsigned int fd)
        __FD_CLR(fd, files->open_fds);
        if (fd < files->next_fd)
                files->next_fd = fd;
+       vx_openfd_dec(fd);
 }
 
 void fastcall put_unused_fd(unsigned int fd)
@@ -1046,7 +1049,6 @@ asmlinkage long sys_close(unsigned int fd)
        FD_CLR(fd, files->close_on_exec);
        __put_unused_fd(files, fd);
        spin_unlock(&files->file_lock);
-       vx_openfd_dec(fd);
        return filp_close(filp, files);
 
 out_unlock:
index dfca2ff..d00c864 100644 (file)
@@ -493,12 +493,12 @@ int proc_pid_delay(struct task_struct *task, char * buffer)
 
        res  = sprintf(buffer,"%u %llu %llu %u %llu %u %llu\n",
                       get_delay(task,runs),
-                      get_delay(task,runcpu_total),
-                      get_delay(task,waitcpu_total),
+                      (unsigned long long)get_delay(task,runcpu_total),
+                      (unsigned long long)get_delay(task,waitcpu_total),
                       get_delay(task,num_iowaits),
-                      get_delay(task,iowait_total),
+                      (unsigned long long)get_delay(task,iowait_total),
                       get_delay(task,num_memwaits),
-                      get_delay(task,mem_iowait_total)
+                      (unsigned long long)get_delay(task,mem_iowait_total)
                );
        return res;
 }
index 1427f01..199e761 100644 (file)
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
-#include <linux/vs_context.h>
 #include <linux/vs_network.h>
 #include <linux/vs_cvirt.h>
 
-
 /*
  * For hysterical raisins we keep the same inumbers as in the old procfs.
  * Feel free to change the macro below - just keep the range distinct from
index 83ccc66..f90884d 100644 (file)
@@ -717,6 +717,7 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st
        {"commit",      .arg_required = 'c', .values = NULL},
        {"usrquota",},
        {"grpquota",},
+       {"tagxid",      .setmask = 1<<REISERFS_TAGXID},
        {NULL,}
     };
        
index 6bda9bf..6e94fc8 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -26,6 +26,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
        stat->nlink = inode->i_nlink;
        stat->uid = inode->i_uid;
        stat->gid = inode->i_gid;
+       stat->xid = inode->i_xid;
        stat->rdev = inode->i_rdev;
        stat->atime = inode->i_atime;
        stat->mtime = inode->i_mtime;
index e348ef8..5c5a9a7 100644 (file)
@@ -1017,6 +1017,8 @@ xfs_ioc_fsgeometry(
 #define LINUX_XFLAG_APPEND     0x00000020 /* writes to file may only append */
 #define LINUX_XFLAG_NODUMP     0x00000040 /* do not dump file */
 #define LINUX_XFLAG_NOATIME    0x00000080 /* do not update atime */
+#define LINUX_XFLAG_BARRIER    0x00004000 /* chroot() barrier */
+#define LINUX_XFLAG_IUNLINK    0x00008000 /* Immutable unlink */
 
 STATIC unsigned int
 xfs_merge_ioc_xflags(
@@ -1057,6 +1059,8 @@ xfs_di2lxflags(
 
        if (di_flags & XFS_DIFLAG_IMMUTABLE)
                flags |= LINUX_XFLAG_IMMUTABLE;
+       if (di_flags & XFS_DIFLAG_IUNLINK)
+               flags |= LINUX_XFLAG_IUNLINK;
        if (di_flags & XFS_DIFLAG_APPEND)
                flags |= LINUX_XFLAG_APPEND;
        if (di_flags & XFS_DIFLAG_SYNC)
@@ -1081,6 +1085,7 @@ xfs_ioc_xattr(
        int                     error;
        int                     attr_flags;
        unsigned int            flags;
+       unsigned int            old_flags;
 
        switch (cmd) {
        case XFS_IOC_FSGETXATTR: {
@@ -1105,7 +1110,7 @@ xfs_ioc_xattr(
                attr_flags = 0;
                if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
                        attr_flags |= ATTR_NONBLOCK;
-
+               
                va.va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE;
                va.va_xflags  = fa.fsx_xflags;
                va.va_extsize = fa.fsx_extsize;
index f43f7c3..962cf8d 100644 (file)
@@ -67,6 +67,7 @@
 #include "xfs_utils.h"
 
 #include <linux/xattr.h>
+#include <linux/namei.h>
 
 
 /*
@@ -419,13 +420,16 @@ linvfs_follow_link(
        ASSERT(nd);
 
        link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL);
-       if (!link)
-               return -ENOMEM;
+       if (!link) {
+               nd_set_link(nd, ERR_PTR(-ENOMEM));
+               return 0;
+       }
 
        uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL);
        if (!uio) {
                kfree(link);
-               return -ENOMEM;
+               nd_set_link(nd, ERR_PTR(-ENOMEM));
+               return 0;
        }
 
        vp = LINVFS_GET_VP(dentry->d_inode);
@@ -441,18 +445,22 @@ linvfs_follow_link(
 
        VOP_READLINK(vp, uio, 0, NULL, error);
        if (error) {
-               kfree(uio);
                kfree(link);
-               return -error;
+               link = ERR_PTR(-error);
+       } else {
+               link[MAXNAMELEN - uio->uio_resid] = '\0';
        }
-
-       link[MAXNAMELEN - uio->uio_resid] = '\0';
        kfree(uio);
 
-       /* vfs_follow_link returns (-) errors */
-       error = vfs_follow_link(nd, link);
-       kfree(link);
-       return error;
+       nd_set_link(nd, link);
+       return 0;
+}
+
+static void linvfs_put_link(struct dentry *dentry, struct nameidata *nd)
+{
+       char *s = nd_get_link(nd);
+       if (!IS_ERR(s))
+               kfree(s);
 }
 
 #ifdef CONFIG_XFS_POSIX_ACL
@@ -490,6 +498,28 @@ linvfs_getattr(
        return 0;
 }
 
+STATIC int
+linvfs_setattr_flags(
+       vattr_t *vap,
+       unsigned int flags)
+{
+       unsigned int oldflags, newflags;
+
+       oldflags = vap->va_xflags;
+       newflags = oldflags & ~(XFS_XFLAG_IMMUTABLE |
+               XFS_XFLAG_IUNLINK | XFS_XFLAG_BARRIER);
+       if (flags & ATTR_FLAG_IMMUTABLE)
+               newflags |= XFS_XFLAG_IMMUTABLE;
+       if (flags & ATTR_FLAG_IUNLINK)
+               newflags |= XFS_XFLAG_IUNLINK;
+       if (flags & ATTR_FLAG_BARRIER)
+               newflags |= XFS_XFLAG_BARRIER;
+
+       if (oldflags ^ newflags)
+               vap->va_xflags = newflags;
+       return 0;
+}
+
 STATIC int
 linvfs_setattr(
        struct dentry   *dentry,
@@ -541,6 +571,11 @@ linvfs_setattr(
                flags |= ATTR_NONBLOCK;
 #endif
 
+       if (ia_valid & ATTR_ATTR_FLAG) {
+               vattr.va_mask |= XFS_AT_XFLAGS;
+               linvfs_setattr_flags(&vattr, attr->ia_attr_flags);
+       }
+
        VOP_SETATTR(vp, &vattr, flags, NULL, error);
        if (error)
                return -error;
@@ -692,6 +727,7 @@ struct inode_operations linvfs_dir_inode_operations = {
 struct inode_operations linvfs_symlink_inode_operations = {
        .readlink               = linvfs_readlink,
        .follow_link            = linvfs_follow_link,
+       .put_link               = linvfs_put_link,
        .permission             = linvfs_permission,
        .getattr                = linvfs_getattr,
        .setattr                = linvfs_setattr,
index e7825df..3a2e961 100644 (file)
@@ -76,7 +76,8 @@
 STATIC struct quotactl_ops linvfs_qops;
 STATIC struct super_operations linvfs_sops;
 STATIC struct export_operations linvfs_export_ops;
-STATIC kmem_cache_t * linvfs_inode_cachep;
+STATIC kmem_zone_t *linvfs_inode_zone;
+STATIC kmem_shaker_t xfs_inode_shaker;
 
 STATIC struct xfs_mount_args *
 xfs_args_allocate(
@@ -190,6 +191,14 @@ xfs_revalidate_inode(
                inode->i_flags |= S_IMMUTABLE;
        else
                inode->i_flags &= ~S_IMMUTABLE;
+       if (ip->i_d.di_flags & XFS_DIFLAG_IUNLINK)
+               inode->i_flags |= S_IUNLINK;
+       else
+               inode->i_flags &= ~S_IUNLINK;
+       if (ip->i_d.di_flags & XFS_DIFLAG_BARRIER)
+               inode->i_flags |= S_BARRIER;
+       else
+               inode->i_flags &= ~S_BARRIER;
        if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
                inode->i_flags |= S_APPEND;
        else
@@ -289,7 +298,7 @@ linvfs_alloc_inode(
 {
        vnode_t                 *vp;
 
-       vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_cachep
+       vp = (vnode_t *)kmem_cache_alloc(linvfs_inode_zone
                 kmem_flags_convert(KM_SLEEP));
        if (!vp)
                return NULL;
@@ -300,7 +309,20 @@ STATIC void
 linvfs_destroy_inode(
        struct inode            *inode)
 {
-       kmem_cache_free(linvfs_inode_cachep, LINVFS_GET_VP(inode));
+       kmem_cache_free(linvfs_inode_zone, LINVFS_GET_VP(inode));
+}
+
+int
+xfs_inode_shake(
+       int             priority,
+       unsigned int    gfp_mask)
+{
+       int             pages;
+
+       
+       pages = kmem_zone_shrink(linvfs_inode_zone);
+       pages += kmem_zone_shrink(xfs_inode_zone);
+       return pages;
 }
 
 STATIC void
@@ -319,12 +341,12 @@ init_once(
 STATIC int
 init_inodecache( void )
 {
-       linvfs_inode_cachep = kmem_cache_create("linvfs_icache",
+       linvfs_inode_zone = kmem_cache_create("linvfs_icache",
                                sizeof(vnode_t), 0,
                                SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
                                init_once, NULL);
 
-       if (linvfs_inode_cachep == NULL)
+       if (linvfs_inode_zone == NULL)
                return -ENOMEM;
        return 0;
 }
@@ -332,7 +354,7 @@ init_inodecache( void )
 STATIC void
 destroy_inodecache( void )
 {
-       if (kmem_cache_destroy(linvfs_inode_cachep))
+       if (kmem_cache_destroy(linvfs_inode_zone))
                printk(KERN_WARNING "%s: cache still in use!\n", __FUNCTION__);
 }
 
@@ -835,15 +857,24 @@ init_xfs_fs( void )
        vn_init();
        xfs_init();
        uuid_init();
-       vfs_initdmapi();
        vfs_initquota();
 
+       xfs_inode_shaker = kmem_shake_register(xfs_inode_shake);
+       if (!xfs_inode_shaker) {
+               error = -ENOMEM;
+               goto undo_shaker;
+       }
+
        error = register_filesystem(&xfs_fs_type);
        if (error)
                goto undo_register;
+       XFS_DM_INIT(&xfs_fs_type);
        return 0;
 
 undo_register:
+       kmem_shake_deregister(xfs_inode_shaker);
+
+undo_shaker:
        pagebuf_terminate();
 
 undo_pagebuf:
@@ -857,8 +888,9 @@ STATIC void __exit
 exit_xfs_fs( void )
 {
        vfs_exitquota();
-       vfs_exitdmapi();
+       XFS_DM_EXIT(&xfs_fs_type);
        unregister_filesystem(&xfs_fs_type);
+       kmem_shake_deregister(xfs_inode_shaker);
        xfs_cleanup();
        pagebuf_terminate();
        destroy_inodecache();
index 9240efb..44ba5e5 100644 (file)
@@ -217,6 +217,14 @@ vn_revalidate(
                        inode->i_flags |= S_IMMUTABLE;
                else
                        inode->i_flags &= ~S_IMMUTABLE;
+               if (va.va_xflags & XFS_XFLAG_IUNLINK)
+                       inode->i_flags |= S_IUNLINK;
+               else
+                       inode->i_flags &= ~S_IUNLINK;
+               if (va.va_xflags & XFS_XFLAG_BARRIER)
+                       inode->i_flags |= S_BARRIER;
+               else
+                       inode->i_flags &= ~S_BARRIER;
                if (va.va_xflags & XFS_XFLAG_APPEND)
                        inode->i_flags |= S_APPEND;
                else
index ebf7967..c293149 100644 (file)
@@ -15,9 +15,9 @@
 
 #include <linux/config.h>
 #include <linux/swap.h>
+#include <linux/vs_memory.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
-#include <linux/vs_memory.h>
 
 /*
  * For UP we don't need to worry about TLB flush
diff --git a/include/asm-ppc/gt64260.h b/include/asm-ppc/gt64260.h
deleted file mode 100644 (file)
index cd0ef64..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * include/asm-ppc/gt64260.h
- *
- * Prototypes, etc. for the Marvell/Galileo GT64260 host bridge routines.
- *
- * Author: Mark A. 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.
- */
-#ifndef __ASMPPC_GT64260_H
-#define __ASMPPC_GT64260_H
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/gt64260_defs.h>
-
-
-extern u32     gt64260_base;
-extern u32     gt64260_irq_base;     /* We handle the next 96 IRQs from here */
-extern u32     gt64260_revision;
-extern u8      gt64260_pci_exclude_bridge;
-
-#ifndef        TRUE
-#define        TRUE    1
-#endif
-
-#ifndef        FALSE
-#define        FALSE   0
-#endif
-
-/* IRQs defined by the 64260 */
-#define        GT64260_IRQ_MPSC0               40
-#define        GT64260_IRQ_MPSC1               42
-#define        GT64260_IRQ_SDMA                36
-
-/*
- * Define a default physical memory map to be set up on the bridge.
- * Also define a struct to pass that info from board-specific routines to
- * GT64260 generic set up routines.  By passing this info in, the board
- * support developer can modify it at will.
- */
-
-/*
- * This is the default memory map:
- *                     CPU                     PCI
- *                     ---                     ---
- * PCI 0 I/O:  0xfa000000-0xfaffffff   0x00000000-0x00ffffff
- * PCI 1 I/O:  0xfb000000-0xfbffffff   0x01000000-0x01ffffff
- * PCI 0 MEM:  0x80000000-0x8fffffff   0x80000000-0x8fffffff
- * PCI 1 MEM:  0x90000000-0x9fffffff   0x90000000-0x9fffffff
- */
-
-/* Default physical memory map for the GT64260 bridge */
-
-/*
- * PCI Bus 0 Definitions
- */
-#define GT64260_PCI_0_IO_SIZE          0x01000000U
-#define        GT64260_PCI_0_MEM_SIZE          0x10000000U
-
-/* Processor Physical addresses */
-#define        GT64260_PCI_0_IO_START_PROC     0xfa000000U
-#define        GT64260_PCI_0_IO_END_PROC       (GT64260_PCI_0_IO_START_PROC + \
-                                        GT64260_PCI_0_IO_SIZE - 1)
-
-/* PCI 0 addresses */
-#define        GT64260_PCI_0_IO_START          0x00000000U
-#define        GT64260_PCI_0_IO_END            (GT64260_PCI_0_IO_START + \
-                                        GT64260_PCI_0_IO_SIZE - 1)
-
-/* Processor Physical addresses */
-#define        GT64260_PCI_0_MEM_START_PROC    0x80000000U
-#define        GT64260_PCI_0_MEM_END_PROC      (GT64260_PCI_0_MEM_START_PROC + \
-                                        GT64260_PCI_0_MEM_SIZE - 1)
-
-/* PCI 0 addresses */
-#define        GT64260_PCI_0_MEM_START         0x80000000U
-#define        GT64260_PCI_0_MEM_END           (GT64260_PCI_0_MEM_START + \
-                                        GT64260_PCI_0_MEM_SIZE - 1)
-
-/*
- * PCI Bus 1 Definitions
- */
-#define GT64260_PCI_1_IO_SIZE          0x01000000U
-#define        GT64260_PCI_1_MEM_SIZE          0x10000000U
-
-/* PCI 1 addresses */
-#define        GT64260_PCI_1_IO_START          0x01000000U
-#define        GT64260_PCI_1_IO_END            (GT64260_PCI_1_IO_START + \
-                                        GT64260_PCI_1_IO_SIZE - 1)
-
-/* Processor Physical addresses */
-#define        GT64260_PCI_1_IO_START_PROC     0xfb000000U
-#define        GT64260_PCI_1_IO_END_PROC       (GT64260_PCI_1_IO_START_PROC + \
-                                        GT64260_PCI_1_IO_SIZE - 1)
-
-/* PCI 1 addresses */
-#define        GT64260_PCI_1_MEM_START         0x90000000U
-#define        GT64260_PCI_1_MEM_END           (GT64260_PCI_1_MEM_START + \
-                                        GT64260_PCI_1_MEM_SIZE - 1)
-
-/* Processor Physical addresses */
-#define        GT64260_PCI_1_MEM_START_PROC    0x90000000U
-#define        GT64260_PCI_1_MEM_END_PROC      (GT64260_PCI_1_MEM_START_PROC + \
-                                        GT64260_PCI_1_MEM_SIZE - 1)
-
-/* Define struct to pass mem-map info into gt64260_common.c code */
-typedef struct {
-       struct pci_controller   *hose_a;
-       struct pci_controller   *hose_b;
-
-       u32     mem_size;
-
-       u32     pci_0_io_start_proc;
-       u32     pci_0_io_start_pci;
-       u32     pci_0_io_size;
-       u32     pci_0_io_swap;
-
-       u32     pci_0_mem_start_proc;
-       u32     pci_0_mem_start_pci_hi;
-       u32     pci_0_mem_start_pci_lo;
-       u32     pci_0_mem_size;
-       u32     pci_0_mem_swap;
-
-       u32     pci_1_io_start_proc;
-       u32     pci_1_io_start_pci;
-       u32     pci_1_io_size;
-       u32     pci_1_io_swap;
-
-       u32     pci_1_mem_start_proc;
-       u32     pci_1_mem_start_pci_hi;
-       u32     pci_1_mem_start_pci_lo;
-       u32     pci_1_mem_size;
-       u32     pci_1_mem_swap;
-} gt64260_bridge_info_t;
-
-#define        GT64260_BRIDGE_INFO_DEFAULT(ip, ms) {                           \
-       (ip)->mem_size = (ms);                                          \
-                                                                       \
-       (ip)->pci_0_io_start_proc = GT64260_PCI_0_IO_START_PROC;        \
-       (ip)->pci_0_io_start_pci  = GT64260_PCI_0_IO_START;             \
-       (ip)->pci_0_io_size       = GT64260_PCI_0_IO_SIZE;              \
-       (ip)->pci_0_io_swap       = GT64260_CPU_PCI_SWAP_NONE;          \
-                                                                       \
-       (ip)->pci_0_mem_start_proc   = GT64260_PCI_0_MEM_START_PROC;    \
-       (ip)->pci_0_mem_start_pci_hi = 0x00000000;                      \
-       (ip)->pci_0_mem_start_pci_lo = GT64260_PCI_0_MEM_START;         \
-       (ip)->pci_0_mem_size         = GT64260_PCI_0_MEM_SIZE;          \
-       (ip)->pci_0_mem_swap         = GT64260_CPU_PCI_SWAP_NONE;       \
-                                                                       \
-       (ip)->pci_1_io_start_proc = GT64260_PCI_1_IO_START_PROC;        \
-       (ip)->pci_1_io_start_pci  = GT64260_PCI_1_IO_START;             \
-       (ip)->pci_1_io_size       = GT64260_PCI_1_IO_SIZE;              \
-       (ip)->pci_1_io_swap       = GT64260_CPU_PCI_SWAP_NONE;          \
-                                                                       \
-       (ip)->pci_1_mem_start_proc   = GT64260_PCI_1_MEM_START_PROC;    \
-       (ip)->pci_1_mem_start_pci_hi = 0x00000000;                      \
-       (ip)->pci_1_mem_start_pci_lo = GT64260_PCI_1_MEM_START;         \
-       (ip)->pci_1_mem_size         = GT64260_PCI_1_MEM_SIZE;          \
-       (ip)->pci_1_mem_swap         = GT64260_CPU_PCI_SWAP_NONE;       \
-}
-
-/*
- *****************************************************************************
- *
- *     I/O macros to access the 64260's registers
- *
- *****************************************************************************
- */
-
-extern inline uint32_t gt_read(uint32_t offs){
-       return (in_le32((volatile uint *)(gt64260_base + offs)));
-}
-extern inline void gt_write(uint32_t offs, uint32_t d){
-       out_le32((volatile uint *)(gt64260_base + offs), d);
-}
-
-#if 0 /* paranoid SMP version */
-extern inline void gt_modify(u32 offs, u32 data, u32 mask) \
-{
-       uint32_t reg;
-       spin_lock(&gt64260_lock);
-       reg = gt_read(offs) & (~mask); /* zero any bits we care about*/
-       reg |= data & mask; /* set bits from the data */
-       gt_write(offs, reg);
-       spin_unlock(&gt64260_lock);
-}
-#else
-extern inline void gt_modify(uint32_t offs, uint32_t data, uint32_t mask)
-{
-       uint32_t reg;
-       reg = gt_read(offs) & (~(mask)); /* zero any bits we care about*/
-       reg |= (data) & (mask); /* set bits from the data */
-       gt_write(offs, reg);
-}
-#endif
-#define        gt_set_bits(offs, bits) gt_modify(offs, ~0, bits)
-
-#define        gt_clr_bits(offs, bits) gt_modify(offs, 0, bits)
-
-
-/*
- *****************************************************************************
- *
- *     Function Prototypes
- *
- *****************************************************************************
- */
-
-int gt64260_find_bridges(u32 phys_base_addr, gt64260_bridge_info_t *info,
-       int ((*map_irq)(struct pci_dev *, unsigned char, unsigned char)));
-int gt64260_bridge_init(gt64260_bridge_info_t *info);
-int gt64260_cpu_scs_set_window(u32 window,
-                              u32 base_addr,
-                              u32 size);
-int gt64260_cpu_cs_set_window(u32 window,
-                             u32 base_addr,
-                             u32 size);
-int gt64260_cpu_boot_set_window(u32 base_addr,
-                               u32 size);
-int gt64260_cpu_set_pci_io_window(u32 pci_bus,
-                                 u32 cpu_base_addr,
-                                 u32 pci_base_addr,
-                                 u32 size,
-                                 u32 swap);
-int gt64260_cpu_set_pci_mem_window(u32 pci_bus,
-                                  u32 window,
-                                  u32 cpu_base_addr,
-                                  u32 pci_base_addr_hi,
-                                  u32 pci_base_addr_lo,
-                                  u32 size,
-                                  u32 swap_64bit);
-int gt64260_cpu_prot_set_window(u32 window,
-                               u32 base_addr,
-                               u32 size,
-                               u32 access_bits);
-int gt64260_cpu_snoop_set_window(u32 window,
-                                u32 base_addr,
-                                u32 size,
-                                u32  snoop_type);
-void gt64260_cpu_disable_all_windows(void);
-int gt64260_pci_bar_enable(u32 pci_bus, u32 enable_bits);
-int gt64260_pci_slave_scs_set_window(struct pci_controller *hose,
-                                    u32 window,
-                                    u32 pci_base_addr,
-                                    u32 cpu_base_addr,
-                                    u32 size);
-int gt64260_pci_slave_cs_set_window(struct pci_controller *hose,
-                                   u32 window,
-                                   u32 pci_base_addr,
-                                   u32 cpu_base_addr,
-                                   u32 size);
-int gt64260_pci_slave_boot_set_window(struct pci_controller *hose,
-                                     u32 pci_base_addr,
-                                     u32 cpu_base_addr,
-                                     u32 size);
-int gt64260_pci_slave_p2p_mem_set_window(struct pci_controller *hose,
-                                        u32 window,
-                                        u32 pci_base_addr,
-                                        u32 other_bus_base_addr,
-                                        u32 size);
-int gt64260_pci_slave_p2p_io_set_window(struct pci_controller *hose,
-                                       u32 pci_base_addr,
-                                       u32 other_bus_base_addr,
-                                       u32 size);
-int gt64260_pci_slave_dac_scs_set_window(struct pci_controller *hose,
-                                        u32 window,
-                                        u32 pci_base_addr_hi,
-                                        u32 pci_base_addr_lo,
-                                        u32 cpu_base_addr,
-                                        u32 size);
-int gt64260_pci_slave_dac_cs_set_window(struct pci_controller *hose,
-                                       u32 window,
-                                       u32 pci_base_addr_hi,
-                                       u32 pci_base_addr_lo,
-                                       u32 cpu_base_addr,
-                                       u32 size);
-int gt64260_pci_slave_dac_boot_set_window(struct pci_controller *hose,
-                                         u32 pci_base_addr_hi,
-                                         u32 pci_base_addr_lo,
-                                         u32 cpu_base_addr,
-                                         u32 size);
-int gt64260_pci_slave_dac_p2p_mem_set_window(struct pci_controller *hose,
-                                            u32 window,
-                                            u32 pci_base_addr_hi,
-                                            u32 pci_base_addr_lo,
-                                            u32 other_bus_base_addr,
-                                            u32 size);
-int gt64260_pci_acc_cntl_set_window(u32 pci_bus,
-                                   u32 window,
-                                   u32 base_addr_hi,
-                                   u32 base_addr_lo,
-                                   u32 size,
-                                   u32 features);
-int gt64260_pci_snoop_set_window(u32 pci_bus,
-                                u32 window,
-                                u32 base_addr_hi,
-                                u32 base_addr_lo,
-                                u32 size,
-                                u32 snoop_type);
-int gt64260_set_base(u32 new_base);
-int gt64260_get_base(u32 *base);
-int gt64260_pci_exclude_device(u8 bus, u8 devfn);
-
-void gt64260_init_irq(void);
-int gt64260_get_irq(struct pt_regs *regs);
-
-void gt64260_mpsc_progress(char *s, unsigned short hex);
-
-#endif /* __ASMPPC_GT64260_H */
diff --git a/include/asm-ppc/gt64260_defs.h b/include/asm-ppc/gt64260_defs.h
deleted file mode 100644 (file)
index 6ffd01a..0000000
+++ /dev/null
@@ -1,1010 +0,0 @@
-/*
- * include/asm-ppc/gt64260_defs.h
- *
- * Register definitions for the Marvell/Galileo GT64260 host bridge.
- *
- * Author: Mark A. 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.
- */
-#ifndef __ASMPPC_GT64260_DEFS_H
-#define __ASMPPC_GT64260_DEFS_H
-
-/*
- * Define a macro to represent the supported version of the 64260.
- */
-#define        GT64260                 0x01
-#define        GT64260A                0x10
-
-/*
- *****************************************************************************
- *
- *     CPU Interface Registers
- *
- *****************************************************************************
- */
-
-/* CPU physical address of 64260's registers */
-#define GT64260_INTERNAL_SPACE_DECODE                  0x0068
-#define GT64260_INTERNAL_SPACE_SIZE                    0x10000
-#define GT64260_INTERNAL_SPACE_DEFAULT_ADDR            0x14000000
-
-/* CPU Memory Controller Window Registers (4 windows) */
-#define        GT64260_CPU_SCS_DECODE_WINDOWS                  4
-
-#define        GT64260_CPU_SCS_DECODE_0_BOT                    0x0008
-#define        GT64260_CPU_SCS_DECODE_0_TOP                    0x0010
-#define        GT64260_CPU_SCS_DECODE_1_BOT                    0x0208
-#define        GT64260_CPU_SCS_DECODE_1_TOP                    0x0210
-#define        GT64260_CPU_SCS_DECODE_2_BOT                    0x0018
-#define        GT64260_CPU_SCS_DECODE_2_TOP                    0x0020
-#define        GT64260_CPU_SCS_DECODE_3_BOT                    0x0218
-#define        GT64260_CPU_SCS_DECODE_3_TOP                    0x0220
-
-/* CPU Device Controller Window Registers (4 windows) */
-#define        GT64260_CPU_CS_DECODE_WINDOWS                   4
-
-#define        GT64260_CPU_CS_DECODE_0_BOT                     0x0028
-#define        GT64260_CPU_CS_DECODE_0_TOP                     0x0030
-#define        GT64260_CPU_CS_DECODE_1_BOT                     0x0228
-#define        GT64260_CPU_CS_DECODE_1_TOP                     0x0230
-#define        GT64260_CPU_CS_DECODE_2_BOT                     0x0248
-#define        GT64260_CPU_CS_DECODE_2_TOP                     0x0250
-#define        GT64260_CPU_CS_DECODE_3_BOT                     0x0038
-#define        GT64260_CPU_CS_DECODE_3_TOP                     0x0040
-
-#define        GT64260_CPU_BOOT_CS_DECODE_0_BOT                0x0238
-#define        GT64260_CPU_BOOT_CS_DECODE_0_TOP                0x0240
-
-/* CPU Windows to PCI space (2 PCI buses each w/ 1 I/O & 4 MEM windows) */
-#define        GT64260_PCI_BUSES                               2
-#define        GT64260_PCI_IO_WINDOWS_PER_BUS                  1
-#define        GT64260_PCI_MEM_WINDOWS_PER_BUS                 4
-
-#define        GT64260_CPU_PCI_SWAP_BYTE                       0x00000000
-#define        GT64260_CPU_PCI_SWAP_NONE                       0x01000000
-#define        GT64260_CPU_PCI_SWAP_BYTE_WORD                  0x02000000
-#define        GT64260_CPU_PCI_SWAP_WORD                       0x03000000
-#define        GT64260_CPU_PCI_SWAP_MASK                       0x07000000
-
-#define        GT64260_CPU_PCI_MEM_REQ64                       (1<<27)
-
-#define        GT64260_CPU_PCI_0_IO_DECODE_BOT                 0x0048
-#define        GT64260_CPU_PCI_0_IO_DECODE_TOP                 0x0050
-#define        GT64260_CPU_PCI_0_MEM_0_DECODE_BOT              0x0058
-#define        GT64260_CPU_PCI_0_MEM_0_DECODE_TOP              0x0060
-#define        GT64260_CPU_PCI_0_MEM_1_DECODE_BOT              0x0080
-#define        GT64260_CPU_PCI_0_MEM_1_DECODE_TOP              0x0088
-#define        GT64260_CPU_PCI_0_MEM_2_DECODE_BOT              0x0258
-#define        GT64260_CPU_PCI_0_MEM_2_DECODE_TOP              0x0260
-#define        GT64260_CPU_PCI_0_MEM_3_DECODE_BOT              0x0280
-#define        GT64260_CPU_PCI_0_MEM_3_DECODE_TOP              0x0288
-
-#define        GT64260_CPU_PCI_0_IO_REMAP                      0x00f0
-#define        GT64260_CPU_PCI_0_MEM_0_REMAP_LO                0x00f8
-#define        GT64260_CPU_PCI_0_MEM_0_REMAP_HI                0x0320
-#define        GT64260_CPU_PCI_0_MEM_1_REMAP_LO                0x0100
-#define        GT64260_CPU_PCI_0_MEM_1_REMAP_HI                0x0328
-#define        GT64260_CPU_PCI_0_MEM_2_REMAP_LO                0x02f8
-#define        GT64260_CPU_PCI_0_MEM_2_REMAP_HI                0x0330
-#define        GT64260_CPU_PCI_0_MEM_3_REMAP_LO                0x0300
-#define        GT64260_CPU_PCI_0_MEM_3_REMAP_HI                0x0338
-
-#define        GT64260_CPU_PCI_1_IO_DECODE_BOT                 0x0090
-#define        GT64260_CPU_PCI_1_IO_DECODE_TOP                 0x0098
-#define        GT64260_CPU_PCI_1_MEM_0_DECODE_BOT              0x00a0
-#define        GT64260_CPU_PCI_1_MEM_0_DECODE_TOP              0x00a8
-#define        GT64260_CPU_PCI_1_MEM_1_DECODE_BOT              0x00b0
-#define        GT64260_CPU_PCI_1_MEM_1_DECODE_TOP              0x00b8
-#define        GT64260_CPU_PCI_1_MEM_2_DECODE_BOT              0x02a0
-#define        GT64260_CPU_PCI_1_MEM_2_DECODE_TOP              0x02a8
-#define        GT64260_CPU_PCI_1_MEM_3_DECODE_BOT              0x02b0
-#define        GT64260_CPU_PCI_1_MEM_3_DECODE_TOP              0x02b8
-
-#define        GT64260_CPU_PCI_1_IO_REMAP                      0x0108
-#define        GT64260_CPU_PCI_1_MEM_0_REMAP_LO                0x0110
-#define        GT64260_CPU_PCI_1_MEM_0_REMAP_HI                0x0340
-#define        GT64260_CPU_PCI_1_MEM_1_REMAP_LO                0x0118
-#define        GT64260_CPU_PCI_1_MEM_1_REMAP_HI                0x0348
-#define        GT64260_CPU_PCI_1_MEM_2_REMAP_LO                0x0310
-#define        GT64260_CPU_PCI_1_MEM_2_REMAP_HI                0x0350
-#define        GT64260_CPU_PCI_1_MEM_3_REMAP_LO                0x0318
-#define        GT64260_CPU_PCI_1_MEM_3_REMAP_HI                0x0358
-
-/* CPU Control Registers */
-#define GT64260_CPU_CONFIG                             0x0000
-#define GT64260_CPU_MODE                               0x0120
-#define GT64260_CPU_MASTER_CNTL                                0x0160
-#define GT64260_CPU_XBAR_CNTL_LO                       0x0150
-#define GT64260_CPU_XBAR_CNTL_HI                       0x0158
-#define GT64260_CPU_XBAR_TO                            0x0168
-#define GT64260_CPU_RR_XBAR_CNTL_LO                    0x0170
-#define GT64260_CPU_RR_XBAR_CNTL_HI                    0x0178
-
-/* CPU Sync Barrier Registers */
-#define GT64260_CPU_SYNC_BARRIER_PCI_0                 0x00c0
-#define GT64260_CPU_SYNC_BARRIER_PCI_1                 0x00c8
-
-/* CPU Access Protection Registers */
-#define        GT64260_CPU_PROT_WINDOWS                        8
-
-#define        GT64260_CPU_PROT_ACCPROTECT                     (1<<16)
-#define        GT64260_CPU_PROT_WRPROTECT                      (1<<17)
-#define        GT64260_CPU_PROT_CACHEPROTECT                   (1<<18)
-
-#define GT64260_CPU_PROT_BASE_0                                0x0180
-#define GT64260_CPU_PROT_TOP_0                         0x0188
-#define GT64260_CPU_PROT_BASE_1                                0x0190
-#define GT64260_CPU_PROT_TOP_1                         0x0198
-#define GT64260_CPU_PROT_BASE_2                                0x01a0
-#define GT64260_CPU_PROT_TOP_2                         0x01a8
-#define GT64260_CPU_PROT_BASE_3                                0x01b0
-#define GT64260_CPU_PROT_TOP_3                         0x01b8
-#define GT64260_CPU_PROT_BASE_4                                0x01c0
-#define GT64260_CPU_PROT_TOP_4                         0x01c8
-#define GT64260_CPU_PROT_BASE_5                                0x01d0
-#define GT64260_CPU_PROT_TOP_5                         0x01d8
-#define GT64260_CPU_PROT_BASE_6                                0x01e0
-#define GT64260_CPU_PROT_TOP_6                         0x01e8
-#define GT64260_CPU_PROT_BASE_7                                0x01f0
-#define GT64260_CPU_PROT_TOP_7                         0x01f8
-
-/* CPU Snoop Control Registers */
-#define        GT64260_CPU_SNOOP_WINDOWS                       4
-
-#define        GT64260_CPU_SNOOP_NONE                          0x00000000
-#define        GT64260_CPU_SNOOP_WT                            0x00010000
-#define        GT64260_CPU_SNOOP_WB                            0x00020000
-#define        GT64260_CPU_SNOOP_MASK                          0x00030000
-#define        GT64260_CPU_SNOOP_ALL_BITS                      GT64260_CPU_SNOOP_MASK
-
-#define GT64260_CPU_SNOOP_BASE_0                       0x0380
-#define GT64260_CPU_SNOOP_TOP_0                                0x0388
-#define GT64260_CPU_SNOOP_BASE_1                       0x0390
-#define GT64260_CPU_SNOOP_TOP_1                                0x0398
-#define GT64260_CPU_SNOOP_BASE_2                       0x03a0
-#define GT64260_CPU_SNOOP_TOP_2                                0x03a8
-#define GT64260_CPU_SNOOP_BASE_3                       0x03b0
-#define GT64260_CPU_SNOOP_TOP_3                                0x03b8
-
-/* CPU Error Report Registers */
-#define GT64260_CPU_ERR_ADDR_LO                                0x0070
-#define GT64260_CPU_ERR_ADDR_HI                                0x0078
-#define GT64260_CPU_ERR_DATA_LO                                0x0128
-#define GT64260_CPU_ERR_DATA_HI                                0x0130
-#define GT64260_CPU_ERR_PARITY                         0x0138
-#define GT64260_CPU_ERR_CAUSE                          0x0140
-#define GT64260_CPU_ERR_MASK                           0x0148
-
-
-/*
- *****************************************************************************
- *
- *     SDRAM Cotnroller Registers
- *
- *****************************************************************************
- */
-
-/* SDRAM Config Registers */
-#define        GT64260_SDRAM_CONFIG                            0x0448
-#define        GT64260_SDRAM_OPERATION_MODE                    0x0474
-#define        GT64260_SDRAM_ADDR_CNTL                         0x047c
-#define        GT64260_SDRAM_TIMING_PARAMS                     0x04b4
-#define        GT64260_SDRAM_UMA_CNTL                          0x04a4
-#define        GT64260_SDRAM_XBAR_CNTL_LO                      0x04a8
-#define        GT64260_SDRAM_XBAR_CNTL_HI                      0x04ac
-#define        GT64260_SDRAM_XBAR_CNTL_TO                      0x04b0
-
-/* SDRAM Banks Parameters Registers */
-#define        GT64260_SDRAM_BANK_PARAMS_0                     0x044c
-#define        GT64260_SDRAM_BANK_PARAMS_1                     0x0450
-#define        GT64260_SDRAM_BANK_PARAMS_2                     0x0454
-#define        GT64260_SDRAM_BANK_PARAMS_3                     0x0458
-
-/* SDRAM Error Report Registers */
-#define        GT64260_SDRAM_ERR_DATA_LO                       0x0484
-#define        GT64260_SDRAM_ERR_DATA_HI                       0x0480
-#define        GT64260_SDRAM_ERR_ADDR                          0x0490
-#define        GT64260_SDRAM_ERR_ECC_RCVD                      0x0488
-#define        GT64260_SDRAM_ERR_ECC_CALC                      0x048c
-#define        GT64260_SDRAM_ERR_ECC_CNTL                      0x0494
-#define        GT64260_SDRAM_ERR_ECC_ERR_CNT                   0x0498
-
-
-/*
- *****************************************************************************
- *
- *     Device/BOOT Cotnroller Registers
- *
- *****************************************************************************
- */
-
-/* Device Control Registers */
-#define        GT64260_DEV_BANK_PARAMS_0                       0x045c
-#define        GT64260_DEV_BANK_PARAMS_1                       0x0460
-#define        GT64260_DEV_BANK_PARAMS_2                       0x0464
-#define        GT64260_DEV_BANK_PARAMS_3                       0x0468
-#define        GT64260_DEV_BOOT_PARAMS                         0x046c
-#define        GT64260_DEV_IF_CNTL                             0x04c0
-#define        GT64260_DEV_IF_XBAR_CNTL_LO                     0x04c8
-#define        GT64260_DEV_IF_XBAR_CNTL_HI                     0x04cc
-#define        GT64260_DEV_IF_XBAR_CNTL_TO                     0x04c4
-
-/* Device Interrupt Registers */
-#define        GT64260_DEV_INTR_CAUSE                          0x04d0
-#define        GT64260_DEV_INTR_MASK                           0x04d4
-#define        GT64260_DEV_INTR_ERR_ADDR                       0x04d8
-
-
-/*
- *****************************************************************************
- *
- *     PCI Bridge Interface Registers
- *
- *****************************************************************************
- */
-
-/* PCI Configuration Access Registers */
-#define        GT64260_PCI_0_CONFIG_ADDR                       0x0cf8
-#define        GT64260_PCI_0_CONFIG_DATA                       0x0cfc
-#define        GT64260_PCI_0_IACK                              0x0c34
-
-#define        GT64260_PCI_1_CONFIG_ADDR                       0x0c78
-#define        GT64260_PCI_1_CONFIG_DATA                       0x0c7c
-#define        GT64260_PCI_1_IACK                              0x0cb4
-
-/* PCI Control Registers */
-#define        GT64260_PCI_0_CMD                               0x0c00
-#define        GT64260_PCI_0_MODE                              0x0d00
-#define        GT64260_PCI_0_TO_RETRY                          0x0c04
-#define        GT64260_PCI_0_RD_BUF_DISCARD_TIMER              0x0d04
-#define        GT64260_PCI_0_MSI_TRIGGER_TIMER                 0x0c38
-#define        GT64260_PCI_0_ARBITER_CNTL                      0x1d00
-#define        GT64260_PCI_0_XBAR_CNTL_LO                      0x1d08
-#define        GT64260_PCI_0_XBAR_CNTL_HI                      0x1d0c
-#define        GT64260_PCI_0_XBAR_CNTL_TO                      0x1d04
-#define        GT64260_PCI_0_RD_RESP_XBAR_CNTL_LO              0x1d18
-#define        GT64260_PCI_0_RD_RESP_XBAR_CNTL_HI              0x1d1c
-#define        GT64260_PCI_0_SYNC_BARRIER                      0x1d10
-#define        GT64260_PCI_0_P2P_CONFIG                        0x1d14
-#define        GT64260_PCI_0_P2P_SWAP_CNTL                     0x1d54
-
-#define        GT64260_PCI_1_CMD                               0x0c80
-#define        GT64260_PCI_1_MODE                              0x0d80
-#define        GT64260_PCI_1_TO_RETRY                          0x0c84
-#define        GT64260_PCI_1_RD_BUF_DISCARD_TIMER              0x0d84
-#define        GT64260_PCI_1_MSI_TRIGGER_TIMER                 0x0cb8
-#define        GT64260_PCI_1_ARBITER_CNTL                      0x1d80
-#define        GT64260_PCI_1_XBAR_CNTL_LO                      0x1d88
-#define        GT64260_PCI_1_XBAR_CNTL_HI                      0x1d8c
-#define        GT64260_PCI_1_XBAR_CNTL_TO                      0x1d84
-#define        GT64260_PCI_1_RD_RESP_XBAR_CNTL_LO              0x1d98
-#define        GT64260_PCI_1_RD_RESP_XBAR_CNTL_HI              0x1d9c
-#define        GT64260_PCI_1_SYNC_BARRIER                      0x1d90
-#define        GT64260_PCI_1_P2P_CONFIG                        0x1d94
-#define        GT64260_PCI_1_P2P_SWAP_CNTL                     0x1dd4
-
-/* PCI Access Control Regions Registers */
-#define        GT64260_PCI_ACC_CNTL_WINDOWS                    8
-
-#define        GT64260_PCI_ACC_CNTL_PREFETCHEN                 (1<<12)
-#define        GT64260_PCI_ACC_CNTL_DREADEN                    (1<<13)
-#define        GT64260_PCI_ACC_CNTL_RDPREFETCH                 (1<<16)
-#define        GT64260_PCI_ACC_CNTL_RDLINEPREFETCH             (1<<17)
-#define        GT64260_PCI_ACC_CNTL_RDMULPREFETCH              (1<<18)
-#define        GT64260_PCI_ACC_CNTL_MBURST_4_WORDS             0x00000000
-#define        GT64260_PCI_ACC_CNTL_MBURST_8_WORDS             0x00100000
-#define        GT64260_PCI_ACC_CNTL_MBURST_16_WORDS            0x00200000
-#define        GT64260_PCI_ACC_CNTL_MBURST_MASK                0x00300000
-#define        GT64260_PCI_ACC_CNTL_SWAP_BYTE                  0x00000000
-#define        GT64260_PCI_ACC_CNTL_SWAP_NONE                  0x01000000
-#define        GT64260_PCI_ACC_CNTL_SWAP_BYTE_WORD             0x02000000
-#define        GT64260_PCI_ACC_CNTL_SWAP_WORD                  0x03000000
-#define        GT64260_PCI_ACC_CNTL_SWAP_MASK                  0x03000000
-#define        GT64260_PCI_ACC_CNTL_ACCPROT                    (1<<28)
-#define        GT64260_PCI_ACC_CNTL_WRPROT                     (1<<29)
-
-#define        GT64260_PCI_ACC_CNTL_ALL_BITS   (GT64260_PCI_ACC_CNTL_PREFETCHEN |    \
-                                        GT64260_PCI_ACC_CNTL_DREADEN |       \
-                                        GT64260_PCI_ACC_CNTL_RDPREFETCH |    \
-                                        GT64260_PCI_ACC_CNTL_RDLINEPREFETCH |\
-                                        GT64260_PCI_ACC_CNTL_RDMULPREFETCH | \
-                                        GT64260_PCI_ACC_CNTL_MBURST_MASK |   \
-                                        GT64260_PCI_ACC_CNTL_SWAP_MASK |     \
-                                        GT64260_PCI_ACC_CNTL_ACCPROT|        \
-                                        GT64260_PCI_ACC_CNTL_WRPROT)
-
-#define        GT64260_PCI_0_ACC_CNTL_0_BASE_LO                0x1e00
-#define        GT64260_PCI_0_ACC_CNTL_0_BASE_HI                0x1e04
-#define        GT64260_PCI_0_ACC_CNTL_0_TOP                    0x1e08
-#define        GT64260_PCI_0_ACC_CNTL_1_BASE_LO                0x1e10
-#define        GT64260_PCI_0_ACC_CNTL_1_BASE_HI                0x1e14
-#define        GT64260_PCI_0_ACC_CNTL_1_TOP                    0x1e18
-#define        GT64260_PCI_0_ACC_CNTL_2_BASE_LO                0x1e20
-#define        GT64260_PCI_0_ACC_CNTL_2_BASE_HI                0x1e24
-#define        GT64260_PCI_0_ACC_CNTL_2_TOP                    0x1e28
-#define        GT64260_PCI_0_ACC_CNTL_3_BASE_LO                0x1e30
-#define        GT64260_PCI_0_ACC_CNTL_3_BASE_HI                0x1e34
-#define        GT64260_PCI_0_ACC_CNTL_3_TOP                    0x1e38
-#define        GT64260_PCI_0_ACC_CNTL_4_BASE_LO                0x1e40
-#define        GT64260_PCI_0_ACC_CNTL_4_BASE_HI                0x1e44
-#define        GT64260_PCI_0_ACC_CNTL_4_TOP                    0x1e48
-#define        GT64260_PCI_0_ACC_CNTL_5_BASE_LO                0x1e50
-#define        GT64260_PCI_0_ACC_CNTL_5_BASE_HI                0x1e54
-#define        GT64260_PCI_0_ACC_CNTL_5_TOP                    0x1e58
-#define        GT64260_PCI_0_ACC_CNTL_6_BASE_LO                0x1e60
-#define        GT64260_PCI_0_ACC_CNTL_6_BASE_HI                0x1e64
-#define        GT64260_PCI_0_ACC_CNTL_6_TOP                    0x1e68
-#define        GT64260_PCI_0_ACC_CNTL_7_BASE_LO                0x1e70
-#define        GT64260_PCI_0_ACC_CNTL_7_BASE_HI                0x1e74
-#define        GT64260_PCI_0_ACC_CNTL_7_TOP                    0x1e78
-
-#define        GT64260_PCI_1_ACC_CNTL_0_BASE_LO                0x1e80
-#define        GT64260_PCI_1_ACC_CNTL_0_BASE_HI                0x1e84
-#define        GT64260_PCI_1_ACC_CNTL_0_TOP                    0x1e88
-#define        GT64260_PCI_1_ACC_CNTL_1_BASE_LO                0x1e90
-#define        GT64260_PCI_1_ACC_CNTL_1_BASE_HI                0x1e94
-#define        GT64260_PCI_1_ACC_CNTL_1_TOP                    0x1e98
-#define        GT64260_PCI_1_ACC_CNTL_2_BASE_LO                0x1ea0
-#define        GT64260_PCI_1_ACC_CNTL_2_BASE_HI                0x1ea4
-#define        GT64260_PCI_1_ACC_CNTL_2_TOP                    0x1ea8
-#define        GT64260_PCI_1_ACC_CNTL_3_BASE_LO                0x1eb0
-#define        GT64260_PCI_1_ACC_CNTL_3_BASE_HI                0x1eb4
-#define        GT64260_PCI_1_ACC_CNTL_3_TOP                    0x1eb8
-#define        GT64260_PCI_1_ACC_CNTL_4_BASE_LO                0x1ec0
-#define        GT64260_PCI_1_ACC_CNTL_4_BASE_HI                0x1ec4
-#define        GT64260_PCI_1_ACC_CNTL_4_TOP                    0x1ec8
-#define        GT64260_PCI_1_ACC_CNTL_5_BASE_LO                0x1ed0
-#define        GT64260_PCI_1_ACC_CNTL_5_BASE_HI                0x1ed4
-#define        GT64260_PCI_1_ACC_CNTL_5_TOP                    0x1ed8
-#define        GT64260_PCI_1_ACC_CNTL_6_BASE_LO                0x1ee0
-#define        GT64260_PCI_1_ACC_CNTL_6_BASE_HI                0x1ee4
-#define        GT64260_PCI_1_ACC_CNTL_6_TOP                    0x1ee8
-#define        GT64260_PCI_1_ACC_CNTL_7_BASE_LO                0x1ef0
-#define        GT64260_PCI_1_ACC_CNTL_7_BASE_HI                0x1ef4
-#define        GT64260_PCI_1_ACC_CNTL_7_TOP                    0x1ef8
-
-/* PCI Snoop Control Registers */
-#define        GT64260_PCI_SNOOP_WINDOWS                       4
-
-#define        GT64260_PCI_SNOOP_NONE                          0x00000000
-#define        GT64260_PCI_SNOOP_WT                            0x00001000
-#define        GT64260_PCI_SNOOP_WB                            0x00002000
-
-#define        GT64260_PCI_0_SNOOP_0_BASE_LO                   0x1f00
-#define        GT64260_PCI_0_SNOOP_0_BASE_HI                   0x1f04
-#define        GT64260_PCI_0_SNOOP_0_TOP                       0x1f08
-#define        GT64260_PCI_0_SNOOP_1_BASE_LO                   0x1f10
-#define        GT64260_PCI_0_SNOOP_1_BASE_HI                   0x1f14
-#define        GT64260_PCI_0_SNOOP_1_TOP                       0x1f18
-#define        GT64260_PCI_0_SNOOP_2_BASE_LO                   0x1f20
-#define        GT64260_PCI_0_SNOOP_2_BASE_HI                   0x1f24
-#define        GT64260_PCI_0_SNOOP_2_TOP                       0x1f28
-#define        GT64260_PCI_0_SNOOP_3_BASE_LO                   0x1f30
-#define        GT64260_PCI_0_SNOOP_3_BASE_HI                   0x1f34
-#define        GT64260_PCI_0_SNOOP_3_TOP                       0x1f38
-
-#define        GT64260_PCI_1_SNOOP_0_BASE_LO                   0x1f80
-#define        GT64260_PCI_1_SNOOP_0_BASE_HI                   0x1f84
-#define        GT64260_PCI_1_SNOOP_0_TOP                       0x1f88
-#define        GT64260_PCI_1_SNOOP_1_BASE_LO                   0x1f90
-#define        GT64260_PCI_1_SNOOP_1_BASE_HI                   0x1f94
-#define        GT64260_PCI_1_SNOOP_1_TOP                       0x1f98
-#define        GT64260_PCI_1_SNOOP_2_BASE_LO                   0x1fa0
-#define        GT64260_PCI_1_SNOOP_2_BASE_HI                   0x1fa4
-#define        GT64260_PCI_1_SNOOP_2_TOP                       0x1fa8
-#define        GT64260_PCI_1_SNOOP_3_BASE_LO                   0x1fb0
-#define        GT64260_PCI_1_SNOOP_3_BASE_HI                   0x1fb4
-#define        GT64260_PCI_1_SNOOP_3_TOP                       0x1fb8
-
-/* PCI Error Report Registers */
-#define GT64260_PCI_0_ERR_SERR_MASK                    0x0c28
-#define GT64260_PCI_0_ERR_ADDR_LO                      0x1d40
-#define GT64260_PCI_0_ERR_ADDR_HI                      0x1d44
-#define GT64260_PCI_0_ERR_DATA_LO                      0x1d48
-#define GT64260_PCI_0_ERR_DATA_HI                      0x1d4c
-#define GT64260_PCI_0_ERR_CMD                          0x1d50
-#define GT64260_PCI_0_ERR_CAUSE                                0x1d58
-#define GT64260_PCI_0_ERR_MASK                         0x1d5c
-
-#define GT64260_PCI_1_ERR_SERR_MASK                    0x0ca8
-#define GT64260_PCI_1_ERR_ADDR_LO                      0x1dc0
-#define GT64260_PCI_1_ERR_ADDR_HI                      0x1dc4
-#define GT64260_PCI_1_ERR_DATA_LO                      0x1dc8
-#define GT64260_PCI_1_ERR_DATA_HI                      0x1dcc
-#define GT64260_PCI_1_ERR_CMD                          0x1dd0
-#define GT64260_PCI_1_ERR_CAUSE                                0x1dd8
-#define GT64260_PCI_1_ERR_MASK                         0x1ddc
-
-/* PCI Slave Address Decoding Registers */
-#define        GT64260_PCI_SCS_WINDOWS                         4
-#define        GT64260_PCI_CS_WINDOWS                          4
-#define        GT64260_PCI_BOOT_WINDOWS                        1
-#define        GT64260_PCI_P2P_MEM_WINDOWS                     2
-#define        GT64260_PCI_P2P_IO_WINDOWS                      1
-#define        GT64260_PCI_DAC_SCS_WINDOWS                     4
-#define        GT64260_PCI_DAC_CS_WINDOWS                      4
-#define        GT64260_PCI_DAC_BOOT_WINDOWS                    1
-#define        GT64260_PCI_DAC_P2P_MEM_WINDOWS                 2
-
-#define        GT64260_PCI_0_SLAVE_SCS_0_SIZE                  0x0c08
-#define        GT64260_PCI_0_SLAVE_SCS_1_SIZE                  0x0d08
-#define        GT64260_PCI_0_SLAVE_SCS_2_SIZE                  0x0c0c
-#define        GT64260_PCI_0_SLAVE_SCS_3_SIZE                  0x0d0c
-#define        GT64260_PCI_0_SLAVE_CS_0_SIZE                   0x0c10
-#define        GT64260_PCI_0_SLAVE_CS_1_SIZE                   0x0d10
-#define        GT64260_PCI_0_SLAVE_CS_2_SIZE                   0x0d18
-#define        GT64260_PCI_0_SLAVE_CS_3_SIZE                   0x0c14
-#define        GT64260_PCI_0_SLAVE_BOOT_SIZE                   0x0d14
-#define        GT64260_PCI_0_SLAVE_P2P_MEM_0_SIZE              0x0d1c
-#define        GT64260_PCI_0_SLAVE_P2P_MEM_1_SIZE              0x0d20
-#define        GT64260_PCI_0_SLAVE_P2P_IO_SIZE                 0x0d24
-#define        GT64260_PCI_0_SLAVE_CPU_SIZE                    0x0d28
-
-#define        GT64260_PCI_0_SLAVE_DAC_SCS_0_SIZE              0x0e00
-#define        GT64260_PCI_0_SLAVE_DAC_SCS_1_SIZE              0x0e04
-#define        GT64260_PCI_0_SLAVE_DAC_SCS_2_SIZE              0x0e08
-#define        GT64260_PCI_0_SLAVE_DAC_SCS_3_SIZE              0x0e0c
-#define        GT64260_PCI_0_SLAVE_DAC_CS_0_SIZE               0x0e10
-#define        GT64260_PCI_0_SLAVE_DAC_CS_1_SIZE               0x0e14
-#define        GT64260_PCI_0_SLAVE_DAC_CS_2_SIZE               0x0e18
-#define        GT64260_PCI_0_SLAVE_DAC_CS_3_SIZE               0x0e1c
-#define        GT64260_PCI_0_SLAVE_DAC_BOOT_SIZE               0x0e20
-#define        GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_SIZE          0x0e24
-#define        GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_SIZE          0x0e28
-#define        GT64260_PCI_0_SLAVE_DAC_CPU_SIZE                0x0e2c
-
-#define        GT64260_PCI_0_SLAVE_EXP_ROM_SIZE                0x0d2c
-
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0         (1<<0)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_1         (1<<1)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_2         (1<<2)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_3         (1<<3)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_CS_0          (1<<4)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_CS_1          (1<<5)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_CS_2          (1<<6)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_CS_3          (1<<7)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_BOOT          (1<<8)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_REG_MEM       (1<<9)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_REG_IO        (1<<10)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_P2P_MEM_0     (1<<11)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_P2P_MEM_1     (1<<12)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_P2P_IO        (1<<13)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_CPU           (1<<14)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_SCS_0     (1<<15)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_SCS_1     (1<<16)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_SCS_2     (1<<17)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_SCS_3     (1<<18)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CS_0      (1<<19)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CS_1      (1<<20)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CS_2      (1<<21)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CS_3      (1<<22)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_BOOT      (1<<23)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_P2P_MEM_0 (1<<24)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_P2P_MEM_1 (1<<25)
-#define        GT64260_PCI_SLAVE_BAR_REG_ENABLES_DAC_CPU       (1<<26)
-
-#define        GT64260_PCI_0_SLAVE_BAR_REG_ENABLES             0x0c3c
-#define        GT64260_PCI_0_SLAVE_SCS_0_REMAP                 0x0c48
-#define        GT64260_PCI_0_SLAVE_SCS_1_REMAP                 0x0d48
-#define        GT64260_PCI_0_SLAVE_SCS_2_REMAP                 0x0c4c
-#define        GT64260_PCI_0_SLAVE_SCS_3_REMAP                 0x0d4c
-#define        GT64260_PCI_0_SLAVE_CS_0_REMAP                  0x0c50
-#define        GT64260_PCI_0_SLAVE_CS_1_REMAP                  0x0d50
-#define        GT64260_PCI_0_SLAVE_CS_2_REMAP                  0x0d58
-#define        GT64260_PCI_0_SLAVE_CS_3_REMAP                  0x0c54
-#define        GT64260_PCI_0_SLAVE_BOOT_REMAP                  0x0d54
-#define        GT64260_PCI_0_SLAVE_P2P_MEM_0_REMAP_LO          0x0d5c
-#define        GT64260_PCI_0_SLAVE_P2P_MEM_0_REMAP_HI          0x0d60
-#define        GT64260_PCI_0_SLAVE_P2P_MEM_1_REMAP_LO          0x0d64
-#define        GT64260_PCI_0_SLAVE_P2P_MEM_1_REMAP_HI          0x0d68
-#define        GT64260_PCI_0_SLAVE_P2P_IO_REMAP                0x0d6c
-#define        GT64260_PCI_0_SLAVE_CPU_REMAP                   0x0d70
-
-#define        GT64260_PCI_0_SLAVE_DAC_SCS_0_REMAP             0x0f00
-#define        GT64260_PCI_0_SLAVE_DAC_SCS_1_REMAP             0x0f04
-#define        GT64260_PCI_0_SLAVE_DAC_SCS_2_REMAP             0x0f08
-#define        GT64260_PCI_0_SLAVE_DAC_SCS_3_REMAP             0x0f0c
-#define        GT64260_PCI_0_SLAVE_DAC_CS_0_REMAP              0x0f10
-#define        GT64260_PCI_0_SLAVE_DAC_CS_1_REMAP              0x0f14
-#define        GT64260_PCI_0_SLAVE_DAC_CS_2_REMAP              0x0f18
-#define        GT64260_PCI_0_SLAVE_DAC_CS_3_REMAP              0x0f1c
-#define        GT64260_PCI_0_SLAVE_DAC_BOOT_REMAP              0x0f20
-#define        GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_LO      0x0f24
-#define        GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_HI      0x0f28
-#define        GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_LO      0x0f2c
-#define        GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_HI      0x0f30
-#define        GT64260_PCI_0_SLAVE_DAC_CPU_REMAP               0x0f34
-
-#define        GT64260_PCI_0_SLAVE_EXP_ROM_REMAP               0x0f38
-#define        GT64260_PCI_0_SLAVE_PCI_DECODE_CNTL             0x0d3c
-
-#define        GT64260_PCI_1_SLAVE_SCS_0_SIZE                  0x0c88
-#define        GT64260_PCI_1_SLAVE_SCS_1_SIZE                  0x0d88
-#define        GT64260_PCI_1_SLAVE_SCS_2_SIZE                  0x0c8c
-#define        GT64260_PCI_1_SLAVE_SCS_3_SIZE                  0x0d8c
-#define        GT64260_PCI_1_SLAVE_CS_0_SIZE                   0x0c90
-#define        GT64260_PCI_1_SLAVE_CS_1_SIZE                   0x0d90
-#define        GT64260_PCI_1_SLAVE_CS_2_SIZE                   0x0d98
-#define        GT64260_PCI_1_SLAVE_CS_3_SIZE                   0x0c94
-#define        GT64260_PCI_1_SLAVE_BOOT_SIZE                   0x0d94
-#define        GT64260_PCI_1_SLAVE_P2P_MEM_0_SIZE              0x0d9c
-#define        GT64260_PCI_1_SLAVE_P2P_MEM_1_SIZE              0x0da0
-#define        GT64260_PCI_1_SLAVE_P2P_IO_SIZE                 0x0da4
-#define        GT64260_PCI_1_SLAVE_CPU_SIZE                    0x0da8
-
-#define        GT64260_PCI_1_SLAVE_DAC_SCS_0_SIZE              0x0e80
-#define        GT64260_PCI_1_SLAVE_DAC_SCS_1_SIZE              0x0e84
-#define        GT64260_PCI_1_SLAVE_DAC_SCS_2_SIZE              0x0e88
-#define        GT64260_PCI_1_SLAVE_DAC_SCS_3_SIZE              0x0e8c
-#define        GT64260_PCI_1_SLAVE_DAC_CS_0_SIZE               0x0e90
-#define        GT64260_PCI_1_SLAVE_DAC_CS_1_SIZE               0x0e94
-#define        GT64260_PCI_1_SLAVE_DAC_CS_2_SIZE               0x0e98
-#define        GT64260_PCI_1_SLAVE_DAC_CS_3_SIZE               0x0e9c
-#define        GT64260_PCI_1_SLAVE_DAC_BOOT_SIZE               0x0ea0
-#define        GT64260_PCI_1_SLAVE_DAC_P2P_MEM_0_SIZE          0x0ea4
-#define        GT64260_PCI_1_SLAVE_DAC_P2P_MEM_1_SIZE          0x0ea8
-#define        GT64260_PCI_1_SLAVE_DAC_CPU_SIZE                0x0eac
-
-#define        GT64260_PCI_1_SLAVE_EXP_ROM_SIZE                0x0dac
-
-#define        GT64260_PCI_1_SLAVE_BAR_REG_ENABLES             0x0cbc
-#define        GT64260_PCI_1_SLAVE_SCS_0_REMAP                 0x0cc8
-#define        GT64260_PCI_1_SLAVE_SCS_1_REMAP                 0x0dc8
-#define        GT64260_PCI_1_SLAVE_SCS_2_REMAP                 0x0ccc
-#define        GT64260_PCI_1_SLAVE_SCS_3_REMAP                 0x0dcc
-#define        GT64260_PCI_1_SLAVE_CS_0_REMAP                  0x0cd0
-#define        GT64260_PCI_1_SLAVE_CS_1_REMAP                  0x0dd0
-#define        GT64260_PCI_1_SLAVE_CS_2_REMAP                  0x0dd8
-#define        GT64260_PCI_1_SLAVE_CS_3_REMAP                  0x0cd4
-#define        GT64260_PCI_1_SLAVE_BOOT_REMAP                  0x0dd4
-#define        GT64260_PCI_1_SLAVE_P2P_MEM_0_REMAP_LO          0x0ddc
-#define        GT64260_PCI_1_SLAVE_P2P_MEM_0_REMAP_HI          0x0de0
-#define        GT64260_PCI_1_SLAVE_P2P_MEM_1_REMAP_LO          0x0de4
-#define        GT64260_PCI_1_SLAVE_P2P_MEM_1_REMAP_HI          0x0de8
-#define        GT64260_PCI_1_SLAVE_P2P_IO_REMAP                0x0dec
-#define        GT64260_PCI_1_SLAVE_CPU_REMAP                   0x0df0
-
-#define        GT64260_PCI_1_SLAVE_DAC_SCS_0_REMAP             0x0f80
-#define        GT64260_PCI_1_SLAVE_DAC_SCS_1_REMAP             0x0f84
-#define        GT64260_PCI_1_SLAVE_DAC_SCS_2_REMAP             0x0f88
-#define        GT64260_PCI_1_SLAVE_DAC_SCS_3_REMAP             0x0f8c
-#define        GT64260_PCI_1_SLAVE_DAC_CS_0_REMAP              0x0f90
-#define        GT64260_PCI_1_SLAVE_DAC_CS_1_REMAP              0x0f94
-#define        GT64260_PCI_1_SLAVE_DAC_CS_2_REMAP              0x0f98
-#define        GT64260_PCI_1_SLAVE_DAC_CS_3_REMAP              0x0f9c
-#define        GT64260_PCI_1_SLAVE_DAC_BOOT_REMAP              0x0fa0
-#define        GT64260_PCI_1_SLAVE_DAC_P2P_MEM_0_REMAP_LO      0x0fa4
-#define        GT64260_PCI_1_SLAVE_DAC_P2P_MEM_0_REMAP_HI      0x0fa8
-#define        GT64260_PCI_1_SLAVE_DAC_P2P_MEM_1_REMAP_LO      0x0fac
-#define        GT64260_PCI_1_SLAVE_DAC_P2P_MEM_1_REMAP_HI      0x0fb0
-#define        GT64260_PCI_1_SLAVE_DAC_CPU_REMAP               0x0fb4
-
-#define        GT64260_PCI_1_SLAVE_EXP_ROM_REMAP               0x0fb8
-#define        GT64260_PCI_1_SLAVE_PCI_DECODE_CNTL             0x0dbc
-
-
-/*
- *****************************************************************************
- *
- *     I2O Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* FIXME: fill in */
-
-
-
-/*
- *****************************************************************************
- *
- *     DMA Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* FIXME: fill in */
-
-
-/*
- *****************************************************************************
- *
- *     Timer/Counter Interface Registers
- *
- *****************************************************************************
- */
-
-/* FIXME: fill in */
-
-
-/*
- *****************************************************************************
- *
- *     Communications Controller (Enet, Serial, etc.) Interface Registers
- *
- *****************************************************************************
- */
-
-#define        GT64260_ENET_0_CNTL_LO                          0xf200
-#define        GT64260_ENET_0_CNTL_HI                          0xf204
-#define        GT64260_ENET_0_RX_BUF_PCI_ADDR_HI               0xf208
-#define        GT64260_ENET_0_TX_BUF_PCI_ADDR_HI               0xf20c
-#define        GT64260_ENET_0_RX_DESC_ADDR_HI                  0xf210
-#define        GT64260_ENET_0_TX_DESC_ADDR_HI                  0xf214
-#define        GT64260_ENET_0_HASH_TAB_PCI_ADDR_HI             0xf218
-#define        GT64260_ENET_1_CNTL_LO                          0xf220
-#define        GT64260_ENET_1_CNTL_HI                          0xf224
-#define        GT64260_ENET_1_RX_BUF_PCI_ADDR_HI               0xf228
-#define        GT64260_ENET_1_TX_BUF_PCI_ADDR_HI               0xf22c
-#define        GT64260_ENET_1_RX_DESC_ADDR_HI                  0xf230
-#define        GT64260_ENET_1_TX_DESC_ADDR_HI                  0xf234
-#define        GT64260_ENET_1_HASH_TAB_PCI_ADDR_HI             0xf238
-#define        GT64260_ENET_2_CNTL_LO                          0xf240
-#define        GT64260_ENET_2_CNTL_HI                          0xf244
-#define        GT64260_ENET_2_RX_BUF_PCI_ADDR_HI               0xf248
-#define        GT64260_ENET_2_TX_BUF_PCI_ADDR_HI               0xf24c
-#define        GT64260_ENET_2_RX_DESC_ADDR_HI                  0xf250
-#define        GT64260_ENET_2_TX_DESC_ADDR_HI                  0xf254
-#define        GT64260_ENET_2_HASH_TAB_PCI_ADDR_HI             0xf258
-
-#define        GT64260_MPSC_0_CNTL_LO                          0xf280
-#define        GT64260_MPSC_0_CNTL_HI                          0xf284
-#define        GT64260_MPSC_0_RX_BUF_PCI_ADDR_HI               0xf288
-#define        GT64260_MPSC_0_TX_BUF_PCI_ADDR_HI               0xf28c
-#define        GT64260_MPSC_0_RX_DESC_ADDR_HI                  0xf290
-#define        GT64260_MPSC_0_TX_DESC_ADDR_HI                  0xf294
-#define        GT64260_MPSC_1_CNTL_LO                          0xf2c0
-#define        GT64260_MPSC_1_CNTL_HI                          0xf2c4
-#define        GT64260_MPSC_1_RX_BUF_PCI_ADDR_HI               0xf2c8
-#define        GT64260_MPSC_1_TX_BUF_PCI_ADDR_HI               0xf2cc
-#define        GT64260_MPSC_1_RX_DESC_ADDR_HI                  0xf2d0
-#define        GT64260_MPSC_1_TX_DESC_ADDR_HI                  0xf2d4
-
-#define        GT64260_SER_INIT_PCI_ADDR_HI                    0xf320
-#define        GT64260_SER_INIT_LAST_DATA                      0xf324
-#define        GT64260_SER_INIT_CONTROL                        0xf328
-#define        GT64260_SER_INIT_STATUS                         0xf32c
-
-#define        GT64260_COMM_ARBITER_CNTL                       0xf300
-#define        GT64260_COMM_CONFIG                             0xb40c
-#define        GT64260_COMM_XBAR_TO                            0xf304
-#define        GT64260_COMM_INTR_CAUSE                         0xf310
-#define        GT64260_COMM_INTR_MASK                          0xf314
-#define        GT64260_COMM_ERR_ADDR                           0xf318
-
-
-/*
- *****************************************************************************
- *
- *     Fast Ethernet Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define        GT64260_ENET_PHY_ADDR                           0x2000
-#define        GT64260_ENET_ESMIR                              0x2010
-
-#define        GT64260_ENET_E0PCR                              0x2400
-#define        GT64260_ENET_E0PCXR                             0x2408
-#define        GT64260_ENET_E0PCMR                             0x2410
-#define        GT64260_ENET_E0PSR                              0x2418
-#define        GT64260_ENET_E0SPR                              0x2420
-#define        GT64260_ENET_E0HTPR                             0x2428
-#define        GT64260_ENET_E0FCSAL                            0x2430
-#define        GT64260_ENET_E0FCSAH                            0x2438
-#define        GT64260_ENET_E0SDCR                             0x2440
-#define        GT64260_ENET_E0SDCMR                            0x2448
-#define        GT64260_ENET_E0ICR                              0x2450
-#define        GT64260_ENET_E0IMR                              0x2458
-#define        GT64260_ENET_E0FRDP0                            0x2480
-#define        GT64260_ENET_E0FRDP1                            0x2484
-#define        GT64260_ENET_E0FRDP2                            0x2488
-#define        GT64260_ENET_E0FRDP3                            0x248c
-#define        GT64260_ENET_E0CRDP0                            0x24a0
-#define        GT64260_ENET_E0CRDP1                            0x24a4
-#define        GT64260_ENET_E0CRDP2                            0x24a8
-#define        GT64260_ENET_E0CRDP3                            0x24ac
-#define        GT64260_ENET_E0CTDP0                            0x24e0
-#define        GT64260_ENET_E0CTDP1                            0x24e4
-#define        GT64260_ENET_0_DSCP2P0L                         0x2460
-#define        GT64260_ENET_0_DSCP2P0H                         0x2464
-#define        GT64260_ENET_0_DSCP2P1L                         0x2468
-#define        GT64260_ENET_0_DSCP2P1H                         0x246c
-#define        GT64260_ENET_0_VPT2P                            0x2470
-#define        GT64260_ENET_0_MIB_CTRS                         0x2500
-
-#define        GT64260_ENET_E1PCR                              0x2800
-#define        GT64260_ENET_E1PCXR                             0x2808
-#define        GT64260_ENET_E1PCMR                             0x2810
-#define        GT64260_ENET_E1PSR                              0x2818
-#define        GT64260_ENET_E1SPR                              0x2820
-#define        GT64260_ENET_E1HTPR                             0x2828
-#define        GT64260_ENET_E1FCSAL                            0x2830
-#define        GT64260_ENET_E1FCSAH                            0x2838
-#define        GT64260_ENET_E1SDCR                             0x2840
-#define        GT64260_ENET_E1SDCMR                            0x2848
-#define        GT64260_ENET_E1ICR                              0x2850
-#define        GT64260_ENET_E1IMR                              0x2858
-#define        GT64260_ENET_E1FRDP0                            0x2880
-#define        GT64260_ENET_E1FRDP1                            0x2884
-#define        GT64260_ENET_E1FRDP2                            0x2888
-#define        GT64260_ENET_E1FRDP3                            0x288c
-#define        GT64260_ENET_E1CRDP0                            0x28a0
-#define        GT64260_ENET_E1CRDP1                            0x28a4
-#define        GT64260_ENET_E1CRDP2                            0x28a8
-#define        GT64260_ENET_E1CRDP3                            0x28ac
-#define        GT64260_ENET_E1CTDP0                            0x28e0
-#define        GT64260_ENET_E1CTDP1                            0x28e4
-#define        GT64260_ENET_1_DSCP2P0L                         0x2860
-#define        GT64260_ENET_1_DSCP2P0H                         0x2864
-#define        GT64260_ENET_1_DSCP2P1L                         0x2868
-#define        GT64260_ENET_1_DSCP2P1H                         0x286c
-#define        GT64260_ENET_1_VPT2P                            0x2870
-#define        GT64260_ENET_1_MIB_CTRS                         0x2900
-
-#define        GT64260_ENET_E2PCR                              0x2c00
-#define        GT64260_ENET_E2PCXR                             0x2c08
-#define        GT64260_ENET_E2PCMR                             0x2c10
-#define        GT64260_ENET_E2PSR                              0x2c18
-#define        GT64260_ENET_E2SPR                              0x2c20
-#define        GT64260_ENET_E2HTPR                             0x2c28
-#define        GT64260_ENET_E2FCSAL                            0x2c30
-#define        GT64260_ENET_E2FCSAH                            0x2c38
-#define        GT64260_ENET_E2SDCR                             0x2c40
-#define        GT64260_ENET_E2SDCMR                            0x2c48
-#define        GT64260_ENET_E2ICR                              0x2c50
-#define        GT64260_ENET_E2IMR                              0x2c58
-#define        GT64260_ENET_E2FRDP0                            0x2c80
-#define        GT64260_ENET_E2FRDP1                            0x2c84
-#define        GT64260_ENET_E2FRDP2                            0x2c88
-#define        GT64260_ENET_E2FRDP3                            0x2c8c
-#define        GT64260_ENET_E2CRDP0                            0x2ca0
-#define        GT64260_ENET_E2CRDP1                            0x2ca4
-#define        GT64260_ENET_E2CRDP2                            0x2ca8
-#define        GT64260_ENET_E2CRDP3                            0x2cac
-#define        GT64260_ENET_E2CTDP0                            0x2ce0
-#define        GT64260_ENET_E2CTDP1                            0x2ce4
-#define        GT64260_ENET_2_DSCP2P0L                         0x2c60
-#define        GT64260_ENET_2_DSCP2P0H                         0x2c64
-#define        GT64260_ENET_2_DSCP2P1L                         0x2c68
-#define        GT64260_ENET_2_DSCP2P1H                         0x2c6c
-#define        GT64260_ENET_2_VPT2P                            0x2c70
-#define        GT64260_ENET_2_MIB_CTRS                         0x2d00
-
-
-/*
- *****************************************************************************
- *
- *     Multi-Protocol Serial Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* Signal Routing */
-#define        GT64260_MPSC_MRR                                0xb400
-#define        GT64260_MPSC_RCRR                               0xb404
-#define        GT64260_MPSC_TCRR                               0xb408
-
-/* Main Configuratino Registers */
-#define        GT64260_MPSC_0_MMCRL                            0x8000
-#define        GT64260_MPSC_0_MMCRH                            0x8004
-#define        GT64260_MPSC_0_MPCR                             0x8008
-#define        GT64260_MPSC_0_CHR_1                            0x800c
-#define        GT64260_MPSC_0_CHR_2                            0x8010
-#define        GT64260_MPSC_0_CHR_3                            0x8014
-#define        GT64260_MPSC_0_CHR_4                            0x8018
-#define        GT64260_MPSC_0_CHR_5                            0x801c
-#define        GT64260_MPSC_0_CHR_6                            0x8020
-#define        GT64260_MPSC_0_CHR_7                            0x8024
-#define        GT64260_MPSC_0_CHR_8                            0x8028
-#define        GT64260_MPSC_0_CHR_9                            0x802c
-#define        GT64260_MPSC_0_CHR_10                           0x8030
-#define        GT64260_MPSC_0_CHR_11                           0x8034
-
-#define        GT64260_MPSC_1_MMCRL                            0x9000
-#define        GT64260_MPSC_1_MMCRH                            0x9004
-#define        GT64260_MPSC_1_MPCR                             0x9008
-#define        GT64260_MPSC_1_CHR_1                            0x900c
-#define        GT64260_MPSC_1_CHR_2                            0x9010
-#define        GT64260_MPSC_1_CHR_3                            0x9014
-#define        GT64260_MPSC_1_CHR_4                            0x9018
-#define        GT64260_MPSC_1_CHR_5                            0x901c
-#define        GT64260_MPSC_1_CHR_6                            0x9020
-#define        GT64260_MPSC_1_CHR_7                            0x9024
-#define        GT64260_MPSC_1_CHR_8                            0x9028
-#define        GT64260_MPSC_1_CHR_9                            0x902c
-#define        GT64260_MPSC_1_CHR_10                           0x9030
-#define        GT64260_MPSC_1_CHR_11                           0x9034
-
-#define        GT64260_MPSC_0_INTR_CAUSE                       0xb804
-#define        GT64260_MPSC_0_INTR_MASK                        0xb884
-#define        GT64260_MPSC_1_INTR_CAUSE                       0xb80c
-#define        GT64260_MPSC_1_INTR_MASK                        0xb88c
-
-#define        GT64260_MPSC_UART_CR_TEV                        (1<<1)
-#define        GT64260_MPSC_UART_CR_TA                         (1<<7)
-#define        GT64260_MPSC_UART_CR_TTCS                       (1<<9)
-#define        GT64260_MPSC_UART_CR_REV                        (1<<17)
-#define        GT64260_MPSC_UART_CR_RA                         (1<<23)
-#define        GT64260_MPSC_UART_CR_CRD                        (1<<25)
-#define        GT64260_MPSC_UART_CR_EH                         (1<<31)
-
-#define        GT64260_MPSC_UART_ESR_CTS                       (1<<0)
-#define        GT64260_MPSC_UART_ESR_CD                        (1<<1)
-#define        GT64260_MPSC_UART_ESR_TIDLE                     (1<<3)
-#define        GT64260_MPSC_UART_ESR_RHS                       (1<<5)
-#define        GT64260_MPSC_UART_ESR_RLS                       (1<<7)
-#define        GT64260_MPSC_UART_ESR_RLIDL                     (1<<11)
-
-
-/*
- *****************************************************************************
- *
- *     Serial DMA Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define        GT64260_SDMA_0_SDC                              0x4000
-#define        GT64260_SDMA_0_SDCM                             0x4008
-#define        GT64260_SDMA_0_RX_DESC                          0x4800
-#define        GT64260_SDMA_0_RX_BUF_PTR                       0x4808
-#define        GT64260_SDMA_0_SCRDP                            0x4810
-#define        GT64260_SDMA_0_TX_DESC                          0x4c00
-#define        GT64260_SDMA_0_SCTDP                            0x4c10
-#define        GT64260_SDMA_0_SFTDP                            0x4c14
-
-#define        GT64260_SDMA_1_SDC                              0x6000
-#define        GT64260_SDMA_1_SDCM                             0x6008
-#define        GT64260_SDMA_1_RX_DESC                          0x6800
-#define GT64260_SDMA_1_RX_BUF_PTR                       0x6808
-#define        GT64260_SDMA_1_SCRDP                            0x6810
-#define        GT64260_SDMA_1_TX_DESC                          0x6c00
-#define        GT64260_SDMA_1_SCTDP                            0x6c10
-#define        GT64260_SDMA_1_SFTDP                            0x6c14
-
-#define        GT64260_SDMA_INTR_CAUSE                         0xb800
-#define        GT64260_SDMA_INTR_MASK                          0xb880
-
-#define        GT64260_SDMA_DESC_CMDSTAT_PE                    (1<<0)
-#define        GT64260_SDMA_DESC_CMDSTAT_CDL                   (1<<1)
-#define        GT64260_SDMA_DESC_CMDSTAT_FR                    (1<<3)
-#define        GT64260_SDMA_DESC_CMDSTAT_OR                    (1<<6)
-#define        GT64260_SDMA_DESC_CMDSTAT_BR                    (1<<9)
-#define        GT64260_SDMA_DESC_CMDSTAT_MI                    (1<<10)
-#define        GT64260_SDMA_DESC_CMDSTAT_A                     (1<<11)
-#define        GT64260_SDMA_DESC_CMDSTAT_AM                    (1<<12)
-#define        GT64260_SDMA_DESC_CMDSTAT_CT                    (1<<13)
-#define        GT64260_SDMA_DESC_CMDSTAT_C                     (1<<14)
-#define        GT64260_SDMA_DESC_CMDSTAT_ES                    (1<<15)
-#define        GT64260_SDMA_DESC_CMDSTAT_L                     (1<<16)
-#define        GT64260_SDMA_DESC_CMDSTAT_F                     (1<<17)
-#define        GT64260_SDMA_DESC_CMDSTAT_P                     (1<<18)
-#define        GT64260_SDMA_DESC_CMDSTAT_EI                    (1<<23)
-#define        GT64260_SDMA_DESC_CMDSTAT_O                     (1<<31)
-
-#define        GT64260_SDMA_SDC_RFT                            (1<<0)
-#define        GT64260_SDMA_SDC_SFM                            (1<<1)
-#define        GT64260_SDMA_SDC_BLMR                           (1<<6)
-#define        GT64260_SDMA_SDC_BLMT                           (1<<7)
-#define        GT64260_SDMA_SDC_POVR                           (1<<8)
-#define        GT64260_SDMA_SDC_RIFB                           (1<<9)
-
-#define        GT64260_SDMA_SDCM_ERD                           (1<<7)
-#define        GT64260_SDMA_SDCM_AR                            (1<<15)
-#define        GT64260_SDMA_SDCM_STD                           (1<<16)
-#define        GT64260_SDMA_SDCM_TXD                           (1<<23)
-#define        GT64260_SDMA_SDCM_AT                            (1<<31)
-
-#define        GT64260_SDMA_0_CAUSE_RXBUF                      (1<<0)
-#define        GT64260_SDMA_0_CAUSE_RXERR                      (1<<1)
-#define        GT64260_SDMA_0_CAUSE_TXBUF                      (1<<2)
-#define        GT64260_SDMA_0_CAUSE_TXEND                      (1<<3)
-#define        GT64260_SDMA_1_CAUSE_RXBUF                      (1<<8)
-#define        GT64260_SDMA_1_CAUSE_RXERR                      (1<<9)
-#define        GT64260_SDMA_1_CAUSE_TXBUF                      (1<<10)
-#define        GT64260_SDMA_1_CAUSE_TXEND                      (1<<11)
-
-
-/*
- *****************************************************************************
- *
- *     Baud Rate Generator Interface Registers
- *
- *****************************************************************************
- */
-
-#define        GT64260_BRG_0_BCR                               0xb200
-#define        GT64260_BRG_0_BTR                               0xb204
-#define        GT64260_BRG_1_BCR                               0xb208
-#define        GT64260_BRG_1_BTR                               0xb20c
-#define        GT64260_BRG_2_BCR                               0xb210
-#define        GT64260_BRG_2_BTR                               0xb214
-
-#define        GT64260_BRG_INTR_CAUSE                          0xb834
-#define        GT64260_BRG_INTR_MASK                           0xb8b4
-
-
-/*
- *****************************************************************************
- *
- *     Watchdog Timer Interface Registers
- *
- *****************************************************************************
- */
-
-#define        GT64260_WDT_WDC                                 0xb410
-#define        GT64260_WDT_WDV                                 0xb414
-
-
-/*
- *****************************************************************************
- *
- *      General Purpose Pins Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define        GT64260_GPP_IO_CNTL                             0xf100
-#define        GT64260_GPP_LEVEL_CNTL                          0xf110
-#define        GT64260_GPP_VALUE                               0xf104
-#define        GT64260_GPP_INTR_CAUSE                          0xf108
-#define        GT64260_GPP_INTR_MASK                           0xf10c
-
-
-/*
- *****************************************************************************
- *
- *     Multi-Purpose Pins Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define        GT64260_MPP_CNTL_0                              0xf000
-#define        GT64260_MPP_CNTL_1                              0xf004
-#define        GT64260_MPP_CNTL_2                              0xf008
-#define        GT64260_MPP_CNTL_3                              0xf00c
-#define        GT64260_MPP_SERIAL_PORTS_MULTIPLEX              0xf010
-
-
-/*
- *****************************************************************************
- *
- *     I2C Controller Interface Registers
- *
- *****************************************************************************
- */
-
-/* FIXME: fill in */
-
-
-/*
- *****************************************************************************
- *
- *     Interrupt Controller Interface Registers
- *
- *****************************************************************************
- */
-
-#define        GT64260_IC_MAIN_CAUSE_LO                        0x0c18
-#define        GT64260_IC_MAIN_CAUSE_HI                        0x0c68
-#define        GT64260_IC_CPU_INTR_MASK_LO                     0x0c1c
-#define        GT64260_IC_CPU_INTR_MASK_HI                     0x0c6c
-#define        GT64260_IC_CPU_SELECT_CAUSE                     0x0c70
-#define        GT64260_IC_PCI_0_INTR_MASK_LO                   0x0c24
-#define        GT64260_IC_PCI_0_INTR_MASK_HI                   0x0c64
-#define        GT64260_IC_PCI_0_SELECT_CAUSE                   0x0c74
-#define        GT64260_IC_PCI_1_INTR_MASK_LO                   0x0ca4
-#define        GT64260_IC_PCI_1_INTR_MASK_HI                   0x0ce4
-#define        GT64260_IC_PCI_1_SELECT_CAUSE                   0x0cf4
-#define        GT64260_IC_CPU_INT_0_MASK                       0x0e60
-#define        GT64260_IC_CPU_INT_1_MASK                       0x0e64
-#define        GT64260_IC_CPU_INT_2_MASK                       0x0e68
-#define        GT64260_IC_CPU_INT_3_MASK                       0x0e6c
-
-
-#endif /* __ASMPPC_GT64260_DEFS_H */
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 4ddffc1..89bff31 100644 (file)
@@ -26,8 +26,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        unsigned cpu = smp_processor_id();
 
        if(prev != next){
-               clear_bit(cpu, &prev->cpu_vm_mask);
-               set_bit(cpu, &next->cpu_vm_mask);
+               cpu_clear(cpu, prev->cpu_vm_mask);
+               cpu_set(cpu, next->cpu_vm_mask);
                if(next != &init_mm)
                        CHOOSE_MODE((void) 0, 
                                    switch_mm_skas(next->context.skas.mm_fd));
index 26e0aa3..311e25a 100644 (file)
@@ -531,9 +531,7 @@ __SYSCALL(__NR_tgkill, sys_tgkill)
 #define __NR_utimes            235
 __SYSCALL(__NR_utimes, sys_utimes)
 #define __NR_vserver           236
-__SYSCALL(__NR_vserver, sys_ni_syscall)
-#define __NR_vserver           236
-__SYSCALL(__NR_vserver, sys_ni_syscall)
+__SYSCALL(__NR_vserver, sys_vserver)
 #define __NR_mbind             237
 __SYSCALL(__NR_mbind, sys_mbind)
 #define __NR_set_mempolicy     238
index d3f220b..88354f8 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_BINFMTS_H
 
 #include <linux/capability.h>
+#include <linux/vs_memory.h>
 
 struct pt_regs;
 
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 31f306a..100fba9 100644 (file)
@@ -210,8 +210,6 @@ struct ext3_group_desc
 #ifdef CONFIG_JBD_DEBUG
 #define EXT3_IOC_WAIT_FOR_READONLY     _IOR('f', 99, long)
 #endif
-#define EXT3_IOC_GETRSVSZ              _IOR('r', 1, long)
-#define EXT3_IOC_SETRSVSZ              _IOW('r', 2, long)
 #ifdef CONFIG_VSERVER_LEGACY           
 #define EXT3_IOC_SETXID                        FIOC_SETXIDJ
 #endif
@@ -314,25 +312,24 @@ struct ext3_inode {
 /*
  * Mount flags
  */
-#define EXT3_MOUNT_CHECK               0x00001 /* Do mount-time checks */
-#define EXT3_MOUNT_OLDALLOC            0x00002  /* Don't use the new Orlov allocator */
-#define EXT3_MOUNT_GRPID               0x00004 /* Create files with directory's group */
-#define EXT3_MOUNT_DEBUG               0x00008 /* Some debugging messages */
-#define EXT3_MOUNT_ERRORS_CONT         0x00010 /* Continue on errors */
-#define EXT3_MOUNT_ERRORS_RO           0x00020 /* Remount fs ro on errors */
-#define EXT3_MOUNT_ERRORS_PANIC                0x00040 /* Panic on errors */
-#define EXT3_MOUNT_MINIX_DF            0x00080 /* Mimics the Minix statfs */
-#define EXT3_MOUNT_NOLOAD              0x00100 /* Don't use existing journal*/
-#define EXT3_MOUNT_ABORT               0x00200 /* Fatal error detected */
-#define EXT3_MOUNT_DATA_FLAGS          0x00C00 /* Mode for data writes: */
-#define EXT3_MOUNT_JOURNAL_DATA                0x00400 /* Write data to journal */
-#define EXT3_MOUNT_ORDERED_DATA                0x00800 /* Flush data before commit */
-#define EXT3_MOUNT_WRITEBACK_DATA      0x00C00 /* No data ordering */
-#define EXT3_MOUNT_UPDATE_JOURNAL      0x01000 /* Update the journal format */
-#define EXT3_MOUNT_NO_UID32            0x02000  /* Disable 32-bit UIDs */
-#define EXT3_MOUNT_XATTR_USER          0x04000 /* Extended user attributes */
-#define EXT3_MOUNT_POSIX_ACL           0x08000 /* POSIX Access Control Lists */
-#define EXT3_MOUNT_RESERVATION         0x10000 /* Preallocation */
+#define EXT3_MOUNT_CHECK               0x0001  /* Do mount-time checks */
+#define EXT3_MOUNT_OLDALLOC            0x0002  /* Don't use the new Orlov allocator */
+#define EXT3_MOUNT_GRPID               0x0004  /* Create files with directory's group */
+#define EXT3_MOUNT_DEBUG               0x0008  /* Some debugging messages */
+#define EXT3_MOUNT_ERRORS_CONT         0x0010  /* Continue on errors */
+#define EXT3_MOUNT_ERRORS_RO           0x0020  /* Remount fs ro on errors */
+#define EXT3_MOUNT_ERRORS_PANIC                0x0040  /* Panic on errors */
+#define EXT3_MOUNT_MINIX_DF            0x0080  /* Mimics the Minix statfs */
+#define EXT3_MOUNT_NOLOAD              0x0100  /* Don't use existing journal*/
+#define EXT3_MOUNT_ABORT               0x0200  /* Fatal error detected */
+#define EXT3_MOUNT_DATA_FLAGS          0x0C00  /* Mode for data writes: */
+  #define EXT3_MOUNT_JOURNAL_DATA      0x0400  /* Write data to journal */
+  #define EXT3_MOUNT_ORDERED_DATA      0x0800  /* Flush data before commit */
+  #define EXT3_MOUNT_WRITEBACK_DATA    0x0C00  /* No data ordering */
+#define EXT3_MOUNT_UPDATE_JOURNAL      0x1000  /* Update the journal format */
+#define EXT3_MOUNT_NO_UID32            0x2000  /* Disable 32-bit UIDs */
+#define EXT3_MOUNT_XATTR_USER          0x4000  /* Extended user attributes */
+#define EXT3_MOUNT_POSIX_ACL           0x8000  /* POSIX Access Control Lists */
 #define EXT3_MOUNT_TAG_XID             0x20000 /* Enable Context Tags */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
index 1a4d99b..aea3544 100644 (file)
@@ -258,6 +258,7 @@ typedef void (dio_iodone_t)(struct inode *inode, loff_t offset,
 #define ATTR_ATTR_FLAG 1024
 #define ATTR_KILL_SUID 2048
 #define ATTR_KILL_SGID 4096
+#define        ATTR_XID        8192
 
 /*
  * This is the Inode Attributes structure, used for notify_change().  It
@@ -273,6 +274,7 @@ struct iattr {
        umode_t         ia_mode;
        uid_t           ia_uid;
        gid_t           ia_gid;
+       xid_t           ia_xid;
        loff_t          ia_size;
        struct timespec ia_atime;
        struct timespec ia_mtime;
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 0071428..254fc07 100644 (file)
@@ -60,6 +60,7 @@ struct nfs_mount_data {
 #define NFS_MOUNT_BROKEN_SUID  0x0400  /* 4 */
 #define NFS_MOUNT_STRICTLOCK   0x1000  /* reserved for NFSv4 */
 #define NFS_MOUNT_SECFLAVOUR   0x2000  /* 5 */
+#define        NFS_MOUNT_TAGXID        0x8000  /* tagxid */
 #define NFS_MOUNT_FLAGMASK     0xFFFF
 
 #endif
diff --git a/include/linux/ninline.h b/include/linux/ninline.h
deleted file mode 100644 (file)
index d24d0e2..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-#error THIS FILE SHOULD NO LONGER BE USED
-
-#ifndef _NX_INLINE_H
-#define _NX_INLINE_H
-
-
-// #define NX_DEBUG
-
-#include <linux/kernel.h>
-#include <linux/rcupdate.h>
-#include <linux/sched.h>
-
-#include "vserver/network.h"
-
-#if defined(NX_DEBUG)
-#define nxdprintk(x...) printk("nxd: " x)
-#else
-#define nxdprintk(x...)
-#endif
-
-
-extern int proc_pid_nx_info(struct task_struct *, char *);
-
-
-#define get_nx_info(i) __get_nx_info(i,__FILE__,__LINE__)
-
-static inline struct nx_info *__get_nx_info(struct nx_info *nxi,
-       const char *_file, int _line)
-{
-       if (!nxi)
-               return NULL;
-       nxdprintk("get_nx_info(%p[#%d.%d])\t%s:%d\n",
-               nxi, nxi?nxi->nx_id:0, nxi?atomic_read(&nxi->nx_usecnt):0,
-               _file, _line);
-       atomic_inc(&nxi->nx_usecnt);
-       return nxi;
-}
-
-
-#define        free_nx_info(nxi)       \
-       call_rcu(&nxi->nx_rcu, rcu_free_nx_info, nxi);
-
-#define put_nx_info(i) __put_nx_info(i,__FILE__,__LINE__)
-
-static inline void __put_nx_info(struct nx_info *nxi, const char *_file, int _line)
-{
-       if (!nxi)
-               return;
-       nxdprintk("put_nx_info(%p[#%d.%d])\t%s:%d\n",
-               nxi, nxi?nxi->nx_id:0, nxi?atomic_read(&nxi->nx_usecnt):0,
-               _file, _line);
-       if (atomic_dec_and_test(&nxi->nx_usecnt))
-               free_nx_info(nxi);
-}
-
-
-#define set_nx_info(p,i) __set_nx_info(p,i,__FILE__,__LINE__)
-
-static inline void __set_nx_info(struct nx_info **nxp, struct nx_info *nxi,
-       const char *_file, int _line)
-{
-       BUG_ON(*nxp);
-       if (!nxi)
-               return;
-       nxdprintk("set_nx_info(%p[#%d.%d.%d])\t%s:%d\n",
-               nxi, nxi?nxi->nx_id:0,
-               nxi?atomic_read(&nxi->nx_usecnt):0,
-               nxi?atomic_read(&nxi->nx_refcnt):0,
-               _file, _line);
-       atomic_inc(&nxi->nx_refcnt);
-       *nxp = __get_nx_info(nxi, _file, _line);
-}
-
-#define        clr_nx_info(p)  __clr_nx_info(p,__FILE__,__LINE__)
-
-static inline void __clr_nx_info(struct nx_info **nxp,
-       const char *_file, int _line)
-{
-       struct nx_info *nxo = *nxp;
-
-       if (!nxo)
-               return;
-       nxdprintk("clr_nx_info(%p[#%d.%d.%d])\t%s:%d\n",
-               nxo, nxo?nxo->nx_id:0,
-               nxo?atomic_read(&nxo->nx_usecnt):0,
-               nxo?atomic_read(&nxo->nx_refcnt):0,
-               _file, _line);
-       *nxp = NULL;
-       wmb();
-       if (nxo && atomic_dec_and_test(&nxo->nx_refcnt))
-               unhash_nx_info(nxo);
-       __put_nx_info(nxo, _file, _line);
-}
-
-
-#define task_get_nx_info(i)    __task_get_nx_info(i,__FILE__,__LINE__)
-
-static __inline__ struct nx_info *__task_get_nx_info(struct task_struct *p,
-       const char *_file, int _line)
-{
-       struct nx_info *nxi;
-       
-       task_lock(p);
-       nxi = __get_nx_info(p->nx_info, _file, _line);
-       task_unlock(p);
-       return nxi;
-}
-
-#define nx_verify_info(p,i)    \
-       __nx_verify_info((p)->nx_info,i,__FILE__,__LINE__)
-
-static __inline__ void __nx_verify_info(
-       struct nx_info *ipa, struct nx_info *ipb,
-       const char *_file, int _line)
-{
-       if (ipa == ipb)
-               return;
-       printk(KERN_ERR "ip bad assumption (%p==%p) at %s:%d\n",
-               ipa, ipb, _file, _line);
-}
-
-
-#define nx_task_nid(t) ((t)->nid)
-
-#define nx_current_nid() nx_task_nid(current)
-
-#define nx_check(c,m)  __nx_check(nx_current_nid(),c,m)
-
-#define nx_weak_check(c,m)     ((m) ? nx_check(c,m) : 1)
-
-#undef nxdprintk
-#define nxdprintk(x...)
-
-
-#define __nx_flags(v,m,f)      (((v) & (m)) ^ (f))
-
-#define        __nx_task_flags(t,m,f) \
-       (((t) && ((t)->nx_info)) ? \
-               __nx_flags((t)->nx_info->nx_flags,(m),(f)) : 0)
-
-#define nx_current_flags() \
-       ((current->nx_info) ? current->nx_info->nx_flags : 0)
-
-#define nx_flags(m,f)  __nx_flags(nx_current_flags(),(m),(f))
-
-
-#define nx_current_ncaps() \
-       ((current->nx_info) ? current->nx_info->nx_ncaps : 0)
-
-#define nx_ncaps(c)    (nx_current_ncaps() & (c))
-
-
-
-#define        sock_nx_init(s)  do {           \
-       (s)->sk_nid = 0;                \
-       (s)->sk_nx_info = NULL;         \
-       } while (0)
-
-
-
-#endif
index 3870877..8cc1494 100644 (file)
@@ -444,6 +444,7 @@ enum reiserfs_mount_options {
     REISERFS_XATTRS,
     REISERFS_XATTRS_USER,
     REISERFS_POSIXACL,
+    REISERFS_TAGXID,
 
     REISERFS_TEST1,
     REISERFS_TEST2,
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 8ff2a12..289a968 100644 (file)
@@ -63,6 +63,7 @@ struct kstat {
        unsigned int    nlink;
        uid_t           uid;
        gid_t           gid;
+       xid_t           xid;
        dev_t           rdev;
        loff_t          size;
        struct timespec  atime;
index 746994b..aee265d 100644 (file)
@@ -385,8 +385,9 @@ struct tcp_opt {
        /* FIFO of established children */
        struct open_request     *accept_queue;
 #ifndef CONFIG_ACCEPT_QUEUES
-       struct open_request     *accept_queue_tail;
+       struct open_request     *accept_queue_tail;
 #endif
+
        unsigned int            keepalive_time;   /* time before keep alive takes place */
        unsigned int            keepalive_intvl;  /* time interval between keep alive probes */
        int                     linger2;
diff --git a/include/linux/vinline.h b/include/linux/vinline.h
deleted file mode 100644 (file)
index ab6da1e..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-#error THIS FILE SHOULD NO LONGER BE USED
-
-
-#ifndef _VX_INLINE_H
-#define _VX_INLINE_H
-
-
-// #define VX_DEBUG
-
-#include <linux/kernel.h>
-#include <linux/rcupdate.h>
-#include <linux/sched.h>
-
-#include "vserver/context.h"
-#include "vserver/limit.h"
-#include "vserver/cvirt.h"
-
-#if defined(VX_DEBUG)
-#define vxdprintk(x...) printk("vxd: " x)
-#else
-#define vxdprintk(x...)
-#endif
-
-
-
-extern int proc_pid_vx_info(struct task_struct *, char *);
-
-
-#define get_vx_info(i) __get_vx_info(i,__FILE__,__LINE__)
-
-static inline struct vx_info *__get_vx_info(struct vx_info *vxi,
-       const char *_file, int _line)
-{
-       if (!vxi)
-               return NULL;
-       vxdprintk("get_vx_info(%p[#%d.%d])\t%s:%d\n",
-               vxi, vxi?vxi->vx_id:0, vxi?atomic_read(&vxi->vx_usecnt):0,
-               _file, _line);
-       atomic_inc(&vxi->vx_usecnt);
-       return vxi;
-}
-
-
-#define        free_vx_info(vxi)       \
-       call_rcu(&vxi->vx_rcu, rcu_free_vx_info, vxi);
-
-#define put_vx_info(i) __put_vx_info(i,__FILE__,__LINE__)
-
-static inline void __put_vx_info(struct vx_info *vxi, const char *_file, int _line)
-{
-       if (!vxi)
-               return;
-       vxdprintk("put_vx_info(%p[#%d.%d])\t%s:%d\n",
-               vxi, vxi?vxi->vx_id:0, vxi?atomic_read(&vxi->vx_usecnt):0,
-               _file, _line);
-       if (atomic_dec_and_test(&vxi->vx_usecnt))
-               free_vx_info(vxi);
-}
-
-#define set_vx_info(p,i) __set_vx_info(p,i,__FILE__,__LINE__)
-
-static inline void __set_vx_info(struct vx_info **vxp, struct vx_info *vxi,
-       const char *_file, int _line)
-{
-       BUG_ON(*vxp);
-       if (!vxi)
-               return;
-       vxdprintk("set_vx_info(%p[#%d.%d.%d])\t%s:%d\n",
-               vxi, vxi?vxi->vx_id:0,
-               vxi?atomic_read(&vxi->vx_usecnt):0,
-               vxi?atomic_read(&vxi->vx_refcnt):0,
-               _file, _line);
-       atomic_inc(&vxi->vx_refcnt);
-       *vxp = __get_vx_info(vxi, _file, _line);
-}
-
-#define        clr_vx_info(p)  __clr_vx_info(p,__FILE__,__LINE__)
-
-static inline void __clr_vx_info(struct vx_info **vxp,
-       const char *_file, int _line)
-{
-       struct vx_info *vxo = *vxp;
-
-       if (!vxo)
-               return;
-       vxdprintk("clr_vx_info(%p[#%d.%d.%d])\t%s:%d\n",
-               vxo, vxo?vxo->vx_id:0,
-               vxo?atomic_read(&vxo->vx_usecnt):0,
-               vxo?atomic_read(&vxo->vx_refcnt):0,
-               _file, _line);
-       *vxp = NULL;
-       wmb();
-       if (vxo && atomic_dec_and_test(&vxo->vx_refcnt))
-               unhash_vx_info(vxo);
-       __put_vx_info(vxo, _file, _line);
-}
-
-
-#define task_get_vx_info(i)    __task_get_vx_info(i,__FILE__,__LINE__)
-
-static __inline__ struct vx_info *__task_get_vx_info(struct task_struct *p,
-       const char *_file, int _line)
-{
-       struct vx_info *vxi;
-       
-       task_lock(p);
-       vxi = __get_vx_info(p->vx_info, _file, _line);
-       task_unlock(p);
-       return vxi;
-}
-
-
-#define vx_verify_info(p,i)    \
-       __vx_verify_info((p)->vx_info,i,__FILE__,__LINE__)
-
-static __inline__ void __vx_verify_info(
-       struct vx_info *vxa, struct vx_info *vxb,
-       const char *_file, int _line)
-{
-       if (vxa == vxb)
-               return;
-       printk(KERN_ERR "vx bad assumption (%p==%p) at %s:%d\n",
-               vxa, vxb, _file, _line);
-}
-
-
-#define vx_task_xid(t) ((t)->xid)
-
-#define vx_current_xid() vx_task_xid(current)
-
-#define vx_check(c,m)  __vx_check(vx_current_xid(),c,m)
-
-#define vx_weak_check(c,m)     ((m) ? vx_check(c,m) : 1)
-
-
-/*
- * check current context for ADMIN/WATCH and
- * optionally agains supplied argument
- */
-static __inline__ int __vx_check(xid_t cid, xid_t id, unsigned int mode)
-{
-       if (mode & VX_ARG_MASK) {
-               if ((mode & VX_IDENT) &&
-                       (id == cid))
-                       return 1;
-       }
-       if (mode & VX_ATR_MASK) {
-               if ((mode & VX_DYNAMIC) &&
-                       (id >= MIN_D_CONTEXT) &&
-                       (id <= MAX_S_CONTEXT))
-                       return 1;
-               if ((mode & VX_STATIC) &&
-                       (id > 1) && (id < MIN_D_CONTEXT))
-                       return 1;
-       }
-       return (((mode & VX_ADMIN) && (cid == 0)) ||
-               ((mode & VX_WATCH) && (cid == 1)));
-}
-
-
-#define __vx_flags(v,m,f)      (((v) & (m)) ^ (f))
-
-#define        __vx_task_flags(t,m,f) \
-       (((t) && ((t)->vx_info)) ? \
-               __vx_flags((t)->vx_info->vx_flags,(m),(f)) : 0)
-
-#define vx_current_flags() \
-       ((current->vx_info) ? current->vx_info->vx_flags : 0)
-
-#define vx_flags(m,f)  __vx_flags(vx_current_flags(),(m),(f))
-
-
-#define vx_current_ccaps() \
-       ((current->vx_info) ? current->vx_info->vx_ccaps : 0)
-
-#define vx_ccaps(c)    (vx_current_ccaps() & (c))
-
-#define vx_current_bcaps() \
-       (((current->vx_info) && !vx_flags(VXF_STATE_SETUP, 0)) ? \
-       current->vx_info->vx_bcaps : cap_bset)
-
-
-#define VX_DEBUG_ACC_RSS   0
-#define VX_DEBUG_ACC_VM    0
-#define VX_DEBUG_ACC_VML   0
-
-#undef vxdprintk
-#if    (VX_DEBUG_ACC_RSS) || (VX_DEBUG_ACC_VM) || (VX_DEBUG_ACC_VML)
-#define vxdprintk(x...) printk("vxd: " x)
-#else
-#define vxdprintk(x...)
-#endif
-
-#define vx_acc_page(m, d, v, r) \
-       __vx_acc_page(&(m->v), m->mm_vx_info, r, d, __FILE__, __LINE__)
-
-static inline void __vx_acc_page(unsigned long *v, struct vx_info *vxi,
-                int res, int dir, char *file, int line)
-{
-        if (v) {
-                if (dir > 0)
-                        ++(*v);
-                else
-                        --(*v);
-        }
-        if (vxi) {
-                if (dir > 0)
-                        atomic_inc(&vxi->limit.res[res]);
-                else
-                        atomic_dec(&vxi->limit.res[res]);
-        }
-}
-
-
-#define vx_acc_pages(m, p, v, r) \
-       __vx_acc_pages(&(m->v), m->mm_vx_info, r, p, __FILE__, __LINE__)
-
-static inline void __vx_acc_pages(unsigned long *v, struct vx_info *vxi,
-                int res, int pages, char *file, int line)
-{
-        if ((res == RLIMIT_RSS && VX_DEBUG_ACC_RSS) ||
-               (res == RLIMIT_AS && VX_DEBUG_ACC_VM) ||
-               (res == RLIMIT_MEMLOCK && VX_DEBUG_ACC_VML))
-               vxdprintk("vx_acc_pages  [%5d,%2d]: %5d += %5d in %s:%d\n",
-                       (vxi?vxi->vx_id:-1), res,
-                       (vxi?atomic_read(&vxi->limit.res[res]):0),
-                       pages, file, line);
-        if (pages == 0)
-                return;
-        if (v)
-                *v += pages;
-        if (vxi)
-                atomic_add(pages, &vxi->limit.res[res]);
-}
-
-
-
-#define vx_acc_vmpage(m,d)     vx_acc_page(m, d, total_vm,  RLIMIT_AS)
-#define vx_acc_vmlpage(m,d)    vx_acc_page(m, d, locked_vm, RLIMIT_MEMLOCK)
-#define vx_acc_rsspage(m,d)    vx_acc_page(m, d, rss,      RLIMIT_RSS)
-
-#define vx_acc_vmpages(m,p)    vx_acc_pages(m, p, total_vm,  RLIMIT_AS)
-#define vx_acc_vmlpages(m,p)   vx_acc_pages(m, p, locked_vm, RLIMIT_MEMLOCK)
-#define vx_acc_rsspages(m,p)   vx_acc_pages(m, p, rss,       RLIMIT_RSS)
-
-#define vx_pages_add(s,r,p)    __vx_acc_pages(0, s, r, p, __FILE__, __LINE__)
-#define vx_pages_sub(s,r,p)    __vx_pages_add(s, r, -(p))
-
-#define vx_vmpages_inc(m)      vx_acc_vmpage(m, 1)
-#define vx_vmpages_dec(m)      vx_acc_vmpage(m,-1)
-#define vx_vmpages_add(m,p)    vx_acc_vmpages(m, p)
-#define vx_vmpages_sub(m,p)    vx_acc_vmpages(m,-(p))
-
-#define vx_vmlocked_inc(m)     vx_acc_vmlpage(m, 1)
-#define vx_vmlocked_dec(m)     vx_acc_vmlpage(m,-1)
-#define vx_vmlocked_add(m,p)   vx_acc_vmlpages(m, p)
-#define vx_vmlocked_sub(m,p)   vx_acc_vmlpages(m,-(p))
-
-#define vx_rsspages_inc(m)     vx_acc_rsspage(m, 1)
-#define vx_rsspages_dec(m)     vx_acc_rsspage(m,-1)
-#define vx_rsspages_add(m,p)   vx_acc_rsspages(m, p)
-#define vx_rsspages_sub(m,p)   vx_acc_rsspages(m,-(p))
-
-
-
-#define vx_pages_avail(m, p, r) \
-        __vx_pages_avail((m)->mm_vx_info, (r), (p), __FILE__, __LINE__)
-
-static inline int __vx_pages_avail(struct vx_info *vxi,
-                int res, int pages, char *file, int line)
-{
-        if ((res == RLIMIT_RSS && VX_DEBUG_ACC_RSS) ||
-                (res == RLIMIT_AS && VX_DEBUG_ACC_VM) ||
-                (res == RLIMIT_MEMLOCK && VX_DEBUG_ACC_VML))
-                printk("vx_pages_avail[%5d,%2d]: %5ld > %5d + %5d in %s:%d\n",
-                        (vxi?vxi->vx_id:-1), res,
-                       (vxi?vxi->limit.rlim[res]:1),
-                        (vxi?atomic_read(&vxi->limit.res[res]):0),
-                       pages, file, line);
-        if (!vxi)
-                return 1;
-        if (vxi->limit.rlim[res] == RLIM_INFINITY)
-                return 1;
-        if (atomic_read(&vxi->limit.res[res]) + pages < vxi->limit.rlim[res])
-                return 1;
-        return 0;
-}
-
-#define vx_vmpages_avail(m,p)  vx_pages_avail(m, p, RLIMIT_AS)
-#define vx_vmlocked_avail(m,p) vx_pages_avail(m, p, RLIMIT_MEMLOCK)
-#define vx_rsspages_avail(m,p) vx_pages_avail(m, p, RLIMIT_RSS)
-
-/* file limits */
-
-#define VX_DEBUG_ACC_FILE      0
-#define VX_DEBUG_ACC_OPENFD    0
-
-#undef vxdprintk
-#if    (VX_DEBUG_ACC_FILE) || (VX_DEBUG_ACC_OPENFD)
-#define vxdprintk(x...) printk("vxd: " x)
-#else
-#define vxdprintk(x...)
-#endif
-
-
-#define vx_acc_cres(v,d,r) \
-       __vx_acc_cres((v), (r), (d), __FILE__, __LINE__)
-
-static inline void __vx_acc_cres(struct vx_info *vxi,
-       int res, int dir, char *file, int line)
-{
-        if (vxi) {
-       if ((res == RLIMIT_NOFILE && VX_DEBUG_ACC_FILE) ||
-                       (res == RLIMIT_OPENFD && VX_DEBUG_ACC_OPENFD))
-       printk("vx_acc_cres[%5d,%2d]: %5d%s in %s:%d\n",
-                        (vxi?vxi->vx_id:-1), res,
-                        (vxi?atomic_read(&vxi->limit.res[res]):0),
-                       (dir>0)?"++":"--", file, line);
-                if (dir > 0)
-                        atomic_inc(&vxi->limit.res[res]);
-                else
-                        atomic_dec(&vxi->limit.res[res]);
-        }
-}
-
-#define vx_files_inc(f)        vx_acc_cres(current->vx_info, 1, RLIMIT_NOFILE)
-#define vx_files_dec(f)        vx_acc_cres(current->vx_info,-1, RLIMIT_NOFILE)
-
-#define vx_openfd_inc(f) vx_acc_cres(current->vx_info, 1, RLIMIT_OPENFD)
-#define vx_openfd_dec(f) vx_acc_cres(current->vx_info,-1, RLIMIT_OPENFD)
-
-#define vx_cres_avail(v,n,r) \
-        __vx_cres_avail((v), (r), (n), __FILE__, __LINE__)
-
-static inline int __vx_cres_avail(struct vx_info *vxi,
-                int res, int num, char *file, int line)
-{
-       if ((res == RLIMIT_NOFILE && VX_DEBUG_ACC_FILE) ||
-               (res == RLIMIT_OPENFD && VX_DEBUG_ACC_OPENFD))
-                printk("vx_cres_avail[%5d,%2d]: %5ld > %5d + %5d in %s:%d\n",
-                        (vxi?vxi->vx_id:-1), res,
-                       (vxi?vxi->limit.rlim[res]:1),
-                        (vxi?atomic_read(&vxi->limit.res[res]):0),
-                       num, file, line);
-        if (!vxi)
-                return 1;
-        if (vxi->limit.rlim[res] == RLIM_INFINITY)
-                return 1;
-        if (vxi->limit.rlim[res] < atomic_read(&vxi->limit.res[res]) + num)
-                return 0;
-        return 1;
-}
-
-#define vx_files_avail(n) \
-       vx_cres_avail(current->vx_info, (n), RLIMIT_NOFILE)
-
-#define vx_openfd_avail(n) \
-       vx_cres_avail(current->vx_info, (n), RLIMIT_OPENFD)
-
-/* socket limits */
-
-#define vx_sock_inc(f) vx_acc_cres(current->vx_info, 1, VLIMIT_SOCK)
-#define vx_sock_dec(f) vx_acc_cres(current->vx_info,-1, VLIMIT_SOCK)
-
-#define vx_sock_avail(n) \
-       vx_cres_avail(current->vx_info, (n), VLIMIT_SOCK)
-
-/* procfs ioctls */
-
-#define        FIOC_GETXFLG    _IOR('x', 5, long)
-#define        FIOC_SETXFLG    _IOW('x', 6, long)
-
-/* utsname virtualization */
-
-static inline struct new_utsname *vx_new_utsname(void)
-{
-       if (current->vx_info)
-               return &current->vx_info->cvirt.utsname;
-       return &system_utsname;
-}
-
-#define vx_new_uts(x)          ((vx_new_utsname())->x)
-
-/* generic flag merging */
-
-#define        vx_mask_flags(v,f,m)    (((v) & ~(m)) | ((f) & (m)))
-
-#define        vx_mask_mask(v,f,m)     (((v) & ~(m)) | ((v) & (f) & (m)))
-
-
-/* socket accounting */
-
-#include <linux/socket.h>
-
-static inline int vx_sock_type(int family)
-{
-       int type = 4;
-
-       if (family > 0 && family < 3)
-               type = family;
-       else if (family == PF_INET6)
-               type = 3;
-       return type;
-}
-
-#define vx_acc_sock(v,f,p,s) \
-       __vx_acc_sock((v), (f), (p), (s), __FILE__, __LINE__)
-
-static inline void __vx_acc_sock(struct vx_info *vxi,
-       int family, int pos, int size, char *file, int line)
-{
-        if (vxi) {
-               int type = vx_sock_type(family);
-
-               atomic_inc(&vxi->cacct.sock[type][pos].count);
-               atomic_add(size, &vxi->cacct.sock[type][pos].total);
-        }
-}
-
-#define vx_sock_recv(sk,s) \
-       vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 0, (s))
-#define vx_sock_send(sk,s) \
-       vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 1, (s))
-#define vx_sock_fail(sk,s) \
-       vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 2, (s))
-
-
-#define        sock_vx_init(s)  do {           \
-       (s)->sk_xid = 0;                \
-       (s)->sk_vx_info = NULL;         \
-       } while (0)
-
-
-/* pid faking stuff */
-
-
-#define vx_map_tgid(v,p) \
-       __vx_map_tgid((v), (p), __FILE__, __LINE__)
-
-static inline int __vx_map_tgid(struct vx_info *vxi, int pid,
-       char *file, int line)
-{
-       if (vxi && __vx_flags(vxi->vx_flags, VXF_INFO_INIT, 0)) {
-               vxdprintk("vx_map_tgid: %p/%llx: %d -> %d in %s:%d\n",
-                       vxi, vxi->vx_flags, pid,
-                       (pid == vxi->vx_initpid)?1:pid,
-                       file, line);
-               if (pid == vxi->vx_initpid)
-                       return 1;
-       }
-       return pid;
-}
-
-#define vx_rmap_tgid(v,p) \
-       __vx_rmap_tgid((v), (p), __FILE__, __LINE__)
-
-static inline int __vx_rmap_tgid(struct vx_info *vxi, int pid,
-       char *file, int line)
-{
-       if (vxi && __vx_flags(vxi->vx_flags, VXF_INFO_INIT, 0)) {
-               vxdprintk("vx_rmap_tgid: %p/%llx: %d -> %d in %s:%d\n",
-                       vxi, vxi->vx_flags, pid,
-                       (pid == 1)?vxi->vx_initpid:pid,
-                       file, line);
-               if ((pid == 1) && vxi->vx_initpid)
-                       return vxi->vx_initpid;
-       }
-       return pid;
-}
-
-#undef vxdprintk
-#define vxdprintk(x...)
-
-#endif
index b2e47ed..50c8cf0 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/vs_context.h>
 #include <linux/vs_network.h>
 
-
 #ifndef __KERNEL__
 #warning This file is not supposed to be used outside of kernel.
 #endif
index 6269f12..3787663 100644 (file)
@@ -434,7 +434,6 @@ static inline int sk_acceptq_is_full(struct sock *sk)
 {
        return sk->sk_ack_backlog > sk->sk_max_ack_backlog;
 }
-
 #endif
 
 /*
index 29e794f..7738741 100644 (file)
@@ -179,7 +179,7 @@ config CKRM_CPU_SCHEDULE
          Say N if unsure, Y to use the feature.
 
 config CKRM_CPU_MONITOR
-       tristate  "CKRM CPU Resoure Monitor"
+       bool "CKRM CPU Resoure Monitor"
        depends on CKRM_CPU_SCHEDULE
        default m
        help
@@ -247,7 +247,6 @@ config BSD_PROCESS_ACCT_V3
          for processing it. A preliminary version of these tools is available
          at <http://http://www.de.kernel.org/pub/linux/utils/acct/>.
 
-
 config SYSCTL
        bool "Sysctl support"
        ---help---
index 09c99e8..5c3a795 100644 (file)
 #include <asm/setup.h>
 
 #include <linux/ckrm.h>
+#ifdef CONFIG_CKRM_CPU_SCHEDULE
 int __init init_ckrm_sched_res(void);
-
+#else
+#define init_ckrm_sched_res() ((void)0)
+#endif
 
 /*
  * This is one of the first .c files built. Error out early
index 41310d6..964520e 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <asm/unistd.h>
 
+#include <asm/unistd.h>
+
 #include "util.h"
 
 /**
index 8ec87d0..2b64888 100644 (file)
 #include <linux/mount.h>
 #include <linux/proc_fs.h>
 #include <linux/mempolicy.h>
-#include <linux/vs_limit.h>
-
 #include <linux/ckrm.h>
 #include <linux/ckrm_tsk.h>
+#include <linux/vs_limit.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -391,11 +390,9 @@ static inline void close_files(struct files_struct * files)
                                struct file * file = xchg(&files->fd[i], NULL);
                                if (file) {
                                        filp_close(file, files);
-                                       vx_openfd_dec(fd);
                                        cond_resched();
-                               } else {
-                                       vx_openfd_dec(fd);
                                }
+                               vx_openfd_dec(fd);
                        }
                        i++;
                        set >>= 1;
index f7641cd..76b2c11 100644 (file)
 #include <linux/mount.h>
 #include <linux/audit.h>
 #include <linux/rmap.h>
-
 #include <linux/vs_network.h>
-#include <linux/vs_memory.h>
 #include <linux/vs_limit.h>
-#include <linux/vs_base.h>
-
 #include <linux/ckrm.h>
 #include <linux/ckrm_tsk.h>
 
@@ -1138,7 +1134,7 @@ struct task_struct *copy_process(unsigned long clone_flags,
        vxi = current->vx_info;
        if (vxi) {
                atomic_inc(&vxi->cacct.nr_threads);
-               // atomic_inc(&vxi->limit.res[RLIMIT_NPROC]);
+               // atomic_inc(&vxi->limit.rcur[RLIMIT_NPROC]);
        }
        vx_nproc_inc();
        write_unlock_irq(&tasklist_lock);
index 40fadc7..5d25134 100644 (file)
@@ -40,9 +40,9 @@
 #include <linux/cpu.h>
 #include <linux/percpu.h>
 #include <linux/kthread.h>
-#include <asm/tlb.h>
 #include <linux/vserver/sched.h>
 #include <linux/vs_base.h>
+#include <asm/tlb.h>
 
 #include <asm/unistd.h>
 
@@ -199,6 +199,15 @@ typedef struct runqueue runqueue_t;
 #define TASK_PREEMPTS_CURR(p, rq) \
        (((p)->cpu_class != (rq)->curr->cpu_class) && ((rq)->curr != (rq)->idle))? class_preempts_curr((p),(rq)->curr) : ((p)->prio < (rq)->curr->prio)
 #else
+#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
+struct prio_array {
+       unsigned int nr_active;
+       unsigned long bitmap[BITMAP_SIZE];
+       struct list_head queue[MAX_PRIO];
+};
+#define rq_active(p,rq)   (rq->active)
+#define rq_expired(p,rq)  (rq->expired)
+#define ckrm_rebalance_tick(j,this_cpu) do {} while (0)
 #define TASK_PREEMPTS_CURR(p, rq) \
        ((p)->prio < (rq)->curr->prio)
 #endif
@@ -357,6 +366,9 @@ static inline struct task_struct * rq_get_next_task(struct runqueue* rq)
                array = queue->active;
                //check switch active/expired queue
                if (unlikely(!queue->active->nr_active)) {
+                       prio_array_t *array;
+                      
+                       array = queue->active;
                        queue->active = queue->expired;
                        queue->expired = array;
                        queue->expired_timestamp = 0;
@@ -2245,7 +2257,6 @@ static void active_load_balance(runqueue_t *busiest, int busiest_cpu)
 next_group:
                group = group->next;
        } while (group != sd->groups);
->>>>>>> 1.1.9.3
 }
 #endif /* CONFIG_CKRM_CPU_SCHEDULE*/
 
index 47e07a8..c69f6ed 100644 (file)
@@ -24,9 +24,9 @@
 #include <linux/security.h>
 #include <linux/dcookies.h>
 #include <linux/suspend.h>
+#include <linux/ckrm.h>
 #include <linux/vs_base.h>
 #include <linux/vs_cvirt.h>
-#include <linux/ckrm.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -1539,7 +1539,7 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
        old_rlim = current->rlim + resource;
        if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
             (new_rlim.rlim_max > old_rlim->rlim_max)) &&
-           !capable(CAP_SYS_RESOURCE) && vx_ccaps(VXC_SET_RLIMIT))
+           !capable(CAP_SYS_RESOURCE) && !vx_ccaps(VXC_SET_RLIMIT))
                return -EPERM;
        if (resource == RLIMIT_NOFILE) {
                if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
index dba8af5..28f9c32 100644 (file)
@@ -247,10 +247,10 @@ out_unlock:
 
 void rcu_free_vx_info(struct rcu_head *head)
 {
-        struct vx_info *vxi = container_of(head, struct vx_info, vx_rcu);
+       struct vx_info *vxi = container_of(head, struct vx_info, vx_rcu);
        int usecnt, refcnt;
 
-       BUG_ON(!vxi || !head);
+       BUG_ON(!vxi);
 
        usecnt = atomic_read(&vxi->vx_usecnt);
        BUG_ON(usecnt < 0);
index caf10ee..c7cbe7d 100644 (file)
@@ -155,10 +155,10 @@ struct dl_info *locate_dl_info(struct super_block *sb, xid_t xid)
 
 void rcu_free_dl_info(struct rcu_head *head)
 {
-        struct dl_info *dli = container_of(head, struct dl_info, dl_rcu);
+       struct dl_info *dli = container_of(head, struct dl_info, dl_rcu);
        int usecnt, refcnt;
 
-       BUG_ON(!dli || !head);
+       BUG_ON(!dli);
 
        usecnt = atomic_read(&dli->dl_usecnt);
        BUG_ON(usecnt < 0);
index c240878..2a7d51e 100644 (file)
@@ -218,11 +218,9 @@ out_unlock:
 
 void rcu_free_nx_info(struct rcu_head *head)
 {
-        struct nx_info *nxi = container_of(head, struct nx_info, nx_rcu);
+       struct nx_info *nxi = container_of(head, struct nx_info, nx_rcu);
        int usecnt, refcnt;
 
-       BUG_ON(!nxi || !head);
-
        usecnt = atomic_read(&nxi->nx_usecnt);
        BUG_ON(usecnt < 0);
 
index ddf70df..6bd9581 100644 (file)
@@ -702,7 +702,7 @@ follow_page_pfn(struct mm_struct *mm, unsigned long address, int write,
                goto out;
        if (pmd_huge(*pmd))
                return follow_huge_pmd(mm, address, pmd, write);
-       if (unlikely(pmd_bad(*pmd)))
+       if (pmd_bad(*pmd))
                goto out;
 
        ptep = pte_offset_map(pmd, address);
@@ -714,11 +714,15 @@ follow_page_pfn(struct mm_struct *mm, unsigned long address, int write,
        if (pte_present(pte)) {
                if (write && !pte_write(pte))
                        goto out;
+               if (write && !pte_dirty(pte)) {
+                       struct page *page = pte_page(pte);
+                       if (!PageDirty(page))
+                               set_page_dirty(page);
+               }
                pfn = pte_pfn(pte);
                if (pfn_valid(pfn)) {
-                       page = pfn_to_page(pfn);
-                       if (write && !pte_dirty(pte) && !PageDirty(page))
-                               set_page_dirty(page);
+                       struct page *page = pfn_to_page(pfn);
+                       
                        mark_page_accessed(page);
                        return page;
                } else {
@@ -1506,11 +1510,6 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
        pte_t entry;
        struct page * page = ZERO_PAGE(addr);
 
-       if (!vx_rsspages_avail(mm, 1)) {
-               spin_unlock(&mm->page_table_lock);
-               return VM_FAULT_OOM;
-       }
-
        /* Read-only mapping of ZERO_PAGE. */
        entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
 
@@ -1522,6 +1521,9 @@ do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
 
                if (unlikely(anon_vma_prepare(vma)))
                        goto no_mem;
+               if (!vx_rsspages_avail(mm, 1))
+                       goto no_mem;
+
                page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
                if (!page)
                        goto no_mem;
@@ -1648,8 +1650,7 @@ retry:
        /* Only go through if we didn't race with anybody else... */
        if (pte_none(*page_table)) {
                if (!PageReserved(new_page))
-                       // ++mm->rss;
-                       vx_rsspages_inc(mm);
+                       ++mm->rss;
                flush_icache_page(vma, new_page);
                entry = mk_pte(new_page, vma->vm_page_prot);
                if (write_access)
index a6d2762..2124d30 100644 (file)
@@ -50,7 +50,8 @@ static int mlock_fixup(struct vm_area_struct * vma,
                ret = make_pages_present(start, end);
        }
 
-       vma->vm_mm->locked_vm -= pages;
+       // vma->vm_mm->locked_vm -= pages;
+       vx_vmlocked_sub(vma->vm_mm, pages);
 out:
        return ret;
 }
@@ -183,7 +184,6 @@ asmlinkage long sys_mlockall(int flags)
        ret = -ENOMEM;
        if (!vx_vmlocked_avail(current->mm, current->mm->total_vm))
                goto out;
-       /* check vserver lock limits? */
        if ((current->mm->total_vm <= lock_limit) || capable(CAP_IPC_LOCK))
                ret = do_mlockall(flags);
 out:
index fa6b34f..5ab8fc4 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1226,9 +1226,9 @@ int expand_stack(struct vm_area_struct * vma, unsigned long address)
        address &= PAGE_MASK;
        grow = (address - vma->vm_end) >> PAGE_SHIFT;
 
-       /* Overcommit.. */
-       if (security_vm_enough_memory(grow) ||
-               !vx_vmpages_avail(vma->vm_mm, grow)) {
+       /* Overcommit.. vx check first to avoid vm_unacct_memory() */
+       if (!vx_vmpages_avail(vma->vm_mm, grow) ||
+               security_vm_enough_memory(grow)) {
                anon_vma_unlock(vma);
                return -ENOMEM;
        }
@@ -1240,7 +1240,6 @@ int expand_stack(struct vm_area_struct * vma, unsigned long address)
                vm_unacct_memory(grow);
                return -ENOMEM;
        }
-
        vma->vm_end = address;
        // vma->vm_mm->total_vm += grow;
        vx_vmpages_add(vma->vm_mm, grow);
@@ -1291,9 +1290,9 @@ int expand_stack(struct vm_area_struct *vma, unsigned long address)
        address &= PAGE_MASK;
        grow = (vma->vm_start - address) >> PAGE_SHIFT;
 
-       /* Overcommit.. */
-       if (security_vm_enough_memory(grow) ||
-               !vx_vmpages_avail(vma->vm_mm, grow)) {
+        /* Overcommit.. vx check first to avoid vm_unacct_memory() */
+       if (!vx_vmpages_avail(vma->vm_mm, grow) ||
+               security_vm_enough_memory(grow)) {
                anon_vma_unlock(vma);
                return -ENOMEM;
        }
@@ -1305,7 +1304,6 @@ int expand_stack(struct vm_area_struct *vma, unsigned long address)
                vm_unacct_memory(grow);
                return -ENOMEM;
        }
-
        vma->vm_start = address;
        vma->vm_pgoff -= grow;
        // vma->vm_mm->total_vm += grow;
@@ -1674,7 +1672,8 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
                locked += len;
                if (locked > lock_limit && !capable(CAP_IPC_LOCK))
                        return -EAGAIN;
-               /* vserver checks ? */
+               if (!vx_vmlocked_avail(mm, len >> PAGE_SHIFT))
+                       return -ENOMEM;
        }
 
        /*
index 99b2576..a47554b 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/fs.h>
 #include <linux/highmem.h>
 #include <linux/security.h>
-#include <linux/vs_memory.h>
 
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
@@ -334,6 +333,10 @@ unsigned long do_mremap(unsigned long addr,
                ret = -EAGAIN;
                if (locked > lock_limit && !capable(CAP_IPC_LOCK))
                        goto out;
+               ret = -ENOMEM;
+               if (!vx_vmlocked_avail(current->mm,
+                       (new_len - old_len) >> PAGE_SHIFT))
+                       goto out;
        }
        ret = -ENOMEM;
        if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
@@ -369,7 +372,7 @@ unsigned long do_mremap(unsigned long addr,
                        vx_vmpages_add(current->mm, pages);
                        if (vma->vm_flags & VM_LOCKED) {
                                // current->mm->locked_vm += pages;
-                               vx_vmlocked_add(current->mm, pages);
+                               vx_vmlocked_add(vma->vm_mm, pages);
                                make_pages_present(addr + old_len,
                                                   addr + new_len);
                        }
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:
index cf99236..6eca35a 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/tlbflush.h>
 #include <linux/swapops.h>
 #include <linux/vs_base.h>
-#include <linux/vs_memory.h>
 
 spinlock_t swaplock = SPIN_LOCK_UNLOCKED;
 unsigned int nr_swapfiles;
index 0f47001..944cd9a 100644 (file)
 #include <linux/kallsyms.h>
 #include <linux/netpoll.h>
 #include <linux/rcupdate.h>
+#include <linux/vserver/network.h>
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>            /* Note : will define WIRELESS_EXT */
 #include <net/iw_handler.h>
index 7ca78a3..36e0a9e 100644 (file)
@@ -669,8 +669,6 @@ void sk_free(struct sock *sk)
        security_sk_free(sk);
        BUG_ON(sk->sk_vx_info);
        BUG_ON(sk->sk_nx_info);
-/*     clr_vx_info(&sk->sk_vx_info);
-       clr_nx_info(&sk->sk_nx_info);   */
        kmem_cache_free(sk->sk_slab, sk);
        module_put(owner);
 }
index e42418c..f4f7a57 100644 (file)
@@ -159,8 +159,11 @@ void inet_sock_destruct(struct sock *sk)
        if (inet->opt)
                kfree(inet->opt);
        
-       BUG_ON(sk->sk_nx_info);
-       BUG_ON(sk->sk_vx_info);
+       clr_vx_info(&sk->sk_vx_info);
+       sk->sk_xid = -1;
+       clr_nx_info(&sk->sk_nx_info);
+       sk->sk_nid = -1;
+
        dst_release(sk->sk_dst_cache);
 #ifdef INET_REFCNT_DEBUG
        atomic_dec(&inet_sock_nr);
@@ -297,8 +300,11 @@ static int inet_create(struct socket *sock, int protocol)
        if (!answer)
                goto out_sk_free;
        err = -EPERM;
+       if ((protocol == IPPROTO_ICMP) && vx_ccaps(VXC_RAW_ICMP))
+               goto override;
        if (answer->capability > 0 && !capable(answer->capability))
                goto out_sk_free;
+override:
        err = -EPROTONOSUPPORT;
        if (!protocol)
                goto out_sk_free;
@@ -402,7 +408,9 @@ int inet_release(struct socket *sock)
                        timeout = sk->sk_lingertime;
                sock->sk = NULL;
                clr_vx_info(&sk->sk_vx_info);
+       sk->sk_xid = -1;
                clr_nx_info(&sk->sk_nx_info);
+       sk->sk_nid = -1;
                sk->sk_prot->close(sk, timeout);
        }
        return 0;
index efcd23d..e0007a3 100644 (file)
@@ -526,6 +526,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
                                                         .saddr = saddr,
                                                         .tos = RT_TOS(tos) } },
                                    .proto = IPPROTO_ICMP };
+
                if (ip_route_output_key(&rt, &fl))
                    goto out_unlock;
        }
index cbf2c77..b956390 100644 (file)
@@ -462,6 +462,13 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                                    .proto = inet->hdrincl ? IPPROTO_RAW :
                                                             sk->sk_protocol,
                                  };
+               
+               if (sk->sk_nx_info) {
+                       err = ip_find_src(sk->sk_nx_info, &rt, &fl);
+
+                       if (err)
+                               goto done;
+               }
                err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT));
        }
        if (err)
index 14d0bc3..bceeaee 100644 (file)
@@ -281,6 +281,7 @@ kmem_cache_t *tcp_timewait_cachep;
 atomic_t tcp_orphan_count = ATOMIC_INIT(0);
 
 int sysctl_tcp_default_win_scale = 7;
+
 int sysctl_tcp_mem[3];
 int sysctl_tcp_wmem[3] = { 4 * 1024, 16 * 1024, 128 * 1024 };
 int sysctl_tcp_rmem[3] = { 4 * 1024, 87380, 87380 * 2 };
index dc719ac..1411541 100644 (file)
@@ -814,9 +814,10 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct open_request *req,
                newsk->sk_priority = 0;
                atomic_set(&newsk->sk_refcnt, 2);
 
-               /* hmm, maybe from socket? */
-               set_vx_info(&newsk->sk_vx_info, current->vx_info);
-               set_nx_info(&newsk->sk_nx_info, current->nx_info);
+               set_vx_info(&newsk->sk_vx_info, sk->sk_vx_info);
+               newsk->sk_xid = sk->sk_xid;
+               set_nx_info(&newsk->sk_nx_info, sk->sk_nx_info);
+               newsk->sk_nid = sk->sk_nid;
 #ifdef INET_REFCNT_DEBUG
                atomic_inc(&inet_sock_nr);
 #endif
index 315b162..694301a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/socket.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/spinlock.h>
+#include <linux/vserver/xid.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_AUTH
@@ -259,8 +260,8 @@ rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
        struct rpc_cred *ret;
 
        get_group_info(current->group_info);
-       acred.uid = current->fsuid;
-       acred.gid = current->fsgid;
+       acred.uid = XIDINO_UID(current->fsuid, current->xid);
+       acred.gid = XIDINO_GID(current->fsgid, current->xid);
        acred.group_info = current->group_info;
 
        dprintk("RPC:     looking up %s cred\n",
@@ -278,8 +279,8 @@ rpcauth_bindcred(struct rpc_task *task)
        struct rpc_cred *ret;
 
        get_group_info(current->group_info);
-       acred.uid = current->fsuid;
-       acred.gid = current->fsgid;
+       acred.uid = XIDINO_UID(current->fsuid, current->xid);
+       acred.gid = XIDINO_GID(current->fsgid, current->xid);
        acred.group_info = current->group_info;
 
        dprintk("RPC: %4d looking up %s cred\n",
index edbe8f8..33741fc 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/in.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/auth.h>
+#include <linux/vserver/xid.h>
 
 #define NFS_NGROUPS    16
 
@@ -88,6 +89,8 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 
                cred->uc_uid = acred->uid;
                cred->uc_gid = acred->gid;
+//             cred->uc_puid = XIDINO_UID(current->uid, current->xid);
+//             cred->uc_pgid = XIDINO_GID(current->gid, current->xid);
                cred->uc_puid = current->uid;
                cred->uc_pgid = current->gid;
                for (i = 0; i < groups; i++)
@@ -122,8 +125,8 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
 
                if (cred->uc_uid != acred->uid
                 || cred->uc_gid != acred->gid
-                || cred->uc_puid != current->uid
-                || cred->uc_pgid != current->gid)
+                || cred->uc_puid != XIDINO_UID(current->uid, current->xid)
+                || cred->uc_pgid != XIDINO_GID(current->gid, current->xid))
                        return 0;
 
                groups = acred->group_info->ngroups;
index 7428838..71b54ac 100644 (file)
 #include <linux/mount.h>
 #include <net/checksum.h>
 #include <linux/security.h>
-
 #include <linux/vs_context.h>
 #include <linux/vs_network.h>
 
-
 int sysctl_unix_max_dgram_qlen = 10;
 
 kmem_cache_t *unix_sk_cachep;
index b4e37dc..5f33311 100644 (file)
@@ -90,6 +90,7 @@ foreach $object (sort(keys(%object))) {
                if (($line =~ /\.init$/ || $line =~ /\.init\./) &&
                    ($from !~ /\.init$/ &&
                     $from !~ /\.init\./ &&
+                    $from !~ /\.eh_frame$/ &&
                     $from !~ /\.stab$/ &&
                     $from !~ /\.rodata$/ &&
                     $from !~ /\.text\.lock$/ &&