From c4bc58c20842ff6dd4065064363005ac8c533c1c Mon Sep 17 00:00:00 2001
From: johann <johann>
Date: Fri, 20 Jul 2007 08:54:08 +0000
Subject: [PATCH] Branch b1_6 b=11039 i=nathan i=scjody (get approval by email
 on rmg@)

Remove obsolete kernel patches.
---
 .../patches/2.6-rhel4-kgdb-ga.patch           |  6371 ---
 .../patches/8kstack-2.6-rhel4.patch           |    13 -
 .../patches/bluesmoke-2.6-suse-lnxi.patch     |  5485 ---
 .../patches/brk-locked-2.6-suse-lnxi.patch    |   219 -
 .../compile-fixes-2.6.9-rhel4-22.patch        |    76 -
 .../kernel_patches/patches/elevator-cfq.patch |    20 -
 .../ext3-check-jbd-errors-2.6-sles10.patch    |    83 -
 .../ext3-extents-fixes-2.6.9-rhel4.patch      |    86 -
 ...tents-multiblock-directio-2.6.5-suse.patch |   157 -
 ...ents-multiblock-directio-2.6.9-rhel4.patch |   149 -
 .../ext3-extents-search-2.6.9-rhel4.patch     |   168 -
 .../patches/ext3-external-journal-2.6.9.patch |   150 -
 .../patches/ext3-filterdata-sles10.patch      |    25 -
 .../patches/ext3-htree-dot-2.6.5-suse.patch   |    23 -
 .../patches/ext3-htree-path-ops.patch         |   894 -
 .../ext3-inode-version-2.6-sles10.patch       |   426 -
 .../ext3-inode-version-2.6.18-vanilla.patch   |   426 -
 .../patches/ext3-mballoc3-core.patch          |  4528 --
 .../patches/ext3-mballoc3-rhel4.patch         |   396 -
 .../patches/ext3-mballoc3-sles10.patch        |   377 -
 .../patches/ext3-mballoc3-suse.patch          |   397 -
 .../ext3-multi-mount-protection-2.6-fc5.patch |   381 -
 ...ulti-mount-protection-2.6.18-vanilla.patch |   381 -
 .../patches/ext3-statfs-2.6.12.patch          |   177 -
 .../patches/ext3-uninit-2.6-sles10.patch      |   674 -
 .../patches/ext3-uninit-2.6-suse.patch        |   653 -
 .../patches/ext3-uninit-2.6.9.patch           |   664 -
 .../patches/ext3-wantedi-2.6.15.patch         |   174 -
 .../grab_cache_page_nowait_gfp-2.6-suse.patch |    57 -
 .../patches/jbd-stats-2.6.13.4.patch          |   735 -
 .../patches/kexec-2.6-suse-lnxi.patch         |  1603 -
 .../patches/kjournald_affinity.patch          |    52 -
 .../patches/link_notlast-susefix.patch        |    16 -
 .../kernel_patches/patches/lustre_build.patch |    33 -
 .../patches/mtd-2.6-suse-lnxi.patch           | 35414 ----------------
 .../patches/nfs-cifs-intent-2.6-rhel4.patch   |   123 -
 .../patches/perfctr-2.6-suse-lnxi.patch       | 10070 -----
 .../patches/uml-export-end_iomem.patch        |    12 -
 .../patches/uml-exprt-clearuser-2.6.12.patch  |    11 -
 .../patches/vfs_nointent-2.6-sles10.patch     |   453 -
 40 files changed, 72152 deletions(-)
 delete mode 100644 lustre/kernel_patches/patches/2.6-rhel4-kgdb-ga.patch
 delete mode 100644 lustre/kernel_patches/patches/8kstack-2.6-rhel4.patch
 delete mode 100644 lustre/kernel_patches/patches/bluesmoke-2.6-suse-lnxi.patch
 delete mode 100644 lustre/kernel_patches/patches/brk-locked-2.6-suse-lnxi.patch
 delete mode 100644 lustre/kernel_patches/patches/compile-fixes-2.6.9-rhel4-22.patch
 delete mode 100644 lustre/kernel_patches/patches/elevator-cfq.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-check-jbd-errors-2.6-sles10.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-extents-fixes-2.6.9-rhel4.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-extents-multiblock-directio-2.6.5-suse.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-extents-multiblock-directio-2.6.9-rhel4.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-extents-search-2.6.9-rhel4.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-external-journal-2.6.9.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-filterdata-sles10.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-htree-dot-2.6.5-suse.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-htree-path-ops.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-inode-version-2.6-sles10.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-inode-version-2.6.18-vanilla.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-mballoc3-core.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-mballoc3-rhel4.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-mballoc3-sles10.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-mballoc3-suse.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-multi-mount-protection-2.6-fc5.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-multi-mount-protection-2.6.18-vanilla.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-statfs-2.6.12.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-uninit-2.6-sles10.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-uninit-2.6-suse.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-uninit-2.6.9.patch
 delete mode 100644 lustre/kernel_patches/patches/ext3-wantedi-2.6.15.patch
 delete mode 100644 lustre/kernel_patches/patches/grab_cache_page_nowait_gfp-2.6-suse.patch
 delete mode 100644 lustre/kernel_patches/patches/jbd-stats-2.6.13.4.patch
 delete mode 100644 lustre/kernel_patches/patches/kexec-2.6-suse-lnxi.patch
 delete mode 100644 lustre/kernel_patches/patches/kjournald_affinity.patch
 delete mode 100644 lustre/kernel_patches/patches/link_notlast-susefix.patch
 delete mode 100644 lustre/kernel_patches/patches/lustre_build.patch
 delete mode 100644 lustre/kernel_patches/patches/mtd-2.6-suse-lnxi.patch
 delete mode 100644 lustre/kernel_patches/patches/nfs-cifs-intent-2.6-rhel4.patch
 delete mode 100644 lustre/kernel_patches/patches/perfctr-2.6-suse-lnxi.patch
 delete mode 100644 lustre/kernel_patches/patches/uml-export-end_iomem.patch
 delete mode 100644 lustre/kernel_patches/patches/uml-exprt-clearuser-2.6.12.patch
 delete mode 100644 lustre/kernel_patches/patches/vfs_nointent-2.6-sles10.patch

diff --git a/lustre/kernel_patches/patches/2.6-rhel4-kgdb-ga.patch b/lustre/kernel_patches/patches/2.6-rhel4-kgdb-ga.patch
deleted file mode 100644
index f3067fadcf..0000000000
--- a/lustre/kernel_patches/patches/2.6-rhel4-kgdb-ga.patch
+++ /dev/null
@@ -1,6371 +0,0 @@
-
-
-This kgdb will get called and will trap almost any kernel
-fault WITHOUT BEING ARMED.
-
-It is entered at boot time via "kgdb" in the boot string,
-not "gdb".  This entry occurs when the first setup on the
-boot string is called, not sometime later.  You will not
-find a "waiting for gdb" on your console, as the console has
-not yet been enabled at this time.  (Note, this early stuff
-is a bit fragile as the full trap table has yet to be
-loaded, something I might address, sometime...  So don't try
-to look at memory that can not be reached, for example. 
-Once the full trap table is loaded this restriction goes
-away.)
-
-If you hard code it, you can put a breakpoint() as the FIRST
-LINE OF C CODE.
-
-It does NOT use the serial driver, but if the serial driver
-is loaded, it tells it to release the port to avoid
-conflict.  
-
-The threads stuff is not configurable, does not require
-redirection of schedule() calls and does back track to the
-first non schedule() caller on the info threads command.  If
-you switch to the thread, however, it will show it in the
-switch code (as it should).
-
-It is MUCH more aggressive and paranoid about grabbing the
-other cpus on entry.  It issues a "send_nmi_all_but_self()"
-rather than depending on them to interrupt or hit an NMI
-sometime in the distant future.  If a cpu does not come to
-the party, it will continue without it so all is not lost.
-
-It does not have anything to do with IOCTL calls, but does
-do the control-C thing.
-
-There is a LOT of info in the patch which ends up in
-.../Documentation/i386/kgdb/*
-
-There is a nifty little thing call kgdb_ts() (kgdb time
-stamp) which is a function you can code calls to which puts
-some useful stuff in a circular buffer which can be examined
-with the supplied gdb macros.
-
-It also allows you do to do "p foobar(...)"  i.e. to call a
-function from gdb, just like gdb allows in program
-debugging.
-
-In an SMP system, you can choose to "hold" any given set of
-cpus.  It also defaults to holding other cpus on single step
-(this can be overridden).
-
-This said, you can imagine my consternation when I found it
-"lost it" on continues on 2.5.  I found and fixed this this
-early pm, a hold cpu on exit goof on my part.
-
-Oh, and a final point, the configure options are more
-extensive (the serial port is set up here, for example, (can
-not wait for a command line to do this)).  There is one to
-do system call exit tests.  This is VERY new and causes the
-kernel to hit a hard "int 3" if a system call attempts to
-exit with preempt count other than zero.  This is a fault,
-of course, but the current 2.5 is full of them so I don't
-recommend turning this on.
-
-
-DESC
-kgdbL warning fix
-EDESC
-From: Ingo Molnar <mingo@elte.hu>
-
-this patch fixes a deprecated use of asm input operands. (and shuts up a
-gcc 3.3 warning.)
-
-DESC
-kgdb buffer overflow fix
-EDESC
-From: George Anzinger <george@mvista.com>
-
-
-DESC
-kgdbL warning fix
-EDESC
-From: Ingo Molnar <mingo@elte.hu>
-
-this patch fixes a deprecated use of asm input operands. (and shuts up a
-gcc 3.3 warning.)
-
-DESC
-kgdb: CONFIG_DEBUG_INFO fix
-EDESC
-From: Thomas Schlichter <schlicht@uni-mannheim.de>
-
-that patch sets DEBUG_INFO to y by default, even if whether DEBUG_KERNEL nor 
-KGDB is enabled. The attached patch changes this to enable DEBUG_INFO by 
-default only if KGDB is enabled.
-
-DESC
-x86_64 fixes
-EDESC
-From Andi Kleen
-
-Fix x86_64 for kgdb.  We forget why.
-DESC
-correct kgdb.txt Documentation link (against  2.6.1-rc1-mm2)
-EDESC
-From: Jesper Juhl <juhl-lkml@dif.dk>
-
-The help text for "config KGDB" in arch/i386/Kconfig refers to
-Documentation/i386/kgdb.txt - the actual location is
-Documentation/i386/kgdb/kgdb.txt - patch below to fix that.
-
-DESC
-kgdb: fix for recent gcc
-EDESC
-
-arch/i386/kernel/traps.c:97: error: conflicting types for 'int3'
-arch/i386/kernel/traps.c:77: error: previous declaration of 'int3' was here
-arch/i386/kernel/traps.c:97: error: conflicting types for 'int3'
-arch/i386/kernel/traps.c:77: error: previous declaration of 'int3' was here
-arch/i386/kernel/traps.c:99: error: conflicting types for 'debug'
-arch/i386/kernel/traps.c:75: error: previous declaration of 'debug' was here
-arch/i386/kernel/traps.c:99: error: conflicting types for 'debug'
-arch/i386/kernel/traps.c:75: error: previous declaration of 'debug' was here
-
-DESC
-kgdb warning fixes
-EDESC
-
-arch/i386/kernel/kgdb_stub.c:1306: warning: 'time' might be used uninitialized in this function
-arch/i386/kernel/kgdb_stub.c:1306: warning: 'dum' might be used uninitialized in this function
-DESC
-THREAD_SIZE fixes for kgdb
-EDESC
-From: Matt Mackall <mpm@selenic.com>
-
-Noticed the THREAD_SIZE clean-ups are in -mm now. Here are the missing
-bits for kgdb, tested in -tiny with 4k stacks. 
-DESC
-Fix stack overflow test for non-8k stacks
-EDESC
-From: Matt Mackall <mpm@selenic.com>
-
-This is needed to work properly with 4k and 16k stacks.
-DESC
-kgdb-ga.patch fix for i386 single-step into sysenter
-EDESC
-From: Roland McGrath <roland@redhat.com>
-
-Using kgdb-ga.patch from -mm, if userland single-steps (PTRACE_SINGLESTEP)
-into the `sysenter' instruction, kgdb reports a bogus trap:
-
-	Program received signal SIGTRAP, Trace/breakpoint trap.
-	sysenter_past_esp () at arch/i386/kernel/entry.S:249
-	1: x/i $pc  0xc0106023 <sysenter_past_esp>:	sti    
-	(gdb) 
-
-The hackery in the "FIX_STACK" macro in entry.S changes the saved PC for a
-the spurious kernel-mode debug trap when TF was set on user-mode execution
-of `sysenter', so sysenter_past_esp is where it actually lies in this case.
- The following patch removes the kgdb hiccup when userland
-PTRACE_SINGLESTEP's into sysenter.
-DESC
-fix TRAP_BAD_SYSCALL_EXITS on i386
-EDESC
-From: Andy Whitcroft <apw@shadowen.org>
-
-We are not using the right offset name, nor the right address when checking
-for a non-zero preempt count.  Move to TI_preempt_count(%ebp).
-
-Signed-off-by: Andy Whitcroft <apw@shadowen.org>
-DESC
-add TRAP_BAD_SYSCALL_EXITS config for i386
-EDESC
-From: Andy Whitcroft <apw@shadowen.org>
-
-There seems to be code recently added to -bk and thereby -mm which supports
-extra debug for preempt on system call exit.  Oddly there doesn't seem to
-be configuration options to enable them.  Below is a possible patch to
-allow enabling this on i386.  Sadly the most obvious menu to add this to is
-the Kernel Hacking menu, but that is defined in architecture specific
-configuration.  If this makes sense I could patch the other arches?
-
-Add a configuration option to allow enabling TRAP_BAD_SYSCALL_EXITS to the
-Kernel Hacking menu.
-
-Signed-off-by: Andy Whitcroft <apw@shadowen.org>
-Signed-off-by: Andrew Morton <akpm@osdl.org>
----
-
- 25-akpm/Documentation/i386/kgdb/andthen         |  100 +
- 25-akpm/Documentation/i386/kgdb/debug-nmi.txt   |   37 
- 25-akpm/Documentation/i386/kgdb/gdb-globals.txt |   71 
- 25-akpm/Documentation/i386/kgdb/gdbinit         |   14 
- 25-akpm/Documentation/i386/kgdb/gdbinit-modules |  146 +
- 25-akpm/Documentation/i386/kgdb/gdbinit.hw      |  117 +
- 25-akpm/Documentation/i386/kgdb/kgdb.txt        |  775 +++++++
- 25-akpm/Documentation/i386/kgdb/loadmodule.sh   |   78 
- 25-akpm/MAINTAINERS                             |    6 
- 25-akpm/arch/i386/Kconfig                       |    8 
- 25-akpm/arch/i386/Kconfig.debug                 |    2 
- 25-akpm/arch/i386/Kconfig.kgdb                  |  175 +
- 25-akpm/arch/i386/Makefile                      |    3 
- 25-akpm/arch/i386/kernel/Makefile               |    1 
- 25-akpm/arch/i386/kernel/entry.S                |   29 
- 25-akpm/arch/i386/kernel/kgdb_stub.c            | 2330 ++++++++++++++++++++++++
- 25-akpm/arch/i386/kernel/nmi.c                  |   25 
- 25-akpm/arch/i386/kernel/smp.c                  |   12 
- 25-akpm/arch/i386/kernel/traps.c                |   77 
- 25-akpm/arch/i386/lib/Makefile                  |    1 
- 25-akpm/arch/i386/lib/kgdb_serial.c             |  485 ++++
- 25-akpm/arch/i386/mm/fault.c                    |    6 
- 25-akpm/arch/x86_64/boot/compressed/head.S      |    1 
- 25-akpm/arch/x86_64/boot/compressed/misc.c      |    1 
- 25-akpm/drivers/char/keyboard.c                 |    3 
- 25-akpm/drivers/char/sysrq.c                    |   23 
- 25-akpm/drivers/serial/8250.c                   |   40 
- 25-akpm/drivers/serial/serial_core.c            |    5 
- 25-akpm/include/asm-i386/bugs.h                 |   21 
- 25-akpm/include/asm-i386/kgdb.h                 |   59 
- 25-akpm/include/asm-i386/kgdb_local.h           |  102 +
- 25-akpm/include/linux/config.h                  |    3 
- 25-akpm/include/linux/dwarf2-lang.h             |  132 +
- 25-akpm/include/linux/dwarf2.h                  |  738 +++++++
- 25-akpm/include/linux/serial_core.h             |    4 
- 25-akpm/include/linux/spinlock.h                |   12 
- 25-akpm/kernel/pid.c                            |    6 
- 25-akpm/kernel/sched.c                          |    7 
- 38 files changed, 5645 insertions(+), 10 deletions(-)
-
-diff -puN arch/i386/Kconfig~kgdb-ga arch/i386/Kconfig
---- 25/arch/i386/Kconfig~kgdb-ga	2004-10-21 14:54:15.256604136 -0700
-+++ 25-akpm/arch/i386/Kconfig	2004-10-21 14:54:15.295598208 -0700
-@@ -1184,6 +1184,14 @@ menu "Executable file formats"
- 
- source "fs/Kconfig.binfmt"
- 
-+config TRAP_BAD_SYSCALL_EXITS
-+	bool "Debug bad system call exits"
-+	depends on KGDB
-+	help
-+	  If you say Y here the kernel will check for system calls which
-+	  return without clearing preempt.
-+        default n
-+
- endmenu
- 
- source "drivers/Kconfig"
-diff -puN arch/i386/kernel/entry.S~kgdb-ga arch/i386/kernel/entry.S
---- 25/arch/i386/kernel/entry.S~kgdb-ga	2004-10-21 14:54:15.257603984 -0700
-+++ 25-akpm/arch/i386/kernel/entry.S	2004-10-21 14:54:15.296598056 -0700
-@@ -48,6 +48,18 @@
- #include <asm/smp.h>
- #include <asm/page.h>
- #include "irq_vectors.h"
-+        /* We do not recover from a stack overflow, but at least
-+         * we know it happened and should be able to track it down.
-+         */
-+#ifdef CONFIG_STACK_OVERFLOW_TEST
-+#define STACK_OVERFLOW_TEST \
-+        testl $(THREAD_SIZE - 512),%esp;    \
-+        jnz   10f;            \
-+        call  stack_overflow; \
-+10:
-+#else
-+#define STACK_OVERFLOW_TEST
-+#endif
- 
- #define nr_syscalls ((syscall_table_size)/4)
- 
-@@ -94,7 +106,8 @@ VM_MASK		= 0x00020000
- 	pushl %ebx; \
- 	movl $(__USER_DS), %edx; \
- 	movl %edx, %ds; \
--	movl %edx, %es;
-+	movl %edx, %es; \
-+        STACK_OVERFLOW_TEST
- 
- #define RESTORE_INT_REGS \
- 	popl %ebx;	\
-@@ -198,6 +211,7 @@ need_resched:
- 	# sysenter call handler stub
- ENTRY(sysenter_entry)
- 	movl TSS_sysenter_esp0(%esp),%esp
-+	.globl sysenter_past_esp
- sysenter_past_esp:
- 	sti
- 	pushl $(__USER_DS)
-@@ -260,6 +274,19 @@ syscall_exit:
- 	testw $_TIF_ALLWORK_MASK, %cx	# current->work
- 	jne syscall_exit_work
- restore_all:
-+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
-+	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
-+	movb CS(%esp), %al
-+	testl $(VM_MASK | 3), %eax
-+	jz resume_kernelX		# returning to kernel or vm86-space
-+
-+	cmpl $0,TI_preempt_count(%ebp)  # non-zero preempt_count ?
-+	jz resume_kernelX
-+
-+        int $3
-+
-+resume_kernelX:
-+#endif
- 	RESTORE_ALL
- 
- 	# perform work that needs to be done immediately before resumption
-diff -puN /dev/null arch/i386/kernel/kgdb_stub.c
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/arch/i386/kernel/kgdb_stub.c	2004-10-21 14:54:15.307596384 -0700
-@@ -0,0 +1,2330 @@
-+/*
-+ *
-+ * This program is free software; you can redistribute it and/or modify it
-+ * under the terms of the GNU General Public License as published by the
-+ * Free Software Foundation; either version 2, or (at your option) any
-+ * later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
-+ * General Public License for more details.
-+ *
-+ */
-+
-+/*
-+ * Copyright (c) 2000 VERITAS Software Corporation.
-+ *
-+ */
-+/****************************************************************************
-+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
-+ *
-+ *  Module name: remcom.c $
-+ *  Revision: 1.34 $
-+ *  Date: 91/03/09 12:29:49 $
-+ *  Contributor:     Lake Stevens Instrument Division$
-+ *
-+ *  Description:     low level support for gdb debugger. $
-+ *
-+ *  Considerations:  only works on target hardware $
-+ *
-+ *  Written by:	     Glenn Engel $
-+ *  Updated by:	     David Grothe <dave@gcom.com>
-+ *  ModuleState:     Experimental $
-+ *
-+ *  NOTES:	     See Below $
-+ *
-+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
-+ *  Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
-+ *
-+ *  Changes to allow auto initilization.  All that is needed is that it
-+ *  be linked with the kernel and a break point (int 3) be executed.
-+ *  The header file <asm/kgdb.h> defines BREAKPOINT to allow one to do
-+ *  this. It should also be possible, once the interrupt system is up, to
-+ *  call putDebugChar("+").  Once this is done, the remote debugger should
-+ *  get our attention by sending a ^C in a packet. George Anzinger
-+ *  <george@mvista.com>
-+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
-+ *  Added thread support, support for multiple processors,
-+ *	support for ia-32(x86) hardware debugging.
-+ *	Amit S. Kale ( akale@veritas.com )
-+ *
-+ *
-+ *  To enable debugger support, two things need to happen.  One, a
-+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
-+ *  or error conditions to be properly intercepted and reported to gdb.
-+ *  Two, a breakpoint needs to be generated to begin communication.  This
-+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
-+ *  simulates a breakpoint by executing an int 3.
-+ *
-+ *************
-+ *
-+ *    The following gdb commands are supported:
-+ *
-+ * command	    function				   Return value
-+ *
-+ *    g		    return the value of the CPU registers  hex data or ENN
-+ *    G		    set the value of the CPU registers	   OK or ENN
-+ *
-+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA	   hex data or ENN
-+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA	   OK or ENN
-+ *
-+ *    c		    Resume at current address		   SNN	 ( signal NN)
-+ *    cAA..AA	    Continue at address AA..AA		   SNN
-+ *
-+ *    s		    Step one instruction		   SNN
-+ *    sAA..AA	    Step one instruction from AA..AA	   SNN
-+ *
-+ *    k		    kill
-+ *
-+ *    ?		    What was the last sigval ?		   SNN	 (signal NN)
-+ *
-+ * All commands and responses are sent with a packet which includes a
-+ * checksum.  A packet consists of
-+ *
-+ * $<packet info>#<checksum>.
-+ *
-+ * where
-+ * <packet info> :: <characters representing the command or response>
-+ * <checksum>	 :: < two hex digits computed as modulo 256 sum of <packetinfo>>
-+ *
-+ * When a packet is received, it is first acknowledged with either '+' or '-'.
-+ * '+' indicates a successful transfer.	 '-' indicates a failed transfer.
-+ *
-+ * Example:
-+ *
-+ * Host:		  Reply:
-+ * $m0,10#2a		   +$00010203040506070809101112131415#42
-+ *
-+ ****************************************************************************/
-+#define KGDB_VERSION "<20030915.1651.33>"
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <asm/string.h>		/* for strcpy */
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <asm/vm86.h>
-+#include <asm/system.h>
-+#include <asm/ptrace.h>		/* for linux pt_regs struct */
-+#include <asm/kgdb_local.h>
-+#include <linux/list.h>
-+#include <asm/atomic.h>
-+#include <asm/processor.h>
-+#include <linux/irq.h>
-+#include <asm/desc.h>
-+
-+/************************************************************************
-+ *
-+ * external low-level support routines
-+ */
-+typedef void (*Function) (void);	/* pointer to a function */
-+
-+/* Thread reference */
-+typedef unsigned char threadref[8];
-+
-+extern void putDebugChar(int);	/* write a single character	 */
-+extern int getDebugChar(void);	/* read and return a single char */
-+
-+/************************************************************************/
-+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
-+/* at least NUMREGBYTES*2 are needed for register packets */
-+/* Longer buffer is needed to list all threads */
-+#define BUFMAX 400
-+
-+char *kgdb_version = KGDB_VERSION;
-+
-+/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
-+int debug_regs = 0;		/* set to non-zero to print registers */
-+
-+/* filled in by an external module */
-+char *gdb_module_offsets;
-+
-+static const char hexchars[] = "0123456789abcdef";
-+
-+/* Number of bytes of registers.  */
-+#define NUMREGBYTES 64
-+/*
-+ * Note that this register image is in a different order than
-+ * the register image that Linux produces at interrupt time.
-+ *
-+ * Linux's register image is defined by struct pt_regs in ptrace.h.
-+ * Just why GDB uses a different order is a historical mystery.
-+ */
-+enum regnames { _EAX,		/* 0 */
-+	_ECX,			/* 1 */
-+	_EDX,			/* 2 */
-+	_EBX,			/* 3 */
-+	_ESP,			/* 4 */
-+	_EBP,			/* 5 */
-+	_ESI,			/* 6 */
-+	_EDI,			/* 7 */
-+	_PC /* 8 also known as eip */ ,
-+	_PS /* 9 also known as eflags */ ,
-+	_CS,			/* 10 */
-+	_SS,			/* 11 */
-+	_DS,			/* 12 */
-+	_ES,			/* 13 */
-+	_FS,			/* 14 */
-+	_GS			/* 15 */
-+};
-+
-+/***************************  ASSEMBLY CODE MACROS *************************/
-+/*
-+ * Put the error code here just in case the user cares.
-+ * Likewise, the vector number here (since GDB only gets the signal
-+ * number through the usual means, and that's not very specific).
-+ * The called_from is the return address so he can tell how we entered kgdb.
-+ * This will allow him to seperate out the various possible entries.
-+ */
-+#define REMOTE_DEBUG 0		/* set != to turn on printing (also available in info) */
-+
-+#define PID_MAX PID_MAX_DEFAULT
-+
-+#ifdef CONFIG_SMP
-+void smp_send_nmi_allbutself(void);
-+#define IF_SMP(x) x
-+#undef MAX_NO_CPUS
-+#ifndef CONFIG_NO_KGDB_CPUS
-+#define CONFIG_NO_KGDB_CPUS 2
-+#endif
-+#if CONFIG_NO_KGDB_CPUS > NR_CPUS
-+#define MAX_NO_CPUS NR_CPUS
-+#else
-+#define MAX_NO_CPUS CONFIG_NO_KGDB_CPUS
-+#endif
-+#define hold_init hold_on_sstep: 1,
-+#define MAX_CPU_MASK (unsigned long)((1LL << MAX_NO_CPUS) - 1LL)
-+#define NUM_CPUS num_online_cpus()
-+#else
-+#define IF_SMP(x)
-+#define hold_init
-+#undef MAX_NO_CPUS
-+#define MAX_NO_CPUS 1
-+#define NUM_CPUS 1
-+#endif
-+#define NOCPU (struct task_struct *)0xbad1fbad
-+/* *INDENT-OFF*	 */
-+struct kgdb_info {
-+	int used_malloc;
-+	void *called_from;
-+	long long entry_tsc;
-+	int errcode;
-+	int vector;
-+	int print_debug_info;
-+#ifdef CONFIG_SMP
-+	int hold_on_sstep;
-+	struct {
-+		volatile struct task_struct *task;
-+		int pid;
-+		int hold;
-+		struct pt_regs *regs;
-+	} cpus_waiting[MAX_NO_CPUS];
-+#endif
-+} kgdb_info = {hold_init print_debug_info:REMOTE_DEBUG, vector:-1};
-+
-+/* *INDENT-ON*	*/
-+
-+#define used_m kgdb_info.used_malloc
-+/*
-+ * This is little area we set aside to contain the stack we
-+ * need to build to allow gdb to call functions.  We use one
-+ * per cpu to avoid locking issues.  We will do all this work
-+ * with interrupts off so that should take care of the protection
-+ * issues.
-+ */
-+#define LOOKASIDE_SIZE 200	/* should be more than enough */
-+#define MALLOC_MAX   200	/* Max malloc size */
-+struct {
-+	unsigned int esp;
-+	int array[LOOKASIDE_SIZE];
-+} fn_call_lookaside[MAX_NO_CPUS];
-+
-+static int trap_cpu;
-+static unsigned int OLD_esp;
-+
-+#define END_OF_LOOKASIDE  &fn_call_lookaside[trap_cpu].array[LOOKASIDE_SIZE]
-+#define IF_BIT 0x200
-+#define TF_BIT 0x100
-+
-+#define MALLOC_ROUND 8-1
-+
-+static char malloc_array[MALLOC_MAX];
-+IF_SMP(static void to_gdb(const char *mess));
-+void *
-+malloc(int size)
-+{
-+
-+	if (size <= (MALLOC_MAX - used_m)) {
-+		int old_used = used_m;
-+		used_m += ((size + MALLOC_ROUND) & (~MALLOC_ROUND));
-+		return &malloc_array[old_used];
-+	} else {
-+		return NULL;
-+	}
-+}
-+
-+/*
-+ * Gdb calls functions by pushing agruments, including a return address
-+ * on the stack and the adjusting EIP to point to the function.	 The
-+ * whole assumption in GDB is that we are on a different stack than the
-+ * one the "user" i.e. code that hit the break point, is on.  This, of
-+ * course is not true in the kernel.  Thus various dodges are needed to
-+ * do the call without directly messing with EIP (which we can not change
-+ * as it is just a location and not a register.	 To adjust it would then
-+ * require that we move every thing below EIP up or down as needed.  This
-+ * will not work as we may well have stack relative pointer on the stack
-+ * (such as the pointer to regs, for example).
-+
-+ * So here is what we do:
-+ * We detect gdb attempting to store into the stack area and instead, store
-+ * into the fn_call_lookaside.array at the same relative location as if it
-+ * were the area ESP pointed at.  We also trap ESP modifications
-+ * and uses these to adjust fn_call_lookaside.esp.  On entry
-+ * fn_call_lookaside.esp will be set to point at the last entry in
-+ * fn_call_lookaside.array.  This allows us to check if it has changed, and
-+ * if so, on exit, we add the registers we will use to do the move and a
-+ * trap/ interrupt return exit sequence.  We then adjust the eflags in the
-+ * regs array (remember we now have a copy in the fn_call_lookaside.array) to
-+ * kill the interrupt bit, AND we change EIP to point at our set up stub.
-+ * As part of the register set up we preset the registers to point at the
-+ * begining and end of the fn_call_lookaside.array, so all the stub needs to
-+ * do is move words from the array to the stack until ESP= the desired value
-+ * then do the rti.  This will then transfer to the desired function with
-+ * all the correct registers.  Nifty huh?
-+ */
-+extern asmlinkage void fn_call_stub(void);
-+extern asmlinkage void fn_rtn_stub(void);
-+/*					   *INDENT-OFF*	 */
-+__asm__("fn_rtn_stub:\n\t"
-+	"movl %eax,%esp\n\t"
-+	"fn_call_stub:\n\t"
-+	"1:\n\t"
-+	"addl $-4,%ebx\n\t"
-+	"movl (%ebx), %eax\n\t"
-+	"pushl %eax\n\t"
-+	"cmpl %esp,%ecx\n\t"
-+	"jne  1b\n\t"
-+	"popl %eax\n\t"
-+	"popl %ebx\n\t"
-+	"popl %ecx\n\t"
-+	"iret \n\t");
-+/*					     *INDENT-ON*  */
-+#define gdb_i386vector	kgdb_info.vector
-+#define gdb_i386errcode kgdb_info.errcode
-+#define waiting_cpus	kgdb_info.cpus_waiting
-+#define remote_debug	kgdb_info.print_debug_info
-+#define hold_cpu(cpu)	kgdb_info.cpus_waiting[cpu].hold
-+/* gdb locks */
-+
-+#ifdef CONFIG_SMP
-+static int in_kgdb_called;
-+static spinlock_t waitlocks[MAX_NO_CPUS] =
-+    {[0 ... MAX_NO_CPUS - 1] = SPIN_LOCK_UNLOCKED };
-+/*
-+ * The following array has the thread pointer of each of the "other"
-+ * cpus.  We make it global so it can be seen by gdb.
-+ */
-+volatile int in_kgdb_entry_log[MAX_NO_CPUS];
-+volatile struct pt_regs *in_kgdb_here_log[MAX_NO_CPUS];
-+/*
-+static spinlock_t continuelocks[MAX_NO_CPUS];
-+*/
-+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
-+/* waiters on our spinlock plus us */
-+static atomic_t spinlock_waiters = ATOMIC_INIT(1);
-+static int spinlock_count = 0;
-+static int spinlock_cpu = 0;
-+/*
-+ * Note we use nested spin locks to account for the case where a break
-+ * point is encountered when calling a function by user direction from
-+ * kgdb. Also there is the memory exception recursion to account for.
-+ * Well, yes, but this lets other cpus thru too.  Lets add a
-+ * cpu id to the lock.
-+ */
-+#define KGDB_SPIN_LOCK(x) if( spinlock_count == 0 || \
-+			      spinlock_cpu != smp_processor_id()){\
-+				      atomic_inc(&spinlock_waiters); \
-+				      while (! spin_trylock(x)) {\
-+					    in_kgdb(&regs);\
-+				      }\
-+				      atomic_dec(&spinlock_waiters); \
-+				      spinlock_count = 1; \
-+				      spinlock_cpu = smp_processor_id(); \
-+			  }else{  \
-+				      spinlock_count++; \
-+			  }
-+#define KGDB_SPIN_UNLOCK(x) if( --spinlock_count == 0) spin_unlock(x)
-+#else
-+unsigned kgdb_spinlock = 0;
-+#define KGDB_SPIN_LOCK(x) --*x
-+#define KGDB_SPIN_UNLOCK(x) ++*x
-+#endif
-+
-+int
-+hex(char ch)
-+{
-+	if ((ch >= 'a') && (ch <= 'f'))
-+		return (ch - 'a' + 10);
-+	if ((ch >= '0') && (ch <= '9'))
-+		return (ch - '0');
-+	if ((ch >= 'A') && (ch <= 'F'))
-+		return (ch - 'A' + 10);
-+	return (-1);
-+}
-+
-+/* scan for the sequence $<data>#<checksum>	*/
-+void
-+getpacket(char *buffer)
-+{
-+	unsigned char checksum;
-+	unsigned char xmitcsum;
-+	int i;
-+	int count;
-+	char ch;
-+
-+	do {
-+		/* wait around for the start character, ignore all other characters */
-+		while ((ch = (getDebugChar() & 0x7f)) != '$') ;
-+		checksum = 0;
-+		xmitcsum = -1;
-+
-+		count = 0;
-+
-+		/* now, read until a # or end of buffer is found */
-+		while (count < BUFMAX) {
-+			ch = getDebugChar() & 0x7f;
-+			if (ch == '#')
-+				break;
-+			checksum = checksum + ch;
-+			buffer[count] = ch;
-+			count = count + 1;
-+		}
-+		buffer[count] = 0;
-+
-+		if (ch == '#') {
-+			xmitcsum = hex(getDebugChar() & 0x7f) << 4;
-+			xmitcsum += hex(getDebugChar() & 0x7f);
-+			if ((remote_debug) && (checksum != xmitcsum)) {
-+				printk
-+				    ("bad checksum.	My count = 0x%x, sent=0x%x. buf=%s\n",
-+				     checksum, xmitcsum, buffer);
-+			}
-+
-+			if (checksum != xmitcsum)
-+				putDebugChar('-');	/* failed checksum */
-+			else {
-+				putDebugChar('+');	/* successful transfer */
-+				/* if a sequence char is present, reply the sequence ID */
-+				if (buffer[2] == ':') {
-+					putDebugChar(buffer[0]);
-+					putDebugChar(buffer[1]);
-+					/* remove sequence chars from buffer */
-+					count = strlen(buffer);
-+					for (i = 3; i <= count; i++)
-+						buffer[i - 3] = buffer[i];
-+				}
-+			}
-+		}
-+	} while (checksum != xmitcsum);
-+
-+	if (remote_debug)
-+		printk("R:%s\n", buffer);
-+}
-+
-+/* send the packet in buffer.  */
-+
-+void
-+putpacket(char *buffer)
-+{
-+	unsigned char checksum;
-+	int count;
-+	char ch;
-+
-+	/*  $<packet info>#<checksum>. */
-+	do {
-+		if (remote_debug)
-+			printk("T:%s\n", buffer);
-+		putDebugChar('$');
-+		checksum = 0;
-+		count = 0;
-+
-+		while ((ch = buffer[count])) {
-+			putDebugChar(ch);
-+			checksum += ch;
-+			count += 1;
-+		}
-+
-+		putDebugChar('#');
-+		putDebugChar(hexchars[checksum >> 4]);
-+		putDebugChar(hexchars[checksum % 16]);
-+
-+	} while ((getDebugChar() & 0x7f) != '+');
-+
-+}
-+
-+static char remcomInBuffer[BUFMAX];
-+static char remcomOutBuffer[BUFMAX];
-+static short error;
-+
-+void
-+debug_error(char *format, char *parm)
-+{
-+	if (remote_debug)
-+		printk(format, parm);
-+}
-+
-+static void
-+print_regs(struct pt_regs *regs)
-+{
-+	printk("EAX=%08lx ", regs->eax);
-+	printk("EBX=%08lx ", regs->ebx);
-+	printk("ECX=%08lx ", regs->ecx);
-+	printk("EDX=%08lx ", regs->edx);
-+	printk("\n");
-+	printk("ESI=%08lx ", regs->esi);
-+	printk("EDI=%08lx ", regs->edi);
-+	printk("EBP=%08lx ", regs->ebp);
-+	printk("ESP=%08lx ", (long) &regs->esp);
-+	printk("\n");
-+	printk(" DS=%08x ", regs->xds);
-+	printk(" ES=%08x ", regs->xes);
-+	printk(" SS=%08x ", __KERNEL_DS);
-+	printk(" FL=%08lx ", regs->eflags);
-+	printk("\n");
-+	printk(" CS=%08x ", regs->xcs);
-+	printk(" IP=%08lx ", regs->eip);
-+#if 0
-+	printk(" FS=%08x ", regs->fs);
-+	printk(" GS=%08x ", regs->gs);
-+#endif
-+	printk("\n");
-+
-+}				/* print_regs */
-+
-+#define NEW_esp fn_call_lookaside[trap_cpu].esp
-+
-+static void
-+regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
-+{
-+	gdb_regs[_EAX] = regs->eax;
-+	gdb_regs[_EBX] = regs->ebx;
-+	gdb_regs[_ECX] = regs->ecx;
-+	gdb_regs[_EDX] = regs->edx;
-+	gdb_regs[_ESI] = regs->esi;
-+	gdb_regs[_EDI] = regs->edi;
-+	gdb_regs[_EBP] = regs->ebp;
-+	gdb_regs[_DS] = regs->xds;
-+	gdb_regs[_ES] = regs->xes;
-+	gdb_regs[_PS] = regs->eflags;
-+	gdb_regs[_CS] = regs->xcs;
-+	gdb_regs[_PC] = regs->eip;
-+	/* Note, as we are a debugging the kernel, we will always
-+	 * trap in kernel code, this means no priviledge change,
-+	 * and so the pt_regs structure is not completely valid.  In a non
-+	 * privilege change trap, only EFLAGS, CS and EIP are put on the stack,
-+	 * SS and ESP are not stacked, this means that the last 2 elements of
-+	 * pt_regs is not valid (they would normally refer to the user stack)
-+	 * also, using regs+1 is no good because you end up will a value that is
-+	 * 2 longs (8) too high.  This used to cause stepping over functions
-+	 * to fail, so my fix is to use the address of regs->esp, which
-+	 * should point at the end of the stack frame.	Note I have ignored
-+	 * completely exceptions that cause an error code to be stacked, such
-+	 * as double fault.  Stuart Hughes, Zentropix.
-+	 * original code: gdb_regs[_ESP] =  (int) (regs + 1) ;
-+
-+	 * this is now done on entry and moved to OLD_esp (as well as NEW_esp).
-+	 */
-+	gdb_regs[_ESP] = NEW_esp;
-+	gdb_regs[_SS] = __KERNEL_DS;
-+	gdb_regs[_FS] = 0xFFFF;
-+	gdb_regs[_GS] = 0xFFFF;
-+}				/* regs_to_gdb_regs */
-+
-+static void
-+gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
-+{
-+	regs->eax = gdb_regs[_EAX];
-+	regs->ebx = gdb_regs[_EBX];
-+	regs->ecx = gdb_regs[_ECX];
-+	regs->edx = gdb_regs[_EDX];
-+	regs->esi = gdb_regs[_ESI];
-+	regs->edi = gdb_regs[_EDI];
-+	regs->ebp = gdb_regs[_EBP];
-+	regs->xds = gdb_regs[_DS];
-+	regs->xes = gdb_regs[_ES];
-+	regs->eflags = gdb_regs[_PS];
-+	regs->xcs = gdb_regs[_CS];
-+	regs->eip = gdb_regs[_PC];
-+	NEW_esp = gdb_regs[_ESP];	/* keep the value */
-+#if 0				/* can't change these */
-+	regs->esp = gdb_regs[_ESP];
-+	regs->xss = gdb_regs[_SS];
-+	regs->fs = gdb_regs[_FS];
-+	regs->gs = gdb_regs[_GS];
-+#endif
-+
-+}				/* gdb_regs_to_regs */
-+
-+int thread_list = 0;
-+
-+void
-+get_gdb_regs(struct task_struct *p, struct pt_regs *regs, int *gdb_regs)
-+{
-+	unsigned long stack_page;
-+	int count = 0;
-+	IF_SMP(int i);
-+	if (!p || p == current) {
-+		regs_to_gdb_regs(gdb_regs, regs);
-+		return;
-+	}
-+#ifdef CONFIG_SMP
-+	for (i = 0; i < MAX_NO_CPUS; i++) {
-+		if (p == kgdb_info.cpus_waiting[i].task) {
-+			regs_to_gdb_regs(gdb_regs,
-+					 kgdb_info.cpus_waiting[i].regs);
-+			gdb_regs[_ESP] =
-+			    (int) &kgdb_info.cpus_waiting[i].regs->esp;
-+
-+			return;
-+		}
-+	}
-+#endif
-+	memset(gdb_regs, 0, NUMREGBYTES);
-+	gdb_regs[_ESP] = p->thread.esp;
-+	gdb_regs[_PC] = p->thread.eip;
-+	gdb_regs[_EBP] = *(int *) gdb_regs[_ESP];
-+	gdb_regs[_EDI] = *(int *) (gdb_regs[_ESP] + 4);
-+	gdb_regs[_ESI] = *(int *) (gdb_regs[_ESP] + 8);
-+
-+/*
-+ * This code is to give a more informative notion of where a process
-+ * is waiting.	It is used only when the user asks for a thread info
-+ * list.  If he then switches to the thread, s/he will find the task
-+ * is in schedule, but a back trace should show the same info we come
-+ * up with.  This code was shamelessly purloined from process.c.  It was
-+ * then enhanced to provide more registers than simply the program
-+ * counter.
-+ */
-+
-+	if (!thread_list) {
-+		return;
-+	}
-+
-+	if (p->state == TASK_RUNNING)
-+		return;
-+	stack_page = (unsigned long) p->thread_info;
-+	if (gdb_regs[_ESP] < stack_page || gdb_regs[_ESP] >
-+	    THREAD_SIZE - sizeof(long) + stack_page)
-+		return;
-+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
-+	do {
-+		if (gdb_regs[_EBP] < stack_page ||
-+		    gdb_regs[_EBP] > THREAD_SIZE - 2*sizeof(long) + stack_page)
-+			return;
-+		gdb_regs[_PC] = *(unsigned long *) (gdb_regs[_EBP] + 4);
-+		gdb_regs[_ESP] = gdb_regs[_EBP] + 8;
-+		gdb_regs[_EBP] = *(unsigned long *) gdb_regs[_EBP];
-+		if (!in_sched_functions(gdb_regs[_PC]))
-+			return;
-+	} while (count++ < 16);
-+	return;
-+}
-+
-+/* Indicate to caller of mem2hex or hex2mem that there has been an
-+   error.  */
-+static volatile int mem_err = 0;
-+static volatile int mem_err_expected = 0;
-+static volatile int mem_err_cnt = 0;
-+static int garbage_loc = -1;
-+
-+int
-+get_char(char *addr)
-+{
-+	return *addr;
-+}
-+
-+void
-+set_char(char *addr, int val, int may_fault)
-+{
-+	/*
-+	 * This code traps references to the area mapped to the kernel
-+	 * stack as given by the regs and, instead, stores to the
-+	 * fn_call_lookaside[cpu].array
-+	 */
-+	if (may_fault &&
-+	    (unsigned int) addr < OLD_esp &&
-+	    ((unsigned int) addr > (OLD_esp - (unsigned int) LOOKASIDE_SIZE))) {
-+		addr = (char *) END_OF_LOOKASIDE - ((char *) OLD_esp - addr);
-+	}
-+	*addr = val;
-+}
-+
-+/* convert the memory pointed to by mem into hex, placing result in buf */
-+/* return a pointer to the last char put in buf (null) */
-+/* If MAY_FAULT is non-zero, then we should set mem_err in response to
-+   a fault; if zero treat a fault like any other fault in the stub.  */
-+char *
-+mem2hex(char *mem, char *buf, int count, int may_fault)
-+{
-+	int i;
-+	unsigned char ch;
-+
-+	if (may_fault) {
-+		mem_err_expected = 1;
-+		mem_err = 0;
-+	}
-+	for (i = 0; i < count; i++) {
-+		/* printk("%lx = ", mem) ; */
-+
-+		ch = get_char(mem++);
-+
-+		/* printk("%02x\n", ch & 0xFF) ; */
-+		if (may_fault && mem_err) {
-+			if (remote_debug)
-+				printk("Mem fault fetching from addr %lx\n",
-+				       (long) (mem - 1));
-+			*buf = 0;	/* truncate buffer */
-+			return (buf);
-+		}
-+		*buf++ = hexchars[ch >> 4];
-+		*buf++ = hexchars[ch % 16];
-+	}
-+	*buf = 0;
-+	if (may_fault)
-+		mem_err_expected = 0;
-+	return (buf);
-+}
-+
-+/* convert the hex array pointed to by buf into binary to be placed in mem */
-+/* return a pointer to the character AFTER the last byte written */
-+/* NOTE: We use the may fault flag to also indicate if the write is to
-+ * the registers (0) or "other" memory (!=0)
-+ */
-+char *
-+hex2mem(char *buf, char *mem, int count, int may_fault)
-+{
-+	int i;
-+	unsigned char ch;
-+
-+	if (may_fault) {
-+		mem_err_expected = 1;
-+		mem_err = 0;
-+	}
-+	for (i = 0; i < count; i++) {
-+		ch = hex(*buf++) << 4;
-+		ch = ch + hex(*buf++);
-+		set_char(mem++, ch, may_fault);
-+
-+		if (may_fault && mem_err) {
-+			if (remote_debug)
-+				printk("Mem fault storing to addr %lx\n",
-+				       (long) (mem - 1));
-+			return (mem);
-+		}
-+	}
-+	if (may_fault)
-+		mem_err_expected = 0;
-+	return (mem);
-+}
-+
-+/**********************************************/
-+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
-+/* RETURN NUMBER OF CHARS PROCESSED	      */
-+/**********************************************/
-+int
-+hexToInt(char **ptr, int *intValue)
-+{
-+	int numChars = 0;
-+	int hexValue;
-+
-+	*intValue = 0;
-+
-+	while (**ptr) {
-+		hexValue = hex(**ptr);
-+		if (hexValue >= 0) {
-+			*intValue = (*intValue << 4) | hexValue;
-+			numChars++;
-+		} else
-+			break;
-+
-+		(*ptr)++;
-+	}
-+
-+	return (numChars);
-+}
-+
-+#define stubhex(h) hex(h)
-+#ifdef old_thread_list
-+
-+static int
-+stub_unpack_int(char *buff, int fieldlength)
-+{
-+	int nibble;
-+	int retval = 0;
-+
-+	while (fieldlength) {
-+		nibble = stubhex(*buff++);
-+		retval |= nibble;
-+		fieldlength--;
-+		if (fieldlength)
-+			retval = retval << 4;
-+	}
-+	return retval;
-+}
-+#endif
-+static char *
-+pack_hex_byte(char *pkt, int byte)
-+{
-+	*pkt++ = hexchars[(byte >> 4) & 0xf];
-+	*pkt++ = hexchars[(byte & 0xf)];
-+	return pkt;
-+}
-+
-+#define BUF_THREAD_ID_SIZE 16
-+
-+static char *
-+pack_threadid(char *pkt, threadref * id)
-+{
-+	char *limit;
-+	unsigned char *altid;
-+
-+	altid = (unsigned char *) id;
-+	limit = pkt + BUF_THREAD_ID_SIZE;
-+	while (pkt < limit)
-+		pkt = pack_hex_byte(pkt, *altid++);
-+	return pkt;
-+}
-+
-+#ifdef old_thread_list
-+static char *
-+unpack_byte(char *buf, int *value)
-+{
-+	*value = stub_unpack_int(buf, 2);
-+	return buf + 2;
-+}
-+
-+static char *
-+unpack_threadid(char *inbuf, threadref * id)
-+{
-+	char *altref;
-+	char *limit = inbuf + BUF_THREAD_ID_SIZE;
-+	int x, y;
-+
-+	altref = (char *) id;
-+
-+	while (inbuf < limit) {
-+		x = stubhex(*inbuf++);
-+		y = stubhex(*inbuf++);
-+		*altref++ = (x << 4) | y;
-+	}
-+	return inbuf;
-+}
-+#endif
-+void
-+int_to_threadref(threadref * id, int value)
-+{
-+	unsigned char *scan;
-+
-+	scan = (unsigned char *) id;
-+	{
-+		int i = 4;
-+		while (i--)
-+			*scan++ = 0;
-+	}
-+	*scan++ = (value >> 24) & 0xff;
-+	*scan++ = (value >> 16) & 0xff;
-+	*scan++ = (value >> 8) & 0xff;
-+	*scan++ = (value & 0xff);
-+}
-+int
-+int_to_hex_v(unsigned char * id, int value)
-+{
-+	unsigned char *start = id;
-+	int shift;
-+	int ch;
-+
-+	for (shift = 28; shift >= 0; shift -= 4) {
-+		if ((ch = (value >> shift) & 0xf) || (id != start)) {
-+			*id = hexchars[ch];
-+			id++;
-+		}
-+	}
-+	if (id == start)
-+		*id++ = '0';
-+	return id - start;
-+}
-+#ifdef old_thread_list
-+
-+static int
-+threadref_to_int(threadref * ref)
-+{
-+	int i, value = 0;
-+	unsigned char *scan;
-+
-+	scan = (char *) ref;
-+	scan += 4;
-+	i = 4;
-+	while (i-- > 0)
-+		value = (value << 8) | ((*scan++) & 0xff);
-+	return value;
-+}
-+#endif
-+static int
-+cmp_str(char *s1, char *s2, int count)
-+{
-+	while (count--) {
-+		if (*s1++ != *s2++)
-+			return 0;
-+	}
-+	return 1;
-+}
-+
-+#if 1				/* this is a hold over from 2.4 where O(1) was "sometimes" */
-+extern struct task_struct *kgdb_get_idle(int cpu);
-+#define idle_task(cpu) kgdb_get_idle(cpu)
-+#else
-+#define idle_task(cpu) init_tasks[cpu]
-+#endif
-+
-+extern int kgdb_pid_init_done;
-+
-+struct task_struct *
-+getthread(int pid)
-+{
-+	struct task_struct *thread;
-+	if (pid >= PID_MAX && pid <= (PID_MAX + MAX_NO_CPUS)) {
-+
-+		return idle_task(pid - PID_MAX);
-+	} else {
-+		/*
-+		 * find_task_by_pid is relatively safe all the time
-+		 * Other pid functions require lock downs which imply
-+		 * that we may be interrupting them (as we get here
-+		 * in the middle of most any lock down).
-+		 * Still we don't want to call until the table exists!
-+		 */
-+		if (kgdb_pid_init_done){
-+			thread = find_task_by_pid(pid);
-+			if (thread) {
-+				return thread;
-+			}
-+		}
-+	}
-+	return NULL;
-+}
-+/* *INDENT-OFF*	 */
-+struct hw_breakpoint {
-+	unsigned enabled;
-+	unsigned type;
-+	unsigned len;
-+	unsigned addr;
-+} breakinfo[4] = { {enabled:0},
-+		   {enabled:0},
-+		   {enabled:0},
-+		   {enabled:0}};
-+/* *INDENT-ON*	*/
-+unsigned hw_breakpoint_status;
-+void
-+correct_hw_break(void)
-+{
-+	int breakno;
-+	int correctit;
-+	int breakbit;
-+	unsigned dr7;
-+
-+	asm volatile ("movl %%db7, %0\n":"=r" (dr7)
-+		      :);
-+	/* *INDENT-OFF*	 */
-+	do {
-+		unsigned addr0, addr1, addr2, addr3;
-+		asm volatile ("movl %%db0, %0\n"
-+			      "movl %%db1, %1\n"
-+			      "movl %%db2, %2\n"
-+			      "movl %%db3, %3\n"
-+			      :"=r" (addr0), "=r"(addr1),
-+			      "=r"(addr2), "=r"(addr3)
-+			      :);
-+	} while (0);
-+	/* *INDENT-ON*	*/
-+	correctit = 0;
-+	for (breakno = 0; breakno < 3; breakno++) {
-+		breakbit = 2 << (breakno << 1);
-+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
-+			correctit = 1;
-+			dr7 |= breakbit;
-+			dr7 &= ~(0xf0000 << (breakno << 2));
-+			dr7 |= (((breakinfo[breakno].len << 2) |
-+				 breakinfo[breakno].type) << 16) <<
-+			    (breakno << 2);
-+			switch (breakno) {
-+			case 0:
-+				asm volatile ("movl %0, %%dr0\n"::"r"
-+					      (breakinfo[breakno].addr));
-+				break;
-+
-+			case 1:
-+				asm volatile ("movl %0, %%dr1\n"::"r"
-+					      (breakinfo[breakno].addr));
-+				break;
-+
-+			case 2:
-+				asm volatile ("movl %0, %%dr2\n"::"r"
-+					      (breakinfo[breakno].addr));
-+				break;
-+
-+			case 3:
-+				asm volatile ("movl %0, %%dr3\n"::"r"
-+					      (breakinfo[breakno].addr));
-+				break;
-+			}
-+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled) {
-+			correctit = 1;
-+			dr7 &= ~breakbit;
-+			dr7 &= ~(0xf0000 << (breakno << 2));
-+		}
-+	}
-+	if (correctit) {
-+		asm volatile ("movl %0, %%db7\n"::"r" (dr7));
-+	}
-+}
-+
-+int
-+remove_hw_break(unsigned breakno)
-+{
-+	if (!breakinfo[breakno].enabled) {
-+		return -1;
-+	}
-+	breakinfo[breakno].enabled = 0;
-+	return 0;
-+}
-+
-+int
-+set_hw_break(unsigned breakno, unsigned type, unsigned len, unsigned addr)
-+{
-+	if (breakinfo[breakno].enabled) {
-+		return -1;
-+	}
-+	breakinfo[breakno].enabled = 1;
-+	breakinfo[breakno].type = type;
-+	breakinfo[breakno].len = len;
-+	breakinfo[breakno].addr = addr;
-+	return 0;
-+}
-+
-+#ifdef CONFIG_SMP
-+static int in_kgdb_console = 0;
-+
-+int
-+in_kgdb(struct pt_regs *regs)
-+{
-+	unsigned flags;
-+	int cpu = smp_processor_id();
-+	in_kgdb_called = 1;
-+	if (!spin_is_locked(&kgdb_spinlock)) {
-+		if (in_kgdb_here_log[cpu] ||	/* we are holding this cpu */
-+		    in_kgdb_console) {	/* or we are doing slow i/o */
-+			return 1;
-+		}
-+		return 0;
-+	}
-+
-+	/* As I see it the only reason not to let all cpus spin on
-+	 * the same spin_lock is to allow selected ones to proceed.
-+	 * This would be a good thing, so we leave it this way.
-+	 * Maybe someday....  Done !
-+
-+	 * in_kgdb() is called from an NMI so we don't pretend
-+	 * to have any resources, like printk() for example.
-+	 */
-+
-+	kgdb_local_irq_save(flags);	/* only local here, to avoid hanging */
-+	/*
-+	 * log arival of this cpu
-+	 * The NMI keeps on ticking.  Protect against recurring more
-+	 * than once, and ignor the cpu that has the kgdb lock
-+	 */
-+	in_kgdb_entry_log[cpu]++;
-+	in_kgdb_here_log[cpu] = regs;
-+	if (cpu == spinlock_cpu || waiting_cpus[cpu].task) {
-+		goto exit_in_kgdb;
-+	}
-+	/*
-+	 * For protection of the initilization of the spin locks by kgdb
-+	 * it locks the kgdb spinlock before it gets the wait locks set
-+	 * up.	We wait here for the wait lock to be taken.  If the
-+	 * kgdb lock goes away first??	Well, it could be a slow exit
-+	 * sequence where the wait lock is removed prior to the kgdb lock
-+	 * so if kgdb gets unlocked, we just exit.
-+	 */
-+	while (spin_is_locked(&kgdb_spinlock) &&
-+	       !spin_is_locked(waitlocks + cpu)) ;
-+	if (!spin_is_locked(&kgdb_spinlock)) {
-+		goto exit_in_kgdb;
-+	}
-+	waiting_cpus[cpu].task = current;
-+	waiting_cpus[cpu].pid = (current->pid) ? : (PID_MAX + cpu);
-+	waiting_cpus[cpu].regs = regs;
-+
-+	spin_unlock_wait(waitlocks + cpu);
-+	/*
-+	 * log departure of this cpu
-+	 */
-+	waiting_cpus[cpu].task = 0;
-+	waiting_cpus[cpu].pid = 0;
-+	waiting_cpus[cpu].regs = 0;
-+	correct_hw_break();
-+      exit_in_kgdb:
-+	in_kgdb_here_log[cpu] = 0;
-+	kgdb_local_irq_restore(flags);
-+	return 1;
-+	/*
-+	   spin_unlock(continuelocks + smp_processor_id());
-+	 */
-+}
-+
-+void
-+smp__in_kgdb(struct pt_regs regs)
-+{
-+	ack_APIC_irq();
-+	in_kgdb(&regs);
-+}
-+#else
-+int
-+in_kgdb(struct pt_regs *regs)
-+{
-+	return (kgdb_spinlock);
-+}
-+#endif
-+
-+void
-+printexceptioninfo(int exceptionNo, int errorcode, char *buffer)
-+{
-+	unsigned dr6;
-+	int i;
-+	switch (exceptionNo) {
-+	case 1:		/* debug exception */
-+		break;
-+	case 3:		/* breakpoint */
-+		sprintf(buffer, "Software breakpoint");
-+		return;
-+	default:
-+		sprintf(buffer, "Details not available");
-+		return;
-+	}
-+	asm volatile ("movl %%db6, %0\n":"=r" (dr6)
-+		      :);
-+	if (dr6 & 0x4000) {
-+		sprintf(buffer, "Single step");
-+		return;
-+	}
-+	for (i = 0; i < 4; ++i) {
-+		if (dr6 & (1 << i)) {
-+			sprintf(buffer, "Hardware breakpoint %d", i);
-+			return;
-+		}
-+	}
-+	sprintf(buffer, "Unknown trap");
-+	return;
-+}
-+
-+/*
-+ * This function does all command procesing for interfacing to gdb.
-+ *
-+ * NOTE:  The INT nn instruction leaves the state of the interrupt
-+ *	  enable flag UNCHANGED.  That means that when this routine
-+ *	  is entered via a breakpoint (INT 3) instruction from code
-+ *	  that has interrupts enabled, then interrupts will STILL BE
-+ *	  enabled when this routine is entered.	 The first thing that
-+ *	  we do here is disable interrupts so as to prevent recursive
-+ *	  entries and bothersome serial interrupts while we are
-+ *	  trying to run the serial port in polled mode.
-+ *
-+ * For kernel version 2.1.xx the kgdb_cli() actually gets a spin lock so
-+ * it is always necessary to do a restore_flags before returning
-+ * so as to let go of that lock.
-+ */
-+int
-+kgdb_handle_exception(int exceptionVector,
-+		      int signo, int err_code, struct pt_regs *linux_regs)
-+{
-+	struct task_struct *usethread = NULL;
-+	struct task_struct *thread_list_start = 0, *thread = NULL;
-+	int addr, length;
-+	int breakno, breaktype;
-+	char *ptr;
-+	int newPC;
-+	threadref thref;
-+	int threadid;
-+	int thread_min = PID_MAX + MAX_NO_CPUS;
-+#ifdef old_thread_list
-+	int maxthreads;
-+#endif
-+	int nothreads;
-+	unsigned long flags;
-+	int gdb_regs[NUMREGBYTES / 4];
-+	int dr6;
-+	IF_SMP(int entry_state = 0);	/* 0, ok, 1, no nmi, 2 sync failed */
-+#define NO_NMI 1
-+#define NO_SYNC 2
-+#define	regs	(*linux_regs)
-+#define NUMREGS NUMREGBYTES/4
-+	/*
-+	 * If the entry is not from the kernel then return to the Linux
-+	 * trap handler and let it process the interrupt normally.
-+	 */
-+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
-+		printk("ignoring non-kernel exception\n");
-+		print_regs(&regs);
-+		return (0);
-+	}
-+
-+	kgdb_local_irq_save(flags);
-+
-+	/* Get kgdb spinlock */
-+
-+	KGDB_SPIN_LOCK(&kgdb_spinlock);
-+	rdtscll(kgdb_info.entry_tsc);
-+	/*
-+	 * We depend on this spinlock and the NMI watch dog to control the
-+	 * other cpus.	They will arrive at "in_kgdb()" as a result of the
-+	 * NMI and will wait there for the following spin locks to be
-+	 * released.
-+	 */
-+#ifdef CONFIG_SMP
-+
-+#if 0
-+	if (cpu_callout_map & ~MAX_CPU_MASK) {
-+		printk("kgdb : too many cpus, possibly not mapped"
-+		       " in contiguous space, change MAX_NO_CPUS"
-+		       " in kgdb_stub and make new kernel.\n"
-+		       " cpu_callout_map is %lx\n", cpu_callout_map);
-+		goto exit_just_unlock;
-+	}
-+#endif
-+	if (spinlock_count == 1) {
-+		int time = 0, end_time, dum = 0;
-+		int i;
-+		int cpu_logged_in[MAX_NO_CPUS] = {[0 ... MAX_NO_CPUS - 1] = (0)
-+		};
-+		if (remote_debug) {
-+			printk("kgdb : cpu %d entry, syncing others\n",
-+			       smp_processor_id());
-+		}
-+		for (i = 0; i < MAX_NO_CPUS; i++) {
-+			/*
-+			 * Use trylock as we may already hold the lock if
-+			 * we are holding the cpu.  Net result is all
-+			 * locked.
-+			 */
-+			spin_trylock(&waitlocks[i]);
-+		}
-+		for (i = 0; i < MAX_NO_CPUS; i++)
-+			cpu_logged_in[i] = 0;
-+		/*
-+		 * Wait for their arrival.  We know the watch dog is active if
-+		 * in_kgdb() has ever been called, as it is always called on a
-+		 * watchdog tick.
-+		 */
-+		rdtsc(dum, time);
-+		end_time = time + 2;	/* Note: we use the High order bits! */
-+		i = 1;
-+		if (num_online_cpus() > 1) {
-+			int me_in_kgdb = in_kgdb_entry_log[smp_processor_id()];
-+			smp_send_nmi_allbutself();
-+			while (i < num_online_cpus() && time != end_time) {
-+				int j;
-+				for (j = 0; j < MAX_NO_CPUS; j++) {
-+					if (waiting_cpus[j].task &&
-+					    !cpu_logged_in[j]) {
-+						i++;
-+						cpu_logged_in[j] = 1;
-+						if (remote_debug) {
-+							printk
-+							    ("kgdb : cpu %d arrived at kgdb\n",
-+							     j);
-+						}
-+						break;
-+					} else if (!waiting_cpus[j].task &&
-+						   !cpu_online(j)) {
-+						waiting_cpus[j].task = NOCPU;
-+						cpu_logged_in[j] = 1;
-+						waiting_cpus[j].hold = 1;
-+						break;
-+					}
-+					if (!waiting_cpus[j].task &&
-+					    in_kgdb_here_log[j]) {
-+
-+						int wait = 100000;
-+						while (wait--) ;
-+						if (!waiting_cpus[j].task &&
-+						    in_kgdb_here_log[j]) {
-+							printk
-+							    ("kgdb : cpu %d stall"
-+							     " in in_kgdb\n",
-+							     j);
-+							i++;
-+							cpu_logged_in[j] = 1;
-+							waiting_cpus[j].task =
-+							    (struct task_struct
-+							     *) 1;
-+						}
-+					}
-+				}
-+
-+				if (in_kgdb_entry_log[smp_processor_id()] >
-+				    (me_in_kgdb + 10)) {
-+					break;
-+				}
-+
-+				rdtsc(dum, time);
-+			}
-+			if (i < num_online_cpus()) {
-+				printk
-+				    ("kgdb : time out, proceeding without sync\n");
-+#if 0
-+				printk("kgdb : Waiting_cpus: 0 = %d, 1 = %d\n",
-+				       waiting_cpus[0].task != 0,
-+				       waiting_cpus[1].task != 0);
-+				printk("kgdb : Cpu_logged in: 0 = %d, 1 = %d\n",
-+				       cpu_logged_in[0], cpu_logged_in[1]);
-+				printk
-+				    ("kgdb : in_kgdb_here_log in: 0 = %d, 1 = %d\n",
-+				     in_kgdb_here_log[0] != 0,
-+				     in_kgdb_here_log[1] != 0);
-+#endif
-+				entry_state = NO_SYNC;
-+			} else {
-+#if 0
-+				int ent =
-+				    in_kgdb_entry_log[smp_processor_id()] -
-+				    me_in_kgdb;
-+				printk("kgdb : sync after %d entries\n", ent);
-+#endif
-+			}
-+		} else {
-+			if (remote_debug) {
-+				printk
-+				    ("kgdb : %d cpus, but watchdog not active\n"
-+				     "proceeding without locking down other cpus\n",
-+				     num_online_cpus());
-+				entry_state = NO_NMI;
-+			}
-+		}
-+	}
-+#endif
-+
-+	if (remote_debug) {
-+		unsigned long *lp = (unsigned long *) &linux_regs;
-+
-+		printk("handle_exception(exceptionVector=%d, "
-+		       "signo=%d, err_code=%d, linux_regs=%p)\n",
-+		       exceptionVector, signo, err_code, linux_regs);
-+		if (debug_regs) {
-+			print_regs(&regs);
-+			printk("Stk: %8lx %8lx %8lx %8lx"
-+			       "  %8lx %8lx %8lx %8lx\n",
-+			       lp[0], lp[1], lp[2], lp[3],
-+			       lp[4], lp[5], lp[6], lp[7]);
-+			printk("     %8lx %8lx %8lx %8lx"
-+			       "  %8lx %8lx %8lx %8lx\n",
-+			       lp[8], lp[9], lp[10], lp[11],
-+			       lp[12], lp[13], lp[14], lp[15]);
-+			printk("     %8lx %8lx %8lx %8lx  "
-+			       "%8lx %8lx %8lx %8lx\n",
-+			       lp[16], lp[17], lp[18], lp[19],
-+			       lp[20], lp[21], lp[22], lp[23]);
-+			printk("     %8lx %8lx %8lx %8lx  "
-+			       "%8lx %8lx %8lx %8lx\n",
-+			       lp[24], lp[25], lp[26], lp[27],
-+			       lp[28], lp[29], lp[30], lp[31]);
-+		}
-+	}
-+
-+	/* Disable hardware debugging while we are in kgdb */
-+	/* Get the debug register status register */
-+/*				       *INDENT-OFF*  */
-+      __asm__("movl %0,%%db7"
-+	      :	/* no output */
-+	      :"r"(0));
-+
-+	asm volatile ("movl %%db6, %0\n"
-+		      :"=r" (hw_breakpoint_status)
-+		      :);
-+
-+/*				       *INDENT-ON*  */
-+	switch (exceptionVector) {
-+	case 0:		/* divide error */
-+	case 1:		/* debug exception */
-+	case 2:		/* NMI */
-+	case 3:		/* breakpoint */
-+	case 4:		/* overflow */
-+	case 5:		/* bounds check */
-+	case 6:		/* invalid opcode */
-+	case 7:		/* device not available */
-+	case 8:		/* double fault (errcode) */
-+	case 10:		/* invalid TSS (errcode) */
-+	case 12:		/* stack fault (errcode) */
-+	case 16:		/* floating point error */
-+	case 17:		/* alignment check (errcode) */
-+	default:		/* any undocumented */
-+		break;
-+	case 11:		/* segment not present (errcode) */
-+	case 13:		/* general protection (errcode) */
-+	case 14:		/* page fault (special errcode) */
-+	case 19:		/* cache flush denied */
-+		if (mem_err_expected) {
-+			/*
-+			 * This fault occured because of the
-+			 * get_char or set_char routines.  These
-+			 * two routines use either eax of edx to
-+			 * indirectly reference the location in
-+			 * memory that they are working with.
-+			 * For a page fault, when we return the
-+			 * instruction will be retried, so we
-+			 * have to make sure that these
-+			 * registers point to valid memory.
-+			 */
-+			mem_err = 1;	/* set mem error flag */
-+			mem_err_expected = 0;
-+			mem_err_cnt++;	/* helps in debugging */
-+			/* make valid address */
-+			regs.eax = (long) &garbage_loc;
-+			/* make valid address */
-+			regs.edx = (long) &garbage_loc;
-+			if (remote_debug)
-+				printk("Return after memory error: "
-+				       "mem_err_cnt=%d\n", mem_err_cnt);
-+			if (debug_regs)
-+				print_regs(&regs);
-+			goto exit_kgdb;
-+		}
-+		break;
-+	}
-+	if (remote_debug)
-+		printk("kgdb : entered kgdb on cpu %d\n", smp_processor_id());
-+
-+	gdb_i386vector = exceptionVector;
-+	gdb_i386errcode = err_code;
-+	kgdb_info.called_from = __builtin_return_address(0);
-+#ifdef CONFIG_SMP
-+	/*
-+	 * OK, we can now communicate, lets tell gdb about the sync.
-+	 * but only if we had a problem.
-+	 */
-+	switch (entry_state) {
-+	case NO_NMI:
-+		to_gdb("NMI not active, other cpus not stopped\n");
-+		break;
-+	case NO_SYNC:
-+		to_gdb("Some cpus not stopped, see 'kgdb_info' for details\n");
-+	default:;
-+	}
-+
-+#endif
-+/*
-+ * Set up the gdb function call area.
-+ */
-+	trap_cpu = smp_processor_id();
-+	OLD_esp = NEW_esp = (int) (&linux_regs->esp);
-+
-+      IF_SMP(once_again:)
-+	    /* reply to host that an exception has occurred */
-+	    remcomOutBuffer[0] = 'S';
-+	remcomOutBuffer[1] = hexchars[signo >> 4];
-+	remcomOutBuffer[2] = hexchars[signo % 16];
-+	remcomOutBuffer[3] = 0;
-+
-+	putpacket(remcomOutBuffer);
-+
-+	while (1 == 1) {
-+		error = 0;
-+		remcomOutBuffer[0] = 0;
-+		getpacket(remcomInBuffer);
-+		switch (remcomInBuffer[0]) {
-+		case '?':
-+			remcomOutBuffer[0] = 'S';
-+			remcomOutBuffer[1] = hexchars[signo >> 4];
-+			remcomOutBuffer[2] = hexchars[signo % 16];
-+			remcomOutBuffer[3] = 0;
-+			break;
-+		case 'd':
-+			remote_debug = !(remote_debug);	/* toggle debug flag */
-+			printk("Remote debug %s\n",
-+			       remote_debug ? "on" : "off");
-+			break;
-+		case 'g':	/* return the value of the CPU registers */
-+			get_gdb_regs(usethread, &regs, gdb_regs);
-+			mem2hex((char *) gdb_regs,
-+				remcomOutBuffer, NUMREGBYTES, 0);
-+			break;
-+		case 'G':	/* set the value of the CPU registers - return OK */
-+			hex2mem(&remcomInBuffer[1],
-+				(char *) gdb_regs, NUMREGBYTES, 0);
-+			if (!usethread || usethread == current) {
-+				gdb_regs_to_regs(gdb_regs, &regs);
-+				strcpy(remcomOutBuffer, "OK");
-+			} else {
-+				strcpy(remcomOutBuffer, "E00");
-+			}
-+			break;
-+
-+		case 'P':{	/* set the value of a single CPU register -
-+				   return OK */
-+				/*
-+				 * For some reason, gdb wants to talk about psudo
-+				 * registers (greater than 15).	 These may have
-+				 * meaning for ptrace, but for us it is safe to
-+				 * ignor them.	We do this by dumping them into
-+				 * _GS which we also ignor, but do have memory for.
-+				 */
-+				int regno;
-+
-+				ptr = &remcomInBuffer[1];
-+				regs_to_gdb_regs(gdb_regs, &regs);
-+				if ((!usethread || usethread == current) &&
-+				    hexToInt(&ptr, &regno) &&
-+				    *ptr++ == '=' && (regno >= 0)) {
-+					regno =
-+					    (regno >= NUMREGS ? _GS : regno);
-+					hex2mem(ptr, (char *) &gdb_regs[regno],
-+						4, 0);
-+					gdb_regs_to_regs(gdb_regs, &regs);
-+					strcpy(remcomOutBuffer, "OK");
-+					break;
-+				}
-+				strcpy(remcomOutBuffer, "E01");
-+				break;
-+			}
-+
-+			/* mAA..AA,LLLL	 Read LLLL bytes at address AA..AA */
-+		case 'm':
-+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
-+			ptr = &remcomInBuffer[1];
-+			if (hexToInt(&ptr, &addr) &&
-+			    (*(ptr++) == ',') && (hexToInt(&ptr, &length))) {
-+				ptr = 0;
-+				/*
-+				 * hex doubles the byte count
-+				 */
-+				if (length > (BUFMAX / 2))
-+					length = BUFMAX / 2;
-+				mem2hex((char *) addr,
-+					remcomOutBuffer, length, 1);
-+				if (mem_err) {
-+					strcpy(remcomOutBuffer, "E03");
-+					debug_error("memory fault\n", NULL);
-+				}
-+			}
-+
-+			if (ptr) {
-+				strcpy(remcomOutBuffer, "E01");
-+				debug_error
-+				    ("malformed read memory command: %s\n",
-+				     remcomInBuffer);
-+			}
-+			break;
-+
-+			/* MAA..AA,LLLL:
-+			   Write LLLL bytes at address AA.AA return OK */
-+		case 'M':
-+			/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
-+			ptr = &remcomInBuffer[1];
-+			if (hexToInt(&ptr, &addr) &&
-+			    (*(ptr++) == ',') &&
-+			    (hexToInt(&ptr, &length)) && (*(ptr++) == ':')) {
-+				hex2mem(ptr, (char *) addr, length, 1);
-+
-+				if (mem_err) {
-+					strcpy(remcomOutBuffer, "E03");
-+					debug_error("memory fault\n", NULL);
-+				} else {
-+					strcpy(remcomOutBuffer, "OK");
-+				}
-+
-+				ptr = 0;
-+			}
-+			if (ptr) {
-+				strcpy(remcomOutBuffer, "E02");
-+				debug_error
-+				    ("malformed write memory command: %s\n",
-+				     remcomInBuffer);
-+			}
-+			break;
-+		case 'S':
-+			remcomInBuffer[0] = 's';
-+		case 'C':
-+			/* Csig;AA..AA where ;AA..AA is optional
-+			 * continue with signal
-+			 * Since signals are meaning less to us, delete that
-+			 * part and then fall into the 'c' code.
-+			 */
-+			ptr = &remcomInBuffer[1];
-+			length = 2;
-+			while (*ptr && *ptr != ';') {
-+				length++;
-+				ptr++;
-+			}
-+			if (*ptr) {
-+				do {
-+					ptr++;
-+					*(ptr - length++) = *ptr;
-+				} while (*ptr);
-+			} else {
-+				remcomInBuffer[1] = 0;
-+			}
-+
-+			/* cAA..AA  Continue at address AA..AA(optional) */
-+			/* sAA..AA  Step one instruction from AA..AA(optional) */
-+			/* D	    detach, reply OK and then continue */
-+		case 'c':
-+		case 's':
-+		case 'D':
-+
-+			/* try to read optional parameter,
-+			   pc unchanged if no parm */
-+			ptr = &remcomInBuffer[1];
-+			if (hexToInt(&ptr, &addr)) {
-+				if (remote_debug)
-+					printk("Changing EIP to 0x%x\n", addr);
-+
-+				regs.eip = addr;
-+			}
-+
-+			newPC = regs.eip;
-+
-+			/* clear the trace bit */
-+			regs.eflags &= 0xfffffeff;
-+
-+			/* set the trace bit if we're stepping */
-+			if (remcomInBuffer[0] == 's')
-+				regs.eflags |= 0x100;
-+
-+			/* detach is a friendly version of continue. Note that
-+			   debugging is still enabled (e.g hit control C)
-+			 */
-+			if (remcomInBuffer[0] == 'D') {
-+				strcpy(remcomOutBuffer, "OK");
-+				putpacket(remcomOutBuffer);
-+			}
-+
-+			if (remote_debug) {
-+				printk("Resuming execution\n");
-+				print_regs(&regs);
-+			}
-+			asm volatile ("movl %%db6, %0\n":"=r" (dr6)
-+				      :);
-+			if (!(dr6 & 0x4000)) {
-+				for (breakno = 0; breakno < 4; ++breakno) {
-+					if (dr6 & (1 << breakno) &&
-+					    (breakinfo[breakno].type == 0)) {
-+						/* Set restore flag */
-+						regs.eflags |= 0x10000;
-+						break;
-+					}
-+				}
-+			}
-+			correct_hw_break();
-+			asm volatile ("movl %0, %%db6\n"::"r" (0));
-+			goto exit_kgdb;
-+
-+			/* kill the program */
-+		case 'k':	/* do nothing */
-+			break;
-+
-+			/* query */
-+		case 'q':
-+			nothreads = 0;
-+			switch (remcomInBuffer[1]) {
-+			case 'f':
-+				threadid = 1;
-+				thread_list = 2;
-+				thread_list_start = (usethread ? : current);
-+			case 's':
-+				if (!cmp_str(&remcomInBuffer[2],
-+					     "ThreadInfo", 10))
-+					break;
-+
-+				remcomOutBuffer[nothreads++] = 'm';
-+				for (; threadid < PID_MAX + MAX_NO_CPUS;
-+				     threadid++) {
-+					thread = getthread(threadid);
-+					if (thread) {
-+						nothreads += int_to_hex_v(
-+							&remcomOutBuffer[
-+								nothreads],
-+							threadid);
-+						if (thread_min > threadid)
-+							thread_min = threadid;
-+						remcomOutBuffer[
-+							nothreads] = ',';
-+						nothreads++;
-+						if (nothreads > BUFMAX - 10)
-+							break;
-+					}
-+				}
-+				if (remcomOutBuffer[nothreads - 1] == 'm') {
-+					remcomOutBuffer[nothreads - 1] = 'l';
-+				} else {
-+					nothreads--;
-+				}
-+				remcomOutBuffer[nothreads] = 0;
-+				break;
-+
-+#ifdef old_thread_list /* Old thread info request */
-+			case 'L':
-+				/* List threads */
-+				thread_list = 2;
-+				thread_list_start = (usethread ? : current);
-+				unpack_byte(remcomInBuffer + 3, &maxthreads);
-+				unpack_threadid(remcomInBuffer + 5, &thref);
-+				do {
-+					int buf_thread_limit =
-+					    (BUFMAX - 22) / BUF_THREAD_ID_SIZE;
-+					if (maxthreads > buf_thread_limit) {
-+						maxthreads = buf_thread_limit;
-+					}
-+				} while (0);
-+				remcomOutBuffer[0] = 'q';
-+				remcomOutBuffer[1] = 'M';
-+				remcomOutBuffer[4] = '0';
-+				pack_threadid(remcomOutBuffer + 5, &thref);
-+
-+				threadid = threadref_to_int(&thref);
-+				for (nothreads = 0;
-+				     nothreads < maxthreads &&
-+				     threadid < PID_MAX + MAX_NO_CPUS;
-+				     threadid++) {
-+					thread = getthread(threadid);
-+					if (thread) {
-+						int_to_threadref(&thref,
-+								 threadid);
-+						pack_threadid(remcomOutBuffer +
-+							      21 +
-+							      nothreads * 16,
-+							      &thref);
-+						nothreads++;
-+						if (thread_min > threadid)
-+							thread_min = threadid;
-+					}
-+				}
-+
-+				if (threadid == PID_MAX + MAX_NO_CPUS) {
-+					remcomOutBuffer[4] = '1';
-+				}
-+				pack_hex_byte(remcomOutBuffer + 2, nothreads);
-+				remcomOutBuffer[21 + nothreads * 16] = '\0';
-+				break;
-+#endif
-+			case 'C':
-+				/* Current thread id */
-+				remcomOutBuffer[0] = 'Q';
-+				remcomOutBuffer[1] = 'C';
-+				threadid = current->pid;
-+				if (!threadid) {
-+					/*
-+					 * idle thread
-+					 */
-+					for (threadid = PID_MAX;
-+					     threadid < PID_MAX + MAX_NO_CPUS;
-+					     threadid++) {
-+						if (current ==
-+						    idle_task(threadid -
-+							      PID_MAX))
-+							break;
-+					}
-+				}
-+				int_to_threadref(&thref, threadid);
-+				pack_threadid(remcomOutBuffer + 2, &thref);
-+				remcomOutBuffer[18] = '\0';
-+				break;
-+
-+			case 'E':
-+				/* Print exception info */
-+				printexceptioninfo(exceptionVector,
-+						   err_code, remcomOutBuffer);
-+				break;
-+			case 'T':{
-+				char * nptr;
-+				/* Thread extra info */
-+				if (!cmp_str(&remcomInBuffer[2],
-+					    "hreadExtraInfo,", 15)) {
-+					break;
-+				}
-+				ptr = &remcomInBuffer[17];
-+				hexToInt(&ptr, &threadid);
-+				thread = getthread(threadid);
-+				nptr = &thread->comm[0];
-+				length = 0;
-+				ptr = &remcomOutBuffer[0];
-+				do {
-+					length++;
-+					ptr = pack_hex_byte(ptr, *nptr++);
-+				 } while (*nptr && length < 16);
-+				/*
-+				 * would like that 16 to be the size of
-+				 * task_struct.comm but don't know the
-+				 * syntax..
-+				 */
-+				*ptr = 0;
-+			}
-+			}
-+			break;
-+
-+			/* task related */
-+		case 'H':
-+			switch (remcomInBuffer[1]) {
-+			case 'g':
-+				ptr = &remcomInBuffer[2];
-+				hexToInt(&ptr, &threadid);
-+				thread = getthread(threadid);
-+				if (!thread) {
-+					remcomOutBuffer[0] = 'E';
-+					remcomOutBuffer[1] = '\0';
-+					break;
-+				}
-+				/*
-+				 * Just in case I forget what this is all about,
-+				 * the "thread info" command to gdb causes it
-+				 * to ask for a thread list.  It then switches
-+				 * to each thread and asks for the registers.
-+				 * For this (and only this) usage, we want to
-+				 * fudge the registers of tasks not on the run
-+				 * list (i.e. waiting) to show the routine that
-+				 * called schedule. Also, gdb, is a minimalist
-+				 * in that if the current thread is the last
-+				 * it will not re-read the info when done.
-+				 * This means that in this case we must show
-+				 * the real registers. So here is how we do it:
-+				 * Each entry we keep track of the min
-+				 * thread in the list (the last that gdb will)
-+				 * get info for.  We also keep track of the
-+				 * starting thread.
-+				 * "thread_list" is cleared when switching back
-+				 * to the min thread if it is was current, or
-+				 * if it was not current, thread_list is set
-+				 * to 1.  When the switch to current comes,
-+				 * if thread_list is 1, clear it, else do
-+				 * nothing.
-+				 */
-+				usethread = thread;
-+				if ((thread_list == 1) &&
-+				    (thread == thread_list_start)) {
-+					thread_list = 0;
-+				}
-+				if (thread_list && (threadid == thread_min)) {
-+					if (thread == thread_list_start) {
-+						thread_list = 0;
-+					} else {
-+						thread_list = 1;
-+					}
-+				}
-+				/* follow through */
-+			case 'c':
-+				remcomOutBuffer[0] = 'O';
-+				remcomOutBuffer[1] = 'K';
-+				remcomOutBuffer[2] = '\0';
-+				break;
-+			}
-+			break;
-+
-+			/* Query thread status */
-+		case 'T':
-+			ptr = &remcomInBuffer[1];
-+			hexToInt(&ptr, &threadid);
-+			thread = getthread(threadid);
-+			if (thread) {
-+				remcomOutBuffer[0] = 'O';
-+				remcomOutBuffer[1] = 'K';
-+				remcomOutBuffer[2] = '\0';
-+				if (thread_min > threadid)
-+					thread_min = threadid;
-+			} else {
-+				remcomOutBuffer[0] = 'E';
-+				remcomOutBuffer[1] = '\0';
-+			}
-+			break;
-+
-+		case 'Y': /* set up a hardware breakpoint */
-+			ptr = &remcomInBuffer[1];
-+			hexToInt(&ptr, &breakno);
-+			ptr++;
-+			hexToInt(&ptr, &breaktype);
-+			ptr++;
-+			hexToInt(&ptr, &length);
-+			ptr++;
-+			hexToInt(&ptr, &addr);
-+			if (set_hw_break(breakno & 0x3,
-+					 breaktype & 0x3,
-+					 length & 0x3, addr) == 0) {
-+				strcpy(remcomOutBuffer, "OK");
-+			} else {
-+				strcpy(remcomOutBuffer, "ERROR");
-+			}
-+			break;
-+
-+			/* Remove hardware breakpoint */
-+		case 'y':
-+			ptr = &remcomInBuffer[1];
-+			hexToInt(&ptr, &breakno);
-+			if (remove_hw_break(breakno & 0x3) == 0) {
-+				strcpy(remcomOutBuffer, "OK");
-+			} else {
-+				strcpy(remcomOutBuffer, "ERROR");
-+			}
-+			break;
-+
-+		case 'r':	/* reboot */
-+			strcpy(remcomOutBuffer, "OK");
-+			putpacket(remcomOutBuffer);
-+			/*to_gdb("Rebooting\n"); */
-+			/* triplefault	 no return from here */
-+			{
-+				static long no_idt[2];
-+				__asm__ __volatile__("lidt %0"::"m"(no_idt[0]));
-+				BREAKPOINT;
-+			}
-+
-+		}		/* switch */
-+
-+		/* reply to the request */
-+		putpacket(remcomOutBuffer);
-+	}			/* while(1==1) */
-+	/*
-+	 *  reached by goto only.
-+	 */
-+      exit_kgdb:
-+	/*
-+	 * Here is where we set up to trap a gdb function call.	 NEW_esp
-+	 * will be changed if we are trying to do this.	 We handle both
-+	 * adding and subtracting, thus allowing gdb to put grung on
-+	 * the stack which it removes later.
-+	 */
-+	if (NEW_esp != OLD_esp) {
-+		int *ptr = END_OF_LOOKASIDE;
-+		if (NEW_esp < OLD_esp)
-+			ptr -= (OLD_esp - NEW_esp) / sizeof (int);
-+		*--ptr = linux_regs->eflags;
-+		*--ptr = linux_regs->xcs;
-+		*--ptr = linux_regs->eip;
-+		*--ptr = linux_regs->ecx;
-+		*--ptr = linux_regs->ebx;
-+		*--ptr = linux_regs->eax;
-+		linux_regs->ecx = NEW_esp - (sizeof (int) * 6);
-+		linux_regs->ebx = (unsigned int) END_OF_LOOKASIDE;
-+		if (NEW_esp < OLD_esp) {
-+			linux_regs->eip = (unsigned int) fn_call_stub;
-+		} else {
-+			linux_regs->eip = (unsigned int) fn_rtn_stub;
-+			linux_regs->eax = NEW_esp;
-+		}
-+		linux_regs->eflags &= ~(IF_BIT | TF_BIT);
-+	}
-+#ifdef CONFIG_SMP
-+	/*
-+	 * Release gdb wait locks
-+	 * Sanity check time.  Must have at least one cpu to run.  Also single
-+	 * step must not be done if the current cpu is on hold.
-+	 */
-+	if (spinlock_count == 1) {
-+		int ss_hold = (regs.eflags & 0x100) && kgdb_info.hold_on_sstep;
-+		int cpu_avail = 0;
-+		int i;
-+
-+		for (i = 0; i < MAX_NO_CPUS; i++) {
-+			if (!cpu_online(i))
-+				break;
-+			if (!hold_cpu(i)) {
-+				cpu_avail = 1;
-+			}
-+		}
-+		/*
-+		 * Early in the bring up there will be NO cpus on line...
-+		 */
-+		if (!cpu_avail && !cpus_empty(cpu_online_map)) {
-+			to_gdb("No cpus unblocked, see 'kgdb_info.hold_cpu'\n");
-+			goto once_again;
-+		}
-+		if (hold_cpu(smp_processor_id()) && (regs.eflags & 0x100)) {
-+			to_gdb
-+			    ("Current cpu must be unblocked to single step\n");
-+			goto once_again;
-+		}
-+		if (!(ss_hold)) {
-+			int i;
-+			for (i = 0; i < MAX_NO_CPUS; i++) {
-+				if (!hold_cpu(i)) {
-+					spin_unlock(&waitlocks[i]);
-+				}
-+			}
-+		} else {
-+			spin_unlock(&waitlocks[smp_processor_id()]);
-+		}
-+		/* Release kgdb spinlock */
-+		KGDB_SPIN_UNLOCK(&kgdb_spinlock);
-+		/*
-+		 * If this cpu is on hold, this is where we
-+		 * do it.  Note, the NMI will pull us out of here,
-+		 * but will return as the above lock is not held.
-+		 * We will stay here till another cpu releases the lock for us.
-+		 */
-+		spin_unlock_wait(waitlocks + smp_processor_id());
-+		kgdb_local_irq_restore(flags);
-+		return (0);
-+	}
-+#if 0
-+exit_just_unlock:
-+#endif
-+#endif
-+	/* Release kgdb spinlock */
-+	KGDB_SPIN_UNLOCK(&kgdb_spinlock);
-+	kgdb_local_irq_restore(flags);
-+	return (0);
-+}
-+
-+/* this function is used to set up exception handlers for tracing and
-+ * breakpoints.
-+ * This function is not needed as the above line does all that is needed.
-+ * We leave it for backward compatitability...
-+ */
-+void
-+set_debug_traps(void)
-+{
-+	/*
-+	 * linux_debug_hook is defined in traps.c.  We store a pointer
-+	 * to our own exception handler into it.
-+
-+	 * But really folks, every hear of labeled common, an old Fortran
-+	 * concept.  Lots of folks can reference it and it is define if
-+	 * anyone does.	 Only one can initialize it at link time.  We do
-+	 * this with the hook.	See the statement above.  No need for any
-+	 * executable code and it is ready as soon as the kernel is
-+	 * loaded.  Very desirable in kernel debugging.
-+
-+	 linux_debug_hook = handle_exception ;
-+	 */
-+
-+	/* In case GDB is started before us, ack any packets (presumably
-+	   "$?#xx") sitting there.
-+	   putDebugChar ('+');
-+
-+	   initialized = 1;
-+	 */
-+}
-+
-+/* This function will generate a breakpoint exception.	It is used at the
-+   beginning of a program to sync up with a debugger and can be used
-+   otherwise as a quick means to stop program execution and "break" into
-+   the debugger. */
-+/* But really, just use the BREAKPOINT macro.  We will handle the int stuff
-+ */
-+
-+#ifdef later
-+/*
-+ * possibly we should not go thru the traps.c code at all?  Someday.
-+ */
-+void
-+do_kgdb_int3(struct pt_regs *regs, long error_code)
-+{
-+	kgdb_handle_exception(3, 5, error_code, regs);
-+	return;
-+}
-+#endif
-+#undef regs
-+#ifdef CONFIG_TRAP_BAD_SYSCALL_EXITS
-+asmlinkage void
-+bad_sys_call_exit(int stuff)
-+{
-+	struct pt_regs *regs = (struct pt_regs *) &stuff;
-+	printk("Sys call %d return with %x preempt_count\n",
-+	       (int) regs->orig_eax, preempt_count());
-+}
-+#endif
-+#ifdef CONFIG_STACK_OVERFLOW_TEST
-+#include <asm/kgdb.h>
-+asmlinkage void
-+stack_overflow(void)
-+{
-+#ifdef BREAKPOINT
-+	BREAKPOINT;
-+#else
-+	printk("Kernel stack overflow, looping forever\n");
-+#endif
-+	while (1) {
-+	}
-+}
-+#endif
-+
-+#if defined(CONFIG_SMP) || defined(CONFIG_KGDB_CONSOLE)
-+char gdbconbuf[BUFMAX];
-+
-+static void
-+kgdb_gdb_message(const char *s, unsigned count)
-+{
-+	int i;
-+	int wcount;
-+	char *bufptr;
-+	/*
-+	 * This takes care of NMI while spining out chars to gdb
-+	 */
-+	IF_SMP(in_kgdb_console = 1);
-+	gdbconbuf[0] = 'O';
-+	bufptr = gdbconbuf + 1;
-+	while (count > 0) {
-+		if ((count << 1) > (BUFMAX - 2)) {
-+			wcount = (BUFMAX - 2) >> 1;
-+		} else {
-+			wcount = count;
-+		}
-+		count -= wcount;
-+		for (i = 0; i < wcount; i++) {
-+			bufptr = pack_hex_byte(bufptr, s[i]);
-+		}
-+		*bufptr = '\0';
-+		s += wcount;
-+
-+		putpacket(gdbconbuf);
-+
-+	}
-+	IF_SMP(in_kgdb_console = 0);
-+}
-+#endif
-+#ifdef CONFIG_SMP
-+static void
-+to_gdb(const char *s)
-+{
-+	int count = 0;
-+	while (s[count] && (count++ < BUFMAX)) ;
-+	kgdb_gdb_message(s, count);
-+}
-+#endif
-+#ifdef CONFIG_KGDB_CONSOLE
-+#include <linux/console.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <asm/uaccess.h>
-+#include <asm/semaphore.h>
-+
-+void
-+kgdb_console_write(struct console *co, const char *s, unsigned count)
-+{
-+
-+	if (gdb_i386vector == -1) {
-+		/*
-+		 * We have not yet talked to gdb.  What to do...
-+		 * lets break, on continue we can do the write.
-+		 * But first tell him whats up. Uh, well no can do,
-+		 * as this IS the console.  Oh well...
-+		 * We do need to wait or the messages will be lost.
-+		 * Other option would be to tell the above code to
-+		 * ignore this breakpoint and do an auto return,
-+		 * but that might confuse gdb.	Also this happens
-+		 * early enough in boot up that we don't have the traps
-+		 * set up yet, so...
-+		 */
-+		breakpoint();
-+	}
-+	kgdb_gdb_message(s, count);
-+}
-+
-+/*
-+ * ------------------------------------------------------------
-+ * Serial KGDB driver
-+ * ------------------------------------------------------------
-+ */
-+
-+static struct console kgdbcons = {
-+	name:"kgdb",
-+	write:kgdb_console_write,
-+#ifdef CONFIG_KGDB_USER_CONSOLE
-+	device:kgdb_console_device,
-+#endif
-+	flags:CON_PRINTBUFFER | CON_ENABLED,
-+	index:-1,
-+};
-+
-+/*
-+ * The trick here is that this file gets linked before printk.o
-+ * That means we get to peer at the console info in the command
-+ * line before it does.	 If we are up, we register, otherwise,
-+ * do nothing.	By returning 0, we allow printk to look also.
-+ */
-+static int kgdb_console_enabled;
-+
-+int __init
-+kgdb_console_init(char *str)
-+{
-+	if ((strncmp(str, "kgdb", 4) == 0) || (strncmp(str, "gdb", 3) == 0)) {
-+		register_console(&kgdbcons);
-+		kgdb_console_enabled = 1;
-+	}
-+	return 0;		/* let others look at the string */
-+}
-+
-+__setup("console=", kgdb_console_init);
-+
-+#ifdef CONFIG_KGDB_USER_CONSOLE
-+static kdev_t kgdb_console_device(struct console *c);
-+/* This stuff sort of works, but it knocks out telnet devices
-+ * we are leaving it here in case we (or you) find time to figure it out
-+ * better..
-+ */
-+
-+/*
-+ * We need a real char device as well for when the console is opened for user
-+ * space activities.
-+ */
-+
-+static int
-+kgdb_consdev_open(struct inode *inode, struct file *file)
-+{
-+	return 0;
-+}
-+
-+static ssize_t
-+kgdb_consdev_write(struct file *file, const char *buf,
-+		   size_t count, loff_t * ppos)
-+{
-+	int size, ret = 0;
-+	static char kbuf[128];
-+	static DECLARE_MUTEX(sem);
-+
-+	/* We are not reentrant... */
-+	if (down_interruptible(&sem))
-+		return -ERESTARTSYS;
-+
-+	while (count > 0) {
-+		/* need to copy the data from user space */
-+		size = count;
-+		if (size > sizeof (kbuf))
-+			size = sizeof (kbuf);
-+		if (copy_from_user(kbuf, buf, size)) {
-+			ret = -EFAULT;
-+			break;;
-+		}
-+		kgdb_console_write(&kgdbcons, kbuf, size);
-+		count -= size;
-+		ret += size;
-+		buf += size;
-+	}
-+
-+	up(&sem);
-+
-+	return ret;
-+}
-+
-+struct file_operations kgdb_consdev_fops = {
-+	open:kgdb_consdev_open,
-+	write:kgdb_consdev_write
-+};
-+static kdev_t
-+kgdb_console_device(struct console *c)
-+{
-+	return MKDEV(TTYAUX_MAJOR, 1);
-+}
-+
-+/*
-+ * This routine gets called from the serial stub in the i386/lib
-+ * This is so it is done late in bring up (just before the console open).
-+ */
-+void
-+kgdb_console_finit(void)
-+{
-+	if (kgdb_console_enabled) {
-+		char *cptr = cdevname(MKDEV(TTYAUX_MAJOR, 1));
-+		char *cp = cptr;
-+		while (*cptr && *cptr != '(')
-+			cptr++;
-+		*cptr = 0;
-+		unregister_chrdev(TTYAUX_MAJOR, cp);
-+		register_chrdev(TTYAUX_MAJOR, "kgdb", &kgdb_consdev_fops);
-+	}
-+}
-+#endif
-+#endif
-+#ifdef CONFIG_KGDB_TS
-+#include <asm/msr.h>		/* time stamp code */
-+#include <asm/hardirq.h>	/* in_interrupt */
-+#ifdef CONFIG_KGDB_TS_64
-+#define DATA_POINTS 64
-+#endif
-+#ifdef CONFIG_KGDB_TS_128
-+#define DATA_POINTS 128
-+#endif
-+#ifdef CONFIG_KGDB_TS_256
-+#define DATA_POINTS 256
-+#endif
-+#ifdef CONFIG_KGDB_TS_512
-+#define DATA_POINTS 512
-+#endif
-+#ifdef CONFIG_KGDB_TS_1024
-+#define DATA_POINTS 1024
-+#endif
-+#ifndef DATA_POINTS
-+#define DATA_POINTS 128		/* must be a power of two */
-+#endif
-+#define INDEX_MASK (DATA_POINTS - 1)
-+#if (INDEX_MASK & DATA_POINTS)
-+#error "CONFIG_KGDB_TS_COUNT must be a power of 2"
-+#endif
-+struct kgdb_and_then_struct {
-+#ifdef CONFIG_SMP
-+	int on_cpu;
-+#endif
-+	struct task_struct *task;
-+	long long at_time;
-+	int from_ln;
-+	char *in_src;
-+	void *from;
-+	int *with_shpf;
-+	int data0;
-+	int data1;
-+};
-+struct kgdb_and_then_struct2 {
-+#ifdef CONFIG_SMP
-+	int on_cpu;
-+#endif
-+	struct task_struct *task;
-+	long long at_time;
-+	int from_ln;
-+	char *in_src;
-+	void *from;
-+	int *with_shpf;
-+	struct task_struct *t1;
-+	struct task_struct *t2;
-+};
-+struct kgdb_and_then_struct kgdb_data[DATA_POINTS];
-+
-+struct kgdb_and_then_struct *kgdb_and_then = &kgdb_data[0];
-+int kgdb_and_then_count;
-+
-+void
-+kgdb_tstamp(int line, char *source, int data0, int data1)
-+{
-+	static spinlock_t ts_spin = SPIN_LOCK_UNLOCKED;
-+	int flags;
-+	kgdb_local_irq_save(flags);
-+	spin_lock(&ts_spin);
-+	rdtscll(kgdb_and_then->at_time);
-+#ifdef CONFIG_SMP
-+	kgdb_and_then->on_cpu = smp_processor_id();
-+#endif
-+	kgdb_and_then->task = current;
-+	kgdb_and_then->from_ln = line;
-+	kgdb_and_then->in_src = source;
-+	kgdb_and_then->from = __builtin_return_address(0);
-+	kgdb_and_then->with_shpf = (int *) (((flags & IF_BIT) >> 9) |
-+					    (preempt_count() << 8));
-+	kgdb_and_then->data0 = data0;
-+	kgdb_and_then->data1 = data1;
-+	kgdb_and_then = &kgdb_data[++kgdb_and_then_count & INDEX_MASK];
-+	spin_unlock(&ts_spin);
-+	kgdb_local_irq_restore(flags);
-+#ifdef CONFIG_PREEMPT
-+
-+#endif
-+	return;
-+}
-+#endif
-+typedef int gdb_debug_hook(int exceptionVector,
-+			   int signo, int err_code, struct pt_regs *linux_regs);
-+gdb_debug_hook *linux_debug_hook = &kgdb_handle_exception;	/* histerical reasons... */
-diff -puN arch/i386/kernel/Makefile~kgdb-ga arch/i386/kernel/Makefile
---- 25/arch/i386/kernel/Makefile~kgdb-ga	2004-10-21 14:54:15.259603680 -0700
-+++ 25-akpm/arch/i386/kernel/Makefile	2004-10-21 14:54:15.308596232 -0700
-@@ -14,6 +14,7 @@ obj-y				+= timers/
- obj-$(CONFIG_ACPI_BOOT)		+= acpi/
- obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
- obj-$(CONFIG_MCA)		+= mca.o
-+obj-$(CONFIG_KGDB)		+= kgdb_stub.o
- obj-$(CONFIG_X86_MSR)		+= msr.o
- obj-$(CONFIG_X86_CPUID)		+= cpuid.o
- obj-$(CONFIG_MICROCODE)		+= microcode.o
-diff -puN arch/i386/kernel/nmi.c~kgdb-ga arch/i386/kernel/nmi.c
---- 25/arch/i386/kernel/nmi.c~kgdb-ga	2004-10-21 14:54:15.261603376 -0700
-+++ 25-akpm/arch/i386/kernel/nmi.c	2004-10-21 14:54:15.308596232 -0700
-@@ -34,7 +34,17 @@
- 
- #include "mach_traps.h"
- 
-+#ifdef CONFIG_KGDB
-+#include <asm/kgdb.h>
-+#ifdef CONFIG_SMP
-+unsigned int nmi_watchdog = NMI_IO_APIC;
-+#else
-+unsigned int nmi_watchdog = NMI_LOCAL_APIC;
-+#endif
-+#else
- unsigned int nmi_watchdog = NMI_NONE;
-+#endif
-+
- extern int unknown_nmi_panic;
- static unsigned int nmi_hz = HZ;
- static unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
-@@ -466,6 +476,9 @@ void touch_nmi_watchdog (void)
- 	for (i = 0; i < NR_CPUS; i++)
- 		alert_counter[i] = 0;
- }
-+#ifdef CONFIG_KGDB
-+int tune_watchdog = 5*HZ;
-+#endif
- 
- extern void die_nmi(struct pt_regs *, const char *msg);
- 
-@@ -481,12 +494,24 @@ void nmi_watchdog_tick (struct pt_regs *
- 	 */
- 	sum = irq_stat[cpu].apic_timer_irqs;
- 
-+#ifdef CONFIG_KGDB
-+	if (!in_kgdb(regs) && last_irq_sums[cpu] == sum) {
-+
-+#else
- 	if (last_irq_sums[cpu] == sum) {
-+#endif
- 		/*
- 		 * Ayiee, looks like this CPU is stuck ...
- 		 * wait a few IRQs (5 seconds) before doing the oops ...
- 		 */
- 		alert_counter[cpu]++;
-+#ifdef CONFIG_KGDB
-+		if (alert_counter[cpu] == tune_watchdog) {
-+			kgdb_handle_exception(2, SIGPWR, 0, regs);
-+			last_irq_sums[cpu] = sum;
-+			alert_counter[cpu] = 0;
-+		}
-+#endif
- 		if (alert_counter[cpu] == 30*nmi_hz)
- 			die_nmi(regs, "NMI Watchdog detected LOCKUP");
- 	} else {
-diff -puN arch/i386/kernel/smp.c~kgdb-ga arch/i386/kernel/smp.c
---- 25/arch/i386/kernel/smp.c~kgdb-ga	2004-10-21 14:54:15.262603224 -0700
-+++ 25-akpm/arch/i386/kernel/smp.c	2004-10-21 14:54:15.309596080 -0700
-@@ -466,7 +466,17 @@ void flush_tlb_all(void)
- {
- 	on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
- }
--
-+#ifdef CONFIG_KGDB
-+/*
-+ * By using the NMI code instead of a vector we just sneak thru the
-+ * word generator coming out with just what we want.  AND it does
-+ * not matter if clustered_apic_mode is set or not.
-+ */
-+void smp_send_nmi_allbutself(void)
-+{
-+	send_IPI_allbutself(APIC_DM_NMI);
-+}
-+#endif
- /*
-  * this function sends a 'reschedule' IPI to another CPU.
-  * it goes straight through and wastes no time serializing
-diff -puN arch/i386/kernel/traps.c~kgdb-ga arch/i386/kernel/traps.c
---- 25/arch/i386/kernel/traps.c~kgdb-ga	2004-10-21 14:54:15.264602920 -0700
-+++ 25-akpm/arch/i386/kernel/traps.c	2004-10-21 14:54:15.311595776 -0700
-@@ -105,6 +105,39 @@ int register_die_notifier(struct notifie
- 	return err;
- }
- 
-+#ifdef CONFIG_KGDB
-+extern void sysenter_past_esp(void);
-+#include <asm/kgdb.h>
-+#include <linux/init.h>
-+void set_intr_gate(unsigned int n, void *addr);
-+static void set_intr_usr_gate(unsigned int n, void *addr);
-+/*
-+ * Should be able to call this breakpoint() very early in
-+ * bring up.  Just hard code the call where needed.
-+ * The breakpoint() code is here because set_?_gate() functions
-+ * are local (static) to trap.c.  They need be done only once,
-+ * but it does not hurt to do them over.
-+ */
-+void breakpoint(void)
-+{
-+	set_intr_usr_gate(3,&int3); /* disable ints on trap */
-+	set_intr_gate(1,&debug);
-+	set_intr_gate(14,&page_fault);
-+
-+        BREAKPOINT;
-+}
-+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
-+    {									\
-+	if (!user_mode(regs)  ) \
-+	{								\
-+		kgdb_handle_exception(trapnr, signr, error_code, regs);	\
-+		after;							\
-+	} else if ((trapnr == 3) && (regs->eflags &0x200)) local_irq_enable(); \
-+    }
-+#else
-+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
-+#endif
-+
- static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
- {
- 	return	p > (void *)tinfo &&
-@@ -332,6 +365,15 @@ void die(const char * str, struct pt_reg
- #endif
- 		if (nl)
- 			printk("\n");
-+#ifdef CONFIG_KGDB
-+	/* This is about the only place we want to go to kgdb even if in
-+	 * user mode.  But we must go in via a trap so within kgdb we will
-+	 * always be in kernel mode.
-+	 */
-+		if (user_mode(regs))
-+			BREAKPOINT;
-+#endif
-+	 	CHK_REMOTE_DEBUG(0,SIGTRAP,err,regs,)
- 	notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV);
- 		show_registers(regs);
-   	} else
-@@ -406,6 +448,7 @@ static inline void do_trap(int trapnr, i
- #define DO_ERROR(trapnr, signr, str, name) \
- asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
- { \
-+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,) \
- 	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
- 						== NOTIFY_STOP) \
- 		return; \
-@@ -429,6 +472,7 @@ asmlinkage void do_##name(struct pt_regs
- #define DO_VM86_ERROR(trapnr, signr, str, name) \
- asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
- { \
-+	CHK_REMOTE_DEBUG(trapnr, signr, error_code,regs, return) \
- 	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
- 						== NOTIFY_STOP) \
- 		return; \
-@@ -512,7 +556,8 @@ gp_in_vm86:
- 
- gp_in_kernel:
- 	if (!fixup_exception(regs)) {
- 	die:
-+ 		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
- 		if (notify_die(DIE_GPF, "general protection fault", regs,
- 				error_code, 13, SIGSEGV) == NOTIFY_STOP)
- 			return;
-@@ -721,8 +766,18 @@ asmlinkage void do_debug(struct pt_regs 
- 		 * allowing programs to debug themselves without the ptrace()
- 		 * interface.
- 		 */
-+#ifdef CONFIG_KGDB
-+		/*
-+		 * I think this is the only "real" case of a TF in the kernel
-+		 * that really belongs to user space.  Others are
-+		 * "Ours all ours!"
-+		 */
-+		if (((regs->xcs & 3) == 0) && ((void *)regs->eip == sysenter_past_esp))
-+			goto clear_TF_reenable;
-+#else
- 		if ((regs->xcs & 3) == 0)
- 			goto clear_TF_reenable;
-+#endif
- 		if ((tsk->ptrace & (PT_DTRACE|PT_PTRACED)) == PT_DTRACE)
- 			goto clear_TF;
- 	}
-@@ -734,6 +789,17 @@ asmlinkage void do_debug(struct pt_regs 
- 	info.si_errno = 0;
- 	info.si_code = TRAP_BRKPT;
- 	
-+#ifdef CONFIG_KGDB
-+        /*
-+	 * If this is a kernel mode trap, we need to reset db7 to allow us
-+	 * to continue sanely ALSO skip the signal delivery
-+         */
-+	if ((regs->xcs & 3) == 0)
-+		goto clear_dr7;
-+
-+        /* if not kernel, allow ints but only if they were on */
-+       if ( regs->eflags & 0x200) local_irq_enable();
-+#endif
- 	/* If this is a kernel mode trap, save the user PC on entry to 
- 	 * the kernel, that's what the debugger can make sense of.
- 	 */
-@@ -748,6 +814,7 @@ clear_dr7:
- 	__asm__("movl %0,%%db7"
- 		: /* no output */
- 		: "r" (0));
-+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
- 	return;
- 
- debug_vm86:
-@@ -1004,6 +1071,12 @@ static void __init set_task_gate(unsigne
- {
- 	_set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
- }
-+#ifdef CONFIG_KGDB
-+void set_intr_usr_gate(unsigned int n, void *addr)
-+{
-+	_set_gate(idt_table+n,14,3,addr,__KERNEL_CS);
-+}
-+#endif
- 
- 
- void __init trap_init(void)
-@@ -1021,7 +1094,11 @@ void __init trap_init(void)
- 	set_trap_gate(0,&divide_error);
- 	set_intr_gate(1,&debug);
- 	set_intr_gate(2,&nmi);
-+#ifndef CONFIG_KGDB
- 	set_system_intr_gate(3, &int3); /* int3-5 can be called from all */
-+#else
-+	set_intr_usr_gate(3,&int3);	/* int3-5 can be called from all */
-+#endif
- 	set_system_gate(4,&overflow);
- 	set_system_gate(5,&bounds);
- 	set_trap_gate(6,&invalid_op);
-diff -puN /dev/null arch/i386/lib/kgdb_serial.c
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/arch/i386/lib/kgdb_serial.c	2004-10-21 14:54:15.313595472 -0700
-@@ -0,0 +1,485 @@
-+/*
-+ * Serial interface GDB stub
-+ *
-+ * Written (hacked together) by David Grothe (dave@gcom.com)
-+ * Modified to allow invokation early in boot see also
-+ * kgdb.h for instructions by George Anzinger(george@mvista.com)
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/signal.h>
-+#include <linux/sched.h>
-+#include <linux/timer.h>
-+#include <linux/interrupt.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/serial.h>
-+#include <linux/serial_reg.h>
-+#include <linux/config.h>
-+#include <linux/major.h>
-+#include <linux/string.h>
-+#include <linux/fcntl.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/mm.h>
-+#include <linux/init.h>
-+#include <linux/highmem.h>
-+#include <asm/system.h>
-+#include <asm/io.h>
-+#include <asm/segment.h>
-+#include <asm/bitops.h>
-+#include <asm/system.h>
-+#include <asm/kgdb_local.h>
-+#ifdef CONFIG_KGDB_USER_CONSOLE
-+extern void kgdb_console_finit(void);
-+#endif
-+#define PRNT_off
-+#define TEST_EXISTANCE
-+#ifdef PRNT
-+#define dbprintk(s) printk s
-+#else
-+#define dbprintk(s)
-+#endif
-+#define TEST_INTERRUPT_off
-+#ifdef TEST_INTERRUPT
-+#define intprintk(s) printk s
-+#else
-+#define intprintk(s)
-+#endif
-+
-+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
-+
-+#define	GDB_BUF_SIZE	512	/* power of 2, please */
-+
-+static char gdb_buf[GDB_BUF_SIZE];
-+static int gdb_buf_in_inx;
-+static atomic_t gdb_buf_in_cnt;
-+static int gdb_buf_out_inx;
-+
-+struct async_struct *gdb_async_info;
-+static int gdb_async_irq;
-+
-+#define outb_px(a,b) outb_p(b,a)
-+
-+static void program_uart(struct async_struct *info);
-+static void write_char(struct async_struct *info, int chr);
-+/*
-+ * Get a byte from the hardware data buffer and return it
-+ */
-+static int
-+read_data_bfr(struct async_struct *info)
-+{
-+	char it = inb_p(info->port + UART_LSR);
-+
-+	if (it & UART_LSR_DR)
-+		return (inb_p(info->port + UART_RX));
-+	/*
-+	 * If we have a framing error assume somebody messed with
-+	 * our uart.  Reprogram it and send '-' both ways...
-+	 */
-+	if (it & 0xc) {
-+		program_uart(info);
-+		write_char(info, '-');
-+		return ('-');
-+	}
-+	return (-1);
-+
-+}				/* read_data_bfr */
-+
-+/*
-+ * Get a char if available, return -1 if nothing available.
-+ * Empty the receive buffer first, then look at the interface hardware.
-+
-+ * Locking here is a bit of a problem.	We MUST not lock out communication
-+ * if we are trying to talk to gdb about a kgdb entry.	ON the other hand
-+ * we can loose chars in the console pass thru if we don't lock.  It is also
-+ * possible that we could hold the lock or be waiting for it when kgdb
-+ * NEEDS to talk.  Since kgdb locks down the world, it does not need locks.
-+ * We do, of course have possible issues with interrupting a uart operation,
-+ * but we will just depend on the uart status to help keep that straight.
-+
-+ */
-+static spinlock_t uart_interrupt_lock = SPIN_LOCK_UNLOCKED;
-+#ifdef CONFIG_SMP
-+extern spinlock_t kgdb_spinlock;
-+#endif
-+
-+static int
-+read_char(struct async_struct *info)
-+{
-+	int chr;
-+	unsigned long flags;
-+	local_irq_save(flags);
-+#ifdef CONFIG_SMP
-+	if (!spin_is_locked(&kgdb_spinlock)) {
-+		spin_lock(&uart_interrupt_lock);
-+	}
-+#endif
-+	if (atomic_read(&gdb_buf_in_cnt) != 0) {	/* intr routine has q'd chars */
-+		chr = gdb_buf[gdb_buf_out_inx++];
-+		gdb_buf_out_inx &= (GDB_BUF_SIZE - 1);
-+		atomic_dec(&gdb_buf_in_cnt);
-+	} else {
-+		chr = read_data_bfr(info);
-+	}
-+#ifdef CONFIG_SMP
-+	if (!spin_is_locked(&kgdb_spinlock)) {
-+		spin_unlock(&uart_interrupt_lock);
-+	}
-+#endif
-+	local_irq_restore(flags);
-+	return (chr);
-+}
-+
-+/*
-+ * Wait until the interface can accept a char, then write it.
-+ */
-+static void
-+write_char(struct async_struct *info, int chr)
-+{
-+	while (!(inb_p(info->port + UART_LSR) & UART_LSR_THRE)) ;
-+
-+	outb_p(chr, info->port + UART_TX);
-+
-+}				/* write_char */
-+
-+/*
-+ * Mostly we don't need a spinlock, but since the console goes
-+ * thru here with interrutps on, well, we need to catch those
-+ * chars.
-+ */
-+/*
-+ * This is the receiver interrupt routine for the GDB stub.
-+ * It will receive a limited number of characters of input
-+ * from the gdb  host machine and save them up in a buffer.
-+ *
-+ * When the gdb stub routine getDebugChar() is called it
-+ * draws characters out of the buffer until it is empty and
-+ * then reads directly from the serial port.
-+ *
-+ * We do not attempt to write chars from the interrupt routine
-+ * since the stubs do all of that via putDebugChar() which
-+ * writes one byte after waiting for the interface to become
-+ * ready.
-+ *
-+ * The debug stubs like to run with interrupts disabled since,
-+ * after all, they run as a consequence of a breakpoint in
-+ * the kernel.
-+ *
-+ * Perhaps someone who knows more about the tty driver than I
-+ * care to learn can make this work for any low level serial
-+ * driver.
-+ */
-+static irqreturn_t
-+gdb_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+	struct async_struct *info;
-+	unsigned long flags;
-+
-+	info = gdb_async_info;
-+	if (!info || !info->tty || irq != gdb_async_irq)
-+		return IRQ_NONE;
-+
-+	local_irq_save(flags);
-+	spin_lock(&uart_interrupt_lock);
-+	do {
-+		int chr = read_data_bfr(info);
-+		intprintk(("Debug char on int: %x hex\n", chr));
-+		if (chr < 0)
-+			continue;
-+
-+		if (chr == 3) {	/* Ctrl-C means remote interrupt */
-+			BREAKPOINT;
-+			continue;
-+		}
-+
-+		if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE) {
-+			/* buffer overflow tosses early char */
-+			read_char(info);
-+		}
-+		gdb_buf[gdb_buf_in_inx++] = chr;
-+		gdb_buf_in_inx &= (GDB_BUF_SIZE - 1);
-+	} while (inb_p(info->port + UART_IIR) & UART_IIR_RDI);
-+	spin_unlock(&uart_interrupt_lock);
-+	local_irq_restore(flags);
-+	return IRQ_HANDLED;
-+}				/* gdb_interrupt */
-+
-+/*
-+ * Just a NULL routine for testing.
-+ */
-+void
-+gdb_null(void)
-+{
-+}				/* gdb_null */
-+
-+/* These structure are filled in with values defined in asm/kgdb_local.h
-+ */
-+static struct serial_state state = SB_STATE;
-+static struct async_struct local_info = SB_INFO;
-+static int ok_to_enable_ints = 0;
-+static void kgdb_enable_ints_now(void);
-+
-+extern char *kgdb_version;
-+/*
-+ * Hook an IRQ for KGDB.
-+ *
-+ * This routine is called from putDebugChar, below.
-+ */
-+static int ints_disabled = 1;
-+int
-+gdb_hook_interrupt(struct async_struct *info, int verb)
-+{
-+	struct serial_state *state = info->state;
-+	unsigned long flags;
-+	int port;
-+#ifdef TEST_EXISTANCE
-+	int scratch, scratch2;
-+#endif
-+
-+	/* The above fails if memory managment is not set up yet.
-+	 * Rather than fail the set up, just keep track of the fact
-+	 * and pick up the interrupt thing later.
-+	 */
-+	gdb_async_info = info;
-+	port = gdb_async_info->port;
-+	gdb_async_irq = state->irq;
-+	if (verb) {
-+		printk("kgdb %s : port =%x, IRQ=%d, divisor =%d\n",
-+		       kgdb_version,
-+		       port,
-+		       gdb_async_irq, gdb_async_info->state->custom_divisor);
-+	}
-+	local_irq_save(flags);
-+#ifdef TEST_EXISTANCE
-+	/* Existance test */
-+	/* Should not need all this, but just in case.... */
-+
-+	scratch = inb_p(port + UART_IER);
-+	outb_px(port + UART_IER, 0);
-+	outb_px(0xff, 0x080);
-+	scratch2 = inb_p(port + UART_IER);
-+	outb_px(port + UART_IER, scratch);
-+	if (scratch2) {
-+		printk
-+		    ("gdb_hook_interrupt: Could not clear IER, not a UART!\n");
-+		local_irq_restore(flags);
-+		return 1;	/* We failed; there's nothing here */
-+	}
-+	scratch2 = inb_p(port + UART_LCR);
-+	outb_px(port + UART_LCR, 0xBF);	/* set up for StarTech test */
-+	outb_px(port + UART_EFR, 0);	/* EFR is the same as FCR */
-+	outb_px(port + UART_LCR, 0);
-+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO);
-+	scratch = inb_p(port + UART_IIR) >> 6;
-+	if (scratch == 1) {
-+		printk("gdb_hook_interrupt: Undefined UART type!"
-+		       "  Not a UART! \n");
-+		local_irq_restore(flags);
-+		return 1;
-+	} else {
-+		dbprintk(("gdb_hook_interrupt: UART type "
-+			  "is %d where 0=16450, 2=16550 3=16550A\n", scratch));
-+	}
-+	scratch = inb_p(port + UART_MCR);
-+	outb_px(port + UART_MCR, UART_MCR_LOOP | scratch);
-+	outb_px(port + UART_MCR, UART_MCR_LOOP | 0x0A);
-+	scratch2 = inb_p(port + UART_MSR) & 0xF0;
-+	outb_px(port + UART_MCR, scratch);
-+	if (scratch2 != 0x90) {
-+		printk("gdb_hook_interrupt: "
-+		       "Loop back test failed! Not a UART!\n");
-+		local_irq_restore(flags);
-+		return scratch2 + 1000;	/* force 0 to fail */
-+	}
-+#endif				/* test existance */
-+	program_uart(info);
-+	local_irq_restore(flags);
-+
-+	return (0);
-+
-+}				/* gdb_hook_interrupt */
-+
-+static void
-+program_uart(struct async_struct *info)
-+{
-+	int port = info->port;
-+
-+	(void) inb_p(port + UART_RX);
-+	outb_px(port + UART_IER, 0);
-+
-+	(void) inb_p(port + UART_RX);	/* serial driver comments say */
-+	(void) inb_p(port + UART_IIR);	/* this clears the interrupt regs */
-+	(void) inb_p(port + UART_MSR);
-+	outb_px(port + UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB);
-+	outb_px(port + UART_DLL, info->state->custom_divisor & 0xff);	/* LS */
-+	outb_px(port + UART_DLM, info->state->custom_divisor >> 8);	/* MS  */
-+	outb_px(port + UART_MCR, info->MCR);
-+
-+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1 | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);	/* set fcr */
-+	outb_px(port + UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
-+	outb_px(port + UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1);	/* set fcr */
-+	if (!ints_disabled) {
-+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
-+			   gdb_async_info->IER,
-+			   (int) gdb_async_info->port, UART_IER));
-+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
-+	}
-+	return;
-+}
-+
-+/*
-+ * getDebugChar
-+ *
-+ * This is a GDB stub routine.	It waits for a character from the
-+ * serial interface and then returns it.  If there is no serial
-+ * interface connection then it returns a bogus value which will
-+ * almost certainly cause the system to hang.  In the
-+ */
-+int kgdb_in_isr = 0;
-+int kgdb_in_lsr = 0;
-+extern spinlock_t kgdb_spinlock;
-+
-+/* Caller takes needed protections */
-+
-+int
-+getDebugChar(void)
-+{
-+	volatile int chr, dum, time, end_time;
-+
-+	dbprintk(("getDebugChar(port %x): ", gdb_async_info->port));
-+
-+	if (gdb_async_info == NULL) {
-+		gdb_hook_interrupt(&local_info, 0);
-+	}
-+	/*
-+	 * This trick says if we wait a very long time and get
-+	 * no char, return the -1 and let the upper level deal
-+	 * with it.
-+	 */
-+	rdtsc(dum, time);
-+	end_time = time + 2;
-+	while (((chr = read_char(gdb_async_info)) == -1) &&
-+	       (end_time - time) > 0) {
-+		rdtsc(dum, time);
-+	};
-+	/*
-+	 * This covers our butts if some other code messes with
-+	 * our uart, hay, it happens :o)
-+	 */
-+	if (chr == -1)
-+		program_uart(gdb_async_info);
-+
-+	dbprintk(("%c\n", chr > ' ' && chr < 0x7F ? chr : ' '));
-+	return (chr);
-+
-+}				/* getDebugChar */
-+
-+static int count = 3;
-+static spinlock_t one_at_atime = SPIN_LOCK_UNLOCKED;
-+
-+static int __init
-+kgdb_enable_ints(void)
-+{
-+	if (gdb_async_info == NULL) {
-+		gdb_hook_interrupt(&local_info, 1);
-+	}
-+	ok_to_enable_ints = 1;
-+	kgdb_enable_ints_now();
-+#ifdef CONFIG_KGDB_USER_CONSOLE
-+	kgdb_console_finit();
-+#endif
-+	return 0;
-+}
-+
-+#ifdef CONFIG_SERIAL_8250
-+void shutdown_for_kgdb(struct async_struct *gdb_async_info);
-+#endif
-+
-+#ifdef CONFIG_DISCONTIGMEM
-+static inline int kgdb_mem_init_done(void)
-+{
-+	return highmem_start_page != NULL;
-+}
-+#else
-+static inline int kgdb_mem_init_done(void)
-+{
-+	return max_mapnr != 0;
-+}
-+#endif
-+
-+static void
-+kgdb_enable_ints_now(void)
-+{
-+	if (!spin_trylock(&one_at_atime))
-+		return;
-+	if (!ints_disabled)
-+		goto exit;
-+	if (kgdb_mem_init_done() &&
-+			ints_disabled) {	/* don't try till mem init */
-+#ifdef CONFIG_SERIAL_8250
-+		/*
-+		 * The ifdef here allows the system to be configured
-+		 * without the serial driver.
-+		 * Don't make it a module, however, it will steal the port
-+		 */
-+		shutdown_for_kgdb(gdb_async_info);
-+#endif
-+		ints_disabled = request_irq(gdb_async_info->state->irq,
-+					    gdb_interrupt,
-+					    IRQ_T(gdb_async_info),
-+					    "KGDB-stub", NULL);
-+		intprintk(("KGDB: request_irq returned %d\n", ints_disabled));
-+	}
-+	if (!ints_disabled) {
-+		intprintk(("KGDB: Sending %d to port %x offset %d\n",
-+			   gdb_async_info->IER,
-+			   (int) gdb_async_info->port, UART_IER));
-+		outb_px(gdb_async_info->port + UART_IER, gdb_async_info->IER);
-+	}
-+      exit:
-+	spin_unlock(&one_at_atime);
-+}
-+
-+/*
-+ * putDebugChar
-+ *
-+ * This is a GDB stub routine.	It waits until the interface is ready
-+ * to transmit a char and then sends it.  If there is no serial
-+ * interface connection then it simply returns to its caller, having
-+ * pretended to send the char.	Caller takes needed protections.
-+ */
-+void
-+putDebugChar(int chr)
-+{
-+	dbprintk(("putDebugChar(port %x): chr=%02x '%c', ints_on=%d\n",
-+		  gdb_async_info->port,
-+		  chr,
-+		  chr > ' ' && chr < 0x7F ? chr : ' ', ints_disabled ? 0 : 1));
-+
-+	if (gdb_async_info == NULL) {
-+		gdb_hook_interrupt(&local_info, 0);
-+	}
-+
-+	write_char(gdb_async_info, chr);	/* this routine will wait */
-+	count = (chr == '#') ? 0 : count + 1;
-+	if ((count == 2)) {	/* try to enable after */
-+		if (ints_disabled & ok_to_enable_ints)
-+			kgdb_enable_ints_now();	/* try to enable after */
-+
-+		/* We do this a lot because, well we really want to get these
-+		 * interrupts.	The serial driver will clear these bits when it
-+		 * initializes the chip.  Every thing else it does is ok,
-+		 * but this.
-+		 */
-+		if (!ints_disabled) {
-+			outb_px(gdb_async_info->port + UART_IER,
-+				gdb_async_info->IER);
-+		}
-+	}
-+
-+}				/* putDebugChar */
-+
-+module_init(kgdb_enable_ints);
-diff -puN arch/i386/lib/Makefile~kgdb-ga arch/i386/lib/Makefile
---- 25/arch/i386/lib/Makefile~kgdb-ga	2004-10-21 14:54:15.265602768 -0700
-+++ 25-akpm/arch/i386/lib/Makefile	2004-10-21 14:54:15.313595472 -0700
-@@ -8,3 +8,4 @@ lib-y = checksum.o delay.o usercopy.o ge
- 
- lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
- lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
-+lib-$(CONFIG_KGDB) += kgdb_serial.o
-diff -puN arch/i386/Makefile~kgdb-ga arch/i386/Makefile
---- 25/arch/i386/Makefile~kgdb-ga	2004-10-21 14:54:15.266602616 -0700
-+++ 25-akpm/arch/i386/Makefile	2004-10-21 14:54:15.314595320 -0700
-@@ -99,6 +99,9 @@ core-$(CONFIG_X86_ES7000)	:= arch/i386/m
- # default subarch .h files
- mflags-y += -Iinclude/asm-i386/mach-default
- 
-+mflags-$(CONFIG_KGDB) += -gdwarf-2
-+mflags-$(CONFIG_KGDB_MORE) += $(shell echo $(CONFIG_KGDB_OPTIONS) | sed -e 's/"//g')
-+
- head-y := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
- 
- libs-y 					+= arch/i386/lib/
-diff -puN arch/i386/mm/fault.c~kgdb-ga arch/i386/mm/fault.c
---- 25/arch/i386/mm/fault.c~kgdb-ga	2004-10-21 14:54:15.268602312 -0700
-+++ 25-akpm/arch/i386/mm/fault.c	2004-10-21 14:54:15.314595320 -0700
-@@ -430,6 +430,12 @@ no_context:
-  * Oops. The kernel tried to access some bad page. We'll have to
-  * terminate things with extreme prejudice.
-  */
-+#ifdef CONFIG_KGDB
-+        if (!user_mode(regs)){
-+                kgdb_handle_exception(14,SIGBUS, error_code, regs);
-+                return;
-+        }
-+#endif
- 
- 	bust_spinlocks(1);
- 
-diff -puN arch/x86_64/boot/compressed/head.S~kgdb-ga arch/x86_64/boot/compressed/head.S
---- 25/arch/x86_64/boot/compressed/head.S~kgdb-ga	2004-10-21 14:54:15.269602160 -0700
-+++ 25-akpm/arch/x86_64/boot/compressed/head.S	2004-10-21 14:54:15.315595168 -0700
-@@ -26,6 +26,7 @@
- .code32
- .text
- 
-+#define IN_BOOTLOADER
- #include <linux/linkage.h>
- #include <asm/segment.h>
- 
-diff -puN arch/x86_64/boot/compressed/misc.c~kgdb-ga arch/x86_64/boot/compressed/misc.c
---- 25/arch/x86_64/boot/compressed/misc.c~kgdb-ga	2004-10-21 14:54:15.270602008 -0700
-+++ 25-akpm/arch/x86_64/boot/compressed/misc.c	2004-10-21 14:54:15.315595168 -0700
-@@ -9,6 +9,7 @@
-  * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
-  */
- 
-+#define IN_BOOTLOADER
- #include "miscsetup.h"
- #include <asm/io.h>
- 
-diff -puN /dev/null Documentation/i386/kgdb/andthen
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/andthen	2004-10-21 14:54:15.316595016 -0700
-@@ -0,0 +1,100 @@
-+
-+define	set_andthen
-+	set var $thp=0
-+	set var $thp=(struct kgdb_and_then_struct *)&kgdb_data[0]
-+	set var $at_size = (sizeof kgdb_data)/(sizeof *$thp)
-+	set var $at_oc=kgdb_and_then_count
-+	set var $at_cc=$at_oc
-+end
-+
-+define andthen_next
-+	set var $at_cc=$arg0
-+end
-+
-+define andthen
-+	andthen_set_edge
-+	if ($at_cc >= $at_oc)
-+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
-+	else
-+		printf "%d: ",$at_cc
-+		output *($thp+($at_cc++ % $at_size ))
-+		printf "\n"
-+	end
-+end
-+define andthen_set_edge
-+	set var $at_oc=kgdb_and_then_count
-+	set var $at_low = $at_oc - $at_size
-+	if ($at_low < 0 )
-+		set var $at_low = 0
-+	end
-+	if (( $at_cc > $at_oc) || ($at_cc < $at_low))
-+		printf "Count outside of window, setting count to "
-+		if ($at_cc >= $at_oc)
-+			set var $at_cc = $at_oc
-+		else
-+			set var $at_cc = $at_low
-+		end
-+		printf "%d\n",$at_cc
-+	end
-+end
-+
-+define beforethat
-+	andthen_set_edge
-+	if ($at_cc <= $at_low)
-+		printf "Outside window.  Window size is %d\n",($at_oc-$at_low)
-+	else
-+		printf "%d: ",$at_cc-1
-+		output *($thp+(--$at_cc % $at_size ))
-+		printf "\n"
-+	end
-+end
-+
-+document andthen_next
-+	andthen_next <count>
-+	.	sets the number of the event to display next. If this event
-+	.	is not in the event pool, either andthen or beforethat will
-+	.	correct it to the nearest event pool edge.  The event pool
-+	.	ends at the last event recorded and begins <number of events>
-+	.	prior to that.  If beforethat is used next, it will display
-+	.	event <count> -1.
-+.
-+	andthen commands are: set_andthen, andthen_next, andthen and beforethat
-+end
-+
-+
-+document andthen
-+	andthen
-+.	displays the next event in the list.  <set_andthen> sets up to display
-+.	the oldest saved event first.
-+.	<count> (optional) count of the event to display.
-+.	note the number of events saved is specified at configure time.
-+.	if events are saved between calls to andthen the index will change
-+.	but the displayed event will be the next one (unless the event buffer
-+.	is overrun).
-+.
-+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
-+end
-+
-+document set_andthen
-+	set_andthen
-+.	sets up to use the <andthen> and <beforethat> commands.
-+.		if you have defined your own struct, use the above and
-+.		then enter the following:
-+.		p $thp=(struct kgdb_and_then_structX *)&kgdb_data[0]
-+.		where <kgdb_and_then_structX> is the name of your structure.
-+.
-+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
-+end
-+
-+document beforethat
-+	beforethat
-+.	displays the next prior event in the list. <set_andthen> sets up to
-+.	display the last occuring event first.
-+.
-+.	note the number of events saved is specified at configure time.
-+.	if events are saved between calls to beforethat the index will change
-+.	but the displayed event will be the next one (unless the event buffer
-+.	is overrun).
-+.
-+.	andthen commands are: set_andthen, andthen_next, andthen and beforethat
-+end
-diff -puN /dev/null Documentation/i386/kgdb/debug-nmi.txt
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/debug-nmi.txt	2004-10-21 14:54:15.316595016 -0700
-@@ -0,0 +1,37 @@
-+Subject: Debugging with NMI
-+Date: Mon, 12 Jul 1999 11:28:31 -0500
-+From: David Grothe <dave@gcom.com>
-+Organization: Gcom, Inc
-+To: David Grothe <dave@gcom.com>
-+
-+Kernel hackers:
-+
-+Maybe this is old hat, but it is new to me --
-+
-+On an ISA bus machine, if you short out the A1 and B1 pins of an ISA
-+slot you will generate an NMI to the CPU.  This interrupts even a
-+machine that is hung in a loop with interrupts disabled.  Used in
-+conjunction with kgdb <
-+ftp://ftp.gcom.com/pub/linux/src/kgdb-2.3.35/kgdb-2.3.35.tgz > you can
-+gain debugger control of a machine that is hung in the kernel!  Even
-+without kgdb the kernel will print a stack trace so you can find out
-+where it was hung.
-+
-+The A1/B1 pins are directly opposite one another and the farthest pins
-+towards the bracket end of the ISA bus socket.  You can stick a paper
-+clip or multi-meter probe between them to short them out.
-+
-+I had a spare ISA bus to PC104 bus adapter around.  The PC104 end of the
-+board consists of two rows of wire wrap pins.  So I wired a push button
-+between the A1/B1 pins and now have an ISA board that I can stick into
-+any ISA bus slot for debugger entry.
-+
-+Microsoft has a circuit diagram of a PCI card at
-+http://www.microsoft.com/hwdev/DEBUGGING/DMPSW.HTM.  If you want to
-+build one you will have to mail them and ask for the PAL equations.
-+Nobody makes one comercially.
-+
-+[THIS TIP COMES WITH NO WARRANTY WHATSOEVER.  It works for me, but if
-+your machine catches fire, it is your problem, not mine.]
-+
-+-- Dave (the kgdb guy)
-diff -puN /dev/null Documentation/i386/kgdb/gdb-globals.txt
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/gdb-globals.txt	2004-10-21 14:54:15.317594864 -0700
-@@ -0,0 +1,71 @@
-+Sender: akale@veritas.com
-+Date: Fri, 23 Jun 2000 19:26:35 +0530
-+From: "Amit S. Kale" <akale@veritas.com>
-+Organization: Veritas Software (India)
-+To: Dave Grothe <dave@gcom.com>, linux-kernel@vger.rutgers.edu
-+CC: David Milburn <dmilburn@wirespeed.com>,
-+        "Edouard G. Parmelan" <Edouard.Parmelan@quadratec.fr>,
-+        ezannoni@cygnus.com, Keith Owens <kaos@ocs.com.au>
-+Subject: Re: Module debugging using kgdb
-+
-+Dave Grothe wrote:
-+>
-+> Amit:
-+>
-+> There is a 2.4.0 version of kgdb on our ftp site:
-+> ftp://ftp.gcom.com/pub/linux/src/kgdb.  I mirrored your version of gdb
-+> and loadmodule.sh there.
-+>
-+> Have a look at the README file and see if I go it right.  If not, send
-+> me some corrections and I will update it.
-+>
-+> Does your version of gdb solve the global variable problem?
-+
-+Yes.
-+Thanks to Elena Zanoni, gdb (developement version) can now calculate
-+correctly addresses  of dynamically loaded object files. I have not been
-+following gdb developement for sometime and am not sure when symbol
-+address calculation fix is going to appear in a gdb stable version.
-+
-+Elena, any idea when the fix will make it to a prebuilt gdb from a
-+redhat release?
-+
-+For the time being I have built a gdb developement version. It can be
-+used for module debugging with loadmodule.sh script.
-+
-+The problem with calculating of module addresses with previous versions
-+of gdb was as follows:
-+gdb did not use base address of a section while calculating address of
-+a symbol in the section in an object file loaded via 'add-symbol-file'.
-+It used address of .text segment instead. Due to this addresses of
-+symbols in .data, .bss etc. (e.g. global variables) were calculated incorrectly.
-+
-+Above mentioned fix allow gdb to use base address of a segment while
-+calculating address of a symbol in it. It adds a parameter '-s' to
-+'add-symbol-file' command for specifying base address of a segment.
-+
-+loadmodule.sh script works as follows.
-+
-+1. Copy a module file to target machine.
-+2. Load the module on the target machine using insmod with -m parameter.
-+insmod produces a module load map which contains base addresses of all
-+sections in the module and addresses of symbols in the module file.
-+3. Find all sections and their base addresses in the module from
-+the module map.
-+4. Generate a script that loads the module file. The script uses
-+'add-symbol-file' and specifies address of text segment followed by
-+addresses of all segments in the module.
-+
-+Here is an example gdb script produced by loadmodule.sh script.
-+
-+add-symbol-file foo 0xd082c060 -s .text.lock 0xd08cbfb5
-+-s .fixup 0xd08cfbdf -s .rodata 0xd08cfde0 -s __ex_table 0xd08e3b38
-+-s .data 0xd08e3d00 -s .bss 0xd08ec8c0 -s __ksymtab 0xd08ee838
-+
-+With this command gdb can calculate addresses of symbols in ANY segment
-+in a module file.
-+
-+Regards.
-+--
-+Amit Kale
-+Veritas Software ( http://www.veritas.com )
-diff -puN /dev/null Documentation/i386/kgdb/gdbinit
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/gdbinit	2004-10-21 14:54:15.317594864 -0700
-@@ -0,0 +1,14 @@
-+shell echo -e "\003" >/dev/ttyS0
-+set remotebaud 38400
-+target remote /dev/ttyS0
-+define si
-+stepi
-+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
-+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
-+x/i $eip
-+end
-+define ni
-+nexti
-+printf "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n", $eax, $ebx, $ecx, $edx
-+printf "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n", $esi, $edi, $ebp, $esp
-+x/i $eip
-diff -puN /dev/null Documentation/i386/kgdb/gdbinit.hw
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/gdbinit.hw	2004-10-21 14:54:15.318594712 -0700
-@@ -0,0 +1,117 @@
-+
-+#Using ia-32 hardware breakpoints.
-+#
-+#4 hardware breakpoints are available in ia-32 processors. These breakpoints
-+#do not need code modification. They are set using debug registers.
-+#
-+#Each hardware breakpoint can be of one of the
-+#three types: execution, write, access.
-+#1. An Execution breakpoint is triggered when code at the breakpoint address is
-+#executed.
-+#2. A write breakpoint ( aka watchpoints ) is triggered when memory location
-+#at the breakpoint address is written.
-+#3. An access breakpoint is triggered when memory location at the breakpoint
-+#address is either read or written.
-+#
-+#As hardware breakpoints are available in limited number, use software
-+#breakpoints ( br command in gdb ) instead of execution hardware breakpoints.
-+#
-+#Length of an access or a write breakpoint defines length of the datatype to
-+#be watched. Length is 1 for char, 2 short , 3 int.
-+#
-+#For placing execution, write and access breakpoints, use commands
-+#hwebrk, hwwbrk, hwabrk
-+#To remove a breakpoint use hwrmbrk command.
-+#
-+#These commands take following types of arguments. For arguments associated
-+#with each command, use help command.
-+#1. breakpointno: 0 to 3
-+#2. length: 1 to 3
-+#3. address: Memory location in hex ( without 0x ) e.g c015e9bc
-+#
-+#Use the command exinfo to find which hardware breakpoint occured.
-+
-+#hwebrk breakpointno address
-+define hwebrk
-+	maintenance packet Y$arg0,0,0,$arg1
-+end
-+document hwebrk
-+	hwebrk <breakpointno> <address>
-+	Places a hardware execution breakpoint
-+	<breakpointno> = 0 - 3
-+	<address> = Hex digits without leading "0x".
-+end
-+
-+#hwwbrk breakpointno length address
-+define hwwbrk
-+	maintenance packet Y$arg0,1,$arg1,$arg2
-+end
-+document hwwbrk
-+	hwwbrk <breakpointno> <length> <address>
-+	Places a hardware write breakpoint
-+	<breakpointno> = 0 - 3
-+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
-+	<address> = Hex digits without leading "0x".
-+end
-+
-+#hwabrk breakpointno length address
-+define hwabrk
-+	maintenance packet Y$arg0,1,$arg1,$arg2
-+end
-+document hwabrk
-+	hwabrk <breakpointno> <length> <address>
-+	Places a hardware access breakpoint
-+	<breakpointno> = 0 - 3
-+	<length> = 1 (1 byte), 2 (2 byte), 3 (4 byte)
-+	<address> = Hex digits without leading "0x".
-+end
-+
-+#hwrmbrk breakpointno
-+define hwrmbrk
-+	maintenance packet y$arg0
-+end
-+document hwrmbrk
-+	hwrmbrk <breakpointno>
-+	<breakpointno> = 0 - 3
-+	Removes a hardware breakpoint
-+end
-+
-+define reboot
-+        maintenance packet r
-+end
-+#exinfo
-+define exinfo
-+	maintenance packet qE
-+end
-+document exinfo
-+	exinfo
-+	Gives information about a breakpoint.
-+end
-+define get_th
-+	p $th=(struct thread_info *)((int)$esp & ~8191)
-+end
-+document get_th
-+	get_tu
-+	Gets and prints the current thread_info pointer, Defines th to be it.
-+end
-+define get_cu
-+	p $cu=((struct thread_info *)((int)$esp & ~8191))->task
-+end
-+document get_cu
-+	get_cu
-+	Gets and print the "current" value.  Defines $cu to be it.
-+end
-+define int_off
-+	set var $flags=$eflags
-+	set $eflags=$eflags&~0x200
-+	end
-+define int_on
-+	set var $eflags|=$flags&0x200
-+	end
-+document int_off
-+	saves the current interrupt state and clears the processor interrupt
-+	flag.  Use int_on to restore the saved flag.
-+end
-+document int_on
-+	Restores the interrupt flag saved by int_off.
-+end
-diff -puN /dev/null Documentation/i386/kgdb/gdbinit-modules
---- /dev/null	Thu Apr 11 07:25:15 2002
-+++ 25-akpm/Documentation/i386/kgdb/gdbinit-modules	Fri Jan 13 17:54:25 2006
-@@ -0,0 +1,149 @@
-+#
-+# Usefull GDB user-command to debug Linux Kernel Modules with gdbstub.
-+#
-+# This don't work for Linux-2.0 or older.
-+#
-+# Author Edouard G. Parmelan <Edouard.Parmelan@quadratec.fr>
-+#
-+#
-+# Fri Apr 30 20:33:29 CEST 1999
-+#   First public release.
-+#
-+#   Major cleanup after experiment Linux-2.0 kernel without success.
-+#   Symbols of a module are not in the correct order, I can't explain
-+#   why :(
-+#
-+# Fri Mar 19 15:41:40 CET 1999
-+#   Initial version.
-+#
-+# Thu Jan  6 16:29:03 CST 2000
-+#   A little fixing by Dave Grothe <dave@gcom.com>
-+#
-+# Mon Jun 19 09:33:13 CDT 2000
-+#   Alignment changes from Edouard Parmelan
-+#
-+# The basic idea is to find where insmod load the module and inform
-+# GDB to load the symbol table of the module with the GDB command
-+# ``add-symbol-file <object> <address>''.
-+#
-+# The Linux kernel holds the list of all loaded modules in module_list,
-+# this list end with &kernel_module (exactly with module->next == NULL,
-+# but the last module is not a real module).
-+#
-+# Insmod allocates the struct module before the object file.  Since
-+# Linux-2.1, this structure contain his size.  The real address of
-+# the object file is then (char*)module + module->size_of_struct.
-+#
-+# You can use three user functions ``mod-list'', ``mod-print-symbols''
-+# and ``add-module-symbols''.
-+#
-+# mod-list list all loaded modules with the format:
-+#    <module-address> <module-name>
-+#
-+# As soon as you have found the address of your module, you can
-+# print its exported symbols (mod-print-symbols) or inform GDB to add
-+# symbols from your module file (mod-add-symbols).
-+#
-+# The argument that you give to mod-print-symbols or mod-add-symbols
-+# is the <module-address> from the mod-list command.
-+#
-+# When using the mod-add-symbols command you must also give the full
-+# pathname of the modules object code file.
-+#
-+# The command mod-add-lis is an example of how to make this easier.
-+# You can edit this macro to contain the path name of your own
-+# favorite module and then use it as a shorthand to load it.  You
-+# still need the module-address, however.
-+#
-+# The internal function ``mod-validate'' set the GDB variable $mod
-+# as a ``struct module*'' if the kernel known the module otherwise
-+# $mod is set to NULL.  This ensure to not add symbols for a wrong
-+# address.
-+#
-+#
-+# Sat Feb 12 20:05:47 CET 2005
-+#
-+# Adapted to the 2.6.* module data structure.
-+# (Getting miffed at gdb for not having "offsetof" in the process :-/ )
-+#
-+# Autogenerate add-symbol-file statements from the module list instead
-+# of relying on a no-longer-working loadmodule.sh program.
-+#
-+#                                   Matthias Urlichs <smurf@debian.org>
-+#
-+#
-+# Have a nice hacking day !
-+#
-+#
-+define mod-list
-+    set $lmod = modules->next
-+    # This is a circular data structure
-+    while $lmod != &modules
-+		set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
-+        printf "%p\t%s\n", $mod, $mod->name
-+		set $lmod = $lmod->next
-+    end
-+end
-+document mod-list
-+mod-list
-+List all modules in the form: <module-address> <module-name>
-+Use the <module-address> as the argument for the other
-+mod-commands: mod-print-symbols, mod-add-symbols.
-+end
-+
-+define mod-list-syms
-+    set $lmod = modules->next
-+    # This is a circular data structure
-+    while $lmod != &modules
-+		set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
-+        printf "add-symbol-file %s.ko %p\n", $mod->name, $mod->module_core
-+		set $lmod = $lmod->next
-+    end
-+end
-+document mod-list-syms
-+mod-list-syms
-+List all modules in the form: add-symbol-file <module-path> <module-core>
-+for adding modules' symbol tables without loadmodule.sh.
-+end
-+
-+define mod-validate
-+    set $lmod = modules->next
-+	set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
-+    while ($lmod != &modules) && ($mod != $arg0)
-+        set $lmod = $lmod->next
-+	    set $mod = (struct module *)(((char *)$lmod) - ((int)&(((struct module *)0) -> list)))
-+    end
-+    if $lmod == &modules
-+    	set $mod = 0
-+        printf "%p is not a module\n", $arg0
-+    end
-+end
-+document mod-validate
-+mod-validate <module-address>
-+Internal user-command used to validate the module parameter.
-+If <module> is a real loaded module, set $mod to it, otherwise set $mod
-+to 0.
-+end
-+
-+define mod-print-symbols
-+    mod-validate $arg0
-+    if $mod != 0
-+		set $i = 0
-+		while $i < $mod->num_syms
-+			set $sym = $mod->syms[$i]
-+			printf "%p\t%s\n", $sym->value, $sym->name
-+			set $i = $i + 1
-+		end
-+		set $i = 0
-+		while $i < $mod->num_gpl_syms
-+			set $sym = $mod->gpl_syms[$i]
-+			printf "%p\t%s\n", $sym->value, $sym->name
-+			set $i = $i + 1
-+		end
-+    end
-+end
-+document mod-print-symbols
-+mod-print-symbols <module-address>
-+Print all exported symbols of the module.  See mod-list
-+end
-+
-diff -puN /dev/null Documentation/i386/kgdb/kgdb.txt
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/kgdb.txt	2004-10-21 14:54:15.324593800 -0700
-@@ -0,0 +1,775 @@
-+Last edit: <20030806.1637.12>
-+This file has information specific to the i386 kgdb option.  Other
-+platforms with the kgdb option may behave in a similar fashion.
-+
-+New features:
-+============
-+20030806.1557.37
-+This version was made against the 2.6.0-test2 kernel. We have made the
-+following changes:
-+
-+- The getthread() code in the stub calls find_task_by_pid().  It fails
-+  if we are early in the bring up such that the pid arrays have yet to
-+  be allocated.  We have added a line to kernel/pid.c to make
-+  "kgdb_pid_init_done" true once the arrays are allocated.  This way the
-+  getthread() code knows not to call.  This is only used by the thread
-+  debugging stuff and threads will not yet exist at this point in the
-+  boot.
-+
-+- For some reason, gdb was not asking for a new thread list when the
-+  "info thread" command was given.  We changed to the newer version of
-+  the thread info command and gdb now seems to ask when needed.  Result,
-+  we now get all threads in the thread list.
-+
-+- We now respond to the ThreadExtraInfo request from gdb with the thread
-+  name from task_struct .comm.  This then appears in the thread list.
-+  Thoughts on additional options for this are welcome.  Things such as
-+  "has BKL" and "Preempted" come to mind.  I think we could have a flag
-+  word that could enable different bits of info here.
-+
-+- We now honor, sort of, the C and S commands.  These are continue and
-+  single set after delivering a signal.  We ignore the signal and do the
-+  requested action.  This only happens when we told gdb that a signal
-+  was the reason for entry, which is only done on memory faults.  The
-+  result is that you can now continue into the Oops.
-+
-+- We changed the -g to -gdwarf-2.  This seems to be the same as -ggdb,
-+  but it is more exact on what language to use.
-+
-+- We added two dwarf2 include files and a bit of code at the end of
-+  entry.S.  This does not yet work, so it is disabled.  Still we want to
-+  keep track of the code and "maybe" someone out there can fix it.
-+
-+- Randy Dunlap sent some fix ups for this file which are now merged.
-+
-+- Hugh Dickins sent a fix to a bit of code in traps.c that prevents a
-+  compiler warning if CONFIG_KGDB is off (now who would do that :).
-+
-+- Andrew Morton sent a fix for the serial driver which is now merged.
-+
-+- Andrew also sent a change to the stub around the cpu managment code
-+  which is also merged.
-+
-+- Andrew also sent a patch to make "f" as well as "g" work as SysRq
-+  commands to enter kgdb, merged.
-+
-+- If CONFIG_KGDB and CONFIG_DEBUG_SPINLOCKS are both set we added a
-+  "who" field to the spinlock data struct.  This is filled with
-+  "current" when ever the spinlock suceeds.  Useful if you want to know
-+  who has the lock.
-+
-+_ And last, but not least, we fixed the "get_cu" macro to properly get
-+  the current value of "current".
-+
-+New features:
-+============
-+20030505.1827.27
-+We are starting to align with the sourceforge version, at least in
-+commands.  To this end, the boot command string to start kgdb at
-+boot time has been changed from "kgdb" to "gdb".
-+
-+Andrew Morton sent a couple of patches which are now included as follows:
-+1.) We now return a flag to the interrupt handler.
-+2.) We no longer use smp_num_cpus (a conflict with the lock meter).
-+3.) And from William Lee Irwin III <wli@holomorphy.com> code to make
-+    sure high-mem is set up before we attempt to register our interrupt
-+    handler.
-+We now include asm/kgdb.h from config.h so you will most likely never
-+have to include it.  It also 'NULLS' the kgdb macros you might have in
-+your code when CONFIG_KGDB is not defined.  This allows you to just
-+turn off CONFIG_KGDB to turn off all the kgdb_ts() calls and such.
-+This include is conditioned on the machine being an x86 so as to not
-+mess with other archs.
-+
-+20020801.1129.03
-+This is currently the version for the 2.4.18 (and beyond?) kernel.
-+
-+We have several new "features" beginning with this version:
-+
-+1.) Kgdb now syncs the "other" CPUs with a cross-CPU NMI.  No more
-+    waiting and it will pull that guy out of an IRQ off spin lock :)
-+
-+2.) We doctored up the code that tells where a task is waiting and
-+    included it so that the "info thread" command will show a bit more
-+    than "schedule()".  Try it...
-+
-+3.) Added the ability to call a function from gdb.  All the standard gdb
-+    issues apply, i.e. if you hit a breakpoint in the function, you are
-+    not allowed to call another (gdb limitation, not kgdb).  To help
-+    this capability we added a memory allocation function.  Gdb does not
-+    return this memory (it is used for strings that you pass to that function
-+    you are calling from gdb) so we fixed up a way to allow you to
-+    manually return the memory (see below).
-+
-+4.) Kgdb time stamps (kgdb_ts()) are enhanced to expand what was the
-+    interrupt flag to now also include the preemption count and the
-+    "in_interrupt" info.  The flag is now called "with_pif" to indicate
-+    the order, preempt_count, in_interrupt, flag.  The preempt_count is
-+    shifted left by 4 bits so you can read the count in hex by dropping
-+    the low order digit.  In_interrupt is in bit 1, and the flag is in
-+    bit 0.
-+
-+5.) The command: "p kgdb_info" is now expanded and prints something
-+    like:
-+(gdb) p kgdb_info
-+$2 = {used_malloc = 0, called_from = 0xc0107506, entry_tsc = 67468627259,
-+  errcode = 0, vector = 3, print_debug_info = 0, hold_on_sstep = 1,
-+  cpus_waiting = {{task = 0xc027a000, pid = 32768, hold = 0,
-+      regs = 0xc027bf84}, {task = 0x0, pid = 0, hold = 0, regs = 0x0}}}
-+
-+    Things to note here: a.) used_malloc is the amount of memory that
-+    has been malloc'ed to do calls from gdb.  You can reclaim this
-+    memory like this: "p kgdb_info.used_malloc=0" Cool, huh?  b.)
-+    cpus_waiting is now "sized" by the number of CPUs you enter at
-+    configure time in the kgdb configure section.  This is NOT used
-+    anywhere else in the system, but it is "nice" here.  c.)  The task's
-+    "pid" is now in the structure.  This is the pid you will need to use
-+    to decode to the thread id to get gdb to look at that thread.
-+    Remember that the "info thread" command prints a list of threads
-+    wherein it numbers each thread with its reference number followed
-+    by the thread's pid.  Note that the per-CPU idle threads actually
-+    have pids of 0 (yes, there is more than one pid 0 in an SMP system).
-+    To avoid confusion, kgdb numbers these threads with numbers beyond
-+    the MAX_PID.  That is why you see 32768 and above.
-+
-+6.) A subtle change, we now provide the complete register set for tasks
-+    that are active on the other CPUs.  This allows better trace back on
-+    those tasks.
-+
-+    And, let's mention what we could not fix.  Back-trace from all but the
-+    thread that we trapped will, most likely, have a bogus entry in it.
-+    The problem is that gdb does not recognize the entry code for
-+    functions that use "current" near (at all?) the entry.  The compiler
-+    is putting the "current" decode as the first two instructions of the
-+    function where gdb expects to find %ebp changing code.  Back trace
-+    also has trouble with interrupt frames.  I am talking with Daniel
-+    Jacobowitz about some way to fix this, but don't hold your breath.
-+
-+20011220.0050.35
-+Major enhancement with this version is the ability to hold one or more
-+CPUs in an SMP system while allowing the others to continue.  Also, by
-+default only the current CPU is enabled on single-step commands (please
-+note that gdb issues single-step commands at times other than when you
-+use the si command).
-+
-+Another change is to collect some useful information in
-+a global structure called "kgdb_info".  You should be able to just:
-+
-+p kgdb_info
-+
-+although I have seen cases where the first time this is done gdb just
-+prints the first member but prints the whole structure if you then enter
-+CR (carriage return or enter).  This also works:
-+
-+p *&kgdb_info
-+
-+Here is a sample:
-+(gdb) p kgdb_info
-+$4 = {called_from = 0xc010732c, entry_tsc = 32804123790856, errcode = 0,
-+  vector = 3, print_debug_info = 0}
-+
-+"Called_from" is the return address from the current entry into kgdb.
-+Sometimes it is useful to know why you are in kgdb, for example, was
-+it an NMI or a real breakpoint?  The simple way to interrogate this
-+return address is:
-+
-+l *0xc010732c
-+
-+which will print the surrounding few lines of source code.
-+
-+"Entry_tsc" is the CPU TSC on entry to kgdb (useful to compare to the
-+kgdb_ts entries).
-+
-+"errcode" and "vector" are other entry parameters which may be helpful on
-+some traps.
-+
-+"print_debug_info" is the internal debugging kgdb print enable flag.  Yes,
-+you can modify it.
-+
-+In SMP systems kgdb_info also includes the "cpus_waiting" structure and
-+"hold_on_step":
-+
-+(gdb) p kgdb_info
-+$7 = {called_from = 0xc0112739, entry_tsc = 1034936624074, errcode = 0,
-+  vector = 2, print_debug_info = 0, hold_on_sstep = 1, cpus_waiting = {{
-+      task = 0x0, hold = 0, regs = 0x0}, {task = 0xc71b8000, hold = 0,
-+      regs = 0xc71b9f70}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
-+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
-+      hold = 0, regs = 0x0}, {task = 0x0, hold = 0, regs = 0x0}, {task = 0x0,
-+      hold = 0, regs = 0x0}}}
-+
-+"Cpus_waiting" has an entry for each CPU other than the current one that
-+has been stopped.  Each entry contains the task_struct address for that
-+CPU, the address of the regs for that task and a hold flag.  All these
-+have the proper typing so that, for example:
-+
-+p *kgdb_info.cpus_waiting[1].regs
-+
-+will print the registers for CPU 1.
-+
-+"Hold_on_sstep" is a new feature with this version and comes up set or
-+true.  What this means is that whenever kgdb is asked to single-step all
-+other CPUs are held (i.e. not allowed to execute).  The flag applies to
-+all but the current CPU and, again, can be changed:
-+
-+p kgdb_info.hold_on_sstep=0
-+
-+restores the old behavior of letting all CPUs run during single-stepping.
-+
-+Likewise, each CPU has a "hold" flag, which if set, locks that CPU out
-+of execution.  Note that this has some risk in cases where the CPUs need
-+to communicate with each other.  If kgdb finds no CPU available on exit,
-+it will push a message thru gdb and stay in kgdb.  Note that it is legal
-+to hold the current CPU as long as at least one CPU can execute.
-+
-+20010621.1117.09
-+This version implements an event queue.  Events are signaled by calling
-+a function in the kgdb stub and may be examined from gdb.  See EVENTS
-+below for details.  This version also tightens up the interrupt and SMP
-+handling to not allow interrupts on the way to kgdb from a breakpoint
-+trap.  It is fine to allow these interrupts for user code, but not
-+system debugging.
-+
-+Version
-+=======
-+
-+This version of the kgdb package was developed and tested on
-+kernel version 2.4.16.  It will not install on any earlier kernels.
-+It is possible that it will continue to work on later versions
-+of 2.4 and then versions of 2.5 (I hope).
-+
-+
-+Debugging Setup
-+===============
-+
-+Designate one machine as the "development" machine.  This is the
-+machine on which you run your compiles and which has your source
-+code for the kernel.  Designate a second machine as the "target"
-+machine.  This is the machine that will run your experimental
-+kernel.
-+
-+The two machines will be connected together via a serial line out
-+one or the other of the COM ports of the PC.  You will need the
-+appropriate modem eliminator (null modem) cable(s) for this.
-+
-+Decide on which tty port you want the machines to communicate, then
-+connect them up back-to-back using the null modem cable.  COM1 is
-+/dev/ttyS0 and COM2 is /dev/ttyS1. You should test this connection
-+with the two machines prior to trying to debug a kernel.  Once you
-+have it working, on the TARGET machine, enter:
-+
-+setserial /dev/ttyS0 (or what ever tty you are using)
-+
-+and record the port address and the IRQ number.
-+
-+On the DEVELOPMENT machine you need to apply the patch for the kgdb
-+hooks.  You have probably already done that if you are reading this
-+file.
-+
-+On your DEVELOPMENT machine, go to your kernel source directory and do
-+"make Xconfig" where X is one of "x", "menu", or "".  If you are
-+configuring in the standard serial driver, it must not be a module.
-+Either yes or no is ok, but making the serial driver a module means it
-+will initialize after kgdb has set up the UART interrupt code and may
-+cause a failure of the control-C option discussed below.  The configure
-+question for the serial driver is under the "Character devices" heading
-+and is:
-+
-+"Standard/generic (8250/16550 and compatible UARTs) serial support"
-+
-+Go down to the kernel debugging menu item and open it up.  Enable the
-+kernel kgdb stub code by selecting that item.  You can also choose to
-+turn on the "-ggdb -O1" compile options.  The -ggdb causes the compiler
-+to put more debug info (like local symbols) in the object file.  On the
-+i386 -g and -ggdb are the same so this option just reduces to "O1".  The
-+-O1 reduces the optimization level.  This may be helpful in some cases,
-+be aware, however, that this may also mask the problem you are looking
-+for.
-+
-+The baud rate.  Default is 115200.  What ever you choose be sure that
-+the host machine is set to the same speed.  I recommend the default.
-+
-+The port.  This is the I/O address of the serial UART that you should
-+have gotten using setserial as described above.  The standard COM1 port
-+(3f8) using IRQ 4 is default.  COM2 is 2f8 which by convention uses IRQ
-+3.
-+
-+The port IRQ (see above).
-+
-+Stack overflow test.  This option makes a minor change in the trap,
-+system call and interrupt code to detect stack overflow and transfer
-+control to kgdb if it happens.  (Some platforms have this in the
-+baseline code, but the i386 does not.)
-+
-+You can also configure the system to recognize the boot option
-+"console=kgdb" which if given will cause all console output during
-+booting to be put thru gdb as well as other consoles.  This option
-+requires that gdb and kgdb be connected prior to sending console output
-+so, if they are not, a breakpoint is executed to force the connection.
-+This will happen before any kernel output (it is going thru gdb, right),
-+and will stall the boot until the connection is made.
-+
-+You can also configure in a patch to SysRq to enable the kGdb SysRq.
-+This request generates a breakpoint.  Since the serial port IRQ line is
-+set up after any serial drivers, it is possible that this command will
-+work when the control-C will not.
-+
-+Save and exit the Xconfig program.  Then do "make clean" , "make dep"
-+and "make bzImage" (or whatever target you want to make).  This gets the
-+kernel compiled with the "-g" option set -- necessary for debugging.
-+
-+You have just built the kernel on your DEVELOPMENT machine that you
-+intend to run on your TARGET machine.
-+
-+To install this new kernel, use the following installation procedure.
-+Remember, you are on the DEVELOPMENT machine patching the kernel source
-+for the kernel that you intend to run on the TARGET machine.
-+
-+Copy this kernel to your target machine using your usual procedures.  I
-+usually arrange to copy development:
-+/usr/src/linux/arch/i386/boot/bzImage to /vmlinuz on the TARGET machine
-+via a LAN based NFS access.  That is, I run the cp command on the target
-+and copy from the development machine via the LAN.  Run Lilo (see "man
-+lilo" for details on how to set this up) on the new kernel on the target
-+machine so that it will boot!  Then boot the kernel on the target
-+machine.
-+
-+On the DEVELOPMENT machine, create a file called .gdbinit in the
-+directory /usr/src/linux.  An example .gdbinit file looks like this:
-+
-+shell echo -e "\003" >/dev/ttyS0
-+set remotebaud 38400 (or what ever speed you have chosen)
-+target remote /dev/ttyS0
-+
-+
-+Change the "echo" and "target" definition so that it specifies the tty
-+port that you intend to use.  Change the "remotebaud" definition to
-+match the data rate that you are going to use for the com line.
-+
-+You are now ready to try it out.
-+
-+Boot your target machine with "kgdb" in the boot command i.e. something
-+like:
-+
-+lilo> test kgdb
-+
-+or if you also want console output thru gdb:
-+
-+lilo> test kgdb console=kgdb
-+
-+You should see the lilo message saying it has loaded the kernel and then
-+all output stops.  The kgdb stub is trying to connect with gdb.  Start
-+gdb something like this:
-+
-+
-+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
-+When gdb gets the symbols loaded it will read your .gdbinit file and, if
-+everything is working correctly, you should see gdb print out a few
-+lines indicating that a breakpoint has been taken.  It will actually
-+show a line of code in the target kernel inside the kgdb activation
-+code.
-+
-+The gdb interaction should look something like this:
-+
-+    linux-dev:/usr/src/linux# gdb vmlinux
-+    GDB is free software and you are welcome to distribute copies of it
-+     under certain conditions; type "show copying" to see the conditions.
-+    There is absolutely no warranty for GDB; type "show warranty" for details.
-+    GDB 4.15.1 (i486-slackware-linux),
-+    Copyright 1995 Free Software Foundation, Inc...
-+    breakpoint () at i386-stub.c:750
-+    750     }
-+    (gdb)
-+
-+You can now use whatever gdb commands you like to set breakpoints.
-+Enter "continue" to start your target machine executing again.  At this
-+point the target system will run at full speed until it encounters
-+your breakpoint or gets a segment violation in the kernel, or whatever.
-+
-+If you have the kgdb console enabled when you continue, gdb will print
-+out all the console messages.
-+
-+The above example caused a breakpoint relatively early in the boot
-+process.  For the i386 kgdb it is possible to code a break instruction
-+as the first C-language point in init/main.c, i.e. as the first instruction
-+in start_kernel().  This could be done as follows:
-+
-+#include <asm/kgdb.h>
-+	 breakpoint();
-+
-+This breakpoint() is really a function that sets up the breakpoint and
-+single-step hardware trap cells and then executes a breakpoint.  Any
-+early hard coded breakpoint will need to use this function.  Once the
-+trap cells are set up they need not be set again, but doing it again
-+does not hurt anything, so you don't need to be concerned about which
-+breakpoint is hit first.  Once the trap cells are set up (and the kernel
-+sets them up in due course even if breakpoint() is never called) the
-+macro:
-+
-+BREAKPOINT;
-+
-+will generate an inline breakpoint.  This may be more useful as it stops
-+the processor at the instruction instead of in a function a step removed
-+from the location of interest.  In either case <asm/kgdb.h> must be
-+included to define both breakpoint() and BREAKPOINT.
-+
-+Triggering kgdbstub at other times
-+==================================
-+
-+Often you don't need to enter the debugger until much later in the boot
-+or even after the machine has been running for some time.  Once the
-+kernel is booted and interrupts are on, you can force the system to
-+enter the debugger by sending a control-C to the debug port. This is
-+what the first line of the recommended .gdbinit file does.  This allows
-+you to start gdb any time after the system is up as well as when the
-+system is already at a breakpoint.  (In the case where the system is
-+already at a breakpoint the control-C is not needed, however, it will
-+be ignored by the target so no harm is done.  Also note the the echo
-+command assumes that the port speed is already set.  This will be true
-+once gdb has connected, but it is best to set the port speed before you
-+run gdb.)
-+
-+Another simple way to do this is to put the following file in you ~/bin
-+directory:
-+
-+#!/bin/bash
-+echo  -e "\003"  > /dev/ttyS0
-+
-+Here, the ttyS0 should be replaced with what ever port you are using.
-+The "\003" is control-C.  Once you are connected with gdb, you can enter
-+control-C at the command prompt.
-+
-+An alternative way to get control to the debugger is to enable the kGdb
-+SysRq command.  Then you would enter Alt-SysRq-g (all three keys at the
-+same time, but push them down in the order given).  To refresh your
-+memory of the available SysRq commands try Alt-SysRq-=.  Actually any
-+undefined command could replace the "=", but I like to KNOW that what I
-+am pushing will never be defined.
-+
-+Debugging hints
-+===============
-+
-+You can break into the target machine at any time from the development
-+machine by typing ^C (see above paragraph).  If the target machine has
-+interrupts enabled this will stop it in the kernel and enter the
-+debugger.
-+
-+There is unfortunately no way of breaking into the kernel if it is
-+in a loop with interrupts disabled, so if this happens to you then
-+you need to place exploratory breakpoints or printk's into the kernel
-+to find out where it is looping.  The exploratory breakpoints can be
-+entered either thru gdb or hard coded into the source.  This is very
-+handy if you do something like:
-+
-+if (<it hurts>) BREAKPOINT;
-+
-+
-+There is a copy of an e-mail in the Documentation/i386/kgdb/ directory
-+(debug-nmi.txt) which describes how to create an NMI on an ISA bus
-+machine using a paper clip.  I have a sophisticated version of this made
-+by wiring a push button switch into a PC104/ISA bus adapter card.  The
-+adapter card nicely furnishes wire wrap pins for all the ISA bus
-+signals.
-+
-+When you are done debugging the kernel on the target machine it is a
-+good idea to leave it in a running state.  This makes reboots faster,
-+bypassing the fsck.  So do a gdb "continue" as the last gdb command if
-+this is possible.  To terminate gdb itself on the development machine
-+and leave the target machine running, first clear all breakpoints and
-+continue, then type ^Z to suspend gdb and then kill it with "kill %1" or
-+something similar.
-+
-+If gdbstub Does Not Work
-+========================
-+
-+If it doesn't work, you will have to troubleshoot it.  Do the easy
-+things first like double checking your cabling and data rates.  You
-+might try some non-kernel based programs to see if the back-to-back
-+connection works properly.  Just something simple like cat /etc/hosts
-+>/dev/ttyS0 on one machine and cat /dev/ttyS0 on the other will tell you
-+if you can send data from one machine to the other.  Make sure it works
-+in both directions.  There is no point in tearing out your hair in the
-+kernel if the line doesn't work.
-+
-+All of the real action takes place in the file
-+/usr/src/linux/arch/i386/kernel/kgdb_stub.c.  That is the code on the target
-+machine that interacts with gdb on the development machine.  In gdb you can
-+turn on a debug switch with the following command:
-+
-+	set remotedebug
-+
-+This will print out the protocol messages that gdb is exchanging with
-+the target machine.
-+
-+Another place to look is /usr/src/arch/i386/lib/kgdb_serial.c. This is
-+the code that talks to the serial port on the target side.  There might
-+be a problem there.  In particular there is a section of this code that
-+tests the UART which will tell you what UART you have if you define
-+"PRNT" (just remove "_off" from the #define PRNT_off).  To view this
-+report you will need to boot the system without any beakpoints.  This
-+allows the kernel to run to the point where it calls kgdb to set up
-+interrupts.  At this time kgdb will test the UART and print out the type
-+it finds.  (You need to wait so that the printks are actually being
-+printed.  Early in the boot they are cached, waiting for the console to
-+be enabled.  Also, if kgdb is entered thru a breakpoint it is possible
-+to cause a dead lock by calling printk when the console is locked.  The
-+stub thus avoids doing printks from breakpoints, especially in the
-+serial code.)  At this time, if the UART fails to do the expected thing,
-+kgdb will print out (using printk) information on what failed.  (These
-+messages will be buried in all the other boot up messages.  Look for
-+lines that start with "gdb_hook_interrupt:".  You may want to use dmesg
-+once the system is up to view the log.  If this fails or if you still
-+don't connect, review your answers for the port address.  Use:
-+
-+setserial /dev/ttyS0
-+
-+to get the current port and IRQ information.  This command will also
-+tell you what the system found for the UART type. The stub recognizes
-+the following UART types:
-+
-+16450, 16550, and 16550A
-+
-+If you are really desperate you can use printk debugging in the
-+kgdbstub code in the target kernel until you get it working.  In particular,
-+there is a global variable in /usr/src/linux/arch/i386/kernel/kgdb_stub.c
-+named "remote_debug".  Compile your kernel with this set to 1, rather
-+than 0 and the debug stub will print out lots of stuff as it does
-+what it does.  Likewise there are debug printks in the kgdb_serial.c
-+code that can be turned on with simple changes in the macro defines.
-+
-+
-+Debugging Loadable Modules
-+==========================
-+
-+This technique comes courtesy of Edouard Parmelan
-+<Edouard.Parmelan@quadratec.fr>
-+
-+When you run gdb, enter the command
-+
-+source gdbinit-modules
-+
-+This will read in a file of gdb macros that was installed in your
-+kernel source directory when kgdb was installed.  This file implements
-+the following commands:
-+
-+mod-list
-+    Lists the loaded modules in the form <module-address> <module-name>
-+
-+mod-print-symbols <module-address>
-+    Prints all the symbols in the indicated module.
-+
-+mod-add-symbols <module-address> <object-file-path-name>
-+    Loads the symbols from the object file and associates them
-+    with the indicated module.
-+
-+After you have loaded the module that you want to debug, use the command
-+mod-list to find the <module-address> of your module.  Then use that
-+address in the mod-add-symbols command to load your module's symbols.
-+From that point onward you can debug your module as if it were a part
-+of the kernel.
-+
-+The file gdbinit-modules also contains a command named mod-add-lis as
-+an example of how to construct a command of your own to load your
-+favorite module.  The idea is to "can" the pathname of the module
-+in the command so you don't have to type so much.
-+
-+Threads
-+=======
-+
-+Each process in a target machine is seen as a gdb thread. gdb thread
-+related commands (info threads, thread n) can be used.
-+
-+ia-32 hardware breakpoints
-+==========================
-+
-+kgdb stub contains support for hardware breakpoints using debugging features
-+of ia-32(x86) processors. These breakpoints do not need code modification.
-+They use debugging registers. 4 hardware breakpoints are available in ia-32
-+processors.
-+
-+Each hardware breakpoint can be of one of the following three types.
-+
-+1. Execution breakpoint - An Execution breakpoint is triggered when code
-+	at the breakpoint address is executed.
-+
-+	As limited number of hardware breakpoints are available, it is
-+	advisable to use software breakpoints ( break command ) instead
-+	of execution hardware breakpoints, unless modification of code
-+	is to be avoided.
-+
-+2. Write breakpoint - A write breakpoint is triggered when memory
-+	location at the breakpoint address is written.
-+
-+	A write or can be placed for data of variable length. Length of
-+	a write breakpoint indicates length of the datatype to be
-+	watched. Length is 1 for 1 byte data , 2 for 2 byte data, 3 for
-+	4 byte data.
-+
-+3. Access breakpoint - An access breakpoint is triggered when memory
-+	location at the breakpoint address is either read or written.
-+
-+	Access breakpoints also have lengths similar to write breakpoints.
-+
-+IO breakpoints in ia-32 are not supported.
-+
-+Since gdb stub at present does not use the protocol used by gdb for hardware
-+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
-+for hardware breakpoints are described below.
-+
-+hwebrk	- Places an execution breakpoint
-+	hwebrk breakpointno address
-+hwwbrk	- Places a write breakpoint
-+	hwwbrk breakpointno length address
-+hwabrk	- Places an access breakpoint
-+	hwabrk breakpointno length address
-+hwrmbrk	- Removes a breakpoint
-+	hwrmbrk breakpointno
-+exinfo	- Tells whether a software or hardware breakpoint has occurred.
-+	Prints number of the hardware breakpoint if a hardware breakpoint has
-+	occurred.
-+
-+Arguments required by these commands are as follows
-+breakpointno	- 0 to 3
-+length		- 1 to 3
-+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
-+
-+SMP support
-+==========
-+
-+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb
-+client, all the processors are forced to enter the debugger. Current
-+thread corresponds to the thread running on the processor where
-+breakpoint occurred.  Threads running on other processor(s) appear
-+similar to other non-running threads in the 'info threads' output.
-+Within the kgdb stub there is a structure "waiting_cpus" in which kgdb
-+records the values of "current" and "regs" for each CPU other than the
-+one that hit the breakpoint.  "current" is a pointer to the task
-+structure for the task that CPU is running, while "regs" points to the
-+saved registers for the task.  This structure can be examined with the
-+gdb "p" command.
-+
-+ia-32 hardware debugging registers on all processors are set to same
-+values.  Hence any hardware breakpoints may occur on any processor.
-+
-+gdb troubleshooting
-+===================
-+
-+1. gdb hangs
-+Kill it. restart gdb. Connect to target machine.
-+
-+2. gdb cannot connect to target machine (after killing a gdb and
-+restarting another) If the target machine was not inside debugger when
-+you killed gdb, gdb cannot connect because the target machine won't
-+respond.  In this case echo "Ctrl+C"(ASCII 3) to the serial line.
-+e.g. echo -e "\003" > /dev/ttyS1
-+This forces that target machine into the debugger, after which you
-+can connect.
-+
-+3. gdb cannot connect even after echoing Ctrl+C into serial line
-+Try changing serial line settings min to 1 and time to 0
-+e.g. stty min 1 time 0 < /dev/ttyS1
-+Try echoing again
-+
-+Check serial line speed and set it to correct value if required
-+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
-+
-+EVENTS
-+======
-+
-+Ever want to know the order of things happening?  Which CPU did what and
-+when?  How did the spinlock get the way it is?  Then events are for
-+you.  Events are defined by calls to an event collection interface and
-+saved for later examination.  In this case, kgdb events are saved by a
-+very fast bit of code in kgdb which is fully SMP and interrupt protected
-+and they are examined by using gdb to display them.  Kgdb keeps only
-+the last N events, where N must be a power of two and is defined at
-+configure time.
-+
-+
-+Events are signaled to kgdb by calling:
-+
-+kgdb_ts(data0,data1)
-+
-+For each call kgdb records each call in an array along with other info.
-+Here is the array definition:
-+
-+struct kgdb_and_then_struct {
-+#ifdef CONFIG_SMP
-+	int	on_cpu;
-+#endif
-+	long long at_time;
-+	int  	from_ln;
-+	char	* in_src;
-+	void	*from;
-+        int     with_if;
-+	int	data0;
-+	int	data1;
-+};
-+
-+For SMP machines the CPU is recorded, for all machines the TSC is
-+recorded (gets a time stamp) as well as the line number and source file
-+the call was made from.  The address of the (from), the "if" (interrupt
-+flag) and the two data items are also recorded.  The macro kgdb_ts casts
-+the types to int, so you can put any 32-bit values here.  There is a
-+configure option to select the number of events you want to keep.  A
-+nice number might be 128, but you can keep up to 1024 if you want.  The
-+number must be a power of two.  An "andthen" macro library is provided
-+for gdb to help you look at these events.  It is also possible to define
-+a different structure for the event storage and cast the data to this
-+structure.  For example the following structure is defined in kgdb:
-+
-+struct kgdb_and_then_struct2 {
-+#ifdef CONFIG_SMP
-+	int	on_cpu;
-+#endif
-+	long long at_time;
-+	int  	from_ln;
-+	char	* in_src;
-+	void	*from;
-+        int     with_if;
-+	struct task_struct *t1;
-+	struct task_struct *t2;
-+};
-+
-+If you use this for display, the data elements will be displayed as
-+pointers to task_struct entries.  You may want to define your own
-+structure to use in casting.  You should only change the last two items
-+and you must keep the structure size the same.  Kgdb will handle these
-+as 32-bit ints, but within that constraint you can define a structure to
-+cast to any 32-bit quantity.  This need only be available to gdb and is
-+only used for casting in the display code.
-+
-+Final Items
-+===========
-+
-+I picked up this code from Amit S. Kale and enhanced it.
-+
-+If you make some really cool modification to this stuff, or if you
-+fix a bug, please let me know.
-+
-+George Anzinger
-+<george@mvista.com>
-+
-+Amit S. Kale
-+<akale@veritas.com>
-+
-+(First kgdb by David Grothe <dave@gcom.com>)
-+
-+(modified by Tigran Aivazian <tigran@sco.com>)
-+    Putting gdbstub into the kernel config menu.
-+
-+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
-+    Hooks for entering gdbstub at boot time.
-+
-+(modified by Amit S. Kale <akale@veritas.com>)
-+    Threads, ia-32 hw debugging, mp support, console support,
-+    nmi watchdog handling.
-+
-+(modified by George Anzinger <george@mvista.com>)
-+    Extended threads to include the idle threads.
-+    Enhancements to allow breakpoint() at first C code.
-+    Use of module_init() and __setup() to automate the configure.
-+    Enhanced the cpu "collection" code to work in early bring-up.
-+    Added ability to call functions from gdb
-+    Print info thread stuff without going back to schedule()
-+    Now collect the "other" cpus with an IPI/ NMI.
-diff -puN /dev/null Documentation/i386/kgdb/loadmodule.sh
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/Documentation/i386/kgdb/loadmodule.sh	2004-10-21 14:54:15.325593648 -0700
-@@ -0,0 +1,78 @@
-+#/bin/sh
-+# This script loads a module on a target machine and generates a gdb script.
-+# source generated gdb script to load the module file at appropriate addresses
-+# in gdb.
-+#
-+# Usage:
-+# Loading the module on target machine and generating gdb script)
-+#	[foo]$ loadmodule.sh <modulename>
-+#
-+# Loading the module file into gdb
-+#	(gdb) source <gdbscriptpath>
-+#
-+# Modify following variables according to your setup.
-+#	TESTMACHINE - Name of the target machine
-+#	GDBSCRIPTS - The directory where a gdb script will be generated
-+#
-+# Author: Amit S. Kale (akale@veritas.com).
-+#
-+# If you run into problems, please check files pointed to by following
-+# variables.
-+#	ERRFILE - /tmp/<modulename>.errs contains stderr output of insmod
-+#	MAPFILE - /tmp/<modulename>.map contains stdout output of insmod
-+#	GDBSCRIPT - $GDBSCRIPTS/load<modulename> gdb script.
-+
-+TESTMACHINE=foo
-+GDBSCRIPTS=/home/bar
-+
-+if [ $# -lt 1 ] ; then {
-+	echo Usage: $0 modulefile
-+	exit
-+} ; fi
-+
-+MODULEFILE=$1
-+MODULEFILEBASENAME=`basename $1`
-+
-+if [ $MODULEFILE = $MODULEFILEBASENAME ] ; then {
-+	MODULEFILE=`pwd`/$MODULEFILE
-+} fi
-+
-+ERRFILE=/tmp/$MODULEFILEBASENAME.errs
-+MAPFILE=/tmp/$MODULEFILEBASENAME.map
-+GDBSCRIPT=$GDBSCRIPTS/load$MODULEFILEBASENAME
-+
-+function findaddr() {
-+	local ADDR=0x$(echo "$SEGMENTS" | \
-+		grep "$1" | sed 's/^[^ ]*[ ]*[^ ]*[ ]*//' | \
-+		sed 's/[ ]*[^ ]*$//')
-+	echo $ADDR
-+}
-+
-+function checkerrs() {
-+	if [ "`cat $ERRFILE`" != "" ] ; then {
-+		cat $ERRFILE
-+		exit
-+	} fi
-+}
-+
-+#load the module
-+echo Copying $MODULEFILE to $TESTMACHINE
-+rcp $MODULEFILE root@${TESTMACHINE}:
-+
-+echo Loading module $MODULEFILE
-+rsh -l root $TESTMACHINE  /sbin/insmod -m ./`basename $MODULEFILE` \
-+	> $MAPFILE 2> $ERRFILE
-+checkerrs
-+
-+SEGMENTS=`head -n 11 $MAPFILE | tail -n 10`
-+TEXTADDR=$(findaddr "\\.text[^.]")
-+LOADSTRING="add-symbol-file $MODULEFILE $TEXTADDR"
-+SEGADDRS=`echo "$SEGMENTS" | awk '//{
-+	if ($1 != ".text" && $1 != ".this" &&
-+	    $1 != ".kstrtab" && $1 != ".kmodtab") {
-+		print " -s " $1 " 0x" $3 " "
-+	}
-+}'`
-+LOADSTRING="$LOADSTRING $SEGADDRS"
-+echo Generating script $GDBSCRIPT
-+echo $LOADSTRING > $GDBSCRIPT
-diff -puN drivers/char/keyboard.c~kgdb-ga drivers/char/keyboard.c
---- 25/drivers/char/keyboard.c~kgdb-ga	2004-10-21 14:54:15.273601552 -0700
-+++ 25-akpm/drivers/char/keyboard.c	2004-10-21 14:54:15.326593496 -0700
-@@ -1081,6 +1081,9 @@ void kbd_keycode(unsigned int keycode, i
- 	}
- 	if (sysrq_down && down && !rep) {
- 		handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
-+#ifdef CONFIG_KGDB_SYSRQ
-+                sysrq_down = 0;        /* in case we miss the "up" event */
-+#endif
- 		return;
- 	}
- #endif
-diff -puN drivers/char/sysrq.c~kgdb-ga drivers/char/sysrq.c
---- 25/drivers/char/sysrq.c~kgdb-ga	2004-10-21 14:54:15.275601248 -0700
-+++ 25-akpm/drivers/char/sysrq.c	2004-10-21 14:54:15.326593496 -0700
-@@ -35,6 +35,25 @@
- #include <linux/spinlock.h>
- 
- #include <asm/ptrace.h>
-+#ifdef CONFIG_KGDB_SYSRQ
-+
-+#define  GDB_OP &kgdb_op
-+static void kgdb_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
-+{
-+	printk("kgdb sysrq\n");
-+	breakpoint();
-+}
-+
-+static struct sysrq_key_op kgdb_op = {
-+	.handler	= kgdb_sysrq,
-+	.help_msg	= "kGdb|Fgdb",
-+	.action_msg	= "Debug breakpoint\n",
-+};
-+
-+#else
-+#define  GDB_OP NULL
-+#endif
-+
- 
- extern void reset_vc(unsigned int);
- 
-@@ -238,8 +257,8 @@ static struct sysrq_key_op *sysrq_key_ta
- /* c */ NULL,
- /* d */	NULL,
- /* e */	&sysrq_term_op,
--/* f */	NULL,
--/* g */	NULL,
-+/* f */	GDB_OP,
-+/* g */	GDB_OP,
- /* h */	NULL,
- /* i */	&sysrq_kill_op,
- /* j */	NULL,
-diff -puN drivers/serial/8250.c~kgdb-ga drivers/serial/8250.c
---- 25/drivers/serial/8250.c~kgdb-ga	2004-10-21 14:54:15.276601096 -0700
-+++ 25-akpm/drivers/serial/8250.c	2004-10-21 14:54:15.328593192 -0700
-@@ -983,7 +983,7 @@ receive_chars(struct uart_8250_port *up,
- 		if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
- 			tty->flip.work.func((void *)tty);
- 			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
--				return; // if TTY_DONT_FLIP is set
-+				return;	/* if TTY_DONT_FLIP is set */
- 		}
- 		ch = serial_inp(up, UART_RX);
- 		*tty->flip.char_buf_ptr = ch;
-@@ -1348,12 +1348,21 @@ static void serial8250_break_ctl(struct 
- 	spin_unlock_irqrestore(&up->port.lock, flags);
- }
- 
-+#ifdef CONFIG_KGDB
-+static int kgdb_irq = -1;
-+#endif
-+
- static int serial8250_startup(struct uart_port *port)
- {
- 	struct uart_8250_port *up = (struct uart_8250_port *)port;
- 	unsigned long flags;
- 	int retval;
- 
-+#ifdef CONFIG_KGDB
-+	if (up->port.irq == kgdb_irq)
-+		return -EBUSY;
-+#endif
-+
- 	up->capabilities = uart_config[up->port.type].flags;
- 	up->mcr = 0;
- 
-@@ -1990,6 +1999,10 @@ serial8250_register_ports(struct uart_dr
- 	for (i = 0; i < UART_NR; i++) {
- 		struct uart_8250_port *up = &serial8250_ports[i];
- 
-+#ifdef CONFIG_KGDB
-+		if (up->port.irq == kgdb_irq)
-+			up->port.kgdb = 1;
-+#endif
- 		up->port.line = i;
- 		up->port.ops = &serial8250_pops;
- 		up->port.dev = dev;
-@@ -2376,6 +2389,31 @@ void serial8250_unregister_port(int line
- }
- EXPORT_SYMBOL(serial8250_unregister_port);
- 
-+#ifdef CONFIG_KGDB
-+/*
-+ * Find all the ports using the given irq and shut them down.
-+ * Result should be that the irq will be released.
-+ */
-+void shutdown_for_kgdb(struct async_struct * info)
-+{
-+        int irq = info->state->irq;
-+        struct uart_8250_port *up;
-+	int ttyS;
-+
-+	kgdb_irq = irq;			/* save for later init */
-+	for (ttyS = 0; ttyS < UART_NR; ttyS++){
-+		up =  &serial8250_ports[ttyS];
-+		if (up->port.irq == irq && (irq_lists + irq)->head) {
-+#ifdef CONFIG_DEBUG_SPINLOCK   /* ugly business... */
-+			if(up->port.lock.magic != SPINLOCK_MAGIC)
-+				spin_lock_init(&up->port.lock);
-+#endif
-+			serial8250_shutdown(&up->port);
-+		}
-+        }
-+}
-+#endif	/* CONFIG_KGDB */
-+
- static int __init serial8250_init(void)
- {
- 	int ret, i;
-diff -puN drivers/serial/serial_core.c~kgdb-ga drivers/serial/serial_core.c
---- 25/drivers/serial/serial_core.c~kgdb-ga	2004-10-21 14:54:15.278600792 -0700
-+++ 25-akpm/drivers/serial/serial_core.c	2004-10-21 14:54:15.330592888 -0700
-@@ -1976,6 +1976,11 @@ uart_configure_port(struct uart_driver *
- {
- 	unsigned int flags;
- 
-+#ifdef CONFIG_KGDB
-+	if (port->kgdb)
-+		return;
-+#endif
-+
- 	/*
- 	 * If there isn't a port here, don't do anything further.
- 	 */
-diff -puN include/asm-i386/bugs.h~kgdb-ga include/asm-i386/bugs.h
---- 25/include/asm-i386/bugs.h~kgdb-ga	2004-10-21 14:54:15.279600640 -0700
-+++ 25-akpm/include/asm-i386/bugs.h	2004-10-21 14:54:15.331592736 -0700
-@@ -1,11 +1,11 @@
- /*
-  *  include/asm-i386/bugs.h
-  *
-- *  Copyright (C) 1994  Linus Torvalds
-+ *  Copyright (C) 1994	Linus Torvalds
-  *
-  *  Cyrix stuff, June 1998 by:
-  *	- Rafael R. Reilova (moved everything from head.S),
-- *        <rreilova@ececs.uc.edu>
-+ *	  <rreilova@ececs.uc.edu>
-  *	- Channing Corn (tests & fixes),
-  *	- Andrew D. Balsa (code cleanup).
-  *
-@@ -25,7 +25,20 @@
- #include <asm/processor.h>
- #include <asm/i387.h>
- #include <asm/msr.h>
--
-+#ifdef CONFIG_KGDB
-+/*
-+ * Provied the command line "gdb" initial break
-+ */
-+int __init kgdb_initial_break(char * str)
-+{
-+	if (*str == '\0'){
-+		breakpoint();
-+		return 1;
-+	}
-+	return 0;
-+}
-+__setup("gdb",kgdb_initial_break);
-+#endif
- static int __init no_halt(char *s)
- {
- 	boot_cpu_data.hlt_works_ok = 0;
-@@ -140,7 +153,7 @@ static void __init check_popad(void)
- 	  : "ecx", "edi" );
- 	/* If this fails, it means that any user program may lock the CPU hard. Too bad. */
- 	if (res != 12345678) printk( "Buggy.\n" );
--		        else printk( "OK.\n" );
-+			else printk( "OK.\n" );
- #endif
- }
- 
-diff -puN /dev/null include/asm-i386/kgdb.h
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/include/asm-i386/kgdb.h	2004-10-21 14:54:15.331592736 -0700
-@@ -0,0 +1,59 @@
-+#ifndef __KGDB
-+#define __KGDB
-+
-+/*
-+ * This file should not include ANY others.  This makes it usable
-+ * most anywhere without the fear of include order or inclusion.
-+ * Make it so!
-+ *
-+ * This file may be included all the time.  It is only active if
-+ * CONFIG_KGDB is defined, otherwise it stubs out all the macros
-+ * and entry points.
-+ */
-+#if defined(CONFIG_KGDB) && !defined(__ASSEMBLY__)
-+
-+extern void breakpoint(void);
-+#define INIT_KGDB_INTS kgdb_enable_ints()
-+
-+#ifndef BREAKPOINT
-+#define BREAKPOINT   asm("   int $3")
-+#endif
-+/*
-+ * GDB debug stub (or any debug stub) can point the 'linux_debug_hook'
-+ * pointer to its routine and it will be entered as the first thing
-+ * when a trap occurs.
-+ *
-+ * Return values are, at present, undefined.
-+ *
-+ * The debug hook routine does not necessarily return to its caller.
-+ * It has the register image and thus may choose to resume execution
-+ * anywhere it pleases.
-+ */
-+struct pt_regs;
-+
-+extern int kgdb_handle_exception(int trapno,
-+				 int signo, int err_code, struct pt_regs *regs);
-+extern int in_kgdb(struct pt_regs *regs);
-+
-+#ifdef CONFIG_KGDB_TS
-+void kgdb_tstamp(int line, char *source, int data0, int data1);
-+/*
-+ * This is the time stamp function.  The macro adds the source info and
-+ * does a cast on the data to allow most any 32-bit value.
-+ */
-+
-+#define kgdb_ts(data0,data1) kgdb_tstamp(__LINE__,__FILE__,(int)data0,(int)data1)
-+#else
-+#define kgdb_ts(data0,data1)
-+#endif
-+#else				/* CONFIG_KGDB  && ! __ASSEMBLY__ ,stubs follow... */
-+#ifndef BREAKPOINT
-+#define BREAKPOINT
-+#endif
-+#define kgdb_ts(data0,data1)
-+#define in_kgdb
-+#define kgdb_handle_exception
-+#define breakpoint
-+#define INIT_KGDB_INTS
-+#endif
-+#endif				/* __KGDB */
-diff -puN /dev/null include/asm-i386/kgdb_local.h
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/include/asm-i386/kgdb_local.h	2004-10-21 14:54:15.332592584 -0700
-@@ -0,0 +1,102 @@
-+#ifndef __KGDB_LOCAL
-+#define ___KGDB_LOCAL
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <linux/serial.h>
-+#include <linux/serialP.h>
-+#include <linux/spinlock.h>
-+#include <asm/processor.h>
-+#include <asm/msr.h>
-+#include <asm/kgdb.h>
-+
-+#define PORT 0x3f8
-+#ifdef CONFIG_KGDB_PORT
-+#undef PORT
-+#define PORT CONFIG_KGDB_PORT
-+#endif
-+#define IRQ 4
-+#ifdef CONFIG_KGDB_IRQ
-+#undef IRQ
-+#define IRQ CONFIG_KGDB_IRQ
-+#endif
-+#define SB_CLOCK 1843200
-+#define SB_BASE (SB_CLOCK/16)
-+#define SB_BAUD9600 SB_BASE/9600
-+#define SB_BAUD192  SB_BASE/19200
-+#define SB_BAUD384  SB_BASE/38400
-+#define SB_BAUD576  SB_BASE/57600
-+#define SB_BAUD1152 SB_BASE/115200
-+#ifdef CONFIG_KGDB_9600BAUD
-+#define SB_BAUD SB_BAUD9600
-+#endif
-+#ifdef CONFIG_KGDB_19200BAUD
-+#define SB_BAUD SB_BAUD192
-+#endif
-+#ifdef CONFIG_KGDB_38400BAUD
-+#define SB_BAUD SB_BAUD384
-+#endif
-+#ifdef CONFIG_KGDB_57600BAUD
-+#define SB_BAUD SB_BAUD576
-+#endif
-+#ifdef CONFIG_KGDB_115200BAUD
-+#define SB_BAUD SB_BAUD1152
-+#endif
-+#ifndef SB_BAUD
-+#define SB_BAUD SB_BAUD1152	/* Start with this if not given */
-+#endif
-+
-+#ifndef CONFIG_X86_TSC
-+#undef rdtsc
-+#define rdtsc(a,b) if (a++ > 10000){a = 0; b++;}
-+#undef rdtscll
-+#define rdtscll(s) s++
-+#endif
-+
-+#ifdef _raw_read_unlock		/* must use a name that is "define"ed, not an inline */
-+#undef spin_lock
-+#undef spin_trylock
-+#undef spin_unlock
-+#define spin_lock	 _raw_spin_lock
-+#define spin_trylock	 _raw_spin_trylock
-+#define spin_unlock	 _raw_spin_unlock
-+#else
-+#endif
-+#undef spin_unlock_wait
-+#define spin_unlock_wait(x)  do { cpu_relax(); barrier();} \
-+                                     while(spin_is_locked(x))
-+
-+#define SB_IER 1
-+#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
-+
-+#define FLAGS 0
-+#define SB_STATE { \
-+     magic: SSTATE_MAGIC, \
-+     baud_base: SB_BASE,  \
-+     port:      PORT,     \
-+     irq:       IRQ,      \
-+     flags:     FLAGS,    \
-+     custom_divisor:SB_BAUD}
-+#define SB_INFO  { \
-+      magic: SERIAL_MAGIC, \
-+      port:  PORT,0,FLAGS, \
-+      state: &state,       \
-+      tty:   (struct tty_struct *)&state, \
-+      IER:   SB_IER,       \
-+      MCR:   SB_MCR}
-+extern void putDebugChar(int);
-+/* RTAI support needs us to really stop/start interrupts */
-+
-+#define kgdb_sti() __asm__ __volatile__("sti": : :"memory")
-+#define kgdb_cli() __asm__ __volatile__("cli": : :"memory")
-+#define kgdb_local_save_flags(x) __asm__ __volatile__(\
-+                                   "pushfl ; popl %0":"=g" (x): /* no input */)
-+#define kgdb_local_irq_restore(x) __asm__ __volatile__(\
-+                                   "pushl %0 ; popfl": \
-+                                     /* no output */ :"g" (x):"memory", "cc")
-+#define kgdb_local_irq_save(x) kgdb_local_save_flags(x); kgdb_cli()
-+
-+#ifdef CONFIG_SERIAL
-+extern void shutdown_for_kgdb(struct async_struct *info);
-+#endif
-+#define INIT_KDEBUG putDebugChar("+");
-+#endif				/* __KGDB_LOCAL */
-diff -puN include/linux/config.h~kgdb-ga include/linux/config.h
---- 25/include/linux/config.h~kgdb-ga	2004-10-21 14:54:15.281600336 -0700
-+++ 25-akpm/include/linux/config.h	2004-10-21 14:54:15.332592584 -0700
-@@ -2,6 +2,9 @@
- #define _LINUX_CONFIG_H
- 
- #include <linux/autoconf.h>
-+#if defined(__i386__) && !defined(IN_BOOTLOADER)
-+#include <asm/kgdb.h>
-+#endif
- #if !defined (__KERNEL__) && !defined(__KERNGLUE__)
- #error including kernel header in userspace; use the glibc headers instead!
- #endif
-diff -puN /dev/null include/linux/dwarf2.h
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/include/linux/dwarf2.h	2004-10-21 14:54:15.336591976 -0700
-@@ -0,0 +1,738 @@
-+/* Declarations and definitions of codes relating to the DWARF2 symbolic
-+   debugging information format.
-+   Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002
-+   Free Software Foundation, Inc.
-+
-+   Written by Gary Funck (gary@intrepid.com) The Ada Joint Program
-+   Office (AJPO), Florida State Unviversity and Silicon Graphics Inc.
-+   provided support for this effort -- June 21, 1995.
-+
-+   Derived from the DWARF 1 implementation written by Ron Guilmette
-+   (rfg@netcom.com), November 1990.
-+
-+   This file is part of GCC.
-+
-+   GCC 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.
-+
-+   GCC 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 GCC; see the file COPYING.  If not, write to the Free
-+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-+   02111-1307, USA.  */
-+
-+/* This file is derived from the DWARF specification (a public document)
-+   Revision 2.0.0 (July 27, 1993) developed by the UNIX International
-+   Programming Languages Special Interest Group (UI/PLSIG) and distributed
-+   by UNIX International.  Copies of this specification are available from
-+   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
-+
-+   This file also now contains definitions from the DWARF 3 specification.  */
-+
-+/* This file is shared between GCC and GDB, and should not contain
-+   prototypes.	*/
-+
-+#ifndef _ELF_DWARF2_H
-+#define _ELF_DWARF2_H
-+
-+/* Structure found in the .debug_line section.	*/
-+#ifndef __ASSEMBLY__
-+typedef struct
-+{
-+  unsigned char li_length	   [4];
-+  unsigned char li_version	   [2];
-+  unsigned char li_prologue_length [4];
-+  unsigned char li_min_insn_length [1];
-+  unsigned char li_default_is_stmt [1];
-+  unsigned char li_line_base	   [1];
-+  unsigned char li_line_range	   [1];
-+  unsigned char li_opcode_base	   [1];
-+}
-+DWARF2_External_LineInfo;
-+
-+typedef struct
-+{
-+  unsigned long  li_length;
-+  unsigned short li_version;
-+  unsigned int	 li_prologue_length;
-+  unsigned char  li_min_insn_length;
-+  unsigned char  li_default_is_stmt;
-+  int		 li_line_base;
-+  unsigned char  li_line_range;
-+  unsigned char  li_opcode_base;
-+}
-+DWARF2_Internal_LineInfo;
-+
-+/* Structure found in .debug_pubnames section.	*/
-+typedef struct
-+{
-+  unsigned char pn_length  [4];
-+  unsigned char pn_version [2];
-+  unsigned char pn_offset  [4];
-+  unsigned char pn_size    [4];
-+}
-+DWARF2_External_PubNames;
-+
-+typedef struct
-+{
-+  unsigned long  pn_length;
-+  unsigned short pn_version;
-+  unsigned long  pn_offset;
-+  unsigned long  pn_size;
-+}
-+DWARF2_Internal_PubNames;
-+
-+/* Structure found in .debug_info section.  */
-+typedef struct
-+{
-+  unsigned char  cu_length	  [4];
-+  unsigned char  cu_version	  [2];
-+  unsigned char  cu_abbrev_offset [4];
-+  unsigned char  cu_pointer_size  [1];
-+}
-+DWARF2_External_CompUnit;
-+
-+typedef struct
-+{
-+  unsigned long  cu_length;
-+  unsigned short cu_version;
-+  unsigned long  cu_abbrev_offset;
-+  unsigned char  cu_pointer_size;
-+}
-+DWARF2_Internal_CompUnit;
-+
-+typedef struct
-+{
-+  unsigned char  ar_length	 [4];
-+  unsigned char  ar_version	 [2];
-+  unsigned char  ar_info_offset  [4];
-+  unsigned char  ar_pointer_size [1];
-+  unsigned char  ar_segment_size [1];
-+}
-+DWARF2_External_ARange;
-+
-+typedef struct
-+{
-+  unsigned long  ar_length;
-+  unsigned short ar_version;
-+  unsigned long  ar_info_offset;
-+  unsigned char  ar_pointer_size;
-+  unsigned char  ar_segment_size;
-+}
-+DWARF2_Internal_ARange;
-+
-+#define ENUM(name) enum name {
-+#define IF_NOT_ASM(a) a
-+#define COMMA ,
-+#else
-+#define ENUM(name)
-+#define IF_NOT_ASM(a)
-+#define COMMA
-+
-+#endif
-+
-+/* Tag names and codes.  */
-+ENUM(dwarf_tag)
-+
-+    DW_TAG_padding = 0x00 COMMA
-+    DW_TAG_array_type = 0x01 COMMA
-+    DW_TAG_class_type = 0x02 COMMA
-+    DW_TAG_entry_point = 0x03 COMMA
-+    DW_TAG_enumeration_type = 0x04 COMMA
-+    DW_TAG_formal_parameter = 0x05 COMMA
-+    DW_TAG_imported_declaration = 0x08 COMMA
-+    DW_TAG_label = 0x0a COMMA
-+    DW_TAG_lexical_block = 0x0b COMMA
-+    DW_TAG_member = 0x0d COMMA
-+    DW_TAG_pointer_type = 0x0f COMMA
-+    DW_TAG_reference_type = 0x10 COMMA
-+    DW_TAG_compile_unit = 0x11 COMMA
-+    DW_TAG_string_type = 0x12 COMMA
-+    DW_TAG_structure_type = 0x13 COMMA
-+    DW_TAG_subroutine_type = 0x15 COMMA
-+    DW_TAG_typedef = 0x16 COMMA
-+    DW_TAG_union_type = 0x17 COMMA
-+    DW_TAG_unspecified_parameters = 0x18 COMMA
-+    DW_TAG_variant = 0x19 COMMA
-+    DW_TAG_common_block = 0x1a COMMA
-+    DW_TAG_common_inclusion = 0x1b COMMA
-+    DW_TAG_inheritance = 0x1c COMMA
-+    DW_TAG_inlined_subroutine = 0x1d COMMA
-+    DW_TAG_module = 0x1e COMMA
-+    DW_TAG_ptr_to_member_type = 0x1f COMMA
-+    DW_TAG_set_type = 0x20 COMMA
-+    DW_TAG_subrange_type = 0x21 COMMA
-+    DW_TAG_with_stmt = 0x22 COMMA
-+    DW_TAG_access_declaration = 0x23 COMMA
-+    DW_TAG_base_type = 0x24 COMMA
-+    DW_TAG_catch_block = 0x25 COMMA
-+    DW_TAG_const_type = 0x26 COMMA
-+    DW_TAG_constant = 0x27 COMMA
-+    DW_TAG_enumerator = 0x28 COMMA
-+    DW_TAG_file_type = 0x29 COMMA
-+    DW_TAG_friend = 0x2a COMMA
-+    DW_TAG_namelist = 0x2b COMMA
-+    DW_TAG_namelist_item = 0x2c COMMA
-+    DW_TAG_packed_type = 0x2d COMMA
-+    DW_TAG_subprogram = 0x2e COMMA
-+    DW_TAG_template_type_param = 0x2f COMMA
-+    DW_TAG_template_value_param = 0x30 COMMA
-+    DW_TAG_thrown_type = 0x31 COMMA
-+    DW_TAG_try_block = 0x32 COMMA
-+    DW_TAG_variant_part = 0x33 COMMA
-+    DW_TAG_variable = 0x34 COMMA
-+    DW_TAG_volatile_type = 0x35 COMMA
-+    /* DWARF 3.  */
-+    DW_TAG_dwarf_procedure = 0x36 COMMA
-+    DW_TAG_restrict_type = 0x37 COMMA
-+    DW_TAG_interface_type = 0x38 COMMA
-+    DW_TAG_namespace = 0x39 COMMA
-+    DW_TAG_imported_module = 0x3a COMMA
-+    DW_TAG_unspecified_type = 0x3b COMMA
-+    DW_TAG_partial_unit = 0x3c COMMA
-+    DW_TAG_imported_unit = 0x3d COMMA
-+    /* SGI/MIPS Extensions.  */
-+    DW_TAG_MIPS_loop = 0x4081 COMMA
-+    /* GNU extensions.	*/
-+    DW_TAG_format_label = 0x4101 COMMA	/* For FORTRAN 77 and Fortran 90.  */
-+    DW_TAG_function_template = 0x4102 COMMA	/* For C++.  */
-+    DW_TAG_class_template = 0x4103 COMMA	/* For C++.  */
-+    DW_TAG_GNU_BINCL = 0x4104 COMMA
-+    DW_TAG_GNU_EINCL = 0x4105 COMMA
-+    /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
-+    DW_TAG_upc_shared_type = 0x8765 COMMA
-+    DW_TAG_upc_strict_type = 0x8766 COMMA
-+    DW_TAG_upc_relaxed_type = 0x8767
-+IF_NOT_ASM(};)
-+
-+#define DW_TAG_lo_user	0x4080
-+#define DW_TAG_hi_user	0xffff
-+
-+/* Flag that tells whether entry has a child or not.  */
-+#define DW_children_no	 0
-+#define	DW_children_yes  1
-+
-+/* Form names and codes.  */
-+ENUM(dwarf_form)
-+
-+    DW_FORM_addr = 0x01 COMMA
-+    DW_FORM_block2 = 0x03 COMMA
-+    DW_FORM_block4 = 0x04 COMMA
-+    DW_FORM_data2 = 0x05 COMMA
-+    DW_FORM_data4 = 0x06 COMMA
-+    DW_FORM_data8 = 0x07 COMMA
-+    DW_FORM_string = 0x08 COMMA
-+    DW_FORM_block = 0x09 COMMA
-+    DW_FORM_block1 = 0x0a COMMA
-+    DW_FORM_data1 = 0x0b COMMA
-+    DW_FORM_flag = 0x0c COMMA
-+    DW_FORM_sdata = 0x0d COMMA
-+    DW_FORM_strp = 0x0e COMMA
-+    DW_FORM_udata = 0x0f COMMA
-+    DW_FORM_ref_addr = 0x10 COMMA
-+    DW_FORM_ref1 = 0x11 COMMA
-+    DW_FORM_ref2 = 0x12 COMMA
-+    DW_FORM_ref4 = 0x13 COMMA
-+    DW_FORM_ref8 = 0x14 COMMA
-+    DW_FORM_ref_udata = 0x15 COMMA
-+    DW_FORM_indirect = 0x16
-+IF_NOT_ASM(};)
-+
-+/* Attribute names and codes.  */
-+
-+ENUM(dwarf_attribute)
-+
-+    DW_AT_sibling = 0x01 COMMA
-+    DW_AT_location = 0x02 COMMA
-+    DW_AT_name = 0x03 COMMA
-+    DW_AT_ordering = 0x09 COMMA
-+    DW_AT_subscr_data = 0x0a COMMA
-+    DW_AT_byte_size = 0x0b COMMA
-+    DW_AT_bit_offset = 0x0c COMMA
-+    DW_AT_bit_size = 0x0d COMMA
-+    DW_AT_element_list = 0x0f COMMA
-+    DW_AT_stmt_list = 0x10 COMMA
-+    DW_AT_low_pc = 0x11 COMMA
-+    DW_AT_high_pc = 0x12 COMMA
-+    DW_AT_language = 0x13 COMMA
-+    DW_AT_member = 0x14 COMMA
-+    DW_AT_discr = 0x15 COMMA
-+    DW_AT_discr_value = 0x16 COMMA
-+    DW_AT_visibility = 0x17 COMMA
-+    DW_AT_import = 0x18 COMMA
-+    DW_AT_string_length = 0x19 COMMA
-+    DW_AT_common_reference = 0x1a COMMA
-+    DW_AT_comp_dir = 0x1b COMMA
-+    DW_AT_const_value = 0x1c COMMA
-+    DW_AT_containing_type = 0x1d COMMA
-+    DW_AT_default_value = 0x1e COMMA
-+    DW_AT_inline = 0x20 COMMA
-+    DW_AT_is_optional = 0x21 COMMA
-+    DW_AT_lower_bound = 0x22 COMMA
-+    DW_AT_producer = 0x25 COMMA
-+    DW_AT_prototyped = 0x27 COMMA
-+    DW_AT_return_addr = 0x2a COMMA
-+    DW_AT_start_scope = 0x2c COMMA
-+    DW_AT_stride_size = 0x2e COMMA
-+    DW_AT_upper_bound = 0x2f COMMA
-+    DW_AT_abstract_origin = 0x31 COMMA
-+    DW_AT_accessibility = 0x32 COMMA
-+    DW_AT_address_class = 0x33 COMMA
-+    DW_AT_artificial = 0x34 COMMA
-+    DW_AT_base_types = 0x35 COMMA
-+    DW_AT_calling_convention = 0x36 COMMA
-+    DW_AT_count = 0x37 COMMA
-+    DW_AT_data_member_location = 0x38 COMMA
-+    DW_AT_decl_column = 0x39 COMMA
-+    DW_AT_decl_file = 0x3a COMMA
-+    DW_AT_decl_line = 0x3b COMMA
-+    DW_AT_declaration = 0x3c COMMA
-+    DW_AT_discr_list = 0x3d COMMA
-+    DW_AT_encoding = 0x3e COMMA
-+    DW_AT_external = 0x3f COMMA
-+    DW_AT_frame_base = 0x40 COMMA
-+    DW_AT_friend = 0x41 COMMA
-+    DW_AT_identifier_case = 0x42 COMMA
-+    DW_AT_macro_info = 0x43 COMMA
-+    DW_AT_namelist_items = 0x44 COMMA
-+    DW_AT_priority = 0x45 COMMA
-+    DW_AT_segment = 0x46 COMMA
-+    DW_AT_specification = 0x47 COMMA
-+    DW_AT_static_link = 0x48 COMMA
-+    DW_AT_type = 0x49 COMMA
-+    DW_AT_use_location = 0x4a COMMA
-+    DW_AT_variable_parameter = 0x4b COMMA
-+    DW_AT_virtuality = 0x4c COMMA
-+    DW_AT_vtable_elem_location = 0x4d COMMA
-+    /* DWARF 3 values.	*/
-+    DW_AT_allocated	= 0x4e COMMA
-+    DW_AT_associated	= 0x4f COMMA
-+    DW_AT_data_location = 0x50 COMMA
-+    DW_AT_stride	= 0x51 COMMA
-+    DW_AT_entry_pc	= 0x52 COMMA
-+    DW_AT_use_UTF8	= 0x53 COMMA
-+    DW_AT_extension	= 0x54 COMMA
-+    DW_AT_ranges	= 0x55 COMMA
-+    DW_AT_trampoline	= 0x56 COMMA
-+    DW_AT_call_column	= 0x57 COMMA
-+    DW_AT_call_file	= 0x58 COMMA
-+    DW_AT_call_line	= 0x59 COMMA
-+    /* SGI/MIPS extensions.  */
-+    DW_AT_MIPS_fde = 0x2001 COMMA
-+    DW_AT_MIPS_loop_begin = 0x2002 COMMA
-+    DW_AT_MIPS_tail_loop_begin = 0x2003 COMMA
-+    DW_AT_MIPS_epilog_begin = 0x2004 COMMA
-+    DW_AT_MIPS_loop_unroll_factor = 0x2005 COMMA
-+    DW_AT_MIPS_software_pipeline_depth = 0x2006 COMMA
-+    DW_AT_MIPS_linkage_name = 0x2007 COMMA
-+    DW_AT_MIPS_stride = 0x2008 COMMA
-+    DW_AT_MIPS_abstract_name = 0x2009 COMMA
-+    DW_AT_MIPS_clone_origin = 0x200a COMMA
-+    DW_AT_MIPS_has_inlines = 0x200b COMMA
-+    /* GNU extensions.	*/
-+    DW_AT_sf_names   = 0x2101 COMMA
-+    DW_AT_src_info   = 0x2102 COMMA
-+    DW_AT_mac_info   = 0x2103 COMMA
-+    DW_AT_src_coords = 0x2104 COMMA
-+    DW_AT_body_begin = 0x2105 COMMA
-+    DW_AT_body_end   = 0x2106 COMMA
-+    DW_AT_GNU_vector = 0x2107 COMMA
-+    /* VMS extensions.	*/
-+    DW_AT_VMS_rtnbeg_pd_address = 0x2201 COMMA
-+    /* UPC extension.  */
-+    DW_AT_upc_threads_scaled = 0x3210
-+IF_NOT_ASM(};)
-+
-+#define DW_AT_lo_user	0x2000	/* Implementation-defined range start.	*/
-+#define DW_AT_hi_user	0x3ff0	/* Implementation-defined range end.  */
-+
-+/* Location atom names and codes.  */
-+ENUM(dwarf_location_atom)
-+
-+    DW_OP_addr = 0x03 COMMA
-+    DW_OP_deref = 0x06 COMMA
-+    DW_OP_const1u = 0x08 COMMA
-+    DW_OP_const1s = 0x09 COMMA
-+    DW_OP_const2u = 0x0a COMMA
-+    DW_OP_const2s = 0x0b COMMA
-+    DW_OP_const4u = 0x0c COMMA
-+    DW_OP_const4s = 0x0d COMMA
-+    DW_OP_const8u = 0x0e COMMA
-+    DW_OP_const8s = 0x0f COMMA
-+    DW_OP_constu = 0x10 COMMA
-+    DW_OP_consts = 0x11 COMMA
-+    DW_OP_dup = 0x12 COMMA
-+    DW_OP_drop = 0x13 COMMA
-+    DW_OP_over = 0x14 COMMA
-+    DW_OP_pick = 0x15 COMMA
-+    DW_OP_swap = 0x16 COMMA
-+    DW_OP_rot = 0x17 COMMA
-+    DW_OP_xderef = 0x18 COMMA
-+    DW_OP_abs = 0x19 COMMA
-+    DW_OP_and = 0x1a COMMA
-+    DW_OP_div = 0x1b COMMA
-+    DW_OP_minus = 0x1c COMMA
-+    DW_OP_mod = 0x1d COMMA
-+    DW_OP_mul = 0x1e COMMA
-+    DW_OP_neg = 0x1f COMMA
-+    DW_OP_not = 0x20 COMMA
-+    DW_OP_or = 0x21 COMMA
-+    DW_OP_plus = 0x22 COMMA
-+    DW_OP_plus_uconst = 0x23 COMMA
-+    DW_OP_shl = 0x24 COMMA
-+    DW_OP_shr = 0x25 COMMA
-+    DW_OP_shra = 0x26 COMMA
-+    DW_OP_xor = 0x27 COMMA
-+    DW_OP_bra = 0x28 COMMA
-+    DW_OP_eq = 0x29 COMMA
-+    DW_OP_ge = 0x2a COMMA
-+    DW_OP_gt = 0x2b COMMA
-+    DW_OP_le = 0x2c COMMA
-+    DW_OP_lt = 0x2d COMMA
-+    DW_OP_ne = 0x2e COMMA
-+    DW_OP_skip = 0x2f COMMA
-+    DW_OP_lit0 = 0x30 COMMA
-+    DW_OP_lit1 = 0x31 COMMA
-+    DW_OP_lit2 = 0x32 COMMA
-+    DW_OP_lit3 = 0x33 COMMA
-+    DW_OP_lit4 = 0x34 COMMA
-+    DW_OP_lit5 = 0x35 COMMA
-+    DW_OP_lit6 = 0x36 COMMA
-+    DW_OP_lit7 = 0x37 COMMA
-+    DW_OP_lit8 = 0x38 COMMA
-+    DW_OP_lit9 = 0x39 COMMA
-+    DW_OP_lit10 = 0x3a COMMA
-+    DW_OP_lit11 = 0x3b COMMA
-+    DW_OP_lit12 = 0x3c COMMA
-+    DW_OP_lit13 = 0x3d COMMA
-+    DW_OP_lit14 = 0x3e COMMA
-+    DW_OP_lit15 = 0x3f COMMA
-+    DW_OP_lit16 = 0x40 COMMA
-+    DW_OP_lit17 = 0x41 COMMA
-+    DW_OP_lit18 = 0x42 COMMA
-+    DW_OP_lit19 = 0x43 COMMA
-+    DW_OP_lit20 = 0x44 COMMA
-+    DW_OP_lit21 = 0x45 COMMA
-+    DW_OP_lit22 = 0x46 COMMA
-+    DW_OP_lit23 = 0x47 COMMA
-+    DW_OP_lit24 = 0x48 COMMA
-+    DW_OP_lit25 = 0x49 COMMA
-+    DW_OP_lit26 = 0x4a COMMA
-+    DW_OP_lit27 = 0x4b COMMA
-+    DW_OP_lit28 = 0x4c COMMA
-+    DW_OP_lit29 = 0x4d COMMA
-+    DW_OP_lit30 = 0x4e COMMA
-+    DW_OP_lit31 = 0x4f COMMA
-+    DW_OP_reg0 = 0x50 COMMA
-+    DW_OP_reg1 = 0x51 COMMA
-+    DW_OP_reg2 = 0x52 COMMA
-+    DW_OP_reg3 = 0x53 COMMA
-+    DW_OP_reg4 = 0x54 COMMA
-+    DW_OP_reg5 = 0x55 COMMA
-+    DW_OP_reg6 = 0x56 COMMA
-+    DW_OP_reg7 = 0x57 COMMA
-+    DW_OP_reg8 = 0x58 COMMA
-+    DW_OP_reg9 = 0x59 COMMA
-+    DW_OP_reg10 = 0x5a COMMA
-+    DW_OP_reg11 = 0x5b COMMA
-+    DW_OP_reg12 = 0x5c COMMA
-+    DW_OP_reg13 = 0x5d COMMA
-+    DW_OP_reg14 = 0x5e COMMA
-+    DW_OP_reg15 = 0x5f COMMA
-+    DW_OP_reg16 = 0x60 COMMA
-+    DW_OP_reg17 = 0x61 COMMA
-+    DW_OP_reg18 = 0x62 COMMA
-+    DW_OP_reg19 = 0x63 COMMA
-+    DW_OP_reg20 = 0x64 COMMA
-+    DW_OP_reg21 = 0x65 COMMA
-+    DW_OP_reg22 = 0x66 COMMA
-+    DW_OP_reg23 = 0x67 COMMA
-+    DW_OP_reg24 = 0x68 COMMA
-+    DW_OP_reg25 = 0x69 COMMA
-+    DW_OP_reg26 = 0x6a COMMA
-+    DW_OP_reg27 = 0x6b COMMA
-+    DW_OP_reg28 = 0x6c COMMA
-+    DW_OP_reg29 = 0x6d COMMA
-+    DW_OP_reg30 = 0x6e COMMA
-+    DW_OP_reg31 = 0x6f COMMA
-+    DW_OP_breg0 = 0x70 COMMA
-+    DW_OP_breg1 = 0x71 COMMA
-+    DW_OP_breg2 = 0x72 COMMA
-+    DW_OP_breg3 = 0x73 COMMA
-+    DW_OP_breg4 = 0x74 COMMA
-+    DW_OP_breg5 = 0x75 COMMA
-+    DW_OP_breg6 = 0x76 COMMA
-+    DW_OP_breg7 = 0x77 COMMA
-+    DW_OP_breg8 = 0x78 COMMA
-+    DW_OP_breg9 = 0x79 COMMA
-+    DW_OP_breg10 = 0x7a COMMA
-+    DW_OP_breg11 = 0x7b COMMA
-+    DW_OP_breg12 = 0x7c COMMA
-+    DW_OP_breg13 = 0x7d COMMA
-+    DW_OP_breg14 = 0x7e COMMA
-+    DW_OP_breg15 = 0x7f COMMA
-+    DW_OP_breg16 = 0x80 COMMA
-+    DW_OP_breg17 = 0x81 COMMA
-+    DW_OP_breg18 = 0x82 COMMA
-+    DW_OP_breg19 = 0x83 COMMA
-+    DW_OP_breg20 = 0x84 COMMA
-+    DW_OP_breg21 = 0x85 COMMA
-+    DW_OP_breg22 = 0x86 COMMA
-+    DW_OP_breg23 = 0x87 COMMA
-+    DW_OP_breg24 = 0x88 COMMA
-+    DW_OP_breg25 = 0x89 COMMA
-+    DW_OP_breg26 = 0x8a COMMA
-+    DW_OP_breg27 = 0x8b COMMA
-+    DW_OP_breg28 = 0x8c COMMA
-+    DW_OP_breg29 = 0x8d COMMA
-+    DW_OP_breg30 = 0x8e COMMA
-+    DW_OP_breg31 = 0x8f COMMA
-+    DW_OP_regx = 0x90 COMMA
-+    DW_OP_fbreg = 0x91 COMMA
-+    DW_OP_bregx = 0x92 COMMA
-+    DW_OP_piece = 0x93 COMMA
-+    DW_OP_deref_size = 0x94 COMMA
-+    DW_OP_xderef_size = 0x95 COMMA
-+    DW_OP_nop = 0x96 COMMA
-+    /* DWARF 3 extensions.  */
-+    DW_OP_push_object_address = 0x97 COMMA
-+    DW_OP_call2 = 0x98 COMMA
-+    DW_OP_call4 = 0x99 COMMA
-+    DW_OP_call_ref = 0x9a COMMA
-+    /* GNU extensions.	*/
-+    DW_OP_GNU_push_tls_address = 0xe0
-+IF_NOT_ASM(};)
-+
-+#define DW_OP_lo_user	0xe0	/* Implementation-defined range start.	*/
-+#define DW_OP_hi_user	0xff	/* Implementation-defined range end.  */
-+
-+/* Type encodings.  */
-+ENUM(dwarf_type)
-+
-+    DW_ATE_void = 0x0 COMMA
-+    DW_ATE_address = 0x1 COMMA
-+    DW_ATE_boolean = 0x2 COMMA
-+    DW_ATE_complex_float = 0x3 COMMA
-+    DW_ATE_float = 0x4 COMMA
-+    DW_ATE_signed = 0x5 COMMA
-+    DW_ATE_signed_char = 0x6 COMMA
-+    DW_ATE_unsigned = 0x7 COMMA
-+    DW_ATE_unsigned_char = 0x8 COMMA
-+    /* DWARF 3.  */
-+    DW_ATE_imaginary_float = 0x9
-+IF_NOT_ASM(};)
-+
-+#define	DW_ATE_lo_user 0x80
-+#define	DW_ATE_hi_user 0xff
-+
-+/* Array ordering names and codes.  */
-+ENUM(dwarf_array_dim_ordering)
-+
-+    DW_ORD_row_major = 0 COMMA
-+    DW_ORD_col_major = 1
-+IF_NOT_ASM(};)
-+
-+/* Access attribute.  */
-+ENUM(dwarf_access_attribute)
-+
-+    DW_ACCESS_public = 1 COMMA
-+    DW_ACCESS_protected = 2 COMMA
-+    DW_ACCESS_private = 3
-+IF_NOT_ASM(};)
-+
-+/* Visibility.	*/
-+ENUM(dwarf_visibility_attribute)
-+
-+    DW_VIS_local = 1 COMMA
-+    DW_VIS_exported = 2 COMMA
-+    DW_VIS_qualified = 3
-+IF_NOT_ASM(};)
-+
-+/* Virtuality.	*/
-+ENUM(dwarf_virtuality_attribute)
-+
-+    DW_VIRTUALITY_none = 0 COMMA
-+    DW_VIRTUALITY_virtual = 1 COMMA
-+    DW_VIRTUALITY_pure_virtual = 2
-+IF_NOT_ASM(};)
-+
-+/* Case sensitivity.  */
-+ENUM(dwarf_id_case)
-+
-+    DW_ID_case_sensitive = 0 COMMA
-+    DW_ID_up_case = 1 COMMA
-+    DW_ID_down_case = 2 COMMA
-+    DW_ID_case_insensitive = 3
-+IF_NOT_ASM(};)
-+
-+/* Calling convention.	*/
-+ENUM(dwarf_calling_convention)
-+
-+    DW_CC_normal = 0x1 COMMA
-+    DW_CC_program = 0x2 COMMA
-+    DW_CC_nocall = 0x3
-+IF_NOT_ASM(};)
-+
-+#define DW_CC_lo_user 0x40
-+#define DW_CC_hi_user 0xff
-+
-+/* Inline attribute.  */
-+ENUM(dwarf_inline_attribute)
-+
-+    DW_INL_not_inlined = 0 COMMA
-+    DW_INL_inlined = 1 COMMA
-+    DW_INL_declared_not_inlined = 2 COMMA
-+    DW_INL_declared_inlined = 3
-+IF_NOT_ASM(};)
-+
-+/* Discriminant lists.	*/
-+ENUM(dwarf_discrim_list)
-+
-+    DW_DSC_label = 0 COMMA
-+    DW_DSC_range = 1
-+IF_NOT_ASM(};)
-+
-+/* Line number opcodes.  */
-+ENUM(dwarf_line_number_ops)
-+
-+    DW_LNS_extended_op = 0 COMMA
-+    DW_LNS_copy = 1 COMMA
-+    DW_LNS_advance_pc = 2 COMMA
-+    DW_LNS_advance_line = 3 COMMA
-+    DW_LNS_set_file = 4 COMMA
-+    DW_LNS_set_column = 5 COMMA
-+    DW_LNS_negate_stmt = 6 COMMA
-+    DW_LNS_set_basic_block = 7 COMMA
-+    DW_LNS_const_add_pc = 8 COMMA
-+    DW_LNS_fixed_advance_pc = 9 COMMA
-+    /* DWARF 3.  */
-+    DW_LNS_set_prologue_end = 10 COMMA
-+    DW_LNS_set_epilogue_begin = 11 COMMA
-+    DW_LNS_set_isa = 12
-+IF_NOT_ASM(};)
-+
-+/* Line number extended opcodes.  */
-+ENUM(dwarf_line_number_x_ops)
-+
-+    DW_LNE_end_sequence = 1 COMMA
-+    DW_LNE_set_address = 2 COMMA
-+    DW_LNE_define_file = 3
-+IF_NOT_ASM(};)
-+
-+/* Call frame information.  */
-+ENUM(dwarf_call_frame_info)
-+
-+    DW_CFA_advance_loc = 0x40 COMMA
-+    DW_CFA_offset = 0x80 COMMA
-+    DW_CFA_restore = 0xc0 COMMA
-+    DW_CFA_nop = 0x00 COMMA
-+    DW_CFA_set_loc = 0x01 COMMA
-+    DW_CFA_advance_loc1 = 0x02 COMMA
-+    DW_CFA_advance_loc2 = 0x03 COMMA
-+    DW_CFA_advance_loc4 = 0x04 COMMA
-+    DW_CFA_offset_extended = 0x05 COMMA
-+    DW_CFA_restore_extended = 0x06 COMMA
-+    DW_CFA_undefined = 0x07 COMMA
-+    DW_CFA_same_value = 0x08 COMMA
-+    DW_CFA_register = 0x09 COMMA
-+    DW_CFA_remember_state = 0x0a COMMA
-+    DW_CFA_restore_state = 0x0b COMMA
-+    DW_CFA_def_cfa = 0x0c COMMA
-+    DW_CFA_def_cfa_register = 0x0d COMMA
-+    DW_CFA_def_cfa_offset = 0x0e COMMA
-+
-+    /* DWARF 3.  */
-+    DW_CFA_def_cfa_expression = 0x0f COMMA
-+    DW_CFA_expression = 0x10 COMMA
-+    DW_CFA_offset_extended_sf = 0x11 COMMA
-+    DW_CFA_def_cfa_sf = 0x12 COMMA
-+    DW_CFA_def_cfa_offset_sf = 0x13 COMMA
-+
-+    /* SGI/MIPS specific.  */
-+    DW_CFA_MIPS_advance_loc8 = 0x1d COMMA
-+
-+    /* GNU extensions.	*/
-+    DW_CFA_GNU_window_save = 0x2d COMMA
-+    DW_CFA_GNU_args_size = 0x2e COMMA
-+    DW_CFA_GNU_negative_offset_extended = 0x2f
-+IF_NOT_ASM(};)
-+
-+#define DW_CIE_ID	  0xffffffff
-+#define DW_CIE_VERSION	  1
-+
-+#define DW_CFA_extended   0
-+#define DW_CFA_lo_user	  0x1c
-+#define DW_CFA_hi_user	  0x3f
-+
-+#define DW_CHILDREN_no		     0x00
-+#define DW_CHILDREN_yes		     0x01
-+
-+#define DW_ADDR_none		0
-+
-+/* Source language names and codes.  */
-+ENUM(dwarf_source_language)
-+
-+    DW_LANG_C89 = 0x0001 COMMA
-+    DW_LANG_C = 0x0002 COMMA
-+    DW_LANG_Ada83 = 0x0003 COMMA
-+    DW_LANG_C_plus_plus = 0x0004 COMMA
-+    DW_LANG_Cobol74 = 0x0005 COMMA
-+    DW_LANG_Cobol85 = 0x0006 COMMA
-+    DW_LANG_Fortran77 = 0x0007 COMMA
-+    DW_LANG_Fortran90 = 0x0008 COMMA
-+    DW_LANG_Pascal83 = 0x0009 COMMA
-+    DW_LANG_Modula2 = 0x000a COMMA
-+    DW_LANG_Java = 0x000b COMMA
-+    /* DWARF 3.  */
-+    DW_LANG_C99 = 0x000c COMMA
-+    DW_LANG_Ada95 = 0x000d COMMA
-+    DW_LANG_Fortran95 = 0x000e COMMA
-+    /* MIPS.  */
-+    DW_LANG_Mips_Assembler = 0x8001 COMMA
-+    /* UPC.  */
-+    DW_LANG_Upc = 0x8765
-+IF_NOT_ASM(};)
-+
-+#define DW_LANG_lo_user 0x8000	/* Implementation-defined range start.	*/
-+#define DW_LANG_hi_user 0xffff	/* Implementation-defined range start.	*/
-+
-+/* Names and codes for macro information.  */
-+ENUM(dwarf_macinfo_record_type)
-+
-+    DW_MACINFO_define = 1 COMMA
-+    DW_MACINFO_undef = 2 COMMA
-+    DW_MACINFO_start_file = 3 COMMA
-+    DW_MACINFO_end_file = 4 COMMA
-+    DW_MACINFO_vendor_ext = 255
-+IF_NOT_ASM(};)
-+
-+/* @@@ For use with GNU frame unwind information.  */
-+
-+#define DW_EH_PE_absptr		0x00
-+#define DW_EH_PE_omit		0xff
-+
-+#define DW_EH_PE_uleb128	0x01
-+#define DW_EH_PE_udata2		0x02
-+#define DW_EH_PE_udata4		0x03
-+#define DW_EH_PE_udata8		0x04
-+#define DW_EH_PE_sleb128	0x09
-+#define DW_EH_PE_sdata2		0x0A
-+#define DW_EH_PE_sdata4		0x0B
-+#define DW_EH_PE_sdata8		0x0C
-+#define DW_EH_PE_signed		0x08
-+
-+#define DW_EH_PE_pcrel		0x10
-+#define DW_EH_PE_textrel	0x20
-+#define DW_EH_PE_datarel	0x30
-+#define DW_EH_PE_funcrel	0x40
-+#define DW_EH_PE_aligned	0x50
-+
-+#define DW_EH_PE_indirect	0x80
-+
-+#endif /* _ELF_DWARF2_H */
-diff -puN /dev/null include/linux/dwarf2-lang.h
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/include/linux/dwarf2-lang.h	2004-10-21 14:54:15.337591824 -0700
-@@ -0,0 +1,132 @@
-+#ifndef DWARF2_LANG
-+#define DWARF2_LANG
-+#include <linux/dwarf2.h>
-+
-+/*
-+ * This 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 defines macros that allow generation of DWARF debug records
-+ * for asm files.  This file is platform independent.  Register numbers
-+ * (which are about the only thing that is platform dependent) are to be
-+ * supplied by a platform defined file.
-+ */
-+#define DWARF_preamble()	.section	.debug_frame,"",@progbits
-+/*
-+ * This macro starts a debug frame section.  The debug_frame describes
-+ * where to find the registers that the enclosing function saved on
-+ * entry.
-+ *
-+ * ORD is use by the label generator and should be the same as what is
-+ * passed to CFI_postamble.
-+ *
-+ * pc,	pc register gdb ordinal.
-+ *
-+ * code_align this is the factor used to define locations or regions
-+ * where the given definitions apply.  If you use labels to define these
-+ * this should be 1.
-+ *
-+ * data_align this is the factor used to define register offsets.  If
-+ * you use struct offset, this should be the size of the register in
-+ * bytes or the negative of that.  This is how it is used: you will
-+ * define a register as the reference register, say the stack pointer,
-+ * then you will say where a register is located relative to this
-+ * reference registers value, say 40 for register 3 (the gdb register
-+ * number).  The <40> will be multiplied by <data_align> to define the
-+ * byte offset of the given register (3, in this example).  So if your
-+ * <40> is the byte offset and the reference register points at the
-+ * begining, you would want 1 for the data_offset.  If <40> was the 40th
-+ * 4-byte element in that structure you would want 4.  And if your
-+ * reference register points at the end of the structure you would want
-+ * a negative data_align value(and you would have to do other math as
-+ * well).
-+ */
-+
-+#define CFI_preamble(ORD, pc, code_align, data_align)	\
-+.section	.debug_frame,"",@progbits ;		\
-+frame/**/_/**/ORD:						\
-+	.long end/**/_/**/ORD-start/**/_/**/ORD;			\
-+start/**/_/**/ORD:						\
-+	.long	DW_CIE_ID;				\
-+	.byte	DW_CIE_VERSION;			\
-+	.byte 0	 ;				\
-+	.uleb128 code_align;				\
-+	.sleb128 data_align;				\
-+	.byte pc;
-+
-+/*
-+ * After the above macro and prior to the CFI_postamble, you need to
-+ * define the initial state.  This starts with defining the reference
-+ * register and, usually the pc.  Here are some helper macros:
-+ */
-+
-+#define CFA_define_reference(reg, offset)	\
-+	.byte DW_CFA_def_cfa;			\
-+	.uleb128 reg;				\
-+	.uleb128 (offset);
-+
-+#define CFA_define_offset(reg, offset)		\
-+	.byte (DW_CFA_offset + reg);		\
-+	.uleb128 (offset);
-+
-+#define CFI_postamble(ORD)			\
-+	.align 4;				\
-+end/**/_/**/ORD:
-+/*
-+ * So now your code pushs stuff on the stack, you need a new location
-+ * and the rules for what to do.  This starts a running description of
-+ * the call frame.  You need to describe what changes with respect to
-+ * the call registers as the location of the pc moves through the code.
-+ * The following builds an FDE (fram descriptor entry?).  Like the
-+ * above, it has a preamble and a postamble.  It also is tied to the CFI
-+ * above.
-+ * The first entry after the preamble must be the location in the code
-+ * that the call frame is being described for.
-+ */
-+#define FDE_preamble(ORD, fde_no, initial_address, length)	\
-+	.long FDE_end/**/_/**/fde_no-FDE_start/**/_/**/fde_no;		\
-+FDE_start/**/_/**/fde_no:						\
-+	.long frame/**/_/**/ORD;					\
-+	.long initial_address;					\
-+	.long length;
-+
-+#define FDE_postamble(fde_no)			\
-+	.align 4;				\
-+FDE_end/**/_/**/fde_no:
-+/*
-+ * That done, you can now add registers, subtract registers, move the
-+ * reference and even change the reference.  You can also define a new
-+ * area of code the info applies to.  For discontinuous bits you should
-+ * start a new FDE.  You may have as many as you like.
-+ */
-+
-+/*
-+ * To advance the address by <bytes>
-+ */
-+
-+#define FDE_advance(bytes)			\
-+	.byte DW_CFA_advance_loc4		\
-+	.long bytes
-+
-+
-+
-+/*
-+ * With the above you can define all the register locations.  But
-+ * suppose the reference register moves... Takes the new offset NOT an
-+ * increment.  This is how esp is tracked if it is not saved.
-+ */
-+
-+#define CFA_define_cfa_offset(offset) \
-+	.byte $DW_CFA_def_cfa_offset; \
-+	.uleb128 (offset);
-+/*
-+ * Or suppose you want to use a different reference register...
-+ */
-+#define CFA_define_cfa_register(reg)		\
-+	.byte DW_CFA_def_cfa_register;		\
-+	.uleb128 reg;
-+
-+#endif
-diff -puN include/linux/serial_core.h~kgdb-ga include/linux/serial_core.h
---- 25/include/linux/serial_core.h~kgdb-ga	2004-10-21 14:54:15.282600184 -0700
-+++ 25-akpm/include/linux/serial_core.h	2004-10-21 14:54:15.338591672 -0700
-@@ -172,7 +172,9 @@ struct uart_port {
- 	unsigned char		x_char;			/* xon/xoff char */
- 	unsigned char		regshift;		/* reg offset shift */
- 	unsigned char		iotype;			/* io access style */
--
-+#ifdef CONFIG_KGDB
-+	int			kgdb;			/* in use by kgdb */
-+#endif
- #define UPIO_PORT		(0)
- #define UPIO_HUB6		(1)
- #define UPIO_MEM		(2)
-diff -puN include/linux/spinlock.h~kgdb-ga include/linux/spinlock.h
---- 25/include/linux/spinlock.h~kgdb-ga	2004-10-21 14:54:15.284599880 -0700
-+++ 25-akpm/include/linux/spinlock.h	2004-10-21 14:54:15.338591672 -0700
-@@ -15,6 +15,12 @@
- 
- #include <asm/processor.h>	/* for cpu relax */
- #include <asm/system.h>
-+#ifdef CONFIG_KGDB
-+#include <asm/current.h>
-+#define SET_WHO(x, him) (x)->who = him;
-+#else
-+#define SET_WHO(x, him)
-+#endif
- 
- /*
-  * Must define these before including other files, inline functions need them
-@@ -88,6 +94,9 @@ typedef struct {
- 	const char *module;
- 	char *owner;
- 	int oline;
-+#ifdef CONFIG_KGDB
-+	struct task_struct *who;
-+#endif
- } spinlock_t;
- #define SPIN_LOCK_UNLOCKED (spinlock_t) { SPINLOCK_MAGIC, 0, 10, __FILE__ , NULL, 0}
- 
-@@ -99,6 +108,7 @@ typedef struct {
- 		(x)->module = __FILE__; \
- 		(x)->owner = NULL; \
- 		(x)->oline = 0; \
-+                SET_WHO(x, NULL) \
- 	} while (0)
- 
- #define CHECK_LOCK(x) \
-@@ -121,6 +131,7 @@ typedef struct {
- 		(x)->lock = 1; \
- 		(x)->owner = __FILE__; \
- 		(x)->oline = __LINE__; \
-+                SET_WHO(x, current)       \
- 	} while (0)
- 
- /* without debugging, spin_is_locked on UP always says
-@@ -151,6 +162,7 @@ typedef struct {
- 		(x)->lock = 1; \
- 		(x)->owner = __FILE__; \
- 		(x)->oline = __LINE__; \
-+                SET_WHO(x, current)       \
- 		1; \
- 	})
- 
-diff -puN kernel/pid.c~kgdb-ga kernel/pid.c
---- 25/kernel/pid.c~kgdb-ga	2004-10-21 14:54:15.285599728 -0700
-+++ 25-akpm/kernel/pid.c	2004-10-21 14:54:15.339591520 -0700
-@@ -252,6 +252,9 @@ void switch_exec_pids(task_t *leader, ta
-  * machine.  From a minimum of 16 slots up to 4096 slots at one gigabyte or
-  * more.
-  */
-+#ifdef CONFIG_KGDB
-+int kgdb_pid_init_done; /* so we don't call prior to... */
-+#endif
- void __init pidhash_init(void)
- {
- 	int i, j, pidhash_size;
-@@ -273,6 +276,9 @@ void __init pidhash_init(void)
- 		for (j = 0; j < pidhash_size; j++)
- 			INIT_HLIST_HEAD(&pid_hash[i][j]);
- 	}
-+#ifdef CONFIG_KGDB
-+	kgdb_pid_init_done++;
-+#endif
- }
- 
- void __init pidmap_init(void)
-diff -puN kernel/sched.c~kgdb-ga kernel/sched.c
---- 25/kernel/sched.c~kgdb-ga	2004-10-21 14:54:15.287599424 -0700
-+++ 25-akpm/kernel/sched.c	2004-10-21 14:54:15.342591064 -0700
-@@ -2931,6 +2931,13 @@ out_unlock:
- 
- EXPORT_SYMBOL(set_user_nice);
- 
-+#ifdef CONFIG_KGDB
-+struct task_struct *kgdb_get_idle(int this_cpu)
-+{
-+        return cpu_rq(this_cpu)->idle;
-+}
-+#endif
-+
- #ifdef __ARCH_WANT_SYS_NICE
- 
- /*
-diff -puN MAINTAINERS~kgdb-ga MAINTAINERS
---- 25/MAINTAINERS~kgdb-ga	2004-10-21 14:54:15.288599272 -0700
-+++ 25-akpm/MAINTAINERS	2004-10-21 14:54:15.344590760 -0700
-@@ -1242,6 +1242,12 @@ W:	http://sf.net/projects/kernel-janitor
- W:	http://developer.osdl.org/rddunlap/kj-patches/
- S:	Maintained
- 
-+KGDB FOR I386 PLATFORM
-+P:	George Anzinger
-+M:	george@mvista.com
-+L:	linux-net@vger.kernel.org
-+S:	Supported
-+
- KERNEL NFSD
- P:	Neil Brown
- M:	neilb@cse.unsw.edu.au
-diff -puN arch/i386/Kconfig.debug~kgdb-ga arch/i386/Kconfig.debug
---- 25/arch/i386/Kconfig.debug~kgdb-ga	2004-10-21 14:54:15.290598968 -0700
-+++ 25-akpm/arch/i386/Kconfig.debug	2004-10-21 14:54:15.344590760 -0700
-@@ -65,4 +65,6 @@ config X86_MPPARSE
- 	depends on X86_LOCAL_APIC && !X86_VISWS
- 	default y
- 
-+source "arch/i386/Kconfig.kgdb"
-+
- endmenu
-diff -puN /dev/null arch/i386/Kconfig.kgdb
---- /dev/null	2003-09-15 06:40:47.000000000 -0700
-+++ 25-akpm/arch/i386/Kconfig.kgdb	2004-10-21 14:54:15.345590608 -0700
-@@ -0,0 +1,175 @@
-+config KGDB
-+	bool "Include kgdb kernel debugger"
-+	depends on DEBUG_KERNEL
-+	help
-+	  If you say Y here, the system will be compiled with the debug
-+	  option (-g) and a debugging stub will be included in the
-+	  kernel.  This stub communicates with gdb on another (host)
-+	  computer via a serial port.  The host computer should have
-+	  access to the kernel binary file (vmlinux) and a serial port
-+	  that is connected to the target machine.  Gdb can be made to
-+	  configure the serial port or you can use stty and setserial to
-+	  do this. See the 'target' command in gdb. This option also
-+	  configures in the ability to request a breakpoint early in the
-+	  boot process.  To request the breakpoint just include 'kgdb'
-+	  as a boot option when booting the target machine.  The system
-+	  will then break as soon as it looks at the boot options.  This
-+	  option also installs a breakpoint in panic and sends any
-+	  kernel faults to the debugger. For more information see the
-+	  Documentation/i386/kgdb/kgdb.txt file.
-+
-+choice
-+	depends on KGDB
-+    	prompt "Debug serial port BAUD"
-+	default KGDB_115200BAUD
-+	help
-+	  Gdb and the kernel stub need to agree on the baud rate to be
-+	  used.  Some systems (x86 family at this writing) allow this to
-+	  be configured.
-+
-+config KGDB_9600BAUD
-+	bool "9600"
-+
-+config KGDB_19200BAUD
-+	bool "19200"
-+
-+config KGDB_38400BAUD
-+	bool "38400"
-+
-+config KGDB_57600BAUD
-+	bool "57600"
-+
-+config KGDB_115200BAUD
-+	bool "115200"
-+endchoice
-+
-+config KGDB_PORT
-+	hex "hex I/O port address of the debug serial port"
-+	depends on KGDB
-+	default  3f8
-+	help
-+	  Some systems (x86 family at this writing) allow the port
-+	  address to be configured.  The number entered is assumed to be
-+	  hex, don't put 0x in front of it.  The standard address are:
-+	  COM1 3f8 , irq 4 and COM2 2f8 irq 3.  Setserial /dev/ttySx
-+	  will tell you what you have.  It is good to test the serial
-+	  connection with a live system before trying to debug.
-+
-+config KGDB_IRQ
-+	int "IRQ of the debug serial port"
-+	depends on KGDB
-+	default 4
-+	help
-+	  This is the irq for the debug port.  If everything is working
-+	  correctly and the kernel has interrupts on a control C to the
-+	  port should cause a break into the kernel debug stub.
-+
-+config DEBUG_INFO
-+	bool
-+	depends on KGDB
-+	default y
-+
-+config KGDB_MORE
-+	bool "Add any additional compile options"
-+	depends on KGDB
-+	default n
-+	help
-+	  Saying yes here turns on the ability to enter additional
-+	  compile options.
-+
-+
-+config KGDB_OPTIONS
-+	depends on KGDB_MORE
-+	string "Additional compile arguments"
-+	default "-O1"
-+	help
-+	  This option allows you enter additional compile options for
-+	  the whole kernel compile.  Each platform will have a default
-+	  that seems right for it.  For example on PPC "-ggdb -O1", and
-+	  for i386 "-O1".  Note that by configuring KGDB "-g" is already
-+	  turned on.  In addition, on i386 platforms
-+	  "-fomit-frame-pointer" is deleted from the standard compile
-+	  options.
-+
-+config NO_KGDB_CPUS
-+	int "Number of CPUs"
-+	depends on KGDB && SMP
-+	default NR_CPUS
-+	help
-+
-+	  This option sets the number of cpus for kgdb ONLY.  It is used
-+	  to prune some internal structures so they look "nice" when
-+	  displayed with gdb.  This is to overcome possibly larger
-+	  numbers that may have been entered above.  Enter the real
-+	  number to get nice clean kgdb_info displays.
-+
-+config KGDB_TS
-+	bool "Enable kgdb time stamp macros?"
-+	depends on KGDB
-+	default n
-+	help
-+	  Kgdb event macros allow you to instrument your code with calls
-+	  to the kgdb event recording function.  The event log may be
-+	  examined with gdb at a break point.  Turning on this
-+	  capability also allows you to choose how many events to
-+	  keep. Kgdb always keeps the lastest events.
-+
-+choice
-+	depends on KGDB_TS
-+	prompt "Max number of time stamps to save?"
-+	default KGDB_TS_128
-+
-+config KGDB_TS_64
-+	bool "64"
-+
-+config KGDB_TS_128
-+	bool "128"
-+
-+config KGDB_TS_256
-+	bool "256"
-+
-+config KGDB_TS_512
-+	bool "512"
-+
-+config KGDB_TS_1024
-+	bool "1024"
-+
-+endchoice
-+
-+config STACK_OVERFLOW_TEST
-+	bool "Turn on kernel stack overflow testing?"
-+	depends on KGDB
-+	default n
-+	help
-+	  This option enables code in the front line interrupt handlers
-+	  to check for kernel stack overflow on interrupts and system
-+	  calls.  This is part of the kgdb code on x86 systems.
-+
-+config KGDB_CONSOLE
-+	bool "Enable serial console thru kgdb port"
-+	depends on KGDB
-+	default n
-+	help
-+	  This option enables the command line "console=kgdb" option.
-+	  When the system is booted with this option in the command line
-+	  all kernel printk output is sent to gdb (as well as to other
-+	  consoles).  For this to work gdb must be connected.  For this
-+	  reason, this command line option will generate a breakpoint if
-+	  gdb has not yet connected.  After the gdb continue command is
-+	  given all pent up console output will be printed by gdb on the
-+	  host machine.  Neither this option, nor KGDB require the
-+	  serial driver to be configured.
-+
-+config KGDB_SYSRQ
-+	bool "Turn on SysRq 'G' command to do a break?"
-+	depends on KGDB
-+	default y
-+	help
-+	  This option includes an option in the SysRq code that allows
-+	  you to enter SysRq G which generates a breakpoint to the KGDB
-+	  stub.  This will work if the keyboard is alive and can
-+	  interrupt the system.  Because of constraints on when the
-+	  serial port interrupt can be enabled, this code may allow you
-+	  to interrupt the system before the serial port control C is
-+	  available.  Just say yes here.
-+
-_
diff --git a/lustre/kernel_patches/patches/8kstack-2.6-rhel4.patch b/lustre/kernel_patches/patches/8kstack-2.6-rhel4.patch
deleted file mode 100644
index 36fea122e3..0000000000
--- a/lustre/kernel_patches/patches/8kstack-2.6-rhel4.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-Index: linux-2.6.9-5.0.3.EL/include/asm-i386/thread_info.h
-===================================================================
---- linux-2.6.9-5.0.3.EL.orig/include/asm-i386/thread_info.h	2005-02-25 10:25:33.000000000 +0200
-+++ linux-2.6.9-5.0.3.EL/include/asm-i386/thread_info.h	2005-02-25 20:19:11.676139032 +0200
-@@ -54,7 +54,7 @@
- #endif
- 
- #define PREEMPT_ACTIVE		0x4000000
--#define THREAD_SIZE            (4096)
-+#define THREAD_SIZE            (8192)
- 
- #define STACK_WARN             (THREAD_SIZE/8)
- /*
diff --git a/lustre/kernel_patches/patches/bluesmoke-2.6-suse-lnxi.patch b/lustre/kernel_patches/patches/bluesmoke-2.6-suse-lnxi.patch
deleted file mode 100644
index a6501a4c71..0000000000
--- a/lustre/kernel_patches/patches/bluesmoke-2.6-suse-lnxi.patch
+++ /dev/null
@@ -1,5485 +0,0 @@
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Kconfig
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/Kconfig	2004-11-11 10:28:08.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Kconfig	2004-12-17 12:45:23.000000000 -0500
-@@ -6,6 +6,8 @@
- 
- source "drivers/mtd/Kconfig"
- 
-+source "drivers/bluesmoke/Kconfig"
-+
- source "drivers/parport/Kconfig"
- 
- source "drivers/pnp/Kconfig"
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Makefile
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/Makefile	2004-11-11 10:28:16.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Makefile	2004-12-17 12:45:23.000000000 -0500
-@@ -29,6 +29,7 @@
- obj-$(CONFIG_IEEE1394)		+= ieee1394/
- obj-y				+= cdrom/ video/
- obj-$(CONFIG_MTD)		+= mtd/
-+obj-$(CONFIG_BLUESMOKE)		+= bluesmoke/
- obj-$(CONFIG_PCMCIA)		+= pcmcia/
- obj-$(CONFIG_DIO)		+= dio/
- obj-$(CONFIG_SBUS)		+= sbus/
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Kconfig
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/Kconfig	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Kconfig	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,72 @@
-+#
-+#	Bluesmoke Kconfig
-+#	Copyright (c) 2003 Linux Networx
-+#	Licensed and distributed under the GPL
-+#
-+# $Id: Kconfig,v 1.4 2004/11/10 01:12:35 thayne Exp $
-+#
-+
-+menu 'Bluesmoke - error detection and reporting (RAS)'
-+
-+config BLUESMOKE
-+	tristate "Bluesmoke core system error reporting"
-+	help
-+	  Bluesmoke is designed to report errors in the core system.
-+	  These are low-level errors that are reported in the CPU or
-+	  supporting chipset: memory errors, cache errors, PCI errors,
-+	  thermal throttling, etc..  If unsure, select 'Y'.
-+
-+
-+comment "Reporting subsystems"
-+	depends on BLUESMOKE
-+
-+config BLUESMOKE_DEBUG
-+	bool "Debugging"
-+	depends on BLUESMOKE
-+	help
-+	  This turns on debugging information for the entire Bluesmoke
-+	  sub-system.  Usually you should select 'N'.
-+
-+config BULESMOKE_DEBUG_VERBOSE
-+	int "Debugging verbosity (0=quiet, 3=noisy)"
-+	depends on BLUESMOKE_DEBUG
-+	default "0"
-+	help
-+	  Verbosity level of Bluesmoke debug messages.
-+
-+config BLUESMOKE_MM_EDAC
-+	tristate "Bluesmoke Main Memory EDAC (Error Detection And Correction) reporting"
-+	depends on BLUESMOKE
-+	help
-+	  Some systems are able to detect and correct errors in main
-+	  memory.  Bluesmoke can report statistics on memory error
-+	  detection and correction (EDAC - or commonly referred to ECC
-+	  errors).  Bluesmoke will also try to decode where these errors
-+	  occurred so that a particular failing memory module can be
-+	  replaced.  If unsure, select 'Y'.
-+
-+
-+comment "Bluesmoke system controller/chipset support"
-+	depends on BLUESMOKE
-+
-+config BLUESMOKE_AMD76X
-+	tristate "AMD 76x (760, 762, 768)"
-+	depends on BLUESMOKE
-+
-+config BLUESMOKE_E7XXX
-+	tristate "Intel e7xxx (e7205, e7500, e7501, e7505)"
-+	depends on BLUESMOKE
-+
-+config BLUESMOKE_E752X
-+	tristate "Intel e752x (e7520)"
-+	depends on BLUESMOKE
-+
-+config BLUESMOKE_I82875P
-+	tristate "Intel 82875p"
-+	depends on BLUESMOKE
-+
-+config BLUESMOKE_K8
-+	tristate "AMD K8 (Athlon FX, Athlon 64, Opteron)"
-+	depends on BLUESMOKE
-+
-+endmenu
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Makefile
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/Makefile	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/Makefile	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,26 @@
-+#
-+# Makefile for the Linux kernel bluesmoke drivers.
-+#
-+# Copyright 02 Jul 2003, Linux Networx (http://lnxi.com)
-+# This file may be distributed under the terms of the
-+# GNU General Public License.
-+#
-+# $Id: Makefile,v 1.4 2004/11/10 01:12:35 thayne Exp $
-+
-+
-+obj-$(CONFIG_BLUESMOKE_MM_EDAC)		+= bluesmoke_mc.o
-+obj-$(CONFIG_BLUESMOKE_AMD76X)		+= bluesmoke_amd76x.o 
-+obj-$(CONFIG_BLUESMOKE_E7XXX)		+= bluesmoke_e7xxx.o 
-+obj-$(CONFIG_BLUESMOKE_E752X)		+= bluesmoke_e752x.o 
-+obj-$(CONFIG_BLUESMOKE_I82875P)		+= bluesmoke_i82875p.o 
-+obj-$(CONFIG_BLUESMOKE_K8)		+= bluesmoke_k8.o 
-+
-+ifeq ($(PATCHLEVEL),4)
-+
-+export-objs	:= bluesmoke_mc.o
-+
-+O_TARGET	:= bluesmokelink.o
-+
-+include $(TOPDIR)/Rules.make
-+
-+endif
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_amd76x.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_amd76x.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_amd76x.c	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,323 @@
-+/*
-+ * AMD 76x Memory Controller kernel module
-+ * (C) 2003 Linux Networx (http://lnxi.com)
-+ * This file may be distributed under the terms of the
-+ * GNU General Public License.
-+ *
-+ * Written by Thayne Harbaugh
-+ * Based on work by Dan Hollis <goemon at anime dot net> and others.
-+ *	http://www.anime.net/~goemon/linux-ecc/
-+ *
-+ * $Id: bluesmoke_amd76x.c,v 1.4 2004/11/10 01:12:35 thayne Exp $
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/pci.h>
-+#include <linux/pci_ids.h>
-+
-+#include <linux/slab.h>
-+
-+#include "bluesmoke_mc.h"
-+
-+
-+#define AMD76X_NR_CSROWS 8
-+#define AMD76X_NR_CHANS  1
-+#define AMD76X_NR_DIMMS  4
-+
-+
-+/* AMD 76x register addresses - device 0 function 0 - PCI bridge */
-+#define AMD76X_ECC_MODE_STATUS	0x48	/* Mode and status of ECC (32b)
-+					 *
-+					 * 31:16 reserved
-+					 * 15:14 SERR enabled: x1=ue 1x=ce
-+					 * 13    reserved
-+					 * 12    diag: disabled, enabled
-+					 * 11:10 mode: dis, EC, ECC, ECC+scrub
-+					 *  9:8  status: x1=ue 1x=ce
-+					 *  7:4  UE cs row
-+					 *  3:0  CE cs row
-+					 */
-+#define AMD76X_DRAM_MODE_STATUS	0x58	/* DRAM Mode and status (32b)
-+					 *
-+					 * 31:26 clock disable 5 - 0
-+					 * 25    SDRAM init
-+					 * 24    reserved
-+					 * 23    mode register service
-+					 * 22:21 suspend to RAM
-+					 * 20    burst refresh enable
-+					 * 19    refresh disable
-+					 * 18    reserved
-+					 * 17:16 cycles-per-refresh
-+					 * 15:8  reserved
-+					 *  7:0  x4 mode enable 7 - 0
-+					 */
-+#define AMD76X_MEM_BASE_ADDR	0xC0	/* Memory base address (8 x 32b)
-+					 *
-+					 * 31:23 chip-select base
-+					 * 22:16 reserved
-+					 * 15:7  chip-select mask
-+					 *  6:3  reserved
-+					 *  2:1  address mode
-+					 *  0    chip-select enable
-+					 */
-+
-+
-+enum amd76x_chips {
-+	AMD761 = 0,
-+	AMD762
-+};
-+
-+
-+struct amd76x_dev_info {
-+	const char *ctl_name;
-+};
-+
-+
-+static const struct amd76x_dev_info amd76x_devs[] = {
-+	[AMD761] = {
-+		.ctl_name = "AMD761"
-+	},
-+	[AMD762] = {
-+		.ctl_name = "AMD762"
-+	},
-+};
-+
-+
-+static void amd76x_check(struct mem_ctl_info *mci)
-+{
-+	u32 ems;
-+
-+	debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+
-+	pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS, &ems);
-+
-+	if ( ems & BIT(8) ) {	/* UE? */
-+		u32 ems_ue_row = (ems >> 4) & 0xf;
-+
-+		pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
-+				  (u32)BIT(8), (u32)BIT(8) );
-+
-+		bluesmoke_mc_handle_ue( mci, mci->csrows[ems_ue_row].first_page,
-+					0, ems_ue_row, mci->ctl_name );
-+	}
-+
-+	if ( ems & BIT(9) ) {	/* CE? */
-+		u32 ems_ce_row = ems & 0xf;
-+
-+		pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
-+				  (u32)BIT(9), (u32)BIT(9) );
-+
-+		bluesmoke_mc_handle_ce( mci, mci->csrows[ems_ce_row].first_page,
-+					0, 0, ems_ce_row, 0, mci->ctl_name );
-+	}
-+	return;
-+}
-+
-+
-+static int amd76x_probe1( struct pci_dev *pdev, int dev_idx )
-+{
-+	int rc = -ENODEV;
-+	int index;
-+	struct mem_ctl_info *mci = NULL;
-+	enum edac_type ems_modes[] = { EDAC_NONE,
-+				       EDAC_EC,
-+				       EDAC_SECDED,
-+				       EDAC_SECDED };
-+	u32 ems;
-+	u32 ems_mode;
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
-+	ems_mode = ( ems >> 10 ) & 0x3;
-+
-+	mci = bluesmoke_mc_init_structs(0,
-+					AMD76X_NR_CSROWS,
-+					AMD76X_NR_CHANS);
-+
-+	if ( ! mci ) {
-+		rc = -ENOMEM;
-+		goto FAIL_FINISHED;
-+	}
-+
-+	debugf0( "MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci );
-+
-+	mci->pdev = pdev;
-+	mci->mtype_cap = MEM_FLAG_RDDR;
-+
-+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
-+	if ( ems_mode ) {
-+		mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
-+	} else {
-+		mci->edac_cap = EDAC_FLAG_NONE;
-+	}
-+
-+	mci->mod_name = BS_MOD_STR;
-+	mci->mod_ver = "$Revision: 1.4 $";
-+	mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
-+	mci->edac_check = amd76x_check;
-+	mci->clear_err = NULL;
-+	mci->ctl_page_to_phys = NULL;
-+
-+	for ( index = 0; index < mci->nr_csrows; index++ ) {
-+		struct csrow_info *csrow = &mci->csrows[ index ];
-+		u32 mba;
-+		u32 mba_base;
-+		u32 mba_mask;
-+		u32 dms;
-+
-+		/* find the DRAM Chip Select Base address and mask */
-+		pci_read_config_dword( mci->pdev,
-+				       AMD76X_MEM_BASE_ADDR + (index*4),
-+				       &mba );
-+
-+		if ( ! (mba & BIT(0)) ) {
-+			continue;
-+		}
-+
-+		mba_base = mba & 0xff800000UL;
-+		mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL;
-+
-+		pci_read_config_dword( mci->pdev,
-+				       AMD76X_DRAM_MODE_STATUS,
-+				       &dms );
-+
-+		csrow->first_page = mba_base >> PAGE_SHIFT;
-+		csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT;
-+		csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
-+		csrow->page_mask = mba_mask >> PAGE_SHIFT;
-+		csrow->grain = csrow->nr_pages << PAGE_SHIFT;
-+		csrow->mtype = MEM_RDDR;
-+		csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN;
-+		csrow->edac_mode = ems_modes[ ems_mode ];
-+	}
-+
-+	/* clear counters */
-+	pci_write_bits32( mci->pdev, AMD76X_ECC_MODE_STATUS,
-+			  (u32)(0x3 << 8), (u32)(0x3 << 8) );
-+
-+	if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
-+		debugf3( "MC: " __FILE__
-+			 ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	/* get this far and it's successful */
-+	debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
-+	rc = 0;
-+	goto FINISHED;
-+
-+ FAIL_FINISHED:
-+	if ( mci ) {
-+		kfree( mci );
-+	}
-+
-+ FINISHED:
-+	return( rc );
-+}
-+
-+
-+#ifdef CONFIG_PM
-+
-+static int amd76x_suspend (struct pci_dev *pdev, u32 state)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+
-+static int amd76x_resume (struct pci_dev *pdev)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+#endif /* CONFIG_PM */
-+
-+
-+/* returns count (>= 0), or negative on error */
-+static int __devinit amd76x_init_one( struct pci_dev *pdev,
-+				      const struct pci_device_id *ent )
-+{
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	/* don't need to call pci_device_enable() */
-+	return amd76x_probe1( pdev, ent->driver_data );
-+}
-+
-+
-+static void __devexit amd76x_remove_one( struct pci_dev *pdev )
-+{
-+	struct mem_ctl_info *mci;
-+
-+	debugf0( __FILE__ ": %s()\n", __func__);
-+
-+	if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
-+		goto FINISHED;
-+	}
-+
-+	if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
-+		goto FINISHED;
-+	}
-+
-+	kfree( mci );
-+
-+ FINISHED:
-+	return;
-+}
-+
-+
-+static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
-+	{ PCI_VEND_DEV( AMD, FE_GATE_700C ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD762 },
-+	{ PCI_VEND_DEV( AMD, FE_GATE_700E ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD761 },
-+	{0,}						/* 0 terminated list. */
-+};
-+
-+MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
-+
-+
-+static struct pci_driver amd76x_driver = {
-+	.name		= BS_MOD_STR,
-+	.probe		= amd76x_init_one,
-+	.remove		= __devexit_p(amd76x_remove_one),
-+	.id_table	= amd76x_pci_tbl,
-+#ifdef CONFIG_PM
-+	.suspend	= amd76x_suspend,
-+	.resume		= amd76x_resume,
-+#endif /* CONFIG_PM */
-+};
-+
-+
-+int __init amd76x_init(void)
-+{
-+	int pci_rc;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+	pci_rc = pci_module_init( &amd76x_driver );
-+	if ( pci_rc < 0 ) return pci_rc;
-+
-+	return 0;
-+}
-+
-+
-+static void __exit amd76x_exit(void)
-+{
-+	debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
-+	pci_unregister_driver( &amd76x_driver );
-+}
-+
-+
-+module_init(amd76x_init);
-+module_exit(amd76x_exit);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
-+MODULE_DESCRIPTION("MC support for AMD 76x memory controllers");
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e752x.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_e752x.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e752x.c	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,1027 @@
-+/*
-+ * Intel e752x Memory Controller kernel module
-+ * (C) 2004 Linux Networx (http://lnxi.com)
-+ * This file may be distributed under the terms of the
-+ * GNU General Public License.
-+ *
-+ * See "enum e752x_chips" below for supported chipsets
-+ *
-+ * Written by Tom Zimmerman
-+ *
-+ * Contributors:
-+ * 	Thayne Harbaugh (Linux Networx)
-+ *
-+ * $Id: bluesmoke_e752x.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/pci.h>
-+#include <linux/pci_ids.h>
-+
-+#include <linux/slab.h>
-+
-+#include "bluesmoke_mc.h"
-+
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7520_0     
-+#define PCI_DEVICE_ID_INTEL_7520_0      0x3590
-+#endif /* PCI_DEVICE_ID_INTEL_7520_0      */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7520_1_ERR 
-+#define PCI_DEVICE_ID_INTEL_7520_1_ERR  0x3591
-+#endif /* PCI_DEVICE_ID_INTEL_7520_1_ERR  */
-+
-+
-+#define E752X_NR_CSROWS		8	/* number of csrows */
-+
-+
-+/* E752X register addresses - device 0 function 0 */
-+#define E752X_DRB		0x60	/* DRAM row boundary register (8b) */
-+#define E752X_DRA		0x70	/* DRAM row attribute register (8b) */
-+					/*
-+					 * 31:30   Device width row 7 
-+					 * 	01=x8 10=x4 11=x8 DDR2
-+					 * 27:26   Device width row 6
-+					 * 23:22   Device width row 5
-+					 * 19:20   Device width row 4
-+					 * 15:14   Device width row 3
-+					 * 11:10   Device width row 2
-+					 *  7:6    Device width row 1
-+					 *  3:2    Device width row 0
-+					 */
-+#define E752X_DRC		0x7C	/* DRAM controller mode reg (32b) */
-+					/*
-+					 * 22    Number channels 0=1,1=2
-+					 * 19:18 DRB Granularity 32/64MB
-+					 */
-+#define E752X_DRM		0x80	/* Dimm mapping register */
-+#define E752X_DDRCSR		0x9A	/* DDR control and status reg (16b) */
-+					/*
-+					 * 14:12 1 single A, 2 single B, 3 dual
-+ 					 */
-+#define E752X_TOLM		0xC4	/* DRAM top of low memory reg (16b) */
-+#define E752X_REMAPBASE		0xC6	/* DRAM remap base address reg (16b) */
-+#define E752X_REMAPLIMIT	0xC8	/* DRAM remap limit address reg (16b) */
-+#define E752X_REMAPOFFSET	0xCA	/* DRAM remap limit offset reg (16b) */
-+
-+/* E752X register addresses - device 0 function 1 */
-+#define E752X_FERR_GLOBAL	0x40	/* Global first error register (32b)*/
-+#define E752X_NERR_GLOBAL	0x44	/* Global next error register (32b) */
-+#define E752X_HI_FERR		0x50	/* Hub interface first error reg (8b)*/
-+#define E752X_HI_NERR		0x52	/* Hub interface next error reg (8b)*/
-+#define E752X_HI_ERRMASK	0x54	/* Hub interface error mask reg (8b)*/
-+#define E752X_HI_SMICMD		0x5A	/* Hub interface SMI command reg (8b)*/
-+#define E752X_SYSBUS_FERR	0x60	/* System buss first error reg (16b)*/
-+#define E752X_SYSBUS_NERR	0x62	/* System buss next error reg (16b)*/
-+#define E752X_SYSBUS_ERRMASK	0x64	/* System buss error mask reg (16b) */
-+#define E752X_SYSBUS_SMICMD	0x6A	/* System buss SMI command reg (16b) */
-+#define E752X_BUF_FERR		0x70	/* Memory buffer first error reg (8b)*/
-+#define E752X_BUF_NERR		0x72	/* Memory buffer next error reg (8b)*/
-+#define E752X_BUF_ERRMASK	0x74	/* Memory buffer error mask reg (8b)*/
-+#define E752X_BUF_SMICMD	0x7A	/* Memory buffer SMI command reg (8b)*/
-+#define E752X_DRAM_FERR		0x80	/* DRAM first error register (16b) */
-+#define E752X_DRAM_NERR		0x82	/* DRAM next error register (16b) */
-+#define E752X_DRAM_ERRMASK	0x84	/* DRAM error mask register (8b) */
-+#define E752X_DRAM_SMICMD	0x8A	/* DRAM SMI command register (8b) */
-+#define E752X_DRAM_RETRY_ADD	0xAC	/* DRAM Retry address register (32b) */
-+#define E752X_DRAM_CELOG1_ADD	0xA0	/* DRAM first correctable memory */
-+					/*     error address register (32b) */
-+					/*
-+					 * 31    Reserved
-+					 * 30:2  CE address (64 byte block 34:6)
-+					 * 1     Reserved
-+					 * 0     HiLoCS
-+					 */
-+#define E752X_DRAM_CELOG2_ADD	0xC8	/* DRAM first correctable memory */
-+					/*     error address register (32b) */
-+					/*
-+					 * 31    Reserved
-+					 * 30:2  CE address (64 byte block 34:6)
-+					 * 1     Reserved
-+					 * 0     HiLoCS
-+					 */
-+#define E752X_DRAM_UELOG_ADD	0xA4	/* DRAM first uncorrectable memory */
-+					/*     error address register (32b) */
-+					/*
-+					 * 31    Reserved
-+					 * 30:2  CE address (64 byte block 34:6)
-+					 * 1     Reserved
-+					 * 0     HiLoCS
-+					 */
-+#define E752X_DRAM_UELOGS_ADD	0xA8	/* DRAM first uncorrectable scrub memory */
-+					/*     error address register (32b) */
-+					/*
-+					 * 31    Reserved
-+					 * 30:2  CE address (64 byte block 34:6)
-+					 * 1     Reserved
-+					 * 0     HiLoCS
-+					 */
-+#define E752X_DRAM_CELOG1_SYNDROME 0xC4	/* DRAM first correctable memory */
-+					/*     error syndrome register (16b) */
-+#define E752X_DRAM_CELOG2_SYNDROME 0xC6	/* DRAM second correctable memory */
-+					/*     error syndrome register (16b) */
-+#define E752X_DEVPRES1		0xF4	/* Device Present 1 register (8b) */
-+
-+/* ICH5R register addresses - device 30 function 0 */
-+#define ICH5R_PCI_STAT		0x06	/* PCI status register (16b) */
-+#define ICH5R_PCI_2ND_STAT	0x1E	/* PCI status secondary reg (16b) */
-+#define ICH5R_PCI_BRIDGE_CTL	0x3E	/* PCI bridge control register (16b) */
-+
-+enum e752x_chips {
-+	E7520 = 0,
-+};
-+
-+
-+struct e752x_pvt {
-+	struct pci_dev *bridge_ck;
-+	struct pci_dev *dev_d0f0;
-+	struct pci_dev *dev_d0f1;
-+	u32 tolm;
-+	u32 remapbase;
-+	u32 remaplimit;
-+	int mc_symmetric;
-+	u8 map[8];
-+	int map_type;
-+	const struct e752x_dev_info *dev_info;
-+};
-+
-+
-+struct e752x_dev_info {
-+	u16 err_dev;
-+	const char *ctl_name;
-+};
-+
-+
-+static const struct e752x_dev_info e752x_devs[] = {
-+	[E7520] = {
-+		.err_dev  = PCI_DEVICE_ID_INTEL_7520_1_ERR,
-+		.ctl_name = "E7520"
-+	},
-+};
-+
-+
-+/* FIXME - is this valid for both SECDED and S4ECD4ED? */
-+static inline int e752x_find_channel(u16 syndrome)
-+{
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if((syndrome & 0xff00)==0)
-+		return(0);
-+	if((syndrome & 0x00ff)==0)
-+		return(1);
-+	if((syndrome & 0xf000)==0)
-+		return(0);
-+	if((syndrome & 0x0f00)==0)
-+		return(0);
-+	return(1);
-+}
-+
-+
-+static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
-+				      unsigned long page)
-+{
-+	u32 remap;
-+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if(page < pvt->tolm)
-+		return(page);
-+	if((page >= 0x100000)&&(page < pvt->remapbase))
-+		return(page);
-+	remap = (page - pvt->tolm) + pvt->remapbase;
-+	if(remap < pvt->remaplimit)
-+		return(remap);	
-+	printk(KERN_ERR "Invalid page %lx - out of range\n", page);
-+	return(pvt->tolm-1);
-+}
-+
-+
-+static void process_ce(struct mem_ctl_info *mci, u16 error_one, 
-+			u32 celog1_add, u16 celog1_syndrome)
-+{
-+	u32 error_1b, page;
-+	u16 syndrome;
-+	int row;
-+	int channel;
-+	int i;
-+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if(error_one&0x0101) {
-+		/* read the error address */
-+//		pci_read_config_dword(pvt->bridge_ck,E752X_DRAM_CELOG1_ADD,
-+//					&error_1b);
-+		error_1b = celog1_add;
-+		page = error_1b >> (PAGE_SHIFT-4);  /* convert the addr to 4k page */
-+		/* read the syndrome */
-+//		pci_read_config_word(pvt->bridge_ck,E752X_DRAM_CELOG1_SYNDROME,
-+//				&syndrome);
-+		syndrome = celog1_syndrome;
-+		/* FIXME - check for -1 */
-+		if (pvt->mc_symmetric) {
-+		        row = ((page >>1)&3); /* chip select are bits 14 & 13 */
-+	printk( KERN_WARNING
-+               "Test row %d Table %d %d %d %d %d %d %d %d\n",
-+               row,pvt->map[0],pvt->map[1],pvt->map[2],pvt->map[3],pvt->map[4],
-+			pvt->map[5],pvt->map[6],pvt->map[7]);
-+
-+			/* test for channel remapping */
-+			for(i=0;i<8;i++) {
-+				if(pvt->map[i] == row)
-+					break;
-+			}
-+	printk( KERN_WARNING
-+               "Test computed row %d\n",i); 
-+			if(i<8) {
-+				row = i;
-+			}
-+			else {
-+				printk( KERN_WARNING 
-+		          		"MC%d: row %d not found in remap table\n",
-+		          		mci->mc_idx,row);
-+			}
-+
-+
-+		} else {
-+			row = bluesmoke_mc_find_csrow_by_page( mci, page );
-+		}
-+		if(error_one&1)
-+			channel = 0; /* 0 = channel A */
-+		else
-+			channel = 1; /* 1 = channel B */
-+
-+		if(!pvt->map_type)
-+			row = 7 - row;
-+		bluesmoke_mc_handle_ce( mci, page, 0, syndrome,
-+					row, channel, "e752x CE" );
-+	}
-+}
-+
-+
-+static void process_ue(struct mem_ctl_info *mci, u16 error_one,
-+			u32 uelog_add, u32 uelogs_add)
-+{
-+	u32 error_2b, block_page;
-+	int row;
-+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if(error_one & 0x0202) {
-+		error_2b = uelog_add;
-+		/* convert to 4k address */
-+		block_page = error_2b >> (PAGE_SHIFT - 4);
-+		if (pvt->mc_symmetric) {
-+			/* chip select are bits 14 & 13 */
-+	        	row = ((block_page >>1)&3);
-+		}
-+		else {
-+			row = bluesmoke_mc_find_csrow_by_page(mci, block_page);
-+		}
-+		bluesmoke_mc_handle_ue( mci, block_page, 0, row, 
-+				"e752x UE from Read" );
-+	}
-+	if(error_one & 0x0404) {
-+		error_2b = uelogs_add;
-+		/* convert to 4k address */
-+		block_page = error_2b >> (PAGE_SHIFT - 4);
-+		if (pvt->mc_symmetric) {
-+			/* chip select are bits 14 & 13 */
-+	        	row = ((block_page >>1)&3);
-+		}
-+		else {
-+			row = bluesmoke_mc_find_csrow_by_page(mci, block_page);
-+		}
-+		bluesmoke_mc_handle_ue( mci, block_page, 0, row, 
-+				"e752x UE from Scruber" );
-+	}
-+}
-+
-+#if 0
-+static void process_ue_no_info(struct mem_ctl_info *mci)
-+{
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	bluesmoke_mc_handle_ue_no_info( mci, "e752x UE log register overflow" );
-+}
-+#endif
-+
-+static void process_ue_no_info_wr(struct mem_ctl_info *mci)
-+{
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	bluesmoke_mc_handle_ue_no_info( mci, "e752x UE log memory write" );
-+}
-+
-+static void process_ded_retry(struct mem_ctl_info *mci,u16 error,u32 retry_add)
-+{
-+	u32 error_1b, page;
-+	int row;
-+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
-+
-+	error_1b = retry_add;
-+	page = error_1b >> (PAGE_SHIFT-4);  /* convert the addr to 4k page */
-+	if (pvt->mc_symmetric) {
-+	        row = ((page >>1)&3); /* chip select are bits 14 & 13 */
-+	} else {
-+		row = bluesmoke_mc_find_csrow_by_page( mci, page );
-+	}
-+	printk( KERN_WARNING 
-+	          "MC%d: CE page 0x%lx, row %d : Memory read retry\n",
-+	          mci->mc_idx,(long unsigned int)page,row);
-+}
-+
-+static void process_threshold_ce(struct mem_ctl_info *mci,u16 error)
-+{
-+	printk( KERN_WARNING
-+		"MC%d: Memory threshold CE\n",mci->mc_idx);
-+}
-+			
-+char *global_message[11]= {"PCI Express C1","PCI Express C","PCI Express B1",
-+			   "PCI Express B","PCI Express A1","PCI Express A",
-+			   "DMA Controler","HUB Interface","System Bus",
-+			   "DRAM Controler","Internal Buffer"};
-+char *fatal_message[2]={"Non-Fatal ","Fatal "};
-+
-+static void global_error(int fatal, u32 errors)
-+{
-+	int i;
-+
-+	for(i=0;i<11;i++) {
-+		if(errors & (1<<i)) {
-+			printk( KERN_WARNING "%sError %s\n",
-+					fatal_message[fatal],
-+					global_message[i]);
-+		}
-+	}	
-+}
-+
-+char *hub_message[7]= {"HI Address or Command Parity","HI Illegal Access",
-+		       "HI Internal Parity","Out of Range Access",
-+		       "HI Data Parity","Enhanced Config Access",
-+		       "Hub Interface Target Abort"};
-+;
-+static void hub_error(int fatal, u8 errors)
-+{
-+	int i;
-+
-+	for(i=0;i<7;i++) {
-+		if(errors & (1<<i)) {
-+			printk( KERN_WARNING "%sError %s\n",
-+					fatal_message[fatal],
-+					hub_message[i]);
-+		}
-+	}	
-+}
-+
-+char *membuf_message[4]= {"Internal PMWB to DRAM parity",
-+			"Internal PMWB to System Bus Parity",
-+		       	"Internal System Bus or IO to PMWB Parity",
-+		       	"Internal DRAM to PMWB Parity"};
-+;
-+static void membuf_error(u8 errors)
-+{
-+	int i;
-+
-+	for(i=0;i<4;i++) {
-+		if(errors & (1<<i)) {
-+			printk( KERN_WARNING "Non-Fatal Error %s\n",
-+					membuf_message[i]);
-+		}
-+	}	
-+}
-+
-+char *sysbus_message[10]= {"Addr or Request Parity",
-+			"Data Strobe Glitch",
-+			"Addr Strobe Glitch",
-+			"Data Parity",
-+			"Addr Above TOM",
-+			"Non DRAM Lock Error",
-+			"MCERR", "BINIT",
-+			"Memory Parity",
-+			"IO Subsystem Parity"};
-+
-+static void sysbus_error(int fatal, u32 errors)
-+{
-+	int i;
-+
-+	for(i=0;i<10;i++) {
-+		if(errors & (1<<i)) {
-+			printk( KERN_WARNING "%sError System Bus %s\n",
-+					fatal_message[fatal],
-+					global_message[i]);
-+		}
-+	}	
-+}
-+
-+static void e752x_check(struct mem_ctl_info *mci)
-+{
-+	int i;
-+	u8   stat8;
-+	u16  error_one, error_next, stat;
-+	u32  stat32,error32;
-+	/* Snap shot of error registers */
-+	u8	hi_ferr;
-+	u8	hi_nerr;
-+	u16	sysbus_ferr;
-+	u16	sysbus_nerr;
-+	u8	buf_ferr;
-+	u8	buf_nerr;
-+	u16	dram_ferr;
-+	u16	dram_nerr;
-+	u32	celog1_add;
-+	u32	celog2_add;
-+	u16	celog1_syndrome;
-+	u16	celog2_syndrome;
-+	u32	retry_add;
-+	u32	uelog_add;
-+	u32	uelogs_add;
-+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
-+	struct pci_dev *pres_dev;
-+        struct pci_dev *dev;
-+
-+	/* clear snapshot */
-+	hi_ferr=hi_nerr=buf_ferr=buf_nerr=0;
-+	sysbus_ferr=sysbus_nerr=dram_ferr=dram_nerr=0;
-+	celog1_syndrome=celog2_syndrome=retry_add=0;
-+	celog1_add=celog2_add=uelog_add=uelogs_add=0;
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if (pvt->dev_d0f1 != NULL) {
-+		dev = pvt->dev_d0f1;
-+		pci_read_config_dword(dev,E752X_FERR_GLOBAL,&stat32);
-+		if(stat32) { /* Error, so process */
-+#if 1			
-+			/* dump d0f0 and d0f1 */
-+			printk("\nDevice 0 Function 0");
-+			for(i=0;i<0x100;i++) {
-+				pci_read_config_byte(mci->pdev,i,&stat8);
-+				if((i%16)==0) {
-+					printk("\n%2.2x  ",i);
-+				}
-+				printk("%2.2x ",stat8);
-+			}
-+			printk("\n");
-+			/* dump d0f0 and d0f1 */
-+			printk("\nDevice 0 Function 1");
-+			for(i=0;i<0x100;i++) {
-+				pci_read_config_byte(dev,i,&stat8);
-+				if((i%16)==0) {
-+					printk("\n%2.2x  ",i);
-+				}
-+			printk("%2.2x ",stat8);
-+			}
-+			printk("\n\n");
-+#endif			
-+			/* take a snap shot of first errors */
-+			pci_read_config_byte(dev,E752X_HI_FERR,&hi_ferr);
-+			pci_read_config_word(dev,E752X_SYSBUS_FERR,&sysbus_ferr);
-+			pci_read_config_byte(dev,E752X_BUF_FERR,&buf_ferr);
-+			pci_read_config_word(dev,E752X_DRAM_FERR,&dram_ferr);
-+			pci_read_config_dword(dev,E752X_DRAM_CELOG1_ADD,
-+					&celog1_add);
-+			pci_read_config_word(dev,E752X_DRAM_CELOG1_SYNDROME,
-+					&celog1_syndrome);
-+			pci_read_config_dword(dev,E752X_DRAM_UELOG_ADD,
-+					&uelog_add);
-+			pci_read_config_dword(dev,E752X_DRAM_UELOGS_ADD,
-+					&uelogs_add);
-+			pci_read_config_dword(dev,E752X_DRAM_RETRY_ADD,
-+					&retry_add);
-+			
-+			pci_write_config_dword(dev,E752X_FERR_GLOBAL,stat32);
-+			error32=(stat32>>18)&0x3ff;
-+			stat32=(stat32>>4)&0x7ff;
-+			if(error32) 
-+				global_error(1,error32);
-+			if(stat32)
-+				global_error(0,stat32);
-+		}
-+		
-+		pci_read_config_dword(dev,E752X_NERR_GLOBAL,&stat32);
-+		if(stat32) { /* Error, so process */
-+			/* take a snap shot of second errors */
-+			pci_read_config_byte(dev,E752X_HI_NERR,&hi_nerr);
-+			pci_read_config_word(dev,E752X_SYSBUS_NERR,&sysbus_nerr);
-+			pci_read_config_byte(dev,E752X_BUF_NERR,&buf_nerr);
-+			pci_read_config_word(dev,E752X_DRAM_NERR,&dram_nerr);
-+			pci_read_config_dword(dev,E752X_DRAM_CELOG2_ADD,
-+					&celog2_add);
-+			pci_read_config_word(dev,E752X_DRAM_CELOG2_SYNDROME,
-+					&celog2_syndrome);
-+			
-+			pci_write_config_dword(dev,E752X_NERR_GLOBAL,stat32);
-+			error32=(stat32>>18)&0x3ff;
-+			stat32=(stat32>>4)&0x7ff;
-+			if(error32) 
-+				global_error(1,error32);
-+			if(stat32)
-+				global_error(0,stat32);
-+		}
-+
-+//		pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
-+		stat8=hi_ferr;
-+		if(stat8&0x7f) { /* Error, so process */
-+			pci_write_config_dword(dev,E752X_HI_FERR,stat8);
-+			stat8 &= 0x7f;
-+			if(stat8&0x2b) 
-+				hub_error(1,(stat8&0x2b));
-+			if(stat8 & 0x54)
-+				hub_error(0,(stat8&0x54));
-+		}
-+//		pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
-+		stat8=hi_nerr;
-+		if(stat8&0x7f) { /* Error, so process */
-+			pci_write_config_dword(dev,E752X_HI_NERR,stat8);
-+			stat8 &= 0x7f;
-+			if(stat8&0x2b) 
-+				hub_error(1,(stat8&0x2b));
-+			if(stat8 & 0x54)
-+				hub_error(0,(stat8&0x54));
-+		}
-+//		pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32);
-+		stat32 = sysbus_ferr + (sysbus_nerr <<16);
-+		if(stat32) { /* Error, so process */
-+			pci_write_config_dword(dev,E752X_SYSBUS_FERR,stat32);
-+			error32=(stat32>>16)&0x3ff;
-+			stat32=stat32&0x3ff;
-+			if(stat32 & 0x083) 
-+				sysbus_error(1,(stat32&0x083));
-+			if(stat32 & 0x37c)
-+				sysbus_error(0,(stat32&0x37c));
-+			if(error32 & 0x083) 
-+				sysbus_error(1,(error32&0x083));
-+			if(error32 & 0x37c)
-+				sysbus_error(0,(error32&0x37c));
-+		}
-+//		pci_read_config_byte(dev,E752X_BUF_FERR,&stat8);
-+		stat8 = buf_ferr;
-+		if(stat8&0x0f) { /* Error, so process */
-+			pci_write_config_dword(dev,E752X_BUF_FERR,stat8);
-+			stat8 &= 0x0f;
-+			membuf_error(stat8);
-+		}
-+//		pci_read_config_byte(dev,E752X_BUF_NERR,&stat8);
-+		stat8 = buf_nerr;
-+		if(stat8&0x0f) { /* Error, so process */
-+			pci_write_config_dword(dev,E752X_BUF_NERR,stat8);
-+			stat8 &= 0x0f;
-+			membuf_error(stat8);
-+		}
-+
-+
-+
-+		
-+//		pci_read_config_word(pvt->bridge_ck,E752X_DRAM_FERR,&error_one);
-+//		pci_read_config_word(pvt->bridge_ck,E752X_DRAM_NERR,&error_next);
-+		error_one = dram_ferr;
-+		error_next = dram_nerr;
-+		/* clear any error bits */
-+		if(error_one) {
-+			pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR, 
-+					error_one,error_one);
-+		}
-+		if(error_next) {
-+			pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR, 
-+					error_next, error_next);
-+		}
-+	
-+		/* decode and report errors */
-+		if(error_one & 0x0101) { /* check first error correctable */
-+			process_ce(mci,error_one,celog1_add,celog1_syndrome);
-+		}
-+		if(error_next & 0x0101) { /* check next error correctable */
-+			process_ce(mci,error_next,celog2_add,celog2_syndrome);
-+		}
-+		if(error_one & 0x4040) {
-+			process_ue_no_info_wr(mci);
-+		}
-+		if(error_next & 0x4040) {
-+			process_ue_no_info_wr(mci);
-+		}
-+		if(error_one & 0x2020) {
-+			process_ded_retry(mci,error_one,retry_add);
-+		}
-+		if(error_next & 0x2020) {
-+			process_ded_retry(mci,error_next,retry_add);
-+		}
-+		if(error_one & 0x0808) {
-+			process_threshold_ce(mci,error_one);
-+		}
-+		if(error_next & 0x0808) {
-+			process_threshold_ce(mci,error_next);
-+		}
-+		if(error_one & 0x0606) {
-+			process_ue(mci,error_one,uelog_add,uelogs_add);
-+		}
-+		if(error_next & 0x0606) {
-+			process_ue(mci,error_next,uelog_add,uelogs_add);
-+		}
-+		
-+
-+	}
-+	/* Test for PCI Parity errors in the southbridge */
-+	if (pvt->dev_d0f0 != NULL) {
-+		dev = pvt->dev_d0f0;
-+        	for(pres_dev = dev;
-+		  ((struct pci_dev*)pres_dev->global_list.next != dev);
-+		  pres_dev = (struct pci_dev*)pres_dev->global_list.next) {
-+			pci_read_config_dword(pres_dev,PCI_COMMAND,&stat32);
-+			stat = (u16)(stat32 >>16);
-+			/* test for error any error bits */
-+			if(stat32 & ((1<<6)+(1<<8))) { /* error reporting dev */
-+				if(stat & ((1<<15)+(1<<14)+(1<<8))) {
-+				    pci_write_config_word(pres_dev,6,stat);
-+				    if(stat & (1<<14)) {
-+				      printk( KERN_WARNING
-+					"System Error on %s %s\n",
-+					pres_dev->slot_name,
-+					pci_pretty_name(pres_dev));
-+				    }
-+				    if(stat & ((1<<15)+(1<<8))) {
-+				      printk( KERN_WARNING
-+					"Parity Error on %s %s\n",
-+					pres_dev->slot_name,
-+					pci_pretty_name(pres_dev));
-+				    }
-+				}
-+			}
-+		}
-+	}
-+}
-+
-+
-+static int e752x_probe1( struct pci_dev *pdev, int dev_idx )
-+{
-+	int rc = -ENODEV;
-+	int index;
-+	u16 pci_data, stat;
-+	u32 stat32;
-+	u16 stat16;
-+	u8  stat8;
-+	struct mem_ctl_info *mci = NULL;
-+	struct e752x_pvt *pvt = NULL;
-+	u16 ddrcsr;
-+	u32 drc;
-+	int drc_chan;		/* Number of channels 0=1chan,1=2chan */
-+	int drc_drbg;		/* DRB granularity 0=32mb,1=64mb */
-+	int drc_ddim;		/* DRAM Data Integrity Mode 0=none,2=edac */
-+	u32 dra;
-+	unsigned long last_cumul_size;
-+	struct pci_dev *pres_dev;
-+        struct pci_dev *dev;
-+
-+	debugf0( "MC: " __FILE__ ": %s(): mci\n", __func__ );
-+  printk( KERN_ERR "Starting Probe1\n" );
-+
-+	/* enable device 0 function 1 */
-+	pci_read_config_byte(pdev, E752X_DEVPRES1, &stat8);
-+	stat8 |= (1<<5);
-+	pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
-+
-+	/* need to find out the number of channels */
-+	pci_read_config_dword(pdev, E752X_DRC, &drc);
-+	pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr);
-+	if(((ddrcsr>>12)&3)==3)
-+		drc_chan = 1;  /* Dual channel */
-+	else
-+		drc_chan = 0; /* Single channel */
-+	drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */ 
-+	drc_ddim = ( drc >> 20 ) & 0x3;
-+
-+	mci = bluesmoke_mc_init_structs(sizeof(*pvt),
-+					E752X_NR_CSROWS,
-+					drc_chan + 1);
-+
-+	if ( ! mci ) {
-+		rc = -ENOMEM;
-+		goto FAIL_FINISHED;
-+	}
-+
-+	debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
-+
-+	mci->mtype_cap = MEM_FLAG_RDDR;
-+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED;
-+	/* FIXME - what if different memory types are in different csrows? */
-+	mci->mod_name = BS_MOD_STR;
-+	mci->mod_ver = "$Revision: 1.5 $";
-+	mci->pdev = pdev;
-+
-+	debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ );
-+	pvt = (struct e752x_pvt *)mci->pvt_info;
-+	pvt->dev_info = &e752x_devs[dev_idx];
-+	pvt->bridge_ck = pci_find_device( PCI_VENDOR_ID_INTEL,
-+					  pvt->dev_info->err_dev,
-+					  pvt->bridge_ck );
-+	if ( ! pvt->bridge_ck ) {
-+		pvt->bridge_ck = pci_scan_single_device(pdev->bus, PCI_DEVFN(0,1));
-+	}
-+	if ( ! pvt->bridge_ck ) {
-+		printk( KERN_ERR
-+			"MC: error reporting device not found:"
-+			"vendor %x device 0x%x (broken BIOS?)\n",
-+			PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev );
-+		goto FAIL_FINISHED;
-+	}
-+	if(ddrcsr & 0x10) {
-+		pvt->mc_symmetric = 1;
-+	} else {
-+		pvt->mc_symmetric =0;
-+	}
-+
-+	debugf3( "MC: " __FILE__ ": %s(): more mci init\n", __func__ );
-+	mci->ctl_name = pvt->dev_info->ctl_name;
-+
-+	mci->edac_check = e752x_check;
-+	/* FIXME - why isn't clear_err set to something? */
-+	mci->clear_err = NULL;
-+	mci->ctl_page_to_phys = ctl_page_to_phys;
-+
-+	/* find out the device types */
-+	pci_read_config_dword(pdev, E752X_DRA, &dra);
-+
-+	/*
-+	 * The dram row boundary (DRB) reg values are boundary address
-+	 * for each DRAM row with a granularity of 64 or 128MB (single/dual
-+	 * channel operation).  DRB regs are cumulative; therefore DRB7 will
-+	 * contain the total memory contained in all eight rows.
-+	 */
-+	for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
-+		u8 value;
-+		u32 cumul_size;
-+		/* mem_dev 0=x8, 1=x4 */
-+		int mem_dev = ( dra >> ( index * 4 + 2 ) ) & 0x3;
-+		struct csrow_info *csrow = &mci->csrows[ index ];
-+
-+		if(mem_dev == 2)
-+			mem_dev = 1;
-+		else
-+			mem_dev = 0;
-+		pci_read_config_byte(mci->pdev, E752X_DRB + index, &value);
-+		/* convert a 128 or 64 MiB DRB to a page size. */
-+		cumul_size = value << (25 + drc_drbg - PAGE_SHIFT );
-+		debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
-+			__func__, index, cumul_size );
-+		if ( cumul_size == last_cumul_size ) {
-+			continue;	/* not populated */
-+		}
-+
-+		csrow->first_page = last_cumul_size;
-+		csrow->last_page = cumul_size - 1;
-+		csrow->nr_pages = cumul_size - last_cumul_size;
-+		last_cumul_size = cumul_size;
-+		csrow->grain = 1 << 12;		/* 4KiB - resolution of CELOG */
-+		csrow->mtype = MEM_RDDR;	/* only one type supported */
-+		csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
-+
-+		/*
-+		 * if single channel or x8 devices then SECDED
-+		 * if dual channel and x4 then S4ECD4ED
-+		 */
-+		if ( drc_ddim ) {
-+			if ( drc_chan && mem_dev ) {
-+				csrow->edac_mode = EDAC_S4ECD4ED;
-+				mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-+			} else {
-+				csrow->edac_mode = EDAC_SECDED;
-+				mci->edac_cap |= EDAC_FLAG_SECDED;
-+			}
-+		} else {
-+			csrow->edac_mode = EDAC_NONE;
-+		}
-+	}
-+	
-+	/* Fill in the memory map table */
-+	{
-+		u8 value;
-+		u8 last=0;
-+		u8 row=0;
-+	for(index=0;index<8;index+=2) {
-+		
-+		pci_read_config_byte(mci->pdev, E752X_DRB + index, &value);
-+		/* test if there is a dimm in this slot */
-+		if(value == last) {
-+			/* no dimm in the slot, so flag it as empty */
-+			pvt->map[index]=0xff;
-+			pvt->map[index+1]=0xff;
-+		}
-+		else {  /* there is a dimm in the slot */
-+			pvt->map[index]=row;
-+			row++;
-+			last = value;
-+			/* test the next value to see if the dimm is double sided */
-+			pci_read_config_byte(mci->pdev, E752X_DRB + index + 1, &value);
-+			if(value == last) {
-+				/* the dimm is single sided, so flag as empty */
-+				pvt->map[index+1]=0xff;
-+				row++;
-+			}
-+			else {
-+				/* this is a double sided dimm to save the next row # */
-+				pvt->map[index+1]=row;
-+				row++;
-+			}
-+			last = value;
-+		}
-+	}
-+	}
-+
-+	/* set the map type.  1 = normal, 0 = reversed */
-+	pci_read_config_byte(mci->pdev, E752X_DRM, &stat8);
-+	if((stat8&0x0f) > ((stat8>>4)&0x0f)) {
-+		/* map type is normal */
-+		pvt->map_type = 1;
-+	}
-+	else {
-+		/* map type is reversed */
-+		pvt->map_type = 0;
-+	}
-+
-+	mci->edac_cap |= EDAC_FLAG_NONE;
-+
-+	debugf3( "MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", __func__ );
-+	/* load the top of low memory, remap base, and remap limit vars */
-+	pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data);
-+	pvt->tolm = ((u32)pci_data) << 4;
-+	pci_read_config_word(mci->pdev, E752X_REMAPBASE, &pci_data);
-+	pvt->remapbase = ((u32)pci_data) << 14;
-+	pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data);
-+	pvt->remaplimit = ((u32)pci_data) << 14;
-+	printk( "tolm = %x, remapbase = %x, remaplimit = %x\n",
-+		pvt->tolm, pvt->remapbase, pvt->remaplimit);
-+
-+	if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
-+		debugf3( "MC: " __FILE__ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	/* Walk through the PCI table and clear errors */	
-+	dev = pci_find_device( PCI_VENDOR_ID_INTEL,
-+                  PCI_DEVICE_ID_INTEL_7520_0, NULL );
-+	pvt->dev_d0f0 = dev;
-+        for(pres_dev = dev;
-+		  ((struct pci_dev*)pres_dev->global_list.next != dev);
-+		  pres_dev = (struct pci_dev*)pres_dev->global_list.next) {
-+		pci_read_config_dword(pres_dev,PCI_COMMAND,&stat32);
-+		stat = (u16)(stat32 >>16);
-+		/* clear any error bits */
-+		if(stat32 & ((1<<6)+(1<<8))) {
-+			pci_write_config_word(pres_dev,PCI_STATUS,stat);
-+		}
-+	}
-+	/* find the error reporting device and clear errors */
-+	dev = pvt->dev_d0f1 = pvt->bridge_ck;
-+	/* Turn off error disable & SMI in case the BIOS turned it on */
-+	pci_write_config_byte(dev,E752X_HI_ERRMASK,0x00);
-+	pci_write_config_byte(dev,E752X_HI_SMICMD,0x00);
-+	pci_write_config_word(dev,E752X_SYSBUS_ERRMASK,0x00);
-+	pci_write_config_word(dev,E752X_SYSBUS_SMICMD,0x00);
-+	pci_write_config_byte(dev,E752X_BUF_ERRMASK,0x00);
-+	pci_write_config_byte(dev,E752X_BUF_SMICMD,0x00);
-+	pci_write_config_byte(dev,E752X_DRAM_ERRMASK,0x00);
-+	pci_write_config_byte(dev,E752X_DRAM_SMICMD,0x00);
-+	/* clear other MCH errors */
-+	pci_read_config_dword(dev,E752X_FERR_GLOBAL,&stat32);
-+	pci_write_config_dword(dev,E752X_FERR_GLOBAL,stat32);
-+	pci_read_config_dword(dev,E752X_NERR_GLOBAL,&stat32);
-+	pci_write_config_dword(dev,E752X_NERR_GLOBAL,stat32);
-+	pci_read_config_byte(dev,E752X_HI_FERR,&stat8);
-+	pci_write_config_byte(dev,E752X_HI_FERR,stat8);
-+	pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
-+	pci_write_config_byte(dev,E752X_HI_NERR,stat8);
-+	pci_read_config_dword(dev,E752X_SYSBUS_FERR,&stat32);
-+	pci_write_config_dword(dev,E752X_SYSBUS_FERR,stat32);
-+	pci_read_config_byte(dev,E752X_BUF_FERR,&stat8);
-+	pci_write_config_byte(dev,E752X_BUF_FERR,stat8);
-+	pci_read_config_byte(dev,E752X_BUF_NERR,&stat8);
-+	pci_write_config_byte(dev,E752X_BUF_NERR,stat8);
-+	pci_read_config_word(dev, E752X_DRAM_FERR, &stat16);
-+	pci_write_config_word(dev, E752X_DRAM_FERR, stat16);
-+	pci_read_config_word(dev, E752X_DRAM_NERR, &stat16);
-+	pci_write_config_word(dev, E752X_DRAM_NERR, stat16);
-+	
-+	/* get this far and it's successful */
-+	debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
-+	rc = 0;
-+	goto FINISHED;
-+
-+ FAIL_FINISHED:
-+	if ( mci ) {
-+		kfree( mci );
-+	}
-+ FINISHED:
-+	return( rc );
-+}
-+
-+
-+#ifdef CONFIG_PM
-+
-+static int e752x_suspend (struct pci_dev *pdev, u32 state)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+
-+static int e752x_resume (struct pci_dev *pdev)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+#endif /* CONFIG_PM */
-+
-+
-+/* returns count (>= 0), or negative on error */
-+static int __devinit e752x_init_one( struct pci_dev *pdev,
-+				     const struct pci_device_id *ent )
-+{
-+	int rc;
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	/* wake up and enable device */		
-+	if (pci_enable_device (pdev)) {
-+		rc = -EIO;
-+	} else {
-+		rc = e752x_probe1( pdev, ent->driver_data );
-+	}
-+	return rc;
-+}
-+
-+
-+static void __devexit e752x_remove_one( struct pci_dev *pdev )
-+{
-+	struct mem_ctl_info *mci;
-+
-+	debugf0( __FILE__ ": %s()\n", __func__);
-+
-+	if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
-+		goto FINISHED;
-+	}
-+
-+	if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
-+		goto FINISHED;
-+	}
-+
-+	kfree( mci );
-+
-+ FINISHED:
-+	return;
-+}
-+
-+
-+static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
-+	{ PCI_VEND_DEV( INTEL, 7520_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7520 },
-+	{0,}						/* 0 terminated list. */
-+};
-+
-+MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
-+
-+
-+static struct pci_driver e752x_driver = {
-+	name:		BS_MOD_STR,
-+	probe:		e752x_init_one,
-+	remove:		__devexit_p(e752x_remove_one),
-+	id_table:	e752x_pci_tbl,
-+#ifdef CONFIG_PM
-+	suspend:	e752x_suspend,
-+	resume:		e752x_resume,
-+#endif /* CONFIG_PM */
-+};
-+
-+
-+int __init e752x_init(void)
-+{
-+	int pci_rc;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+	pci_rc = pci_module_init( &e752x_driver );
-+	if ( pci_rc < 0 ) return pci_rc;
-+
-+	return 0;
-+}
-+
-+
-+static void __exit e752x_exit(void)
-+{
-+	debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
-+	pci_unregister_driver( &e752x_driver );
-+}
-+
-+
-+module_init(e752x_init);
-+module_exit(e752x_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");
-+MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e7xxx.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_e7xxx.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_e7xxx.c	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,552 @@
-+/*
-+ * Intel e7xxx Memory Controller kernel module
-+ * (C) 2003 Linux Networx (http://lnxi.com)
-+ * This file may be distributed under the terms of the
-+ * GNU General Public License.
-+ *
-+ * See "enum e7xxx_chips" below for supported chipsets
-+ *
-+ * Written by Thayne Harbaugh
-+ * Based on work by Dan Hollis <goemon at anime dot net> and others.
-+ *	http://www.anime.net/~goemon/linux-ecc/
-+ *
-+ * Contributors:
-+ * 	Eric Biederman (Linux Networx)
-+ * 	Tom Zimmerman (Linux Networx)
-+ * 	Jim Garlic (Lawrence Livermore National Labs)
-+ *	Dave Peterson (Lawrence Livermore National Labs)
-+ *	That One Guy (Some other place)
-+ *
-+ * $Id: bluesmoke_e7xxx.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/pci.h>
-+#include <linux/pci_ids.h>
-+
-+#include <linux/slab.h>
-+
-+#include "bluesmoke_mc.h"
-+
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7205_0
-+#define PCI_DEVICE_ID_INTEL_7205_0	0x255d
-+#endif /* PCI_DEVICE_ID_INTEL_7205_0 */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7205_1_ERR
-+#define PCI_DEVICE_ID_INTEL_7205_1_ERR	0x2551
-+#endif /* PCI_DEVICE_ID_INTEL_7205_1_ERR */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7500_0
-+#define PCI_DEVICE_ID_INTEL_7500_0	0x2540
-+#endif /* PCI_DEVICE_ID_INTEL_7500_0 */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7500_1_ERR
-+#define PCI_DEVICE_ID_INTEL_7500_1_ERR	0x2541
-+#endif /* PCI_DEVICE_ID_INTEL_7500_1_ERR */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7501_0
-+#define PCI_DEVICE_ID_INTEL_7501_0	0x254c
-+#endif /* PCI_DEVICE_ID_INTEL_7501_0 */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7501_1_ERR
-+#define PCI_DEVICE_ID_INTEL_7501_1_ERR	0x2541
-+#endif /* PCI_DEVICE_ID_INTEL_7501_1_ERR */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7505_0
-+#define PCI_DEVICE_ID_INTEL_7505_0	0x2550
-+#endif /* PCI_DEVICE_ID_INTEL_7505_0 */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_7505_1_ERR
-+#define PCI_DEVICE_ID_INTEL_7505_1_ERR	0x2551
-+#endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */
-+
-+
-+#define E7XXX_NR_CSROWS		8	/* number of csrows */
-+#define E7XXX_NR_DIMMS		8	/* FIXME - is this correct? */
-+
-+
-+/* E7XXX register addresses - device 0 function 0 */
-+#define E7XXX_DRB		0x60	/* DRAM row boundary register (8b) */
-+#define E7XXX_DRA		0x70	/* DRAM row attribute register (8b) */
-+					/*
-+					 * 31   Device width row 7 0=x8 1=x4
-+					 * 27   Device width row 6
-+					 * 23   Device width row 5
-+					 * 19   Device width row 4
-+					 * 15   Device width row 3
-+					 * 11   Device width row 2
-+					 *  7   Device width row 1
-+					 *  3   Device width row 0
-+					 */
-+#define E7XXX_DRC		0x7C	/* DRAM controller mode reg (32b) */
-+					/*
-+					 * 22    Number channels 0=1,1=2
-+					 * 19:18 DRB Granularity 32/64MB
-+					 */
-+#define E7XXX_TOLM		0xC4	/* DRAM top of low memory reg (16b) */
-+#define E7XXX_REMAPBASE		0xC6	/* DRAM remap base address reg (16b) */
-+#define E7XXX_REMAPLIMIT	0xC8	/* DRAM remap limit address reg (16b) */
-+
-+/* E7XXX register addresses - device 0 function 1 */
-+#define E7XXX_DRAM_FERR		0x80	/* DRAM first error register (8b) */
-+#define E7XXX_DRAM_NERR		0x82	/* DRAM next error register (8b) */
-+#define E7XXX_DRAM_CELOG_ADD	0xA0	/* DRAM first correctable memory */
-+					/*     error address register (32b) */
-+					/*
-+					 * 31:28 Reserved
-+					 * 27:6  CE address (4k block 33:12)
-+					 *  5:0  Reserved
-+					 */
-+#define E7XXX_DRAM_UELOG_ADD	0xB0	/* DRAM first uncorrectable memory */
-+					/*     error address register (32b) */
-+					/*
-+					 * 31:28 Reserved
-+					 * 27:6  CE address (4k block 33:12)
-+					 *  5:0  Reserved
-+					 */
-+#define E7XXX_DRAM_CELOG_SYNDROME 0xD0	/* DRAM first correctable memory */
-+					/*     error syndrome register (16b) */
-+
-+enum e7xxx_chips {
-+	E7500 = 0,
-+	E7501,
-+	E7505,
-+	E7205,
-+};
-+
-+
-+struct e7xxx_pvt {
-+	struct pci_dev *bridge_ck;
-+	u32 tolm;
-+	u32 remapbase;
-+	u32 remaplimit;
-+	const struct e7xxx_dev_info *dev_info;
-+};
-+
-+
-+struct e7xxx_dev_info {
-+	u16 err_dev;
-+	const char *ctl_name;
-+};
-+
-+
-+static const struct e7xxx_dev_info e7xxx_devs[] = {
-+	[E7500] = {
-+		.err_dev  = PCI_DEVICE_ID_INTEL_7500_1_ERR,
-+		.ctl_name = "E7500"
-+	},
-+	[E7501] = {
-+		.err_dev  = PCI_DEVICE_ID_INTEL_7501_1_ERR,
-+		.ctl_name = "E7501"
-+	},
-+	[E7505] = {
-+		.err_dev  = PCI_DEVICE_ID_INTEL_7505_1_ERR,
-+		.ctl_name = "E7505"
-+	},
-+	[E7205] = {
-+		.err_dev  = PCI_DEVICE_ID_INTEL_7205_1_ERR,
-+		.ctl_name = "E7205"
-+	},
-+};
-+
-+
-+/* FIXME - is this valid for both SECDED and S4ECD4ED? */
-+static inline int e7xxx_find_channel(u16 syndrome)
-+{
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if((syndrome & 0xff00)==0)
-+		return(0);
-+	if((syndrome & 0x00ff)==0)
-+		return(1);
-+	if((syndrome & 0xf000)==0)
-+		return(0);
-+	if((syndrome & 0x0f00)==0)
-+		return(0);
-+	return(1);
-+}
-+
-+
-+static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
-+				      unsigned long page)
-+{
-+	u32 remap;
-+	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if(page < pvt->tolm)
-+		return(page);
-+	if((page >= 0x100000)&&(page < pvt->remapbase))
-+		return(page);
-+	remap = (page - pvt->tolm) + pvt->remapbase;
-+	if(remap < pvt->remaplimit)
-+		return(remap);	
-+	printk(KERN_ERR "Invalid page %lx - out of range\n", page);
-+	return(pvt->tolm-1);
-+}
-+
-+
-+static void process_ce(struct mem_ctl_info *mci)
-+{
-+	u32 error_1b, page;
-+	u16 syndrome;
-+	int row;
-+	int channel;
-+	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	/* read the error address */
-+	pci_read_config_dword(pvt->bridge_ck,E7XXX_DRAM_CELOG_ADD,
-+				&error_1b);
-+	/* FIXME - should use PAGE_SHIFT */
-+	page = error_1b >>6;  /* convert the address to 4k page */
-+	/* read the syndrome */
-+	pci_read_config_word(pvt->bridge_ck,E7XXX_DRAM_CELOG_SYNDROME,
-+			&syndrome);
-+	/* FIXME - check for -1 */
-+	row = bluesmoke_mc_find_csrow_by_page( mci, page );
-+	channel = e7xxx_find_channel(syndrome); /* convert syndrome to channel */
-+	bluesmoke_mc_handle_ce( mci, page, 0, syndrome,
-+				row, channel, "e7xxx CE" );
-+}
-+
-+
-+static void process_ce_no_info(struct mem_ctl_info *mci)
-+{
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	bluesmoke_mc_handle_ce_no_info( mci, "e7xxx CE log register overflow" );
-+}
-+
-+
-+static void process_ue(struct mem_ctl_info *mci)
-+{
-+	u32 error_2b, block_page;
-+	int row;
-+	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	/* read the error address */
-+	pci_read_config_dword( pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD,
-+			       &error_2b );
-+	/* FIXME - should use PAGE_SHIFT */
-+	block_page = error_2b >>6;  /* convert to 4k address */
-+	row = bluesmoke_mc_find_csrow_by_page( mci, block_page );
-+	bluesmoke_mc_handle_ue( mci, block_page, 0, row, "e7xxx UE" );
-+}
-+
-+
-+static void process_ue_no_info(struct mem_ctl_info *mci)
-+{
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	bluesmoke_mc_handle_ue_no_info( mci, "e7xxx UE log register overflow" );
-+}
-+
-+
-+static void e7xxx_check(struct mem_ctl_info *mci)
-+{
-+	u8  error_one, error_next;
-+	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	pci_read_config_byte(pvt->bridge_ck,E7XXX_DRAM_FERR,&error_one);
-+	pci_read_config_byte(pvt->bridge_ck,E7XXX_DRAM_NERR,&error_next);
-+
-+	/* clear any error bits */
-+	if(error_one & 3) {
-+		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);
-+	}
-+	if(error_next & 3) {
-+		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
-+	}
-+
-+	/* decode and report errors */
-+	if(error_one & 1) { /* check first error correctable */
-+		process_ce(mci);
-+		if(error_next & 1) {  /* check next error correctable */
-+			process_ce_no_info(mci);
-+		}
-+		if(error_next & 2) {  /* check next error uncorrectable */
-+			process_ue(mci);
-+		}
-+	} else if(error_one & 2) { /* check first error uncorrectable */
-+		process_ue(mci);
-+		if(error_next & 1) {  /* check next error correctable */
-+			process_ce(mci);
-+		}
-+		if(error_next & 2) {  /* check next error uncorrectable */
-+			process_ue_no_info(mci);
-+		}
-+	}
-+}
-+
-+
-+static int e7xxx_probe1( struct pci_dev *pdev, int dev_idx )
-+{
-+	int rc = -ENODEV;
-+	int index;
-+	u16 pci_data;
-+	struct mem_ctl_info *mci = NULL;
-+	struct e7xxx_pvt *pvt = NULL;
-+	u32 drc;
-+	int drc_chan;		/* Number of channels 0=1chan,1=2chan */
-+	int drc_drbg;		/* DRB granularity 0=32mb,1=64mb */
-+	int drc_ddim;		/* DRAM Data Integrity Mode 0=none,2=edac */
-+	u32 dra;
-+	unsigned long last_cumul_size;
-+	
-+
-+	debugf0( "MC: " __FILE__ ": %s(): mci\n", __func__ );
-+
-+	/* need to find out the number of channels */
-+	pci_read_config_dword(pdev, E7XXX_DRC, &drc);
-+	drc_chan = ( ( drc >> 22 ) & 0x1 );
-+	drc_drbg = ( drc >> 18 ) & 0x3;
-+	drc_ddim = ( drc >> 20 ) & 0x3;
-+
-+	mci = bluesmoke_mc_init_structs(sizeof(*pvt),
-+					E7XXX_NR_CSROWS,
-+					drc_chan + 1);
-+
-+	if ( ! mci ) {
-+		rc = -ENOMEM;
-+		goto FAIL_FINISHED;
-+	}
-+
-+	debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
-+
-+	mci->mtype_cap = MEM_FLAG_RDDR;
-+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED;
-+	/* FIXME - what if different memory types are in different csrows? */
-+	mci->mod_name = BS_MOD_STR;
-+	mci->mod_ver = "$Revision: 1.5 $";
-+	mci->pdev = pdev;
-+
-+	debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ );
-+	pvt = (struct e7xxx_pvt *)mci->pvt_info;
-+	pvt->dev_info = &e7xxx_devs[dev_idx];
-+	pvt->bridge_ck = pci_find_device( PCI_VENDOR_ID_INTEL,
-+					  pvt->dev_info->err_dev,
-+					  pvt->bridge_ck );
-+	if ( ! pvt->bridge_ck ) {
-+		printk( KERN_ERR
-+			"MC: error reporting device not found:"
-+			"vendor %x device 0x%x (broken BIOS?)\n",
-+			PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	debugf3( "MC: " __FILE__ ": %s(): more mci init\n", __func__ );
-+	mci->ctl_name = pvt->dev_info->ctl_name;
-+
-+	mci->edac_check = e7xxx_check;
-+	/* FIXME - why isn't clear_err set to something? */
-+	mci->clear_err = NULL;
-+	mci->ctl_page_to_phys = ctl_page_to_phys;
-+
-+	/* find out the device types */
-+	pci_read_config_dword(pdev, E7XXX_DRA, &dra);
-+
-+	/*
-+	 * The dram row boundary (DRB) reg values are boundary address
-+	 * for each DRAM row with a granularity of 32 or 64MB (single/dual
-+	 * channel operation).  DRB regs are cumulative; therefore DRB7 will
-+	 * contain the total memory contained in all eight rows.
-+	 */
-+	for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
-+		u8 value;
-+		u32 cumul_size;
-+		/* mem_dev 0=x8, 1=x4 */
-+		int mem_dev = ( dra >> ( index * 4 + 3 ) ) & 0x1;
-+		struct csrow_info *csrow = &mci->csrows[ index ];
-+
-+		pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value);
-+		/* convert a 64 or 32 MiB DRB to a page size. */
-+		cumul_size = value << (25 + drc_drbg - PAGE_SHIFT );
-+		debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
-+			__func__, index, cumul_size );
-+		if ( cumul_size == last_cumul_size ) {
-+			continue;	/* not populated */
-+		}
-+
-+		csrow->first_page = last_cumul_size;
-+		csrow->last_page = cumul_size - 1;
-+		csrow->nr_pages = cumul_size - last_cumul_size;
-+		last_cumul_size = cumul_size;
-+		csrow->grain = 1 << 12;		/* 4KiB - resolution of CELOG */
-+		csrow->mtype = MEM_RDDR;	/* only one type supported */
-+		csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
-+
-+		/*
-+		 * if single channel or x8 devices then SECDED
-+		 * if dual channel and x4 then S4ECD4ED
-+		 */
-+		if ( drc_ddim ) {
-+			if ( drc_chan && mem_dev ) {
-+				csrow->edac_mode = EDAC_S4ECD4ED;
-+				mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-+			} else {
-+				csrow->edac_mode = EDAC_SECDED;
-+				mci->edac_cap |= EDAC_FLAG_SECDED;
-+			}
-+		} else {
-+			csrow->edac_mode = EDAC_NONE;
-+		}
-+	}
-+
-+	mci->edac_cap |= EDAC_FLAG_NONE;
-+
-+	debugf3( "MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", __func__ );
-+	/* load the top of low memory, remap base, and remap limit vars */
-+	pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data);
-+	pvt->tolm = ((u32)pci_data) << 4;
-+	pci_read_config_word(mci->pdev, E7XXX_REMAPBASE, &pci_data);
-+	pvt->remapbase = ((u32)pci_data) << 14;
-+	pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data);
-+	pvt->remaplimit = ((u32)pci_data) << 14;
-+	printk( "tolm = %x, remapbase = %x, remaplimit = %x\n",
-+		pvt->tolm, pvt->remapbase, pvt->remaplimit);
-+
-+	/* clear any pending errors, or initial state bits */
-+	pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03);
-+	pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
-+
-+	if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
-+		debugf3( "MC: " __FILE__ ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	/* get this far and it's successful */
-+	debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
-+	rc = 0;
-+	goto FINISHED;
-+
-+ FAIL_FINISHED:
-+	if ( mci ) {
-+		kfree( mci );
-+	}
-+ FINISHED:
-+	return( rc );
-+}
-+
-+
-+#ifdef CONFIG_PM
-+
-+static int e7xxx_suspend (struct pci_dev *pdev, u32 state)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+
-+static int e7xxx_resume (struct pci_dev *pdev)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+#endif /* CONFIG_PM */
-+
-+
-+/* returns count (>= 0), or negative on error */
-+static int __devinit e7xxx_init_one( struct pci_dev *pdev,
-+				     const struct pci_device_id *ent )
-+{
-+	int rc;
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	/* wake up and enable device */		
-+	if (pci_enable_device (pdev)) {
-+		rc = -EIO;
-+	} else {
-+		rc = e7xxx_probe1( pdev, ent->driver_data );
-+	}
-+	return rc;
-+}
-+
-+
-+static void __devexit e7xxx_remove_one( struct pci_dev *pdev )
-+{
-+	struct mem_ctl_info *mci;
-+
-+	debugf0( __FILE__ ": %s()\n", __func__);
-+
-+	if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
-+		goto FINISHED;
-+	}
-+
-+	if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
-+		goto FINISHED;
-+	}
-+
-+	kfree( mci );
-+
-+ FINISHED:
-+	return;
-+}
-+
-+
-+static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
-+	{ PCI_VEND_DEV( INTEL, 7205_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7205 },
-+	{ PCI_VEND_DEV( INTEL, 7500_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7500 },
-+	{ PCI_VEND_DEV( INTEL, 7501_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7501 },
-+	{ PCI_VEND_DEV( INTEL, 7505_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7505 },
-+	{0,}						/* 0 terminated list. */
-+};
-+
-+MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
-+
-+
-+static struct pci_driver e7xxx_driver = {
-+	.name		= BS_MOD_STR,
-+	.probe		= e7xxx_init_one,
-+	.remove		= __devexit_p(e7xxx_remove_one),
-+	.id_table	= e7xxx_pci_tbl,
-+#ifdef CONFIG_PM
-+	.suspend	= e7xxx_suspend,
-+	.resume		= e7xxx_resume,
-+#endif /* CONFIG_PM */
-+};
-+
-+
-+int __init e7xxx_init(void)
-+{
-+	int pci_rc;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+	pci_rc = pci_module_init( &e7xxx_driver );
-+	if ( pci_rc < 0 ) return pci_rc;
-+
-+	return 0;
-+}
-+
-+
-+static void __exit e7xxx_exit(void)
-+{
-+	debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
-+	pci_unregister_driver( &e7xxx_driver );
-+}
-+
-+
-+module_init(e7xxx_init);
-+module_exit(e7xxx_exit);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
-+	      "Based on.work by Dan Hollis et al");
-+MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers");
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_i82875p.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_i82875p.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_i82875p.c	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,510 @@
-+/*
-+ * AMD 76x Memory Controller kernel module
-+ * (C) 2003 Linux Networx (http://lnxi.com)
-+ * This file may be distributed under the terms of the
-+ * GNU General Public License.
-+ *
-+ * Written by Thayne Harbaugh
-+ *
-+ * $Id: bluesmoke_i82875p.c,v 1.5 2004/11/18 22:19:46 thayne Exp $
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/pci.h>
-+#include <linux/pci_ids.h>
-+
-+#include <linux/slab.h>
-+
-+#include "bluesmoke_mc.h"
-+
-+
-+#ifndef PCI_DEVICE_ID_INTEL_82875_0
-+#define PCI_DEVICE_ID_INTEL_82875_0	0x2578
-+#endif /* PCI_DEVICE_ID_INTEL_82875_0 */
-+
-+#ifndef PCI_DEVICE_ID_INTEL_82875_6
-+#define PCI_DEVICE_ID_INTEL_82875_6	0x257e
-+#endif /* PCI_DEVICE_ID_INTEL_82875_6 */
-+
-+
-+/* four csrows in dual channel, eight in single channel */
-+#define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans))
-+
-+
-+/* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */
-+#define I82875P_EAP		0x58	/* Error Address Pointer (32b)
-+					 *
-+					 * 31:12 block address
-+					 * 11:0  reserved
-+					 */
-+
-+#define I82875P_DERRSYN		0x5c	/* DRAM Error Syndrome (8b)
-+					 *
-+					 *  7:0  DRAM ECC Syndrome
-+					 */
-+
-+#define I82875P_DES		0x5d	/* DRAM Error Status (8b)
-+					 *
-+					 *  7:1  reserved
-+					 *  0    Error channel 0/1
-+					 */
-+
-+#define I82875P_ERRSTS		0xc8	/* Error Status Register (16b)
-+					 *
-+					 * 15:10 reserved
-+					 *  9    non-DRAM lock error (ndlock)
-+					 *  8    Sftwr Generated SMI
-+					 *  7    ECC UE
-+					 *  6    reserved
-+					 *  5    MCH detects unimplemented cycle
-+					 *  4    AGP access outside GA
-+					 *  3    Invalid AGP access
-+					 *  2    Invalid GA translation table
-+					 *  1    Unsupported AGP command
-+					 *  0    ECC CE
-+					 */
-+
-+#define I82875P_ERRCMD		0xca	/* Error Command (16b)
-+					 *
-+					 * 15:10 reserved
-+					 *  9    SERR on non-DRAM lock
-+					 *  8    SERR on ECC UE
-+					 *  7    SERR on ECC CE
-+					 *  6    target abort on high exception
-+					 *  5    detect unimplemented cyc
-+					 *  4    AGP access outside of GA
-+					 *  3    SERR on invalid AGP access
-+					 *  2    invalid translation table
-+					 *  1    SERR on unsupported AGP command
-+					 *  0    reserved
-+					 */
-+
-+
-+/* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */
-+#define I82875P_PCICMD6		0x04	/* PCI Command Register (16b)
-+					 *
-+					 * 15:10 reserved
-+					 *  9    fast back-to-back - ro 0
-+					 *  8    SERR enable - ro 0
-+					 *  7    addr/data stepping - ro 0
-+					 *  6    parity err enable - ro 0
-+					 *  5    VGA palette snoop - ro 0
-+					 *  4    mem wr & invalidate - ro 0
-+					 *  3    special cycle - ro 0
-+					 *  2    bus master - ro 0
-+					 *  1    mem access dev6 - 0(dis),1(en)
-+					 *  0    IO access dev3 - 0(dis),1(en)
-+					 */
-+
-+#define I82875P_BAR6		0x10	/* Mem Delays Base ADDR Reg (32b)
-+					 *
-+					 * 31:12 mem base addr [31:12]
-+					 * 11:4  address mask - ro 0
-+					 *  3    prefetchable - ro 0(non),1(pre)
-+					 *  2:1  mem type - ro 0
-+					 *  0    mem space - ro 0
-+					 */
-+
-+/* Intel 82875p MMIO register space - device 0 function 0 - MMR space */
-+
-+#define I82875P_DRB_SHIFT 26		/* 64MiB grain */
-+#define I82875P_DRB		0x00	/* DRAM Row Boundary (8b x 8)
-+					 *
-+					 *  7    reserved
-+					 *  6:0  64MiB row boundary addr
-+					 */
-+
-+#define I82875P_DRA		0x10	/* DRAM Row Attribute (4b x 8)
-+					 *
-+					 *  7    reserved
-+					 *  6:4  row attr row 1
-+					 *  3    reserved
-+					 *  2:0  row attr row 0
-+					 *
-+					 * 000 =  4KiB
-+					 * 001 =  8KiB
-+					 * 010 = 16KiB
-+					 * 011 = 32KiB
-+					 */
-+
-+#define I82875P_DRC		0x68	/* DRAM Controller Mode (32b)
-+					 *
-+					 * 31:30 reserved
-+					 * 29    init complete
-+					 * 28:23 reserved
-+					 * 22:21 nr chan 00=1,01=2
-+					 * 20    reserved
-+					 * 19:18 Data Integ Mode 00=none,01=ecc
-+					 * 17:11 reserved
-+					 * 10:8  refresh mode
-+					 *  7    reserved
-+					 *  6:4  mode select
-+					 *  3:2  reserved
-+					 *  1:0  DRAM type 01=DDR
-+					 */
-+
-+
-+enum i82875p_chips {
-+	I82875P = 0,
-+};
-+
-+
-+struct i82875p_pvt {
-+	struct pci_dev *ovrfl_pdev;
-+	void *ovrfl_window;
-+};
-+
-+
-+struct i82875p_dev_info {
-+	const char *ctl_name;
-+};
-+
-+
-+static const struct i82875p_dev_info i82875p_devs[] = {
-+	[I82875P] = {
-+		.ctl_name = "i828875p"
-+	},
-+};
-+
-+
-+static void i82875p_check(struct mem_ctl_info *mci)
-+{
-+	u8 des;
-+	u8 derrsyn;
-+	u16 errsts, errsts2;
-+	u32 eap;
-+	int row;
-+	int multi_chan = mci->csrows[0].nr_channels - 1;
-+
-+	debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+
-+	/*
-+	 * This is a mess because there is no atomic way to read all
-+	 * the registers at once and the registers can transition
-+	 * from CE being overwritten by UE.
-+	 */
-+	pci_read_config_word( mci->pdev, I82875P_ERRSTS, &errsts );
-+	pci_read_config_dword( mci->pdev, I82875P_EAP, &eap );
-+	pci_read_config_byte( mci->pdev, I82875P_DES, &des );
-+	pci_read_config_byte( mci->pdev, I82875P_DERRSYN, &derrsyn );
-+	pci_read_config_word( mci->pdev, I82875P_ERRSTS, &errsts2 );
-+
-+	pci_write_bits16( mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081 );
-+
-+	/*
-+	 * If the error is the same then we can for both reads then
-+	 * the first set of reads is valid.  If there is a change then
-+	 * there is a CE no info and the second set of reads is valid
-+	 * and should be UE info.
-+	 */
-+	if (! (errsts2 & 0x0081) ) return;
-+	if ( (errsts ^ errsts2) & 0x0081 ) {
-+		bluesmoke_mc_handle_ce_no_info( mci, "UE overwrote CE" );
-+		errsts = errsts2;
-+		pci_read_config_dword( mci->pdev, I82875P_EAP, &eap );
-+		pci_read_config_byte( mci->pdev, I82875P_DES, &des );
-+		pci_read_config_byte( mci->pdev, I82875P_DERRSYN, &derrsyn );
-+	}
-+
-+	eap >>= PAGE_SHIFT;
-+	row = bluesmoke_mc_find_csrow_by_page( mci, eap );
-+
-+	if ( errsts & 0x0080 ) {
-+		bluesmoke_mc_handle_ue( mci, eap, 0, row, "i82875p UE" );
-+	} else {
-+		bluesmoke_mc_handle_ce( mci, eap, 0, derrsyn, row,
-+					multi_chan ? (des & 0x1) : 0,
-+					"i82875p UE" );
-+	}
-+
-+	return;
-+}
-+
-+
-+static int i82875p_probe1( struct pci_dev *pdev, int dev_idx )
-+{
-+	int rc = -ENODEV;
-+	int index;
-+	struct mem_ctl_info *mci = NULL;
-+	struct i82875p_pvt *pvt = NULL;
-+	unsigned long last_cumul_size;
-+	struct pci_dev *ovrfl_pdev;
-+	void *ovrfl_window = NULL;
-+
-+	u32 drc;
-+	u32 drc_chan;		/* Number of channels 0=1chan,1=2chan */
-+	u32 nr_chans;
-+	u32 drc_ddim;		/* DRAM Data Integrity Mode 0=none,2=edac */
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	ovrfl_pdev = pci_find_device( PCI_VEND_DEV( INTEL, 82875_6 ), NULL );
-+
-+	if ( ! ovrfl_pdev ) {
-+		/*
-+		 * Intel tells BIOS developers to hide device 6 which
-+		 * configures the overflow device access containing
-+		 * the DRBs - this is where we expose device 6.
-+		 * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm
-+		 */
-+		pci_write_bits8( pdev, 0xf4, 0x2, 0x2 );
-+		ovrfl_pdev = pci_scan_single_device( pdev->bus, PCI_DEVFN( 6, 0 ) );
-+		if ( ! ovrfl_pdev ) {
-+			goto FAIL_FINISHED;
-+		}
-+	}
-+
-+#ifdef CONFIG_PROC_FS
-+	if ( !ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) {
-+		printk( KERN_ERR "MC: " __FILE__
-+			": %s(): Failed to attach overflow device\n",
-+			__func__ );
-+		goto FAIL_FINISHED;
-+	}
-+#endif /* CONFIG_PROC_FS */
-+	if (pci_enable_device(ovrfl_pdev)) {
-+		printk( KERN_ERR "MC: " __FILE__
-+			": %s(): Failed to enable overflow device\n",
-+			__func__ );
-+		goto FAIL_FINISHED;
-+	}
-+	if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) {
-+		printk( KERN_ERR "MC: " __FILE__
-+			": %s(): Failed to reserve regions - broken BIOS?\n",
-+			__func__ );
-+#ifdef CORRECT_BIOS
-+		goto FAIL_FINISHED;
-+#endif /* CORRECT_BIOS */
-+	}
-+
-+	/* cache is irrelevant for PCI bus reads/writes */
-+	ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0),
-+				       pci_resource_len(ovrfl_pdev, 0));
-+
-+	if (!ovrfl_window) {
-+		printk( KERN_ERR "MC: " __FILE__
-+			": %s(): Failed to ioremap bar6\n",
-+			__func__ );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	/* need to find out the number of channels */
-+	drc = readl(ovrfl_window + I82875P_DRC);
-+	drc_chan = ( ( drc >> 21 ) & 0x1 );
-+	nr_chans = drc_chan + 1;
-+	drc_ddim = ( drc >> 18 ) & 0x1;
-+
-+	mci = bluesmoke_mc_init_structs(sizeof(*pvt),
-+					I82875P_NR_CSROWS(nr_chans),
-+					nr_chans );
-+
-+	if ( ! mci ) {
-+		rc = -ENOMEM;
-+		goto FAIL_FINISHED;
-+	}
-+
-+	debugf3( "MC: " __FILE__ ": %s(): init mci\n", __func__ );
-+
-+	mci->pdev = pdev;
-+	mci->mtype_cap = MEM_FLAG_RDDR;
-+
-+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
-+	mci->edac_cap = EDAC_FLAG_UNKNOWN;
-+	/* adjust FLAGS */
-+
-+	mci->mod_name = BS_MOD_STR;
-+	mci->mod_ver = "$Revision: 1.5 $";
-+	mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
-+	mci->edac_check = i82875p_check;
-+	mci->clear_err = NULL;
-+	mci->ctl_page_to_phys = NULL;
-+
-+	debugf3( "MC: " __FILE__ ": %s(): init pvt\n", __func__ );
-+
-+	pvt = (struct i82875p_pvt *)mci->pvt_info;
-+	pvt->ovrfl_pdev = ovrfl_pdev;
-+	pvt->ovrfl_window = ovrfl_window;
-+
-+	/*
-+	 * The dram row boundary (DRB) reg values are boundary address
-+	 * for each DRAM row with a granularity of 32 or 64MB (single/dual
-+	 * channel operation).  DRB regs are cumulative; therefore DRB7 will
-+	 * contain the total memory contained in all eight rows.
-+	 */
-+	for( last_cumul_size = index = 0; index < mci->nr_csrows; index++ ) {
-+		u8 value;
-+		u32 cumul_size;
-+		struct csrow_info *csrow = &mci->csrows[ index ];
-+
-+		value = readb(ovrfl_window + I82875P_DRB + index);
-+		cumul_size = value << ( I82875P_DRB_SHIFT - PAGE_SHIFT );
-+		debugf3( "MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n",
-+			__func__, index, cumul_size );
-+		if ( cumul_size == last_cumul_size ) {
-+			continue;	/* not populated */
-+		}
-+
-+		csrow->first_page = last_cumul_size;
-+		csrow->last_page = cumul_size - 1;
-+		csrow->nr_pages = cumul_size - last_cumul_size;
-+		last_cumul_size = cumul_size;
-+		csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */
-+		csrow->mtype = MEM_DDR;
-+		csrow->dtype = DEV_UNKNOWN;
-+		csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
-+	}
-+
-+	/* clear counters */
-+	pci_write_bits16( mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081 );
-+
-+	if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
-+		debugf3( "MC: " __FILE__
-+			 ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	/* get this far and it's successful */
-+	debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
-+	rc = 0;
-+	goto FINISHED;
-+
-+ FAIL_FINISHED:
-+	if ( mci ) {
-+		kfree( mci );
-+	}
-+
-+	if (ovrfl_window) {
-+		iounmap(ovrfl_window);
-+	}
-+
-+	if (ovrfl_pdev) {
-+		pci_release_regions( ovrfl_pdev );
-+		pci_disable_device( ovrfl_pdev );
-+	}
-+
-+ FINISHED:
-+	/* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
-+	return( rc );
-+}
-+
-+
-+#ifdef CONFIG_PM
-+
-+static int i82875p_suspend (struct pci_dev *pdev, u32 state)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+
-+static int i82875p_resume (struct pci_dev *pdev)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+#endif /* CONFIG_PM */
-+
-+
-+/* returns count (>= 0), or negative on error */
-+static int __devinit i82875p_init_one( struct pci_dev *pdev,
-+				       const struct pci_device_id *ent )
-+{
-+	int rc;
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if (pci_enable_device (pdev)) {
-+		rc = -EIO;
-+	} else {
-+		rc = i82875p_probe1( pdev, ent->driver_data );
-+	}
-+	return rc;
-+}
-+
-+
-+static void __devexit i82875p_remove_one( struct pci_dev *pdev )
-+{
-+	struct mem_ctl_info *mci;
-+	struct i82875p_pvt *pvt = NULL;
-+
-+	debugf0( __FILE__ ": %s()\n", __func__);
-+
-+	if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
-+		goto FINISHED;
-+	}
-+
-+	pvt = (struct i82875p_pvt *)mci->pvt_info;
-+	if (pvt->ovrfl_window) {
-+		iounmap(pvt->ovrfl_window);
-+	}
-+
-+	if (pvt->ovrfl_pdev) {
-+		pci_release_regions( pvt->ovrfl_pdev );
-+		pci_disable_device( pvt->ovrfl_pdev );
-+	}
-+
-+	if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
-+		goto FINISHED;
-+	}
-+
-+	kfree( mci );
-+
-+ FINISHED:
-+	return;
-+}
-+
-+
-+static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
-+	{ PCI_VEND_DEV( INTEL, 82875_0 ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, I82875P },
-+	{0,}						/* 0 terminated list. */
-+};
-+
-+MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
-+
-+
-+static struct pci_driver i82875p_driver = {
-+	.name		= BS_MOD_STR,
-+	.probe		= i82875p_init_one,
-+	.remove		= __devexit_p(i82875p_remove_one),
-+	.id_table	= i82875p_pci_tbl,
-+#ifdef CONFIG_PM
-+	.suspend	= i82875p_suspend,
-+	.resume		= i82875p_resume,
-+#endif /* CONFIG_PM */
-+};
-+
-+
-+int __init i82875p_init(void)
-+{
-+	int pci_rc;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+	pci_rc = pci_module_init( &i82875p_driver );
-+	if ( pci_rc < 0 ) return pci_rc;
-+
-+	return 0;
-+}
-+
-+
-+static void __exit i82875p_exit(void)
-+{
-+	debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
-+	pci_unregister_driver( &i82875p_driver );
-+}
-+
-+
-+module_init(i82875p_init);
-+module_exit(i82875p_exit);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
-+MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers");
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_k8.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_k8.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_k8.c	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,1252 @@
-+/*
-+ * AMD K8 class Memory Controller kernel module
-+ * (C) 2003 Linux Networx (http://lnxi.com)
-+ * This file may be distributed under the terms of the
-+ * GNU General Public License.
-+ *
-+ * Written by Thayne Harbaugh
-+ *
-+ * $Id: bluesmoke_k8.c,v 1.6 2004/11/23 01:34:25 thayne Exp $
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+
-+#include <linux/pci.h>
-+#include <linux/pci_ids.h>
-+
-+#include <linux/slab.h>
-+
-+#include "bluesmoke_mc.h"
-+
-+
-+#ifndef PCI_DEVICE_ID_AMD_OPT_0_HT
-+#define PCI_DEVICE_ID_AMD_OPT_0_HT	0x1100
-+#endif /* PCI_DEVICE_ID_AMD_OPT_0_HT */
-+
-+#ifndef PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP
-+#define PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP	0x1101
-+#endif /* PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP */
-+
-+#ifndef PCI_DEVICE_ID_AMD_OPT_2_MEMCTL
-+#define PCI_DEVICE_ID_AMD_OPT_2_MEMCTL	0x1102
-+#endif /* PCI_DEVICE_ID_AMD_OPT_2_MEMCTL */
-+
-+#ifndef PCI_DEVICE_ID_AMD_OPT_3_MISCCTL
-+#define PCI_DEVICE_ID_AMD_OPT_3_MISCCTL	0x1103
-+#endif /* PCI_DEVICE_ID_AMD_OPT_3_MISCCTL */
-+
-+
-+#define K8_NR_CSROWS 8
-+
-+
-+/* K8 register addresses - device 0 function 1 - Address Map */
-+#define K8_DBR		0x40	/* DRAM Base Register (8 x 32b
-+				 * interlaced with K8_DLR)
-+				 *
-+				 * 31:16 DRAM Base addr 39:24
-+				 * 15:11 reserved
-+				 * 10:8  interleave enable
-+				 *  7:2  reserved
-+				 *  1    write enable
-+				 *  0    read enable
-+				 */
-+#define K8_DLR		0x44	/* DRAM Limit Register (8 x 32b
-+				 * interlaced with K8_DBR)
-+				 *
-+				 * 31:16 DRAM Limit addr 32:24
-+				 * 15:11 reserved
-+				 * 10:8  interleave select
-+				 *  7:3  reserved
-+				 *  2:0  destination node ID
-+				 */
-+
-+
-+/* K8 register addresses - device 0 function 2 - DRAM controller */
-+#define K8_DCSB		0x40	/* DRAM Chip-Select Base (8 x 32b)
-+				 *
-+				 * 31:21 Base addr high 35:25
-+				 * 20:16 reserved
-+				 * 15:9  Base addr low 19:13 (interlvd)
-+				 *  8:1  reserved
-+				 *  0    chip-select bank enable
-+				 */
-+#define K8_DCSM		0x60	/* DRAM Chip-Select Mask (8 x 32b)
-+				 *
-+				 * 31:30 reserved
-+				 * 29:21 addr mask high 33:25
-+				 * 20:16 reserved
-+				 * 15:9  addr mask low  19:13
-+				 *  8:0  reserved
-+				 */
-+
-+#define K8_DBAM		0x80	/* DRAM Base Addr Mapping (32b) */
-+#define K8_DCL		0x90	/* DRAM configuration low reg (32b)
-+				 *
-+				 * 31:28 reserved
-+				 * 27:25 Bypass Max: 000b=respect
-+				 * 24    Dissable receivers - no sockets
-+				 * 23:20 x4 DIMMS
-+				 * 19    32byte chunks
-+				 * 18    Unbuffered
-+				 * 17    ECC enabled
-+				 * 16    128/64 bit (dual/single chan)
-+				 * 15:14 R/W Queue bypass count
-+				 * 13    Self refresh
-+				 * 12    exit self refresh
-+				 * 11    mem clear status
-+				 * 10    DRAM enable
-+				 *  9    reserved
-+				 *  8    DRAM init
-+				 *  7:4  reserved
-+				 *  3    dis DQS hysteresis
-+				 *  2    QFC enabled
-+				 *  1    DRAM drive strength
-+				 *  0    Digital Locked Loop disable
-+				 */
-+
-+
-+/* K8 register addresses - device 0 function 3 - Misc Control */
-+#define K8_NBCTL	0x40	/* MCA NB Control (32b)
-+				 *
-+				 *  1    MCA UE Reporting
-+				 *  0    MCA CE Reporting
-+				 */
-+#define K8_NBCFG	0x44	/* MCA NB Config (32b)
-+				 *
-+				 * 23    Chip-kill x4 ECC enable
-+				 * 22    ECC enable
-+				 *  1    CPU ECC enable
-+				 */
-+#define K8_NBSL		0x48	/* MCA NB Status Low (32b)
-+				 *
-+				 * 31:24 Syndrome 15:8 chip-kill x4
-+				 * 23:20 reserved
-+				 * 19:16 Extended err code
-+				 * 15:0  Err code
-+				 */
-+#define K8_NBSH		0x4C	/* MCA NB Status High (32b)
-+				 *
-+				 * 31    Err valid
-+				 * 30    Err overflow
-+				 * 29    Uncorrected err
-+				 * 28    Err enable
-+				 * 27    Misc err reg valid
-+				 * 26    Err addr valid
-+				 * 25    proc context corrupt
-+				 * 24:23 reserved
-+				 * 22:15 Syndrome 7:0
-+				 * 14    CE
-+				 * 13    UE
-+				 * 12:9  reserved
-+				 *  8    err found by scrubber
-+				 *  7    reserved
-+				 *  6:4  Hyper-transport link number
-+				 *  3:2  reserved
-+				 *  1    Err CPU 1
-+				 *  0    Err CPU 0
-+				 */
-+#define K8_NBEAL	0x50	/* MCA NB err addr low (32b)
-+				 *
-+				 * 31:3  Err addr low 31:3
-+				 *  2:0  reserved
-+				 */
-+#define K8_NBEAH	0x54	/* MCA NB err addr high (32b)
-+				 *
-+				 * 31:8  reserved
-+				 *  7:0  Err addr high 39:32
-+				 */
-+#define K8_NBCAP	0xE8	/* MCA NB capabilities (32b)
-+				 *
-+				 * 31:9  reserved
-+				 *  4    S4ECD4ED capable
-+				 *  3    SECDED capable
-+				 */
-+
-+
-+				/* MSR's */
-+				/*
-+				 * K8_MSR_MCxCTL (64b)
-+				 * (0x400,404,408,40C,410)
-+				 * 63    Enable reporting source 63
-+				 *  .
-+				 *  .
-+				 *  .
-+				 *  2    Enable error source 2
-+				 *  1    Enable error source 1
-+				 *  0    Enable error source 0
-+				 */
-+				/*
-+				 * K8_MSR_MCxSTAT (64b)
-+				 * (0x401,405,409,40D,411)
-+				 * 63    Error valid
-+				 * 62    Status overflow
-+				 * 61    UE
-+				 * 60    Enabled error condition
-+				 * 59    Misc register valid (not used)
-+				 * 58    Err addr register valid
-+				 * 57    Processor context corrupt
-+				 * 56:32 Other information
-+				 * 31:16 Model specific error code
-+				 * 15:0  MCA err code
-+				 */
-+				/*
-+				 * K8_MSR_MCxADDR (64b)
-+				 * (0x402,406,40A,40E,412)
-+				 * 63:48 reserved
-+				 * 47:0  Address
-+				 */
-+				/*
-+				 * K8_MSR_MCxMISC (64b)
-+				 * (0x403,407,40B,40F,413)
-+				 * Unused on Athlon64 and K8
-+				 */
-+
-+#define K8_MSR_MCGCTL	0x017b	/* Machine Chk Global report ctl (64b)
-+				 *
-+				 * 31:5  reserved
-+				 *  4    North Bridge
-+				 *  3    Load/Store
-+				 *  2    Bus Unit
-+				 *  1    Instruction Cache
-+				 *  0    Data Cache
-+				 */
-+#define K8_MSR_MC4CTL	0x0410	/* North Bridge Check report ctl (64b) */
-+#define K8_MSR_MC4STAT	0x0411	/* North Bridge status (64b) */
-+#define K8_MSR_MC4ADDR	0x0412	/* North Bridge Address (64b) */
-+
-+
-+#define MCI2NID(mci)	(PCI_SLOT(mci->pdev->devfn) - 0x18)
-+
-+
-+enum k8_chips {
-+	OPTERON = 0,
-+};
-+
-+
-+struct k8_pvt {
-+	struct pci_dev *addr_map;
-+	struct pci_dev *misc_ctl;
-+};
-+
-+
-+struct k8_dev_info {
-+	const char *ctl_name;
-+	u16 addr_map;
-+	u16 misc_ctl;
-+};
-+
-+
-+static const struct k8_dev_info k8_devs[] = {
-+	[OPTERON] = {
-+		.ctl_name = "Athlon64/Opteron",
-+		.addr_map = PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP,
-+		.misc_ctl = PCI_DEVICE_ID_AMD_OPT_3_MISCCTL
-+	},
-+};
-+
-+
-+static inline void pci_find_related_function( unsigned int vendor,
-+					      unsigned int device,
-+					      struct pci_dev **from,
-+					      struct pci_dev *related )
-+{
-+	do {
-+		*from = pci_find_device( vendor, device, *from );
-+		if ( ! *from ) return;
-+
-+		if ( ((*from)->bus->number == related->bus->number)
-+		     && (PCI_SLOT((*from)->devfn)
-+			 == PCI_SLOT(related->devfn)) ) {
-+			return;
-+		}
-+	} while ( 1 );
-+}
-+
-+
-+/* FIXME - stolen from msr.c - the calls in msr.c could be exported */
-+#ifdef CONFIG_SMP
-+
-+struct msr_command {
-+	int cpu;
-+	int err;
-+	u32 reg;
-+	u32 data[2];
-+};
-+
-+
-+static void msr_smp_wrmsr(void *cmd_block)
-+{
-+	struct msr_command *cmd = (struct msr_command *) cmd_block;
-+  
-+	debugf1( "MC: " __FILE__ ": %s(): %d ? %d\n",
-+		 __func__, cmd->cpu, smp_processor_id() );
-+
-+	if ( cmd->cpu == smp_processor_id() ) {
-+		debugf1( "MC: " __FILE__ ": %s(): Matched %d\n",
-+			 __func__, cmd->cpu );
-+		wrmsr(cmd->reg, cmd->data[0], cmd->data[1]);
-+	}
-+}
-+
-+
-+static void msr_smp_rdmsr(void *cmd_block)
-+{
-+	struct msr_command *cmd = (struct msr_command *) cmd_block;
-+  
-+	debugf1( "MC: " __FILE__ ": %s(): %d ? %d\n",
-+		 __func__, cmd->cpu, smp_processor_id() );
-+
-+	if ( cmd->cpu == smp_processor_id() ) {
-+		debugf1( "MC: " __FILE__ ": %s(): Matched %d\n",
-+			 __func__, cmd->cpu );
-+		rdmsr(cmd->reg, cmd->data[0], cmd->data[1]);
-+	}
-+}
-+
-+
-+static inline void do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
-+{
-+	struct msr_command cmd;
-+
-+	debugf0( "MC: " __FILE__ ": %s(): %d\n", __func__, cpu );
-+
-+	if ( cpu == smp_processor_id() ) {
-+		wrmsr(reg, eax, edx);
-+	} else {
-+		cmd.cpu = cpu;
-+		cmd.reg = reg;
-+		cmd.data[0] = eax;
-+		cmd.data[1] = edx;
-+    
-+		smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
-+	}
-+}
-+
-+
-+static inline void do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
-+{
-+	struct msr_command cmd;
-+
-+	debugf0( "MC: " __FILE__ ": %s(): %d\n", __func__, cpu );
-+
-+	if ( cpu == smp_processor_id() ) {
-+		rdmsr(reg, eax, edx);
-+	} else {
-+		cmd.cpu = cpu;
-+		cmd.reg = reg;
-+
-+		smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
-+    
-+		*eax = cmd.data[0];
-+		*edx = cmd.data[1];
-+	}
-+}
-+
-+#else /* ! CONFIG_SMP */
-+
-+static inline void do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
-+{
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+	wrmsr(reg, eax, edx);
-+}
-+
-+
-+static inline void do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
-+{
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+	rdmsr(reg, eax, edx);
-+}
-+
-+#endif /* ! CONFIG_SMP */
-+
-+
-+/*
-+ * FIXME - This is a large chunk of memory to suck up just to decode the
-+ * syndrome.  It would be nice to discover a patter in the syndromes that
-+ * could be used to quickly identify the channel.  The big problems with
-+ * this table is memory usage, lookup speed (could sort and binary search),
-+ * correctness (there could be a transcription error).  A zero in any nibble
-+ * for a syndrom is always channel 0, but that only decodes some of the
-+ * syndromes.  Can anyone find any other patterns?
-+ */
-+/*
-+ * The comment in the left column is the nibble that is in error.  The least
-+ * significant nibble of the syndrome is the mask for the bits that are
-+ * in error (need to be toggled) for the particular nibble.
-+ */
-+#define SYNDROME_TABLE_SIZE 270
-+static const unsigned long syndromes_chan0[SYNDROME_TABLE_SIZE] = {
-+	/*0*/	0xe821, 0x7c32, 0x9413, 0xbb44, 0x5365, 0xc776, 0x2f57, 0xdd88, 0x35a9, 0xa1ba, 0x499b, 0x66cc, 0x8eed, 0x1afe, 0xf2df,
-+	/*1*/	0x5d31, 0xa612, 0xfb23, 0x9584, 0xc8b5, 0x3396, 0x6ea7, 0xeac8, 0xb7f9, 0x4cda, 0x11eb, 0x7f4c, 0x227d, 0xd95e, 0x846f,
-+	/*2*/	0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-+	/*3*/	0x2021, 0x3032, 0x1013, 0x4044, 0x6065, 0x7076, 0x5057, 0x8088, 0xa0a9, 0xb0ba, 0x909b, 0xc0cc, 0xe0ed, 0xf0fe, 0xd0df,
-+	/*4*/	0x5041, 0xa082, 0xf0c3, 0x9054, 0xc015, 0x30d6, 0x6097, 0xe0a8, 0xb0e9, 0x402a, 0x106b, 0x70fc, 0x20bd, 0xd07e, 0x803f,
-+	/*5*/	0xbe21, 0xd732, 0x6913, 0x2144, 0x9f65, 0xf676, 0x4857, 0x3288, 0x8ca9, 0xe5ba, 0x5b9b, 0x13cc, 0xaded, 0xc4fe, 0x7adf,
-+	/*6*/	0x4951, 0x8ea2, 0xc7f3, 0x5394, 0x1ac5, 0xdd36, 0x9467, 0xa1e8, 0xe8b9, 0x2f4a, 0x661b, 0xf27c, 0xbb2d, 0x7cde, 0x358f,
-+	/*7*/	0x74e1, 0x9872, 0xec93, 0xd6b4, 0xa255, 0x4ec6, 0x3a27, 0x6bd8, 0x1f39, 0xf3aa, 0x874b, 0xbd6c, 0xc98d, 0x251e, 0x51ff,
-+	/*8*/	0x15c1, 0x2a42, 0x3f83, 0xcef4, 0xdb35, 0xe4b6, 0xf177, 0x4758, 0x5299, 0x6d1a, 0x78db, 0x89ac, 0x9c6d, 0xa3ee, 0xb62f,
-+	/*9*/	0x3d01, 0x1602, 0x2b03, 0x8504, 0xb805, 0x9306, 0xae07, 0xca08, 0xf709, 0xdc0a, 0xe10b, 0x4f0c, 0x720d, 0x590e, 0x640f,
-+	/*a*/	0x9801, 0xec02, 0x7403, 0x6b04, 0xf305, 0x8706, 0x1f07, 0xbd08, 0x2509, 0x510a, 0xc90b, 0xd60c, 0x4e0d, 0x3a0e, 0xa20f,
-+	/*b*/	0xd131, 0x6212, 0xb323, 0x3884, 0xe9b5, 0x5a96, 0x8ba7, 0x1cc8, 0xcdf9, 0x7eda, 0xafeb, 0x244c, 0xf57d, 0x465e, 0x976f,
-+	/*c*/	0xe1d1, 0x7262, 0x93b3, 0xb834, 0x59e5, 0xca56, 0x2b87, 0xdc18, 0x3dc9, 0xae7a, 0x4fab, 0x542c, 0x85fd, 0x164e, 0xf79f,
-+	/*d*/	0x6051, 0xb0a2, 0xd0f3, 0x1094, 0x70c5, 0xa036, 0xc067, 0x20e8, 0x40b9, 0x904a, 0x601b, 0x307c, 0x502d, 0x80de, 0xe08f,
-+	/*e*/	0xa4c1, 0xf842, 0x5c83, 0xe6f4, 0x4235, 0x1eb6, 0xba77, 0x7b58, 0xdf99, 0x831a, 0x27db, 0x9dac, 0x396d, 0x65ee, 0xc12f,
-+	/*f*/	0x11c1, 0x2242, 0x3383, 0xc8f4, 0xd935, 0xeab6, 0xfb77, 0x4c58, 0x5d99, 0x6e1a, 0x7fdb, 0x84ac, 0x9562, 0xa6ee, 0xb72f,
-+
-+	/*20*/	0xbe01, 0xd702, 0x6903, 0x2104, 0x9f05, 0xf606, 0x4807, 0x3208, 0x8c09, 0xe50a, 0x5b0b, 0x130c, 0xad0d, 0xc40e, 0x7a0f,
-+	/*21*/	0x4101, 0x8202, 0xc303, 0x5804, 0x1905, 0xda06, 0x9b07, 0xac08, 0xed09, 0x2e0a, 0x6f0b, 0x640c, 0xb50d, 0x760e, 0x370f
-+};
-+
-+static const unsigned long syndromes_chan1[SYNDROME_TABLE_SIZE] = {
-+	/*10*/	0x45d1, 0x8a62, 0xcfb3, 0x5e34, 0x1be5, 0xd456, 0x9187, 0xa718, 0xe2c9, 0x2d7a, 0x68ab, 0xf92c, 0xbcfd, 0x734e, 0x369f,
-+	/*11*/	0x63e1, 0xb172, 0xd293, 0x14b4, 0x7755, 0xa5c6, 0xc627, 0x28d8, 0x4b39, 0x99aa, 0xfa4b, 0x3c6c, 0x5f8d, 0x8d1e, 0xeeff,
-+	/*12*/	0xb741, 0xd982, 0x6ec3, 0x2254, 0x9515, 0xfbd6, 0x4c97, 0x33a8, 0x84e9, 0xea2a, 0x5d6b, 0x11fc, 0xa6bd, 0xc87e, 0x7f3f,
-+	/*13*/	0xdd41, 0x6682, 0xbbc3, 0x3554, 0xe815, 0x53d6, 0xce97, 0x1aa8, 0xc7e9, 0x7c2a, 0xa1fb, 0x2ffc, 0xf2bd, 0x497e, 0x943f,
-+	/*14*/	0x2bd1, 0x3d62, 0x16b3, 0x4f34, 0x64e5, 0x7256, 0x5987, 0x8518, 0xaec9, 0xb87a, 0x93ab, 0xca2c, 0xe1fd, 0xf74e, 0xdc9f,
-+	/*15*/	0x83c1, 0xc142, 0x4283, 0xa4f4, 0x2735, 0x65b6, 0xe677, 0xf858, 0x7b99, 0x391a, 0xbadb, 0x5cac, 0xdf6d, 0x9dee, 0x1e2f,
-+	/*16*/	0x8fd1, 0xc562, 0x4ab3, 0xa934, 0x26e5, 0x6c56, 0xe387, 0xfe18, 0x71c9, 0x3b7a, 0xb4ab, 0x572c, 0xd8fd, 0x924e, 0x1d9f,
-+	/*17*/	0x4791, 0x89e2, 0xce73, 0x5264, 0x15f5, 0xdb86, 0x9c17, 0xa3b8, 0xe429, 0x2a5a, 0x6dcb, 0xf1dc, 0xb64d, 0x783e, 0x3faf,
-+	/*18*/	0x5781, 0xa9c2, 0xfe43, 0x92a4, 0xc525, 0x3b66, 0x6ce7, 0xe3f8, 0xb479, 0x4a3a, 0x1dbb, 0x715c, 0x26dd, 0xd89e, 0x8f1f,
-+	/*19*/	0xbf41, 0xd582, 0x6ac3, 0x2954, 0x9615, 0xfcd6, 0x4397, 0x3ea8, 0x81e9, 0xeb2a, 0x546b, 0x17fc, 0xa8bd, 0xc27e, 0x7d3f,
-+	/*1a*/	0x9891, 0xe1e2, 0x7273, 0x6464, 0xf7f5, 0x8586, 0x1617, 0xb8b8, 0x2b29, 0x595a, 0xcacb, 0xdcdc, 0x4f4d, 0x3d3e, 0xaeaf,
-+	/*1b*/	0xcce1, 0x4472, 0x8893, 0xfdb4, 0x3f55, 0xb9c6, 0x7527, 0x56d8, 0x9a39, 0x12aa, 0xde4b, 0xab6c, 0x678d, 0xef1e, 0x23ff,
-+	/*1c*/	0xa761, 0xf9b2, 0x5ed3, 0xe214, 0x4575, 0x1ba6, 0xbcc7, 0x7328, 0xd449, 0x8a9a, 0x2dfb, 0x913c, 0x365d, 0x688e, 0xcfef,
-+	/*1d*/	0xff61, 0x55b2, 0xaad3, 0x7914, 0x8675, 0x2ca6, 0xd3c7, 0x9e28, 0x6149, 0xcb9a, 0x34fb, 0xe73c, 0x185d, 0xb28e, 0x4def,
-+	/*1e*/	0x5451, 0xa8a2, 0xfcf3, 0x9694, 0xc2c5, 0x3e36, 0x6a67, 0xebe8, 0xbfb9, 0x434a, 0x171b, 0x7d7c, 0x292d, 0xd5de, 0x818f,
-+	/*1f*/	0x6fc1, 0xb542, 0xda83, 0x19f4, 0x7635, 0xacb6, 0xc377, 0x2e58, 0x4199, 0x9b1a, 0xf4db, 0x37ac, 0x586d, 0x82ee, 0xed2f,
-+		  
-+	/*22*/	0xc441, 0x4882, 0x8cc3, 0xf654, 0x3215, 0xbed6, 0x7a97, 0x5ba8, 0x9fe9, 0x132a, 0xd76b, 0xadfc, 0x69bd, 0xe57e, 0x213f,
-+	/*23*/	0x7621, 0x9b32, 0xed13, 0xda44, 0xac65, 0x4176, 0x3757, 0x6f88, 0x19a9, 0xf4ba, 0x829b, 0xb5cc, 0xc3ed, 0x2efe, 0x58df
-+};
-+
-+
-+/*
-+ * FIXME - either the above table is borken or something is incorrect with
-+ * the way the syndrome is read out of the NB.
-+ */
-+static int chan_from_syndrome( unsigned long syndrome )
-+{
-+	int i;
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	for ( i = 0; i < SYNDROME_TABLE_SIZE; i++ ) {
-+		if ( syndromes_chan0[i] == syndrome ) return 0;
-+		if ( syndromes_chan1[i] == syndrome ) return 1;
-+	}
-+
-+	debugf0( "MC: " __FILE__ ": %s(): syndrome(%lx) not found\n",
-+		 __func__, syndrome );
-+	return -1;
-+}
-+
-+
-+static const char *tt_msgs[] = {	/* transaction type */
-+	"inst",
-+	"data",
-+	"generic",
-+	"reserved"
-+};
-+
-+
-+static const char *ll_msgs[] = {	/* cache level */
-+	"0",
-+	"1",
-+	"2",
-+	"generic"
-+};
-+
-+
-+static const char *memtt_msgs[] = {
-+	"generic",
-+	"generic read",
-+	"generic write",
-+	"data read",
-+	"data write",
-+	"inst fetch",
-+	"prefetch",
-+	"evict",
-+	"snoop",
-+	"unknown error 9",
-+	"unknown error 10",
-+	"unknown error 11",
-+	"unknown error 12",
-+	"unknown error 13",
-+	"unknown error 14",
-+	"unknown error 15"
-+};
-+
-+
-+static const char *pp_msgs[] = {	/* participating processor */
-+	"local node origin",
-+	"local node response",
-+	"local node observed",
-+	"generic"
-+};
-+
-+
-+static const char *to_msgs[] = {
-+	"no timeout",
-+	"timed out"
-+};
-+
-+
-+static const char *ii_msgs[] = {	/* memory or i/o */
-+	"mem access",
-+	"reserved",
-+	"i/o access",
-+	"generic"
-+};
-+
-+
-+static const char *ext_msgs[] = {	/* extended error */
-+	"ECC error",
-+	"CRC error",
-+	"sync error",
-+	"mst abort",
-+	"tgt abort",
-+	"GART error",
-+	"RMW error",
-+	"watchdog error",
-+	"ECC chipkill x4 error",
-+	"unknown error 9",
-+	"unknown error 10",
-+	"unknown error 11",
-+	"unknown error 12",
-+	"unknown error 13",
-+	"unknown error 14",
-+	"unknown error 15"
-+};
-+
-+
-+static const char *htlink_msgs[] = {
-+	"none",
-+	"1",
-+	"2",
-+	"1 2",
-+	"3",
-+	"1 3",
-+	"2 3",
-+	"1 2 3"
-+};
-+
-+
-+static inline void decode_gart_tlb_error( struct mem_ctl_info *mci,
-+					  u32 nbeah, u32 nbeal,
-+					  u32 nbsh, u32 nbsl,
-+					  u32 nbcfg )
-+{
-+	u32 err_code;
-+	u32 ec_tt;	/* error code transaction type (2b) */
-+	u32 ec_ll;	/* error code cache level (2b) */
-+
-+	debugf0( "MC%d: " __FILE__ ": %s(): FIXME\n", mci->mc_idx, __func__ );
-+
-+	err_code = nbsl & 0xffffUL;
-+	ec_tt = ( err_code >> 2 ) & 0x03UL;
-+	ec_ll = ( err_code >> 0 ) & 0x03UL;
-+
-+	printk( "BS%d: GART TLB errorr:"
-+		" transaction type(%s),"
-+		" cache level(%s)\n",
-+		mci->mc_idx,
-+		tt_msgs[ec_tt],
-+		ll_msgs[ec_ll] );
-+}
-+
-+
-+static inline void decode_cache_error( struct mem_ctl_info *mci,
-+				       u32 nbeah, u32 nbeal,
-+				       u32 nbsh, u32 nbsl,
-+				       u32 nbcfg )
-+{
-+	u32 err_code;
-+	u32 ec_rrrr;	/* error code memory transaction (4b) */
-+	u32 ec_tt;	/* error code transaction type (2b) */
-+	u32 ec_ll;	/* error code cache level (2b) */
-+
-+	debugf0( "MC%d: " __FILE__ ": %s(): FIXME\n", mci->mc_idx, __func__ );
-+
-+	err_code = nbsl & 0xffffUL;
-+	ec_rrrr = ( err_code >> 4 ) & 0x0fUL;
-+	ec_tt   = ( err_code >> 2 ) & 0x03UL;
-+	ec_ll   = ( err_code >> 0 ) & 0x03UL;
-+
-+	printk( "BS%d: cache heirarchy error:"
-+		" memory transaction type(%s),"
-+		" transaction type(%s),"
-+		" cache level(%s)\n",
-+		mci->mc_idx,
-+		memtt_msgs[ ec_rrrr ],
-+		tt_msgs[ ec_tt ],
-+		ll_msgs[ ec_ll ] );
-+}
-+
-+
-+static inline void decode_bus_error( struct mem_ctl_info *mci,
-+				     u32 nbeah, u32 nbeal,
-+				     u32 nbsh, u32 nbsl,
-+				     u32 nbcfg )
-+{
-+	u32 page, offset;
-+	u32 err_code, ext_ec;
-+	int row = 0;
-+	u32 ec_pp;	/* error code participating processor (2p) */
-+	u32 ec_to;	/* error code timed out (1b) */
-+	u32 ec_rrrr;	/* error code memory transaction (4b) */
-+	u32 ec_ii;	/* error code memory or I/O (2b) */
-+	u32 ec_ll;	/* error code cache level (2b) */
-+	char msg[1024] = "";
-+	u32 msg_idx = 0;
-+
-+	debugf0( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+
-+	msg_idx = snprintf( msg, 1024, "%s", BS_MOD_STR );
-+
-+	err_code = nbsl & 0xffffUL;
-+	ec_pp   = ( err_code >>  9 ) & 0x03UL;
-+	ec_to   = ( err_code >>  8 ) & 0x01UL;
-+	ec_rrrr = ( err_code >>  4 ) & 0x0fUL;
-+	ec_ii   = ( err_code >>  2 ) & 0x03UL;
-+	ec_ll   = ( err_code >>  0 ) & 0x03UL;
-+
-+	ext_ec = ( nbsl >> 16 ) & 0xfUL;
-+
-+	/* FIXME - these should report through bluesmoke channels */
-+
-+	printk( "BS%d: general bus error:"
-+		" participating processor(%s),"
-+		" time-out(%s),"
-+		" memory transaction type(%s),"
-+		" mem or i/o(%s),"
-+		" cache level(%s)\n",
-+		mci->mc_idx,
-+		pp_msgs[ ec_pp ],
-+		to_msgs[ ec_to ],
-+		memtt_msgs[ ec_rrrr ],
-+		ii_msgs[ ec_ii ],
-+		ll_msgs[ ec_ll ] );
-+
-+	/* FIXME - other errors should have other error handling mechanisms. */
-+	if ( ( 0 != ext_ec ) && ( 0x8 != ext_ec ) ) {
-+		printk( "BS%d: no special error handling for this error\n",
-+			mci->mc_idx );
-+		return;
-+	}
-+
-+	if ( ec_pp & 0x02 ) {
-+		/* We aren't the node involved */
-+		return;
-+	}
-+
-+	offset = nbeal & ~PAGE_MASK & ~0x7UL;
-+	page = ( ( nbeah & 0xff ) << ( 40 - PAGE_SHIFT ) )
-+		| ( ( nbeal & PAGE_MASK ) >> PAGE_SHIFT );
-+
-+	/* process any errors */
-+	if ( nbsh & BIT(14) ) {			/* CE */
-+		unsigned long syndrome;
-+		int chan = 0;
-+
-+		syndrome = ( nbsh >> 15 ) & 0x00ffUL; /* bits 7:0 */
-+		if ( nbcfg & BIT(23) ) {
-+			syndrome |= ( nbsl >> 16 ) & 0xff00UL; /* bits 15:8 */
-+			chan = chan_from_syndrome( syndrome );
-+		}
-+
-+		if ( 0 > chan ) {
-+			/*
-+			 * If the syndrome couldn't be found then
-+			 * the race condition for error reporting
-+			 * registers likely occurred.  There's alot
-+			 * more in doubt than just the channel.
-+			 * Might as well just log the error without
-+			 * any info.
-+			 */
-+			msg_idx += snprintf( &msg[ msg_idx ], 1024 - msg_idx,
-+					     " unknown syndrome 0x%lx - "
-+					     " possible error reporting race",
-+					     syndrome );
-+			bluesmoke_mc_handle_ce_no_info( mci, msg );
-+		} else if ( nbsh & BIT(26) ) {		/* valid address? */
-+			row = bluesmoke_mc_find_csrow_by_page( mci, page );
-+			if ( -1 == row ) {
-+				bluesmoke_mc_handle_ce_no_info( mci, msg );
-+			} else {
-+				bluesmoke_mc_handle_ce( mci, page, offset,
-+							syndrome, row, chan,
-+							msg );
-+			}
-+		} else {
-+			bluesmoke_mc_handle_ce_no_info( mci, msg );
-+		}
-+	} else if ( nbsh & BIT(13) ) {		/* UE */
-+		if ( nbsh & BIT(26) ) {		/* valid address? */
-+			row = bluesmoke_mc_find_csrow_by_page( mci, page );
-+			if ( -1 == row ) {
-+				bluesmoke_mc_handle_ue_no_info( mci, msg );
-+			} else {
-+				bluesmoke_mc_handle_ue( mci, page, offset,
-+							row, msg );
-+			}
-+		} else {
-+			bluesmoke_mc_handle_ue_no_info( mci, msg );
-+		}
-+	}
-+
-+	if ( nbsh & BIT(30) ) {
-+		/*
-+		 * If main error is CE then overflow must be CE.
-+		 * If main error is UE then overflow is unknown.
-+		 * We'll call the overflow a CE - if panic_on_ue
-+		 * is set then we're already panic'ed and won't
-+		 * arrive here.  If panic_on_ue is not set then
-+		 * apparently someone doesn't think that
-+		 * UE's are catastrophic.
-+		 */
-+		bluesmoke_mc_handle_ce_no_info( mci, BS_MOD_STR );
-+	}
-+}
-+
-+
-+static void k8_check(struct mem_ctl_info *mci)
-+{
-+	struct k8_pvt *pvt = (struct k8_pvt *)mci->pvt_info;
-+	u32 nbsl1, nbsh1, nbeal1, nbeah1, nbcfg1;
-+	u32 nbsl2, nbsh2, nbeal2, nbeah2, nbcfg2;
-+	u32 err_code;
-+	u32 ext_ec;
-+
-+	debugf1( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+
-+	/* check for an error */
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBSH, &nbsh1);
-+	if ( ! (nbsh1 & BIT(31) ) ) {	/* err valid? */
-+		return;
-+	}
-+
-+	/* might as well slurp in everything at once */
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBSL, &nbsl1);
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBEAL, &nbeal1);
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBEAH, &nbeah1);
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &nbcfg1);
-+	debugf1( KERN_WARNING
-+		 "NorthBridge ERROR: mci(0x%p) node(%d) nbeah(0x%.8x)"
-+		 " nbeal(0x%.8x) nbsh(0x%.8x) nbsl(0x%.8x): ",
-+		 mci, MCI2NID(mci), nbeah1, nbeal1, nbsh1, nbsl1 );
-+
-+	/*
-+	 * Here's the problem with the K8's EDAC reporting:
-+	 * There are four registers which report pieces of error
-+	 * information.  These four registers are shared between
-+	 * CEs and UEs.  Furthermore, contrary to what is stated in
-+	 * the OBKG, the overflow bit is never used!  Every error
-+	 * always updates the reporting registers.
-+	 *
-+	 * Can you see the race condition?  All four error reporting
-+	 * registers must be read before a new error updates them!
-+	 * There is no way to read all four registers atomically.  The
-+	 * best than can be done is to detect that a race has occured
-+	 * and then report the error without any kind of precision.
-+	 *
-+	 * What is still positive is that errors are
-+	 * still reported and thus problems can still be detected -
-+	 * just not localized because the syndrome and address are
-+	 * spread out across registers.
-+	 *
-+	 * Grrrrr!!!!!  Here's hoping that AMD fixes this in some
-+	 * future K8 rev. UEs and CEs should have separate
-+	 * register sets with proper overflow bits that are used!
-+	 * At very least the problem can be fixed by honoring the
-+	 * ErrValid bit in nbsh and not updating registers - just
-+	 * set the overflow bit - unless the current error is CE
-+	 * and the new error is UE which would be the only situation
-+	 * for overwriting the current values.
-+	 */
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBSH, &nbsh2);
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBSL, &nbsl2);
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBEAL, &nbeal2);
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBEAH, &nbeah2);
-+	pci_read_config_dword(pvt->misc_ctl, K8_NBCFG, &nbcfg2);
-+	debugf1( KERN_WARNING
-+		 "NorthBridge ERROR2: mci(0x%p) node(%d) nbeah2(0x%.8x)"
-+		 " nbeal2(0x%.8x) nbsh2(0x%.8x) nbsl2(0x%.8x): ",
-+		 mci, MCI2NID(mci), nbeah2, nbeal2, nbsh2, nbsl2 );
-+
-+	/* clear the error */
-+	pci_write_bits32( pvt->misc_ctl, K8_NBSH, 0, BIT(31) );
-+
-+	if ( ( nbsh1 != nbsh2 )
-+	     || ( nbsl1 != nbsl2 )
-+	     || ( nbeah1 != nbeah2 )
-+	     || ( nbeal1 != nbeal2 ) ) {
-+		printk( KERN_WARNING "MC%d: race condition detected!\n",
-+			mci->mc_idx );
-+	}
-+
-+	err_code = nbsl2 & 0xffffUL;
-+	ext_ec = (nbsl2 >> 16) & 0x0fUL;
-+
-+	/* Use info from the second read - most current */
-+	if ( 0x0010UL == ( err_code & 0xfff0UL ) ) {
-+		debugf1( "GART TLB error\n" );
-+		decode_gart_tlb_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 );
-+	} else if ( 0x0100UL == ( err_code & 0xff00UL ) ) {
-+		debugf1( "Cache error\n" );
-+		decode_cache_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 );
-+	} else if ( 0x0800UL == ( err_code & 0xf800UL ) ) {
-+		debugf1( "Bus error\n" );
-+		decode_bus_error( mci, nbeah2, nbeal2, nbsh2, nbsl2, nbcfg2 );
-+	} else {
-+		/* shouldn't reach here! */
-+		printk( KERN_WARNING "MC%d: " __FILE__
-+			": %s(): unknown MCE error 0x%x\n",
-+			mci->mc_idx, __func__, err_code );
-+	}
-+
-+	printk( "BS%d: extended error code: %s\n",
-+		mci->mc_idx,
-+		ext_msgs[ ext_ec ] );
-+
-+	if ( ((ext_ec >=1 && ext_ec <= 4) || (ext_ec == 6))
-+	     && ((nbsh2 >> 4) & 0x03UL) ) {
-+		/* need to decode which hypertransport link had the error */
-+		u32 htln = (nbsh2 >> 4) & 0x03UL;
-+		printk( "BS%d: Error on hypertransport link: %s\n",
-+			mci->mc_idx, htlink_msgs[ htln ] );
-+	}
-+
-+	/*
-+	 * If the processor context is corrupt or the error is
-+	 * uncorrectable then panic - why would you want to continue
-+	 * with something seriosly broken?
-+	 */
-+	if ( nbsh2 & ( BIT(29) | BIT(25) ) ) {
-+		if ( nbsh2 & BIT(29) )
-+			printk( "BS%d: uncorrected error\n", mci->mc_idx );
-+
-+		if ( nbsh2 & BIT(25) )
-+			printk( "BS%d: processor context corrupt\n",
-+				mci->mc_idx );
-+
-+		panic( "BS%d: cannot recover\n", mci->mc_idx );
-+	};
-+}
-+
-+
-+static int k8_probe1( struct pci_dev *pdev, int dev_idx )
-+{
-+	int rc = -ENODEV;
-+	int index;
-+	struct mem_ctl_info *mci = NULL;
-+	struct k8_pvt *pvt = NULL;
-+	int nid;
-+	u32 dram_pg_base = 0;
-+	u32 dram_pg_limit = 0;
-+	u32 dcl;
-+	u32 dcl_chans;
-+	u32 dcl_unbuf;
-+	u32 dcl_x4;
-+	u32 dcl_eccen;
-+	u32 dbam;
-+	u32 nbcfg;
-+	u32 nbcfg_ckx4en;
-+	u32 nbcfg_eccen;
-+	u32 nbcap;
-+	u32 nbcap_ckx4;
-+	u32 nbcap_ecc;
-+	u32 csrows_loaded = 0;
-+	u32 mcgctl_l, mcgctl_h;
-+	u32 mc4ctl_l, mc4ctl_h;
-+	const struct k8_dev_info *k8_dev = &k8_devs[dev_idx];
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	pci_read_config_dword(pdev, K8_DCL, &dcl);
-+	dcl_chans = ( dcl >> 16 ) & 0x1;
-+	dcl_unbuf = ( dcl >> 18 ) & 0x1;
-+	dcl_x4    = ( dcl >> 20 ) & 0xf;
-+	dcl_eccen = ( dcl >> 17 ) & 0x1;
-+	pci_read_config_dword(pdev, K8_DBAM, &dbam);
-+
-+	mci = bluesmoke_mc_init_structs(sizeof(*pvt),
-+					K8_NR_CSROWS,
-+					dcl_chans + 1);
-+
-+	if ( ! mci ) {
-+		rc = -ENOMEM;
-+		goto FAIL_FINISHED;
-+	}
-+
-+	debugf0( "MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci );
-+
-+	pvt = (struct k8_pvt *)mci->pvt_info;
-+
-+	mci->pdev = pdev;
-+	nid = MCI2NID(mci);
-+
-+	/* setup private structure */
-+	/*
-+	 * The address mapping device provides a table that indicates
-+	 * which physical address ranges are owned by which node.
-+	 * Each node's memory controller  has memory controller addresses
-+	 * that begin at 0x0.  Locally, the memory controller address
-+	 * must be added to the mapping device address to convert to
-+	 * physical address.
-+	 */
-+	pci_find_related_function( PCI_VENDOR_ID_AMD,
-+				   k8_dev->addr_map,
-+				   &pvt->addr_map,
-+				   mci->pdev );
-+
-+	if ( ! pvt->addr_map ) {
-+		printk( KERN_ERR
-+			"MC: error address map device not found:"
-+			"vendor %x device 0x%x (broken BIOS?)\n",
-+			PCI_VENDOR_ID_AMD,
-+			k8_dev->addr_map );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	debugf1( "Addr Map device PCI Bus ID:\t%s\n", pvt->addr_map->name );
-+
-+	/*
-+	 * Sift through address mapper DRAM table - the documentation isn't
-+	 * explicit, but it is believed to be an error if there are multiple
-+	 * entries for the same node.
-+	 */
-+	for ( index = 0; index < 8; index++ ) {
-+		u32 dbr;
-+		u32 dbr_base = 0;
-+		u32 dbr_inten;
-+		u32 dbr_wen;
-+		u32 dbr_ren;
-+		u32 dlr;
-+		u32 dlr_limit = 0;
-+		u32 dlr_intsel;
-+		u32 dlr_nid;
-+
-+		pci_read_config_dword( pvt->addr_map,
-+				       K8_DLR + (8 * index),
-+				       &dlr );
-+
-+		dlr_nid = dlr & 0x7;
-+
-+		if ( dlr_nid != nid ) continue;
-+
-+		/*
-+		 * dlr_limit has all the low-order bits 1 while dbr_base
-+		 * has all the low-order bits 0.  Here we do some bit
-+		 * jockeying to set all the low-order bits of dlr_limit.
-+		 */
-+		dlr_limit = ((((dlr >> 16) & 0xffff) + 1)
-+			     << (24 - PAGE_SHIFT)) - 1;
-+		dlr_intsel = (dlr >> 8) & 0x1f;
-+
-+		pci_read_config_dword( pvt->addr_map,
-+				       K8_DBR + (8 * index),
-+				       &dbr );
-+
-+		dbr_base = ((dbr >> 16) & 0xffff) << (24 - PAGE_SHIFT);
-+		dbr_inten = (dbr >> 8) & 0x7;
-+		dbr_wen = (dbr >> 1) & 0x1;
-+		dbr_ren = dbr & 0x1;
-+
-+		debugf1( "\tAddr Map: %d:0x%x - 0x%x\n",
-+			 dlr_nid, dbr_base, dlr_limit );
-+
-+		if ( dram_pg_limit ) {
-+			printk( KERN_ERR
-+				"MC: multiple entries for node %d found"
-+				" in Address Mapping device %s:"
-+				" PROBE FAILED!\n",
-+				nid, pci_name(pvt->misc_ctl) );
-+			goto FAIL_FINISHED;
-+		}
-+
-+		dram_pg_limit = dlr_limit;
-+		dram_pg_base = dbr_base;
-+	}
-+
-+	if (! dram_pg_limit) {
-+		printk( KERN_ERR
-+			"MC: no DRAM entry found for node %d in Address"
-+			" Mapping device: %s: POBE FAILED!\n",
-+			nid, pci_name(pvt->misc_ctl) );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	pci_find_related_function( PCI_VENDOR_ID_AMD,
-+				   k8_dev->misc_ctl,
-+				   &pvt->misc_ctl,
-+				   mci->pdev );
-+
-+	if ( ! pvt->misc_ctl ) {
-+		printk( KERN_ERR
-+			"MC: error miscellaneous device not found:"
-+			"vendor %x device 0x%x (broken BIOS?)\n",
-+			PCI_VENDOR_ID_AMD,
-+			k8_dev->misc_ctl );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	debugf1( "Misc device PCI Bus ID:\t\t%.2x:%.2x.%.1x\n",
-+		 pvt->misc_ctl->name );
-+
-+	pci_read_config_dword( pvt->misc_ctl, K8_NBCFG, &nbcfg );
-+	nbcfg_ckx4en = nbcfg & BIT(23);
-+	nbcfg_eccen  = nbcfg & BIT(22);
-+
-+	mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
-+
-+	pci_read_config_dword( pvt->misc_ctl, K8_NBCAP, &nbcap );
-+	nbcap_ckx4 = ( nbcap >> 4 ) & 0x1;
-+	nbcap_ecc  = ( nbcap >> 3 ) & 0x1;
-+	mci->edac_ctl_cap = EDAC_FLAG_NONE;
-+	if ( nbcap_ecc )  mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
-+	if ( nbcap_ckx4 ) mci->edac_ctl_cap |= EDAC_FLAG_S4ECD4ED;
-+
-+	mci->edac_cap = EDAC_FLAG_NONE;
-+	if ( dcl_eccen ) {
-+		mci->edac_cap |= EDAC_FLAG_SECDED;
-+		if ( dcl_chans ) {
-+			mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
-+		}
-+	}
-+
-+	mci->mod_name = BS_MOD_STR;
-+	mci->mod_ver = "$Revision: 1.6 $";
-+	mci->ctl_name = k8_devs[dev_idx].ctl_name;
-+	mci->edac_check = k8_check;
-+	mci->clear_err = NULL;
-+	mci->ctl_page_to_phys = NULL;
-+
-+	for ( index = 0; index < mci->nr_csrows; index++ ) {
-+		struct csrow_info *csrow = &mci->csrows[ index ];
-+		u32 dcsb;
-+		u32 dcsb_bah;
-+		u32 dcsb_bal;
-+		u32 dcsm;
-+		u32 dcsm_amh;
-+		u32 dcsm_aml;
-+		u32 aml;
-+		u32 device_shift = 0;
-+		u32 intlv_shift = 0;
-+		int i;
-+
-+		/* find the DRAM Chip Select Base address for this row */
-+		pci_read_config_dword(mci->pdev, K8_DCSB + (index*4), &dcsb);
-+		if ( ! (dcsb & 0x1) ) {
-+			continue;		/* empty */
-+		}
-+		csrows_loaded++;
-+		dcsb_bal = ((dcsb >> 9)  & 0x7fUL)  << (13 - PAGE_SHIFT);
-+		dcsb_bah = ((dcsb >> 21) & 0x7ffUL) << (25 - PAGE_SHIFT);
-+
-+		pci_read_config_dword(mci->pdev, K8_DCSM + (index*4), &dcsm);
-+		dcsm_aml = ((~dcsm >> 9) & 0x7fUL)  << (13 - PAGE_SHIFT);
-+		dcsm_amh = ((dcsm >> 21) & 0x1ffUL) << (25 - PAGE_SHIFT);
-+
-+		debugf2( "\t%d: dcsb(%x) dcsm(%x)\n", index, dcsb, dcsm );
-+
-+		/* 25 is 32MiB minimum DIMM size */
-+		csrow->first_page = (dcsb_bah | dcsb_bal) + dram_pg_base;
-+		csrow->nr_pages = 1 << ((( dbam >> ((index / 2)*4) ) & 0x7)
-+					+ 25 - PAGE_SHIFT + dcl_chans);
-+		if ( dcsm_aml ) {
-+			aml = dcsm_aml;
-+			i = 0;
-+			while ( ! (aml & 0x1UL) ) {
-+				i++;
-+				aml >>= 1;
-+			}
-+			device_shift = i;
-+
-+			i = 0;
-+			while ( aml & 0x1UL ) {
-+				i++;
-+				aml >>= 1;
-+			}
-+			intlv_shift = i;
-+
-+			csrow->last_page = csrow->first_page
-+				+ ( csrow->nr_pages << intlv_shift )
-+				- ( (1 << device_shift) | 0x1UL );
-+		} else {
-+			csrow->last_page = csrow->first_page
-+				+ csrow->nr_pages - 1;
-+		}
-+
-+		csrow->page_mask = dcsm_aml;
-+		csrow->grain = 8;		/* 8 bytes of resolution */
-+		csrow->mtype = dcl_unbuf ? MEM_DDR : MEM_RDDR;
-+		if ( ( dcl_x4 >> (index / 2 ) ) & 0x1 ) {
-+			csrow->dtype = DEV_X4;
-+		} else {
-+			csrow->dtype = DEV_UNKNOWN;
-+		}
-+
-+		if ( nbcfg_eccen ) {
-+			if ( nbcfg_ckx4en ) {
-+				csrow->edac_mode = EDAC_S4ECD4ED;
-+			} else {
-+				csrow->edac_mode = EDAC_SECDED;
-+			}
-+		} else {
-+			csrow->edac_mode = EDAC_NONE;
-+		}
-+	}
-+
-+	/* clear any pending errors, or initial state bits */
-+	/* FIXME - should log what is already there */
-+	pci_write_bits32( pvt->misc_ctl, K8_NBSH, 0, BIT(31) );
-+
-+	if ( ! csrows_loaded ) {
-+		mci->edac_cap = EDAC_FLAG_NONE;
-+	} else {
-+		/* turn on error reporting */
-+		pci_write_bits32( pvt->misc_ctl, K8_NBCTL, 0x3UL, 0x3UL );
-+
-+		pci_write_bits32( pvt->misc_ctl, K8_NBCTL, 0x3UL, 0x3UL );
-+
-+		do_rdmsr( nid, K8_MSR_MC4CTL, &mc4ctl_l, &mc4ctl_h );
-+		mc4ctl_l |= BIT(0) | BIT(1);
-+		do_wrmsr( nid, K8_MSR_MC4CTL, mc4ctl_l, mc4ctl_h );
-+		do_rdmsr( nid, K8_MSR_MC4CTL, &mc4ctl_l, &mc4ctl_h );
-+
-+		do_rdmsr( nid, K8_MSR_MCGCTL, &mcgctl_l, &mcgctl_h );
-+		mcgctl_l |= BIT(4);
-+		do_wrmsr( nid, K8_MSR_MCGCTL, mcgctl_l, mcgctl_h );
-+		do_rdmsr( nid, K8_MSR_MCGCTL, &mcgctl_l, &mcgctl_h );
-+	}
-+
-+	if ( 0 != bluesmoke_mc_add_mc( mci ) ) {
-+		debugf3( "MC: " __FILE__
-+			 ": %s(): failed bluesmoke_mc_add_mc()\n", __func__ );
-+		goto FAIL_FINISHED;
-+	}
-+
-+	/* get this far and it's successful */
-+	debugf3( "MC: " __FILE__ ": %s(): success\n", __func__ );
-+	rc = 0;
-+	goto FINISHED;
-+
-+ FAIL_FINISHED:
-+	if ( mci ) {
-+		kfree( mci );
-+	}
-+
-+ FINISHED:
-+	return( rc );
-+}
-+
-+
-+#ifdef CONFIG_PM
-+
-+static int k8_suspend (struct pci_dev *pdev, u32 state)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+
-+static int k8_resume (struct pci_dev *pdev)
-+{
-+	debugf0( "MC: " __FILE__ ": %s(): FIXME\n", __func__ );
-+
-+	return -ENOSYS;
-+}
-+
-+#endif /* CONFIG_PM */
-+
-+
-+/* returns count (>= 0), or negative on error */
-+static int __devinit k8_init_one( struct pci_dev *pdev,
-+				  const struct pci_device_id *ent )
-+{
-+	int rc;
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	/* wake up and enable device */		
-+	if (pci_enable_device (pdev)) {
-+		rc = -EIO;
-+	} else {
-+		rc = k8_probe1( pdev, ent->driver_data );
-+	}
-+	return rc;
-+}
-+
-+
-+static void __devexit k8_remove_one( struct pci_dev *pdev )
-+{
-+	struct mem_ctl_info *mci;
-+
-+	debugf0( __FILE__ ": %s()\n", __func__);
-+
-+	if ( NULL == ( mci = bluesmoke_mc_find_mci_by_pdev( pdev ) ) ) {
-+		goto FINISHED;
-+	}
-+
-+	if ( 0 != bluesmoke_mc_del_mc( mci ) ) {
-+		goto FINISHED;
-+	}
-+
-+	kfree( mci );
-+
-+ FINISHED:
-+	return;
-+}
-+
-+
-+static const struct pci_device_id k8_pci_tbl[] __devinitdata = {
-+	{ PCI_VEND_DEV( AMD, OPT_2_MEMCTL ), PCI_ANY_ID, PCI_ANY_ID, 0, 0, OPTERON },
-+	{0,}						/* 0 terminated list. */
-+};
-+
-+MODULE_DEVICE_TABLE(pci, k8_pci_tbl);
-+
-+
-+static struct pci_driver k8_driver = {
-+	.name		= BS_MOD_STR,
-+	.probe		= k8_init_one,
-+	.remove		= __devexit_p(k8_remove_one),
-+	.id_table	= k8_pci_tbl,
-+#ifdef CONFIG_PM
-+	.suspend	= k8_suspend,
-+	.resume		= k8_resume,
-+#endif /* CONFIG_PM */
-+};
-+
-+
-+int __init k8_init(void)
-+{
-+	int pci_rc;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+	pci_rc = pci_module_init( &k8_driver );
-+	if ( pci_rc < 0 ) return pci_rc;
-+
-+	return 0;
-+}
-+
-+
-+static void __exit k8_exit(void)
-+{
-+	debugf3( "MC: "  __FILE__ ": %s()\n", __func__ );
-+	pci_unregister_driver( &k8_driver );
-+}
-+
-+
-+module_init(k8_init);
-+module_exit(k8_exit);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
-+MODULE_DESCRIPTION("MC support for AMD K8 memory controllers");
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_mc.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.c	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,1112 @@
-+/*
-+ * bluesmoke_mc kernel module
-+ * (C) 2003 Linux Networx (http://lnxi.com)
-+ * This file may be distributed under the terms of the
-+ * GNU General Public License.
-+ *
-+ * Written by Thayne Harbaugh
-+ * Based on work by Dan Hollis <goemon at anime dot net> and others.
-+ *	http://www.anime.net/~goemon/linux-ecc/
-+ *
-+ * $Id: bluesmoke_mc.c,v 1.9 2004/12/13 22:19:40 thayne Exp $
-+ *
-+ */
-+
-+
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/proc_fs.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sysctl.h>
-+#include <linux/highmem.h>
-+#include <linux/timer.h>
-+#include <linux/slab.h>
-+
-+#include <asm/uaccess.h>
-+#include <asm/page.h>
-+
-+#include "bluesmoke_mc.h"
-+
-+
-+#ifndef pfn_to_page
-+#define pfn_to_page(pfn)	(mem_map + (pfn)) 
-+#endif /* pfn_to_page */
-+
-+#define MC_PROC_DIR "mc"
-+
-+/* /proc/mc dir */
-+static struct proc_dir_entry *proc_mc;
-+
-+/* Setable by module parameter and sysctl */
-+#if SCRUB
-+/* FIXME - do something with scrubbing */
-+static int mc_scrub		= -1;
-+#endif /* SCRUB */
-+static int panic_on_ue		= 1;
-+static int log_ue		= 1;
-+static int log_ce		= 1;
-+static int poll_msec		= 1000;
-+static struct timer_list timer;
-+
-+static DECLARE_MUTEX(mem_ctls_mutex);
-+
-+/* FIXME - use list.h */
-+/* FIXME - should be dynamic */
-+static struct mem_ctl_info *mcis[MAX_MC_DEVICES];
-+
-+
-+#ifdef CONFIG_SYSCTL
-+static void dimm_labels( char *buf, void *data )
-+{
-+	int mcidx, ridx, chidx;
-+	char *mcstr, *rstr, *chstr, *lstr, *p;
-+
-+	lstr = buf;
-+
-+	mcstr = strsep( &lstr, "." );
-+	if (! lstr)
-+		return;
-+	mcidx = simple_strtol( mcstr, &p, 0 );
-+	if ( *p )
-+		return;
-+	if ( mcidx >= MAX_MC_DEVICES || ! mcis[mcidx] )
-+		return;
-+
-+	rstr = strsep( &lstr, "." );
-+	if (! lstr)
-+		return;
-+	ridx = simple_strtol( rstr, &p, 0 );
-+	if ( *p )
-+		return;
-+	if ( ridx >= mcis[mcidx]->nr_csrows
-+	     || ! mcis[mcidx]->csrows )
-+		return;
-+
-+	chstr = strsep( &lstr, ":" );
-+	if (! lstr)
-+		return;
-+	chidx = simple_strtol( chstr, &p, 0 );
-+	if ( *p )
-+		return;
-+	if ( chidx >= mcis[mcidx]->csrows[ridx].nr_channels
-+	     || ! mcis[mcidx]->csrows[ridx].channels )
-+		return;
-+
-+	debugf1( "%d:%d.%d:%s\n",
-+		 mcidx, ridx, chidx, lstr );
-+
-+	strncpy(mcis[mcidx]->csrows[ridx].channels[chidx].label,
-+		lstr, BLUESMOKE_MC_LABEL_LEN + 1);
-+	/*
-+	 * no need to NUL terminate label since
-+	 * get_user_tok() NUL terminates.
-+	 */
-+}
-+
-+
-+static void counter_reset( char *buf, void *data )
-+{
-+	char *p = buf;
-+	int mcidx, row, chan;
-+	struct mem_ctl_info *mci;
-+
-+	mcidx = simple_strtol( buf, &p, 0 );
-+	if ( *p )
-+		return;
-+	if ( mcidx >= MAX_MC_DEVICES || ! mcis[mcidx] )
-+		return;
-+
-+	mci = mcis[mcidx];
-+	mci->ue_noinfo_count = 0;
-+	mci->ce_noinfo_count = 0;
-+	mci->ue_count = 0;
-+	mci->ce_count = 0;
-+	for ( row = 0; row < mci->nr_csrows; row++ ) {
-+		struct csrow_info *ri = &mci->csrows[row];
-+
-+		ri->ue_count = 0;
-+		ri->ce_count = 0;
-+		for ( chan = 0; chan < ri->nr_channels; chan++ ) {
-+			ri->channels[chan].ce_count = 0;
-+		}
-+	}
-+	do_gettimeofday( &mci->tv );
-+}
-+
-+
-+struct actionvec_info {
-+	void (*action)(char *str, void *data);
-+	char separator;
-+	char *usage;
-+	void *data;
-+};
-+
-+
-+static struct actionvec_info dimm_labels_avi = {
-+	.action    = dimm_labels,
-+	.separator = ',',
-+	.usage     = "<mc>.<row>.<chan>:<label>"
-+	"[,<mc>.<row>.<chan>:<label>[,...]]\n",
-+	.data      = NULL
-+};
-+
-+
-+static struct actionvec_info counter_reset_avi = {
-+	.action    = counter_reset,
-+	.separator = ',',
-+	.usage     = "<mc>[,<mc>[,...]]\n",
-+	.data      = NULL
-+};
-+
-+
-+static int proc_actionvec( ctl_table *table, int write, struct file *filp,
-+			   void *buffer, size_t *lenp )
-+{
-+	size_t len;
-+	char *p, c, *buf, *tok, sep[] = " ";
-+	struct actionvec_info *avi;
-+	
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if ( !table->data || !*lenp || (filp->f_pos && !write)) {
-+		*lenp = 0;
-+		return 0;
-+	}
-+
-+	avi = (struct actionvec_info *)table->data;
-+	
-+	if (write) {
-+		/* dup the string from user space */
-+		len = 0;
-+		p = buffer;
-+		while (len < *lenp) {
-+			if (get_user(c, p++))
-+				return -EFAULT;
-+			if (c == 0 || c == '\n')
-+				break;
-+			len++;
-+		}
-+		if (! (buf = kmalloc(len + 1, GFP_KERNEL)))
-+			return -EFAULT;
-+		if (copy_from_user(buf, buffer, len)) {
-+			kfree(buf);
-+			return -EFAULT;
-+		}
-+		buf[len] = '\0';
-+		filp->f_pos += *lenp;
-+		/* working copy can now be segmented for processing */
-+		p = buf;
-+		sep[0] = avi->separator;
-+		while ((tok = strsep(&p, sep)))
-+			avi->action(tok, avi->data);
-+		kfree(buf);
-+	} else {
-+		len = strlen(avi->usage);
-+		if (len > *lenp)
-+			len = *lenp;
-+		if (len)
-+			if(copy_to_user(buffer, avi->usage, len))
-+				return -EFAULT;
-+		*lenp = len;
-+		filp->f_pos += len;
-+	}
-+	return 0;
-+}
-+
-+
-+static ctl_table mc_table[] = {
-+        {-1, "panic_on_ue", &panic_on_ue,
-+	 sizeof(int), 0644, NULL, proc_dointvec},
-+        {-2, "log_ue", &log_ue,
-+	 sizeof(int), 0644, NULL, proc_dointvec},
-+        {-3, "log_ce", &log_ce,
-+	 sizeof(int), 0644, NULL, proc_dointvec},
-+        {-4, "poll_msec", &poll_msec,
-+	 sizeof(int), 0644, NULL, proc_dointvec},
-+        {-5, "dimm_labels", &dimm_labels_avi,
-+	 0, 0644, NULL, proc_actionvec},
-+        {-6, "counter_reset", &counter_reset_avi,
-+	 0, 0644, NULL, proc_actionvec},
-+        {0}
-+};
-+
-+
-+static ctl_table mc_root_table[] = {
-+        {CTL_DEBUG, MC_PROC_DIR, NULL, 0, 0555, mc_table},
-+        {0}
-+};
-+
-+
-+static struct ctl_table_header *mc_sysctl_header = NULL;
-+#endif /* CONFIG_SYSCTL */
-+
-+
-+#ifdef CONFIG_PROC_FS
-+static const char *mem_types[] = {
-+	[MEM_EMPTY]		= "Empty",
-+	[MEM_RESERVED]		= "Reserved",
-+	[MEM_UNKNOWN]		= "Unknown",
-+	[MEM_FPM]		= "FPM",
-+	[MEM_EDO]		= "EDO",
-+	[MEM_BEDO]		= "BEDO",
-+	[MEM_SDR]		= "Unbuffered-SDR",
-+	[MEM_RDR]		= "Registered-SDR",
-+	[MEM_DDR]		= "Unbuffered-DDR",
-+	[MEM_RDDR]		= "Registered-DDR",
-+	[MEM_RMBS]		= "RMBS"
-+};
-+
-+static const char *dev_types[] = {
-+	[DEV_UNKNOWN]		= "Unknown",
-+	[DEV_X1]		= "x1",
-+	[DEV_X2]		= "x2",
-+	[DEV_X4]		= "x4",
-+	[DEV_X8]		= "x8",
-+	[DEV_X16]		= "x16",
-+	[DEV_X32]		= "x32",
-+	[DEV_X64]		= "x64"
-+};
-+
-+static const char *edac_caps[] = {
-+	[EDAC_UNKNOWN]		= "Unknown",
-+	[EDAC_NONE]		= "None",
-+	[EDAC_RESERVED]		= "Reserved",
-+	[EDAC_PARITY]		= "PARITY",
-+	[EDAC_EC]		= "EC",
-+	[EDAC_SECDED]		= "SECDED",
-+	[EDAC_S2ECD2ED]		= "S2ECD2ED",
-+	[EDAC_S4ECD4ED]		= "S4ECD4ED",
-+	[EDAC_S8ECD8ED]		= "S8ECD8ED",
-+	[EDAC_S16ECD16ED]	= "S16ECD16ED"
-+};
-+
-+
-+#if UNUSED
-+static const char *scrub_caps[] = {
-+	[SCRUB_UNKNOWN]		= "Unknown",
-+	[SCRUB_NONE]		= "None",
-+	[SCRUB_SW_PROG]		= "SProg",
-+	[SCRUB_SW_SRC]		= "SSrc",
-+	[SCRUB_SW_PROG_SRC]	= "SProg+Src",
-+	[SCRUB_SW_TUNABLE]	= "STun",
-+	[SCRUB_HW_PROG]		= "HProg",
-+	[SCRUB_HW_SRC]		= "HSrc",
-+	[SCRUB_HW_PROG_SRC]	= "HProg+Src",
-+	[SCRUB_HW_TUNABLE]	= "HTun"
-+};
-+#endif /* UNUSED */
-+
-+
-+/* FIXME - CHANNEL_PREFIX is pretty bad */
-+#define CHANNEL_PREFIX(...) \
-+	do { \
-+		p += sprintf( p, "%d.%d:%s", \
-+			chan->csrow->csrow_idx, \
-+			chan->chan_idx, \
-+			chan->label ); \
-+		p += sprintf( p, ":" __VA_ARGS__ ); \
-+	} while ( 0 )
-+
-+
-+static inline int mc_proc_output_channel(char *buf, struct channel_info *chan)
-+{
-+	char *p = buf;
-+
-+	CHANNEL_PREFIX( "CE:\t\t%d\n", chan->ce_count );
-+
-+	return p - buf;
-+}
-+
-+#undef CHANNEL_PREFIX
-+
-+
-+#define CSROW_PREFIX(...) \
-+	do { \
-+		int i; \
-+		p += sprintf( p, "%d:", csrow->csrow_idx ); \
-+		p += sprintf( p, "%s", csrow->channels[0].label ); \
-+		for ( i = 1; i < csrow->nr_channels; i++ ) { \
-+			p += sprintf( p, "|%s", csrow->channels[i].label ); \
-+		} \
-+		p += sprintf( p, ":" __VA_ARGS__ ); \
-+	} while ( 0 )
-+
-+
-+static inline int mc_proc_output_csrow(char *buf, struct csrow_info *csrow)
-+{
-+	char *p = buf;
-+	int chan_idx;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	CSROW_PREFIX( "Memory Size:\t%d MiB\n",
-+		     (u32)PAGES_TO_MiB(csrow->nr_pages) );
-+	CSROW_PREFIX( "Mem Type:\t\t%s\n", mem_types[csrow->mtype] );
-+	CSROW_PREFIX( "Dev Type:\t\t%s\n", dev_types[csrow->dtype] );
-+	CSROW_PREFIX( "EDAC Mode:\t\t%s\n", edac_caps[csrow->edac_mode] );
-+	CSROW_PREFIX( "UE:\t\t\t%d\n", csrow->ue_count );
-+	CSROW_PREFIX( "CE:\t\t\t%d\n", csrow->ce_count );
-+
-+	for ( chan_idx = 0; chan_idx < csrow->nr_channels; chan_idx++ ) {
-+		p += mc_proc_output_channel( p, &csrow->channels[chan_idx] );
-+	}
-+	p += sprintf( p, "\n" );
-+	return p - buf;
-+}
-+
-+#undef CSROW_PREFIX
-+
-+
-+static inline int mc_proc_output_edac_cap(char *buf, unsigned long edac_cap)
-+{
-+	char *p = buf;
-+	int bit_idx;
-+
-+	for ( bit_idx = 0; bit_idx < 8 * sizeof(edac_cap); bit_idx++ ) {
-+		if ( ( edac_cap >> bit_idx ) & 0x1 ) {
-+			p += sprintf( p, "%s ", edac_caps[ bit_idx ] );
-+		}
-+	}
-+
-+	return p - buf;
-+}
-+
-+
-+static inline int mc_proc_output_mtype_cap(char *buf, unsigned long mtype_cap)
-+{
-+	char *p = buf;
-+	int bit_idx;
-+
-+	for ( bit_idx = 0; bit_idx < 8 * sizeof(mtype_cap); bit_idx++ ) {
-+		if ( ( mtype_cap >> bit_idx ) & 0x1 ) {
-+			p += sprintf( p, "%s ", mem_types[ bit_idx ] );
-+		}
-+	}
-+
-+	return p - buf;
-+}
-+
-+
-+static int mc_proc_output(struct mem_ctl_info *mci, char *buf)
-+{	
-+	int csrow_idx;
-+	u32 total_pages;
-+	char *p = buf;
-+	struct timeval tv;
-+
-+	debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+
-+	do_gettimeofday( &tv );
-+
-+	p += sprintf( p, "Panic UE:\t\t%d\n",    panic_on_ue );
-+	p += sprintf( p, "Log UE:\t\t\t%d\n",    log_ue );
-+	p += sprintf( p, "Log CE:\t\t\t%d\n",    log_ce );
-+	p += sprintf( p, "Poll msec:\t\t%d\n",   poll_msec );
-+
-+	p += sprintf( p, "\n" );
-+
-+	p += sprintf( p, "MC Module:\t\t%s %s\n", mci->mod_name, mci->mod_ver );
-+	p += sprintf( p, "Memory Controller:\t%s\n", mci->ctl_name );
-+	p += sprintf( p, "PCI Bus ID:\t\t%s (%s)\n",
-+		      mci->pdev->slot_name, pci_name(mci->pdev) );
-+
-+	p += sprintf( p, "EDAC capability:\t" );
-+	p += mc_proc_output_edac_cap( p, mci->edac_ctl_cap );
-+	p += sprintf( p, "\n" );
-+
-+	p += sprintf( p, "Current EDAC capability:\t" );
-+	p += mc_proc_output_edac_cap( p, mci->edac_cap );
-+	p += sprintf( p, "\n" );
-+
-+	p += sprintf( p, "Supported Mem Types:\t" );
-+	p += mc_proc_output_mtype_cap( p, mci->mtype_cap );
-+	p += sprintf( p, "\n" );
-+
-+	p += sprintf( p, "\n" );
-+
-+	for ( total_pages = csrow_idx = 0;
-+	      csrow_idx < mci->nr_csrows;
-+	      csrow_idx++ ) {
-+		struct csrow_info *csrow = &mci->csrows[csrow_idx];
-+
-+		if ( ! csrow->nr_pages ) continue;
-+		total_pages += csrow->nr_pages;
-+		p += mc_proc_output_csrow( p, csrow );
-+	}
-+
-+	p += sprintf( p, "Total Memory Size:\t%d MiB\n",
-+		      (u32)PAGES_TO_MiB(total_pages) );
-+	p += sprintf( p, "Seconds since reset:\t%ld\n",
-+		      tv.tv_sec - mci->tv.tv_sec );
-+	p += sprintf( p, "UE No Info:\t\t%d\n", mci->ue_noinfo_count );
-+	p += sprintf( p, "CE No Info:\t\t%d\n", mci->ce_noinfo_count );
-+	p += sprintf( p, "Total UE:\t\t%d\n", mci->ue_count );
-+	p += sprintf( p, "Total CE:\t\t%d\n", mci->ce_count );
-+	return p - buf;
-+}
-+
-+
-+static int mc_read_proc(char *page, char **start, off_t off,
-+			     int count, int *eof, void *data)
-+{
-+	int len;
-+	struct mem_ctl_info *mci = (struct mem_ctl_info *)data;
-+
-+	debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+
-+	down(&mem_ctls_mutex);
-+        len = mc_proc_output(mci, page);
-+	up(&mem_ctls_mutex);
-+        if (len <= off+count) *eof = 1;
-+        *start = page + off;
-+        len -= off;
-+        if (len>count) len = count;
-+        if (len<0) len = 0;
-+
-+
-+        return len;
-+}
-+#endif /* CONFIG_PROC_FS */
-+
-+
-+#if CONFIG_BLUESMOKE_DEBUG
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_dump_channel);
-+
-+void bluesmoke_mc_dump_channel( struct channel_info *chan )
-+{
-+	printk( KERN_INFO "\tchannel = %p\n", chan );
-+	printk( KERN_INFO "\tchannel->chan_idx = %d\n", chan->chan_idx );
-+	printk( KERN_INFO "\tchannel->ce_count = %d\n", chan->ce_count );
-+	printk( KERN_INFO "\tchannel->label = '%s'\n", chan->label );
-+	printk( KERN_INFO "\tchannel->csrow = %p\n\n", chan->csrow );
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_dump_csrow);
-+
-+void bluesmoke_mc_dump_csrow( struct csrow_info *csrow )
-+{
-+	printk( KERN_INFO "\tcsrow = %p\n", csrow );
-+	printk( KERN_INFO "\tcsrow->csrow_idx = %d\n", csrow->csrow_idx );
-+	printk( KERN_INFO "\tcsrow->first_page = 0x%lx\n", csrow->first_page );
-+	printk( KERN_INFO "\tcsrow->last_page = 0x%lx\n", csrow->last_page );
-+	printk( KERN_INFO "\tcsrow->page_mask = 0x%lx\n", csrow->page_mask );
-+	printk( KERN_INFO "\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages );
-+	printk( KERN_INFO "\tcsrow->nr_channels = %d\n", csrow->nr_channels );
-+	printk( KERN_INFO "\tcsrow->channels = %p\n", csrow->channels );
-+	printk( KERN_INFO "\tcsrow->mci = %p\n\n", csrow->mci );
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_dump_mci);
-+
-+void bluesmoke_mc_dump_mci( struct mem_ctl_info *mci )
-+{
-+	printk( KERN_INFO "\tmci = %p\n", mci );
-+	printk( KERN_INFO "\tmci->mtype_cap = %lx\n", mci->mtype_cap );
-+	printk( KERN_INFO "\tmci->edac_ctl_cap = %lx\n", mci->edac_ctl_cap );
-+	printk( KERN_INFO "\tmci->edac_cap = %lx\n", mci->edac_cap );
-+	printk( KERN_INFO "\tmci->edac_check = %p\n", mci->edac_check );
-+	printk( KERN_INFO "\tmci->clear_err = %p\n", mci->clear_err );
-+	printk( KERN_INFO "\tmci->nr_csrows = %d, csrows = %p\n",
-+		mci->nr_csrows, mci->csrows );
-+	printk( KERN_INFO "\tpdev = %p\n", mci->pdev );
-+	printk( KERN_INFO "\tmod_name:ctl_name = %s:%s\n",
-+		mci->mod_name, mci->ctl_name );
-+	printk( KERN_INFO "\tproc_name = %s, proc_ent = %p\n",
-+		mci->proc_name, mci->proc_ent );
-+	printk( KERN_INFO "\tpvt_info = %p\n\n", mci->pvt_info );
-+}
-+
-+
-+#endif /* CONFIG_BLUESMOKE_DEBUG */
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_init_structs);
-+
-+/*
-+ * Everything is kmalloc'ed as one big chunk - more efficient.
-+ * Only can be used if all structures have the same lifetime - otherwise
-+ * you have to allocate and initialize your own structures.
-+ *
-+ * kmalloc'ed memory must be free'ed by caller.
-+ */
-+struct mem_ctl_info *bluesmoke_mc_init_structs(u32 sz_pvt,
-+					       u32 nr_csrows,
-+					       u32 nr_chans)
-+{
-+	struct mem_ctl_info *mci;
-+	struct channel_info *chi;
-+	u32 malloc_size;
-+	int row, chn;
-+
-+	malloc_size =
-+		sizeof(struct mem_ctl_info)
-+		+ sz_pvt
-+		+ nr_csrows * sizeof(struct csrow_info)
-+		+ nr_chans * nr_csrows * sizeof(struct channel_info);
-+
-+	if (! (mci = kmalloc(malloc_size, GFP_KERNEL)))
-+		goto done;
-+
-+	memset( mci, 0, malloc_size);
-+
-+	/* set all the pointers to the correct offset in the malloc'ed block */
-+	if (sz_pvt)
-+		mci->pvt_info = (pvt_info_t)((char *)mci + sizeof(*mci));
-+
-+	mci->csrows = (struct csrow_info *)((char *)mci + sizeof(*mci) + sz_pvt);
-+	mci->nr_csrows = nr_csrows;
-+
-+	chi = (struct channel_info *)((char *)mci->csrows
-+				      + sizeof(*mci->csrows) * nr_csrows);
-+
-+	for (row = 0; row < nr_csrows; row++) {
-+		struct csrow_info *csrow = &mci->csrows[row];
-+
-+		csrow->csrow_idx = row;
-+		csrow->mci = mci;
-+		csrow->nr_channels = nr_chans;
-+		csrow->channels = &chi[ row * nr_chans ];
-+
-+		for (chn = 0; chn < nr_chans; chn++) {
-+			struct channel_info *chan = &csrow->channels[ chn ];
-+
-+			chan->chan_idx = chn;
-+			chan->csrow = csrow;
-+		}
-+	}
-+
-+ done:
-+	return mci;
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_find_mci_by_pdev);
-+
-+struct mem_ctl_info *bluesmoke_mc_find_mci_by_pdev(struct pci_dev *pdev )
-+{
-+	int i;
-+	struct mem_ctl_info *mci = NULL;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	for (i=0; i < MAX_MC_DEVICES; i++) {
-+		if ( ! mcis[ i ] ) continue;
-+		if ( pdev == mcis[ i ]->pdev ) {
-+			mci = mcis[ i ];
-+			break;
-+		}
-+	}
-+
-+	return mci;
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_add_mc);
-+
-+/* FIXME - should a warning be printed if no error detection? correction? */
-+int bluesmoke_mc_add_mc(struct mem_ctl_info *mci)
-+{
-+	int i;
-+	int rc = 1;
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+#if CONFIG_BLUESMOKE_DEBUG
-+#if 1 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
-+	bluesmoke_mc_dump_mci( mci );
-+#endif /* 1 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE */
-+#if 2 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
-+	for ( i = 0; i < mci->nr_csrows; i++ ) {
-+		int j;
-+		bluesmoke_mc_dump_csrow( &mci->csrows[i] );
-+		for ( j = 0; j < mci->csrows[i].nr_channels; j++ ) {
-+			bluesmoke_mc_dump_channel( &mci->csrows[i].channels[j] );
-+		}
-+	}
-+#endif /* 2 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE */
-+#endif /* CONFIG_BLUESMOKE_DEBUG */
-+	down( &mem_ctls_mutex );
-+
-+	if ( bluesmoke_mc_find_mci_by_pdev( mci->pdev ) ) {
-+		printk( KERN_WARNING
-+			"MC: %s (%s) %s %s already assigned %d\n",
-+			mci->pdev->slot_name, pci_name(mci->pdev),
-+			mci->mod_name,
-+			mci->ctl_name,
-+			mci->mc_idx );
-+		goto FINISH;
-+	}
-+
-+	for (i=0; i < MAX_MC_DEVICES; i++) {
-+		if ( ! mcis[ i ] ) break;
-+	}
-+
-+	if ( MAX_MC_DEVICES == i ) {
-+		printk( KERN_WARNING
-+			"MC: out of slots in mem_ctls for %s %s\n",
-+			mci->mod_name, mci->ctl_name);
-+		goto FINISH;
-+	}
-+
-+	mcis[i] = mci;
-+	mci->mc_idx = i;
-+	printk( KERN_INFO
-+		"MC%d: Giving out device %d to %s %s: PCI %s (%s)\n",
-+		mci->mc_idx,
-+		i, mci->mod_name, mci->ctl_name,
-+		mci->pdev->slot_name, pci_name(mci->pdev) );
-+	__module_get(THIS_MODULE);
-+
-+	/* set load time so that error rate can be tracked */
-+	do_gettimeofday(&mci->tv);
-+
-+#ifdef CONFIG_PROC_FS
-+	if ( snprintf( mci->proc_name, MC_PROC_NAME_MAX_LEN, "%d", i )
-+	     == MC_PROC_NAME_MAX_LEN ) {
-+		printk( KERN_WARNING
-+			"MC%d: proc entry too long for device %d \n",
-+			mci->mc_idx, i );
-+		/* FIXME - should there be an error code and unwind? */
-+		goto FINISH;
-+	}
-+
-+	mci->proc_ent = create_proc_read_entry( mci->proc_name, 0, proc_mc,
-+						mc_read_proc, (void *)mci );
-+
-+	if ( NULL == mci->proc_ent ) {
-+		printk( KERN_WARNING
-+			"MC%d: failed to create proc entry for controller %d \n",
-+			mci->mc_idx, i );
-+		/* FIXME - should there be an error code and unwind? */
-+		goto FINISH;
-+	}
-+#endif /* CONFIG_PROC_FS */
-+
-+	rc = 0;
-+
-+ FINISH:
-+	up( &mem_ctls_mutex );
-+	return rc;
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_del_mc);
-+
-+int bluesmoke_mc_del_mc(struct mem_ctl_info *mci)
-+{
-+	int rc = 1;
-+	
-+	debugf0( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+	down( &mem_ctls_mutex );
-+
-+	if ( mcis[mci->mc_idx] != mci ) {
-+		printk( KERN_WARNING
-+			"MC%d: index of mci for %s %s doesn't match"
-+			" entry in mem_ctls\n",
-+			mci->mc_idx, mci->mod_name, mci->ctl_name);
-+		rc = -ENODEV;
-+		goto FINISHED;
-+	}
-+
-+	mcis[mci->mc_idx] = NULL;
-+	module_put(THIS_MODULE);
-+	if ( ! module_refcount(THIS_MODULE) ) del_timer( &timer );
-+#ifdef CONFIG_PROC_FS
-+	remove_proc_entry( mci->proc_name, proc_mc );
-+#endif
-+
-+	printk( KERN_INFO
-+		"MC%d: Removed device %d for %s %s: PCI %s (%s)\n",
-+		mci->mc_idx, mci->mc_idx, mci->mod_name, mci->ctl_name,
-+		mci->pdev->slot_name, pci_name(mci->pdev) );
-+
-+	rc = 0;
-+
-+ FINISHED:
-+	up( &mem_ctls_mutex );
-+	return rc;
-+}
-+
-+
-+/*
-+ * FIXME - what happens when grain > PAGE_SIZE?
-+ * Need multiple kmap_atomic()
-+ */
-+/* FIXME - this should go in an arch dependant file */
-+EXPORT_SYMBOL(bluesmoke_mc_scrub_block);
-+
-+void bluesmoke_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
-+{
-+        struct page *pg;
-+	volatile unsigned long *virt_addr;
-+	int i;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+#ifndef CONFIG_DISCONTIGMEM
-+	if(page > max_mapnr)
-+		return;		/* pointer is beyond memory, so bail */
-+#else
-+/* FIXME - use the per-pgdat data instead for discontigmem */
-+#endif
-+	pg = pfn_to_page(page);
-+
-+	virt_addr = kmap_atomic(pg, KM_BOUNCE_READ) + offset;
-+
-+	for(i = 0; i < size / sizeof(unsigned long); i++, virt_addr++) {	
-+		/* Very carefully read and write to memory atomically
-+		 * so we are interrupt and smp safe.
-+		 */
-+		__asm__ __volatile__(
-+			"lock; addl $0, %0"
-+			:: "m" (*virt_addr));
-+	}
-+	kunmap_atomic(pg, KM_BOUNCE_READ);
-+}
-+
-+
-+/* FIXME - put in a util library? */
-+/* FIXME - should return -1 */
-+EXPORT_SYMBOL(bluesmoke_mc_find_csrow_by_page);
-+
-+int bluesmoke_mc_find_csrow_by_page( struct mem_ctl_info *mci,
-+				     unsigned long page )
-+{
-+	struct csrow_info *csrows = mci->csrows;
-+	int row = -1, i;
-+
-+	debugf1( "MC%d: " __FILE__ ": %s(): 0x%lx\n",
-+		 mci->mc_idx, __func__, page );
-+
-+	for ( i = 0; i < mci->nr_csrows; i++ ) {
-+		struct csrow_info *csrow = &csrows[i];
-+
-+		if ( 0 == csrow->nr_pages ) continue;
-+
-+		debugf3( "MC%d: " __FILE__
-+			 ": %s(): first(0x%lx) page(0x%lx)"
-+			 " last(0x%lx) mask(0x%lx)\n",
-+			 mci->mc_idx, __func__,
-+			 csrow->first_page,
-+			 page,
-+			 csrow->last_page,
-+			 csrow->page_mask );
-+
-+		if ( ( page >= csrow->first_page )
-+		     && ( page <= csrow->last_page )
-+		     && ((page & csrow->page_mask)
-+			 == (csrow->first_page & csrow->page_mask)) ) {
-+			row = i;
-+			break;
-+		}
-+	}
-+
-+	if (row == -1) {
-+		printk( KERN_ERR
-+			"MC%d: could not look up page error address %lx\n",
-+			mci->mc_idx, (unsigned long)page);
-+	}
-+
-+	return row;
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_handle_ce);
-+
-+/* FIXME - setable log (warning/emerg) levels */
-+/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
-+void bluesmoke_mc_handle_ce(struct mem_ctl_info *mci,
-+			    unsigned long page_frame_number,
-+			    unsigned long offset_in_page,
-+			    unsigned long syndrome,
-+			    int row,
-+			    int channel,
-+			    const char *msg)
-+{
-+	unsigned long remapped_page;
-+
-+	debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+
-+	/* FIXME - maybe make panic on INTERNAL ERROR an option */
-+	if ( row >= mci->nr_csrows  || row < 0 ) {
-+		/* something is wrong */
-+		printk( KERN_ERR
-+			"MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n",
-+			mci->mc_idx,
-+			row, mci->nr_csrows );
-+		bluesmoke_mc_handle_ce_no_info( mci, "INTERNAL ERROR" );
-+		return;
-+	}
-+	if ( channel >= mci->csrows[row].nr_channels || channel < 0 ) {
-+		/* something is wrong */
-+		printk( KERN_ERR
-+			"MC%d: INTERNAL ERROR: channel out of range (%d >= %d)\n",
-+			mci->mc_idx,
-+			channel, mci->csrows[row].nr_channels );
-+		bluesmoke_mc_handle_ce_no_info( mci, "INTERNAL ERROR" );
-+		return;
-+	}
-+
-+	if ( log_ce ) {
-+		/* FIXME - put in DIMM location */
-+		printk( KERN_WARNING
-+			"MC%d: CE page 0x%lx, offset 0x%lx,"
-+			" grain %d, syndrome 0x%lx, row %d, channel %d,"
-+			" label \"%s\": %s\n",
-+			mci->mc_idx,
-+			page_frame_number,
-+			offset_in_page,
-+			mci->csrows[row].grain,
-+			syndrome,
-+			row,
-+			channel,
-+			mci->csrows[row].channels[channel].label,
-+			msg );
-+	}
-+
-+	mci->ce_count++;
-+	mci->csrows[row].ce_count++;
-+	mci->csrows[row].channels[channel].ce_count++;
-+
-+	if ( mci->scrub_mode & SCRUB_SW_SRC ) {
-+		/*
-+		 * Some MC's can remap memory so that it is still available
-+		 * at a different address when PCI devices map into memory.
-+		 * MC's that can't do this lose the memory where PCI devices
-+		 * are mapped.  This mapping is MC dependant and so we call
-+		 * back into the MC driver for it to map the MC page to
-+		 * a physical (CPU) page which can then be mapped to a virtual
-+		 * page - which can then be scrubbed.
-+		 */
-+		if ( mci->ctl_page_to_phys ) {
-+			remapped_page = mci->ctl_page_to_phys(mci,
-+							      page_frame_number);
-+		} else {
-+			remapped_page = page_frame_number;
-+		}
-+		bluesmoke_mc_scrub_block(remapped_page,
-+					 offset_in_page,
-+					 mci->csrows[row].grain);
-+	}
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_handle_ce_no_info);
-+
-+void bluesmoke_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
-+{
-+	if ( log_ce ) {
-+		printk( KERN_WARNING
-+			"MC%d: CE - no information available: %s\n",
-+			mci->mc_idx, msg );
-+	}
-+	mci->ce_noinfo_count++;
-+	mci->ce_count++;
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_handle_ue);
-+
-+void bluesmoke_mc_handle_ue(struct mem_ctl_info *mci,
-+			    unsigned long page_frame_number,
-+			    unsigned long offset_in_page,
-+			    int row,
-+			    const char *msg)
-+{
-+	int len = BLUESMOKE_MC_LABEL_LEN * 4;
-+	char labels[len + 1];
-+	char *pos = labels;
-+	int chan;
-+	int chars;
-+
-+	debugf3( "MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__ );
-+
-+	/* FIXME - maybe make panic on INTERNAL ERROR an option */
-+	if ( row >= mci->nr_csrows || row < 0 ) {
-+		/* something is wrong */
-+		printk( KERN_ERR
-+			"MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n",
-+			mci->mc_idx,
-+			row, mci->nr_csrows );
-+		bluesmoke_mc_handle_ue_no_info( mci, "INTERNAL ERROR" );
-+		return;
-+	}
-+
-+	chars = snprintf( pos, len + 1, "%s",
-+			  mci->csrows[row].channels[0].label );
-+	len -= chars;
-+	pos += chars;
-+	for ( chan = 1;
-+	      (chan < mci->csrows[row].nr_channels) && (len > 0);
-+	      chan++ ) {
-+		chars = snprintf( pos, len + 1, ":%s",
-+				  mci->csrows[row].channels[chan].label );
-+		len -= chars;
-+		pos += chars;
-+	}
-+
-+	if ( log_ue ) {
-+		printk( KERN_EMERG
-+			"MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d,"
-+			" labels \"%s\": %s\n",
-+			mci->mc_idx,
-+			page_frame_number,
-+			offset_in_page,
-+			mci->csrows[row].grain,
-+			row,
-+			labels,
-+			msg );
-+	}
-+
-+	if (panic_on_ue) {
-+		panic( "MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d,"
-+		       " labels \"%s\": %s\n",
-+		       mci->mc_idx,
-+		       page_frame_number,
-+		       offset_in_page,
-+		       mci->csrows[row].grain,
-+		       row,
-+		       labels,
-+		       msg );
-+	}
-+
-+	mci->ue_count++;
-+	mci->csrows[row].ue_count++;
-+}
-+
-+
-+EXPORT_SYMBOL(bluesmoke_mc_handle_ue_no_info);
-+
-+void bluesmoke_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
-+{
-+	if (panic_on_ue) panic("MC%d: Uncorrected Error", mci->mc_idx);
-+
-+	if ( log_ue ) {
-+		printk( KERN_WARNING
-+			"MC%d: UE - no information available: %s\n",
-+			mci->mc_idx, msg );
-+	}
-+	mci->ue_noinfo_count++;
-+	mci->ue_count++;
-+}
-+
-+
-+/*
-+ * Check MC status every poll_msec.
-+ * SMP safe, doesn't use NMI, and auto-rate-limits.
-+ */
-+static void check_mc(unsigned long dummy)
-+{
-+	int i;
-+
-+	debugf3( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+	if (in_atomic()) {
-+		if (down_trylock(&mem_ctls_mutex)) {
-+			if (timer_pending(&timer)) {
-+				mod_timer(&timer, jiffies + (HZ * poll_msec) / 1000);
-+			} else {
-+				timer.function = check_mc;
-+				timer.expires = jiffies + (HZ * poll_msec) / 1000;
-+				add_timer(&timer);
-+			}
-+			return;
-+		}
-+	} else 
-+		down(&mem_ctls_mutex);
-+
-+	for ( i = 0; i < MAX_MC_DEVICES; i++ ) {
-+		struct mem_ctl_info *mci = mcis[ i ];
-+
-+		if ( NULL == mci ) continue;
-+
-+		/* FIXME - should check scrub flag */
-+		if ( ! mci->scrub_needed 
-+		     && mci->edac_check ) {
-+			mci->edac_check(mci);
-+		}
-+
-+		if ( mci->clear_err ) mci->clear_err(mci);
-+	}
-+
-+	if (timer_pending(&timer)) {
-+		mod_timer(&timer, jiffies + (HZ * poll_msec) / 1000);
-+	} else {
-+		timer.function = check_mc;
-+		timer.expires = jiffies + (HZ * poll_msec) /1000;
-+		add_timer(&timer);
-+	}
-+
-+	up( &mem_ctls_mutex );
-+}
-+
-+
-+int __init bluesmoke_mc_init(void)
-+{
-+	int rc = -ENODEV;
-+
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+	printk( KERN_INFO "MC: " __FILE__ " version " BLUESMOKE_MC_VER "\n" );
-+
-+	memset( mcis, 0, sizeof(mcis) );
-+
-+	check_mc(0);
-+
-+#ifdef CONFIG_PROC_FS
-+	if ( NULL == (proc_mc = proc_mkdir( MC_PROC_DIR, &proc_root ) ) ) {
-+		goto FINISHED;
-+	}
-+#endif /* CONFIG_PROC_FS */
-+
-+#ifdef CONFIG_SYSCTL
-+        mc_sysctl_header = register_sysctl_table(mc_root_table, 1);
-+#endif /* CONFIG_SYSCTL */
-+
-+	rc = 0;
-+
-+ FINISHED:
-+	return rc;
-+}
-+
-+
-+static void __exit bluesmoke_mc_exit(void)
-+{
-+	debugf0( "MC: " __FILE__ ": %s()\n", __func__ );
-+
-+#ifdef CONFIG_PROC_FS
-+	if ( proc_mc ) remove_proc_entry( MC_PROC_DIR, &proc_root );
-+#endif /* CONFIG_PROC_FS */
-+
-+#ifdef CONFIG_SYSCTL
-+        if (mc_sysctl_header) {
-+                unregister_sysctl_table(mc_sysctl_header);
-+                mc_sysctl_header = NULL;
-+        }
-+#endif /* CONFIG_SYSCTL */
-+}
-+
-+
-+module_init(bluesmoke_mc_init);
-+module_exit(bluesmoke_mc_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
-+	      "Based on.work by Dan Hollis et al");
-+MODULE_DESCRIPTION("Core library routines for MC reporting");
-+
-+#if SCRUB
-+MODULE_PARM(mc_scrub, "i");
-+MODULE_PARM_DESC(mc_scrub, "Force MC scrubbing: 0=off 1=on");
-+#endif /* SCRUB */
-+MODULE_PARM(panic_on_ue, "i");
-+MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
-+MODULE_PARM(log_ue, "i");
-+MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on");
-+MODULE_PARM(log_ce, "i");
-+MODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on");
-+MODULE_PARM(poll_msec, "i");
-+MODULE_PARM_DESC(poll_msec, "Polling period in milliseconds");
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/bluesmoke_mc.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/bluesmoke_mc.h	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,435 @@
-+/*
-+ * MC kernel module
-+ * (C) 2003 Linux Networx (http://lnxi.com)
-+ * This file may be distributed under the terms of the
-+ * GNU General Public License.
-+ *
-+ * Written by Thayne Harbaugh
-+ * Based on work by Dan Hollis <goemon at anime dot net> and others.
-+ *	http://www.anime.net/~goemon/linux-ecc/
-+ *
-+ * $Id: bluesmoke_mc.h,v 1.4 2004/11/10 01:12:36 thayne Exp $
-+ *
-+ */
-+
-+
-+#ifndef _BLUESMOKE_MC_H_
-+#define _BLUESMOKE_MC_H_
-+
-+
-+#include <linux/pci.h>
-+#include <linux/time.h>
-+
-+
-+#define	BLUESMOKE_MC_VER	"MC $Revision: 1.4 $"
-+#define MAX_MC_DEVICES 4	/* FIXME - this should be dynamic */
-+#define BLUESMOKE_MC_LABEL_LEN	31
-+#define MC_PROC_NAME_MAX_LEN 7
-+
-+#if PAGE_SHIFT < 20
-+#define PAGES_TO_MiB( pages )	( ( pages ) >> ( 20 - PAGE_SHIFT ) )
-+#else	/* PAGE_SHIFT > 20 */
-+#define PAGES_TO_MiB( pages )	( ( pages ) << ( PAGE_SHIFT - 20 ) )
-+#endif
-+
-+#if defined(CONFIG_BLUESMOKE_DEBUG) \
-+	&& defined(CONFIG_BLUESMOKE_DEBUG_VERBOSE)
-+#if 0 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
-+#define debugf0( ... ) printk( __VA_ARGS__ )
-+#else
-+#define debugf0( ... )
-+#endif
-+
-+#if 1 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
-+#define debugf1( ... ) printk( __VA_ARGS__ )
-+#else
-+#define debugf1( ... )
-+#endif
-+
-+#if 2 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
-+#define debugf2( ... ) printk( __VA_ARGS__ )
-+#else
-+#define debugf2( ... )
-+#endif
-+
-+#if 3 <= CONFIG_BLUESMOKE_DEBUG_VERBOSE
-+#define debugf3( ... ) printk( __VA_ARGS__ )
-+#else
-+#define debugf3( ... )
-+#endif
-+
-+#else /* !CONFIG_BLUESMOKE_DEBUG || !CONFIG_BLUESMOKE_DEBUG_VERBOSE */
-+
-+#define debugf0( ... )
-+#define debugf1( ... )
-+#define debugf2( ... )
-+#define debugf3( ... )
-+#endif /* !CONFIG_BLUESMOKE_DEBUG || !CONFIG_BLUESMOKE_DEBUG_VERBOSE */
-+ 
-+
-+#define bs_xstr(s) bs_str(s)
-+#define bs_str(s) #s
-+#define BS_MOD_STR bs_xstr(KBUILD_BASENAME)
-+
-+#define BIT(x) (1 << (x))
-+
-+#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, PCI_DEVICE_ID_ ## vend ## _ ## dev
-+
-+/* memory devices */
-+enum dev_type {
-+	DEV_UNKNOWN = 0,
-+	DEV_X1,
-+	DEV_X2,
-+	DEV_X4,
-+	DEV_X8,
-+	DEV_X16,
-+	DEV_X32,	/* Do these parts exist? */
-+	DEV_X64		/* Do these parts exist? */
-+};
-+
-+#define DEV_FLAG_UNKNOWN	BIT(DEV_UNKNOWN)
-+#define DEV_FLAG_X1		BIT(DEV_X1)
-+#define DEV_FLAG_X2		BIT(DEV_X2)
-+#define DEV_FLAG_X4		BIT(DEV_X4)
-+#define DEV_FLAG_X8		BIT(DEV_X8)
-+#define DEV_FLAG_X16		BIT(DEV_X16)
-+#define DEV_FLAG_X32		BIT(DEV_X32)
-+#define DEV_FLAG_X64		BIT(DEV_X64)
-+
-+/* memory types */
-+enum mem_type {
-+	MEM_EMPTY = 0,	/* Empty csrow */
-+	MEM_RESERVED, 	/* Reserved csrow type */
-+	MEM_UNKNOWN,  	/* Unknown csrow type */
-+	MEM_FPM,	/* Fast page mode */
-+	MEM_EDO,	/* Extended data out */
-+	MEM_BEDO,	/* Burst Extended data out */
-+	MEM_SDR,	/* Single data rate SDRAM */
-+	MEM_RDR,	/* Registered single data rate SDRAM */
-+	MEM_DDR,	/* Double data rate SDRAM */
-+	MEM_RDDR,	/* Registered Double data rate SDRAM */
-+	MEM_RMBS	/* Rambus DRAM */
-+};
-+
-+#define MEM_FLAG_EMPTY		BIT(MEM_EMPTY)
-+#define MEM_FLAG_RESERVED	BIT(MEM_RESERVED)
-+#define MEM_FLAG_UNKNOWN	BIT(MEM_UNKNOWN)
-+#define MEM_FLAG_FPM		BIT(MEM_FPM)
-+#define MEM_FLAG_EDO		BIT(MEM_EDO)
-+#define MEM_FLAG_BEDO		BIT(MEM_BEDO)
-+#define MEM_FLAG_SDR		BIT(MEM_SDR)
-+#define MEM_FLAG_RDR		BIT(MEM_RDR)
-+#define MEM_FLAG_DDR		BIT(MEM_DDR)
-+#define MEM_FLAG_RDDR		BIT(MEM_RDDR)
-+#define MEM_FLAG_RMBS		BIT(MEM_RMBS)
-+
-+
-+/* chipset Error Detection and Correction capabilities and mode */
-+enum edac_type {
-+	EDAC_UNKNOWN = 0,/* Unknown if ECC is available */
-+	EDAC_NONE,	/* Doesnt support ECC */
-+	EDAC_RESERVED,	/* Reserved ECC type */
-+	EDAC_PARITY,	/* Detects parity errors */
-+	EDAC_EC,	/* Error Checking - no correction */
-+	EDAC_SECDED,	/* Single bit error correction, Double detection */
-+	EDAC_S2ECD2ED,	/* Chipkill x2 devices - do these exist? */
-+	EDAC_S4ECD4ED,	/* Chipkill x4 devices */
-+	EDAC_S8ECD8ED,	/* Chipkill x8 devices */
-+	EDAC_S16ECD16ED,/* Chipkill x16 devices */
-+};
-+
-+#define EDAC_FLAG_UNKNOWN	BIT(EDAC_UNKNOWN)
-+#define EDAC_FLAG_NONE		BIT(EDAC_NONE)
-+#define EDAC_FLAG_PARITY	BIT(EDAC_PARITY)
-+#define EDAC_FLAG_EC		BIT(EDAC_EC)
-+#define EDAC_FLAG_SECDED	BIT(EDAC_SECDED)
-+#define EDAC_FLAG_S2ECD2ED	BIT(EDAC_S2ECD2ED)
-+#define EDAC_FLAG_S4ECD4ED	BIT(EDAC_S4ECD4ED)
-+#define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
-+#define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
-+
-+
-+/* scrubbing capabilities */
-+enum scrub_type {
-+	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
-+	SCRUB_NONE,		/* No scrubber */
-+	SCRUB_SW_PROG,		/* Software progressive (sequential) scrubbing */
-+	SCRUB_SW_SRC,		/* Software scrub only errors */
-+	SCRUB_SW_PROG_SRC,	/* Progressive software scrub from an error */
-+	SCRUB_SW_TUNABLE,	/* Software scrub frequency is tunable */
-+	SCRUB_HW_PROG,		/* Hardware progressive (sequential) scrubbing */
-+	SCRUB_HW_SRC,		/* Hardware scrub only errors */
-+	SCRUB_HW_PROG_SRC,	/* Progressive hardware scrub from an error */
-+	SCRUB_HW_TUNABLE	/* Hardware scrub frequency is tunable */
-+};
-+
-+#define SCRUB_FLAG_SW_PROG	BIT(SCRUB_SW_PROG)
-+#define SCRUB_FLAG_SW_SRC	BIT(SCRUB_SW_SRC_CORR)
-+#define SCRUB_FLAG_SW_PROG_SRC	BIT(SCRUB_SW_PROG_SRC_CORR)
-+#define SCRUB_FLAG_SW_TUN	BIT(SCRUB_SW_SCRUB_TUNABLE)
-+#define SCRUB_FLAG_HW_PROG	BIT(SCRUB_HW_PROG)
-+#define SCRUB_FLAG_HW_SRC	BIT(SCRUB_HW_SRC_CORR)
-+#define SCRUB_FLAG_HW_PROG_SRC	BIT(SCRUB_HW_PROG_SRC_CORR)
-+#define SCRUB_FLAG_HW_TUN	BIT(SCRUB_HW_TUNABLE)
-+
-+
-+/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
-+
-+
-+/*
-+ * There are several things to be aware of that aren't at all obvious:
-+ *
-+ *
-+ * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
-+ *
-+ * These are some of the many terms that are thrown about that don't always
-+ * mean what people think they mean (Inconceivable!).  In the interest of
-+ * creating a common ground for discussion, terms and their definitions
-+ * will be established.
-+ *
-+ * Memory devices:	The individual chip on a memory stick.  These devices
-+ *			commonly output 4 and 8 bits each.  Grouping several
-+ *			of these in parallel provides 64 bits which is common
-+ *			for a memory stick.
-+ *
-+ * Memory Stick:	A printed circuit board that agregates multiple
-+ *			memory devices in parallel.  This is the atomic
-+ *			memory component that is purchaseable by Joe consumer
-+ *			and loaded int a memory socket.
-+ *
-+ * Socket:		A physical connector on the motherboard that accepts
-+ *			a single memory stick.
-+ *
-+ * Channel:		Set of memory devices on a memory stick that must be
-+ *			grouped in parallel with one or more additional
-+ *			channels from other memory sticks.  This parallel
-+ *			grouping of the output from multiple channels are
-+ *			necessary for the smallest granularity of memory access.
-+ *			Some memory controllers are capable of single channel -
-+ *			which means that memory sticks can be loaded
-+ *			individually.  Other memory controllers are only
-+ *			capable of dual channel - which means that memory
-+ *			sticks must be loaded as pairs (see "socket set").
-+ *
-+ * Chip-select row:	All of the memory devices that are selected together.
-+ *			for a single, minimum grain of memory access.
-+ *			This selects all of the parallel memory devices across
-+ *			all of the parallel channels.  Common chip-select rows
-+ *			for single channel are 64 bits, for dual channel 128
-+ *			bits.
-+ *
-+ * Double-sided stick:	A double-sided stick has two chip-select rows which
-+ *			access different sets of memory devices.  The two
-+ *			rows cannot be accessed concurrently.  "Double-sided"
-+ *			is irrespective of the memory devices being mounted
-+ *			on both sides of the memory stick.
-+ *
-+ * Socket set:		All of the memory sticks that are required for for
-+ *			a single memory access or all of the memory sticks
-+ *			spanned by a chip-select row.  A single socket set
-+ *			has two chip-select rows if double-sided sticks are
-+ *			used.
-+ *
-+ * Bank:		This term is avoided because it is unclear when
-+ *			needing to distinguish between chip-select rows and
-+ *			socket sets.
-+ *
-+ *
-+ * Controller pages:
-+ *
-+ * Physical pages:
-+ *
-+ * Virtual pages:
-+ *
-+ *
-+ * STRUCTURE ORGANIZATION AND CHOICES
-+ *
-+ * 
-+ *
-+ * PS - I enjoyed writing all that about as much as you enjoyed reading it.
-+ */
-+
-+
-+struct channel_info {
-+	int chan_idx;		/* channel index */
-+	u32 ce_count;	/* Correctable Errors for this CHANNEL */
-+	char label[BLUESMOKE_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */
-+	struct csrow_info *csrow;/* the parent */
-+};
-+
-+
-+struct csrow_info {
-+	unsigned long first_page;/* first page number in dimm */
-+	unsigned long last_page;/* last page number in dimm */
-+	unsigned long page_mask;/* used for interleaving - 0UL for non intlv */
-+	u32 nr_pages;	/* number of pages in csrow */
-+	u32 grain;		/* granularity of reported error in bytes */
-+	int csrow_idx;		/* the chip-select row */
-+	enum dev_type dtype;	/* memory device type */ 
-+	u32 ue_count;	/* Uncorrectable Errors for this csrow */
-+	u32 ce_count;	/* Correctable Errors for this csrow */
-+	enum mem_type mtype;	/* memory csrow type */
-+	enum edac_type edac_mode;/* EDAC mode for this csrow */
-+	struct mem_ctl_info *mci;/* the parent */
-+	/* FIXME the number of CHANNELs might need to become dynamic */
-+	u32 nr_channels;
-+	struct channel_info *channels;
-+};
-+
-+
-+typedef void *pvt_info_t;
-+
-+
-+struct mem_ctl_info {
-+	unsigned long mtype_cap;/* memory types supported by mc */
-+	unsigned long edac_ctl_cap;/* Memory controller EDAC capabilities */
-+	unsigned long edac_cap;	/* configuration capabilities - this is
-+				   closely related to edac_ctl_cap.  The
-+				   difference is that the controller
-+				   may be capable of s4ecd4ed which would
-+				   be listed in edac_ctl_cap, but if
-+				   channels aren't capable of s4ecd4ed then the
-+				   edac_cap would not have that capability. */
-+	unsigned long scrub_cap;/* chipset scrub capabilities */
-+	enum scrub_type scrub_mode;/* current scrub mode */
-+	/* pointer to edac checking routine */
-+	void (*edac_check)(struct mem_ctl_info *mci);
-+	/* pointer to error clear routine */
-+	void (*clear_err)(struct mem_ctl_info *mci);
-+	/*
-+	 * Remaps memory pages: controller pages to physical pages.
-+	 * For most MC's, this will be NULL.
-+	 */
-+	/* FIXME - why not send the phys page to begin with? */
-+	unsigned long (*ctl_page_to_phys)(struct mem_ctl_info *mci,
-+					  unsigned long page);
-+	int mc_idx;
-+	int nr_csrows;
-+	struct csrow_info *csrows;
-+	/*
-+	 * FIXME - what about controllers on other busses? - IDs must be
-+	 * unique.  pdev pointer should be sufficiently unique, but
-+	 * BUS:SLOT.FUNC numbers may not be unique.
-+	 */
-+	struct pci_dev *pdev;
-+	const char *mod_name;
-+	const char *mod_ver;
-+	const char *ctl_name;
-+	char proc_name[MC_PROC_NAME_MAX_LEN + 1];
-+#ifdef CONFIG_PROC_FS
-+	struct proc_dir_entry *proc_ent;
-+#endif
-+	pvt_info_t pvt_info;
-+	int scrub_needed;
-+	u32 ue_noinfo_count;	/* Uncorrectable Errors w/o info */
-+	u32 ce_noinfo_count;	/* Correctable Errors w/o info */
-+	u32 ue_count;	/* Total Uncorrectable Errors for this MC */
-+	u32 ce_count;	/* Total Correctable Errors for this MC */
-+	struct timeval tv;	/* time when counters were zeroed */
-+};
-+
-+
-+/* write all or some bits in a byte-register*/
-+static inline void pci_write_bits8( struct pci_dev *pdev, int offset,
-+				    u8 value, u8 mask )
-+{ 
-+	if ( mask != 0xff ){
-+		u8 buf;
-+		pci_read_config_byte( pdev, offset, &buf);
-+		value &= mask;
-+		buf &= ~mask;
-+		value |= buf;
-+	}
-+	pci_write_config_byte( pdev, offset, value );
-+}  
-+
-+
-+/* write all or some bits in a word-register*/
-+static inline void pci_write_bits16( struct pci_dev *pdev, int offset,
-+				     u16 value, u16 mask )
-+{ 
-+	if ( mask != 0xffff ){
-+		u16 buf;
-+		pci_read_config_word( pdev, offset, &buf );
-+		value &= mask;
-+		buf &= ~mask;
-+		value |= buf;
-+	}
-+	pci_write_config_word( pdev, offset, value);
-+}  
-+
-+
-+/* write all or some bits in a dword-register*/
-+static inline void pci_write_bits32( struct pci_dev *pdev, int offset,
-+				     u32 value, u32 mask )
-+{ 
-+	if ( mask != 0xffff ){
-+		u32 buf;
-+		pci_read_config_dword( pdev, offset, &buf );
-+		value &= mask;
-+		buf &= ~mask;
-+		value |= buf;
-+	}
-+	pci_write_config_dword( pdev, offset, value );
-+}  
-+
-+
-+#if CONFIG_BLUESMOKE_DEBUG
-+void bluesmoke_mc_dump_channel( struct channel_info *chan );
-+void bluesmoke_mc_dump_mci( struct mem_ctl_info *mci );
-+void bluesmoke_mc_dump_csrow( struct csrow_info *csrow );
-+#endif /* CONFIG_BLUESMOKE_DEBUG */
-+
-+extern int bluesmoke_mc_add_mc(struct mem_ctl_info *mci);
-+extern int bluesmoke_mc_del_mc(struct mem_ctl_info *mci);
-+
-+extern int bluesmoke_mc_find_csrow_by_page( struct mem_ctl_info *mci,
-+					    unsigned long page );
-+
-+extern struct mem_ctl_info *bluesmoke_mc_find_mci_by_pdev(struct pci_dev *pdev );
-+
-+extern void bluesmoke_mc_scrub_block(unsigned long page,
-+				     unsigned long offset,
-+				     u32 size);
-+
-+/*
-+ * The no info errors are used when error overflows are reported.
-+ * There are a limited number of error logging registers that can
-+ * be exausted.  When all registers are exhausted and an additional
-+ * error occurs then an error overflow register records that an
-+ * error occured and the type of error, but doesn't have any
-+ * further information.  The ce/ue versions make for cleaner
-+ * reporting logic and function interface - reduces conditional
-+ * statement clutter and extra function arguments.
-+ */
-+extern void bluesmoke_mc_handle_ce(struct mem_ctl_info *mci,
-+				   unsigned long page_frame_number,
-+				   unsigned long offset_in_page,
-+				   unsigned long syndrome,
-+				   int row,
-+				   int channel,
-+				   const char *msg);
-+
-+extern void bluesmoke_mc_handle_ce_no_info(struct mem_ctl_info *mci,
-+					   const char *msg);
-+
-+extern void bluesmoke_mc_handle_ue(struct mem_ctl_info *mci,
-+				   unsigned long page_frame_number,
-+				   unsigned long offset_in_page,
-+				   int row,
-+				   const char *msg);
-+
-+extern void bluesmoke_mc_handle_ue_no_info(struct mem_ctl_info *mci,
-+					   const char *msg);
-+
-+/*
-+ * This kmalloc's and initializes all the structures.
-+ * Can't be used if all structures don't have the same lifetime.
-+ */
-+extern struct mem_ctl_info *bluesmoke_mc_init_structs(u32 sz_pvt,
-+						      u32 nr_csrows,
-+						      u32 nr_chans);
-+
-+#include "compatmac.h"
-+
-+#endif /* _BLUESMOKE_MC_H_ */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/compatmac.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/bluesmoke/compatmac.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/bluesmoke/compatmac.h	2004-12-17 12:46:23.000000000 -0500
-@@ -0,0 +1,63 @@
-+#ifndef __LINUX_BLUESMOKE_COMPATMAC_H__
-+#define __LINUX_BLUESMOKE_COMPATMAC_H__
-+
-+#include <linux/version.h>
-+#include <linux/pci.h>
-+
-+/*
-+ * Assume that if the kernel isn't 2.6.x then it is a 2.4.x - this will
-+ * obviously break 2.5.x but we don't care!
-+ */
-+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
-+
-+#define pci_name(pci_dev)              ((pci_dev)->slot_name)
-+
-+#ifndef pci_pretty_name
-+# define pci_pretty_name(pdev) ""
-+#endif
-+
-+#define try_module_get(m) try_inc_mod_count(m)
-+#define __module_get(m) do { if (!try_inc_mod_count(m)) BUG(); } while(0)
-+#define module_put(m) do { if (m) __MOD_DEC_USE_COUNT((struct module *)(m)); } while(0)
-+#define module_refcount(m) (MOD_IN_USE)
-+#define set_module_owner(x) do { x->owner = THIS_MODULE; } while(0)
-+
-+
-+/*
-+ * The real pci_scan_single_device() in the 2.6.x series
-+ * has a few more features.  It calls pci_name_device() and
-+ * pci_fixup_device().  Unfortunately neither of those are
-+ * exported symbols.  The pci_name is a nicety that we can
-+ * live without.  As far as pci quirks, if your device has them
-+ * then you better just fix them in your driver rather than
-+ * trying to call some generic kernel code.
-+ */
-+static inline struct pci_dev *pci_scan_single_device( struct pci_bus *bus,
-+						      int devfn )
-+{
-+		struct pci_dev tmp_pdev, *pdev = NULL;
-+
-+		memset( &tmp_pdev, 0, sizeof(tmp_pdev) );
-+		tmp_pdev.bus = bus;
-+		tmp_pdev.devfn = devfn;
-+		if ( (pdev = pci_scan_device( &tmp_pdev ) ) ) {
-+			pci_insert_device( pdev, bus );
-+		}
-+		return pdev;
-+}
-+
-+
-+#else
-+
-+#ifndef pci_pretty_name
-+# define pci_pretty_name(pdev) ((pdev)->pretty_name)
-+#endif
-+
-+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) */
-+
-+#ifndef in_atomic
-+#define in_atomic() 0
-+#define down_trylock(mtx) 1
-+#endif /* in_atomic */
-+
-+#endif /* __LINUX_BLUESMOKE_COMPATMAC_H__ */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/pci_ids.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/linux/pci_ids.h	2004-11-11 10:28:34.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/pci_ids.h	2004-12-17 12:45:23.000000000 -0500
-@@ -454,6 +454,10 @@
- #define PCI_DEVICE_ID_AMI_MEGARAID2	0x9060
- 
- #define PCI_VENDOR_ID_AMD		0x1022
-+#define PCI_DEVICE_ID_AMD_OPT_0_HT	0x1100
-+#define PCI_DEVICE_ID_AMD_OPT_1_ADDRMAP	0x1101
-+#define PCI_DEVICE_ID_AMD_OPT_2_MEMCTL	0x1102
-+#define PCI_DEVICE_ID_AMD_OPT_3_MISCCTL	0x1103
- #define PCI_DEVICE_ID_AMD_LANCE		0x2000
- #define PCI_DEVICE_ID_AMD_LANCE_HOME	0x2001
- #define PCI_DEVICE_ID_AMD_SCSI		0x2020
-@@ -2078,6 +2082,22 @@
- #define PCI_DEVICE_ID_INTEL_82801EB_7	0x24d7
- #define PCI_DEVICE_ID_INTEL_82801EB_11	0x24db
- #define PCI_DEVICE_ID_INTEL_82801EB_13	0x24dd
-+#define PCI_DEVICE_ID_INTEL_7205_0	0x255d
-+#define PCI_DEVICE_ID_INTEL_7205_1_ERR	0x2551
-+#define PCI_DEVICE_ID_INTEL_7500_0	0x2540
-+#define PCI_DEVICE_ID_INTEL_7500_1_ERR	0x2541
-+#define PCI_DEVICE_ID_INTEL_7501_0	0x254c
-+#define PCI_DEVICE_ID_INTEL_7501_1_ERR	0x2541
-+#define PCI_DEVICE_ID_INTEL_7505_0	0x2550
-+#define PCI_DEVICE_ID_INTEL_7505_1_ERR	0x2551
-+#define PCI_DEVICE_ID_INTEL_7520_0      0x3590
-+#define PCI_DEVICE_ID_INTEL_7520_1_ERR  0x3591
-+#define PCI_DEVICE_ID_INTEL_ICH5R_D30_F0  0x244e
-+#define PCI_DEVICE_ID_INTEL_ICH5R_D31_F0  0x24D0
-+#define PCI_DEVICE_ID_INTEL_82875_0	0x2578
-+#define PCI_DEVICE_ID_INTEL_82875_6	0x257e
-+#define PCI_DEVICE_ID_INTEL_7520_0	0x3590
-+#define PCI_DEVICE_ID_INTEL_7520_1_ERR	0x3591
- #define PCI_DEVICE_ID_INTEL_ESB_0	0x25a0
- #define PCI_DEVICE_ID_INTEL_ESB_1	0x25a1
- #define PCI_DEVICE_ID_INTEL_ESB_2	0x25a2
diff --git a/lustre/kernel_patches/patches/brk-locked-2.6-suse-lnxi.patch b/lustre/kernel_patches/patches/brk-locked-2.6-suse-lnxi.patch
deleted file mode 100644
index 950b6eba85..0000000000
--- a/lustre/kernel_patches/patches/brk-locked-2.6-suse-lnxi.patch
+++ /dev/null
@@ -1,219 +0,0 @@
-diff -urN clean/arch/mips/kernel/irixelf.c linux-2.6.5-SLES9_SP1_BRANCH_91/arch/mips/kernel/irixelf.c
---- clean/arch/mips/kernel/irixelf.c	2005-01-09 12:25:26.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_91/arch/mips/kernel/irixelf.c	2005-01-19 19:29:59.909824951 -0500
-@@ -128,7 +128,7 @@
- 	end = PAGE_ALIGN(end);
- 	if (end <= start)
- 		return;
--	do_brk(start, end - start);
-+	do_brk_locked(start, end - start);
- }
- 
- 
-diff -urN clean/arch/x86_64/ia32/ia32_aout.c linux-2.6.5-SLES9_SP1_BRANCH_91/arch/x86_64/ia32/ia32_aout.c
---- clean/arch/x86_64/ia32/ia32_aout.c	2005-01-09 12:25:33.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_91/arch/x86_64/ia32/ia32_aout.c	2005-01-19 19:30:50.255145196 -0500
-@@ -114,7 +114,7 @@
- 	start = PAGE_ALIGN(start);
- 	end = PAGE_ALIGN(end);
- 	if (end > start) {
--		unsigned long addr = do_brk(start, end - start);
-+		unsigned long addr = do_brk_locked(start, end - start);
- 		if (BAD_ADDR(addr))
- 			return addr;
- 	}
-@@ -327,7 +327,7 @@
- 		pos = 32;
- 		map_size = ex.a_text+ex.a_data;
- 
--		error = do_brk(text_addr & PAGE_MASK, map_size);
-+		error = do_brk_locked(text_addr & PAGE_MASK, map_size);
- 		if (error != (text_addr & PAGE_MASK)) {
- 			send_sig(SIGKILL, current, 0);
- 			return error;
-@@ -363,7 +363,7 @@
- 
- 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
- 			loff_t pos = fd_offset;
--			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
-+			do_brk_locked(N_TXTADDR(ex), ex.a_text+ex.a_data);
- 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
- 					ex.a_text+ex.a_data, &pos);
- 			flush_icache_range((unsigned long) N_TXTADDR(ex),
-@@ -476,7 +476,7 @@
- 		}
- #endif
- 
--		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
-+		do_brk_locked(start_addr, ex.a_text + ex.a_data + ex.a_bss);
- 		
- 		file->f_op->read(file, (char *)start_addr,
- 			ex.a_text + ex.a_data, &pos);
-@@ -500,7 +500,7 @@
- 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
- 	bss = ex.a_text + ex.a_data + ex.a_bss;
- 	if (bss > len) {
--		error = do_brk(start_addr + len, bss - len);
-+		error = do_brk_locked(start_addr + len, bss - len);
- 		retval = error;
- 		if (error != start_addr + len)
- 			goto out;
-diff -urN clean/fs/binfmt_aout.c linux-2.6.5-SLES9_SP1_BRANCH_91/fs/binfmt_aout.c
---- clean/fs/binfmt_aout.c	2005-01-09 12:25:33.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_91/fs/binfmt_aout.c	2005-01-19 19:31:40.480490745 -0500
-@@ -51,7 +51,7 @@
- 	start = PAGE_ALIGN(start);
- 	end = PAGE_ALIGN(end);
- 	if (end > start) {
--		unsigned long addr = do_brk(start, end - start);
-+		unsigned long addr = do_brk_locked(start, end - start);
- 		if (BAD_ADDR(addr))
- 			return addr;
- 	}
-@@ -323,10 +323,10 @@
- 		loff_t pos = fd_offset;
- 		/* Fuck me plenty... */
- 		/* <AOL></AOL> */
--		error = do_brk(N_TXTADDR(ex), ex.a_text);
-+		error = do_brk_locked(N_TXTADDR(ex), ex.a_text);
- 		bprm->file->f_op->read(bprm->file, (char *) N_TXTADDR(ex),
- 			  ex.a_text, &pos);
--		error = do_brk(N_DATADDR(ex), ex.a_data);
-+		error = do_brk_locked(N_DATADDR(ex), ex.a_data);
- 		bprm->file->f_op->read(bprm->file, (char *) N_DATADDR(ex),
- 			  ex.a_data, &pos);
- 		goto beyond_if;
-@@ -347,7 +347,7 @@
- 		map_size = ex.a_text+ex.a_data;
- #endif
- 
--		error = do_brk(text_addr & PAGE_MASK, map_size);
-+		error = do_brk_locked(text_addr & PAGE_MASK, map_size);
- 		if (error != (text_addr & PAGE_MASK)) {
- 			send_sig(SIGKILL, current, 0);
- 			return error;
-@@ -381,7 +381,7 @@
- 
- 		if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
- 			loff_t pos = fd_offset;
--			do_brk(N_TXTADDR(ex), ex.a_text+ex.a_data);
-+			do_brk_locked(N_TXTADDR(ex), ex.a_text+ex.a_data);
- 			bprm->file->f_op->read(bprm->file,(char *)N_TXTADDR(ex),
- 					ex.a_text+ex.a_data, &pos);
- 			flush_icache_range((unsigned long) N_TXTADDR(ex),
-@@ -486,7 +486,7 @@
- 			error_time = jiffies;
- 		}
- 
--		do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
-+		do_brk_locked(start_addr, ex.a_text + ex.a_data + ex.a_bss);
- 		
- 		file->f_op->read(file, (char *)start_addr,
- 			ex.a_text + ex.a_data, &pos);
-@@ -510,7 +510,7 @@
- 	len = PAGE_ALIGN(ex.a_text + ex.a_data);
- 	bss = ex.a_text + ex.a_data + ex.a_bss;
- 	if (bss > len) {
--		error = do_brk(start_addr + len, bss - len);
-+		error = do_brk_locked(start_addr + len, bss - len);
- 		retval = error;
- 		if (error != start_addr + len)
- 			goto out;
-diff -urN clean/fs/binfmt_elf.c linux-2.6.5-SLES9_SP1_BRANCH_91/fs/binfmt_elf.c
---- clean/fs/binfmt_elf.c	2005-01-09 12:25:33.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_91/fs/binfmt_elf.c	2005-01-19 19:29:59.914823791 -0500
-@@ -88,7 +88,7 @@
- 	start = ELF_PAGEALIGN(start);
- 	end = ELF_PAGEALIGN(end);
- 	if (end > start) {
--		unsigned long addr = do_brk(start, end - start);
-+		unsigned long addr = do_brk_locked(start, end - start);
- 		if (BAD_ADDR(addr))
- 			return addr;
- 	}
-@@ -406,7 +406,7 @@
- 
- 	/* Map the last of the bss segment */
- 	if (last_bss > elf_bss) {
--		error = do_brk(elf_bss, last_bss - elf_bss);
-+		error = do_brk_locked(elf_bss, last_bss - elf_bss);
- 		if (BAD_ADDR(error))
- 			goto out_close;
- 	}
-@@ -446,7 +446,7 @@
- 		goto out;
- 	}
- 
--	do_brk(0, text_data);
-+	do_brk_locked(0, text_data);
- 	if (!interpreter->f_op || !interpreter->f_op->read)
- 		goto out;
- 	if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0)
-@@ -454,7 +454,7 @@
- 	flush_icache_range((unsigned long)addr,
- 	                   (unsigned long)addr + text_data);
- 
--	do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
-+	do_brk_locked(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
- 		interp_ex->a_bss);
- 	elf_entry = interp_ex->a_entry;
- 
-@@ -1006,7 +1006,7 @@
- 	len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
- 	bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
- 	if (bss > len)
--		do_brk(len, bss - len);
-+		do_brk_locked(len, bss - len);
- 	error = 0;
- 
- out_free_ph:
-diff -urN clean/include/linux/mm.h linux-2.6.5-SLES9_SP1_BRANCH_91/include/linux/mm.h
---- clean/include/linux/mm.h	2005-01-09 12:25:34.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_91/include/linux/mm.h	2005-01-19 19:29:59.915823559 -0500
-@@ -821,6 +821,7 @@
- extern int do_munmap(struct mm_struct *, unsigned long, size_t);
- 
- extern unsigned long do_brk(unsigned long, unsigned long);
-+extern unsigned long do_brk_locked(unsigned long, unsigned long);
- 
- /* vma merging helpers */
- static inline void
-diff -urN clean/mm/mmap.c linux-2.6.5-SLES9_SP1_BRANCH_91/mm/mmap.c
---- clean/mm/mmap.c	2005-01-09 12:25:34.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_91/mm/mmap.c	2005-01-19 19:29:59.917823095 -0500
-@@ -1658,6 +1658,20 @@
- 
- EXPORT_SYMBOL(do_brk);
- 
-+/* locking version of do_brk. */
-+unsigned long do_brk_locked(unsigned long addr, unsigned long len)
-+{
-+	unsigned long ret;
-+
-+	down_write(&current->mm->mmap_sem);
-+	ret = do_brk(addr, len);
-+	up_write(&current->mm->mmap_sem);
-+
-+	return ret;
-+}
-+
-+EXPORT_SYMBOL(do_brk_locked);
-+
- /* Release all mmaps. */
- void exit_mmap(struct mm_struct *mm)
- {
-diff -urN clean/mm/nommu.c linux-2.6.5-SLES9_SP1_BRANCH_91/mm/nommu.c
---- clean/mm/nommu.c	2005-01-09 12:25:27.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_91/mm/nommu.c	2005-01-19 19:29:59.918822864 -0500
-@@ -227,6 +227,11 @@
- 	return audit_lresult(mm->brk = brk);
- }
- 
-+unsigned long do_brk_locked(unsigned long addr, unsigned long len)
-+{
-+	return -ENOMEM;
-+}
-+
- /*
-  * Combine the mmap "prot" and "flags" argument into one "vm_flags" used
-  * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits
diff --git a/lustre/kernel_patches/patches/compile-fixes-2.6.9-rhel4-22.patch b/lustre/kernel_patches/patches/compile-fixes-2.6.9-rhel4-22.patch
deleted file mode 100644
index 98b8715e92..0000000000
--- a/lustre/kernel_patches/patches/compile-fixes-2.6.9-rhel4-22.patch
+++ /dev/null
@@ -1,76 +0,0 @@
---- linux-2.6.9/arch/i386/kernel/apic.c.orig	2005-08-04 08:11:13.000000000 -0400
-+++ linux-2.6.9/arch/i386/kernel/apic.c	2005-08-04 08:27:04.000000000 -0400
-@@ -1125,8 +1125,10 @@ asmlinkage void smp_local_timer_interrup
- 
- void smp_apic_timer_interrupt(struct pt_regs regs)
- {
-+#ifdef CONFIG_4KSTACKS
- 	union irq_ctx	*curctx;
- 	union irq_ctx	*irqctx;
-+#endif
- 	int		cpu;
- 	u32		*isp;
- 
-@@ -1147,11 +1149,11 @@ void smp_apic_timer_interrupt(struct pt_
- 	 * interrupt lock, which is the WrongThing (tm) to do.
- 	 */
- 	irq_enter();
-+
-+#ifdef CONFIG_4KSTACKS
- 	curctx = (union irq_ctx *) current_thread_info();
- 	irqctx = hardirq_ctx[cpu];
--	if (curctx == irqctx) {
--		smp_local_timer_interrupt(&regs);
--	} else {
-+	if (curctx != irqctx) {
- 		/* build the stack frame on the IRQ stack */
- 		isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
- 		irqctx->tinfo.task = curctx->tinfo.task;
-@@ -1167,7 +1169,10 @@ void smp_apic_timer_interrupt(struct pt_
- 			: : "b"(isp)
- 			: "memory", "cc", "edx", "ecx"
- 		);
--	}
-+	} else
-+#endif
-+		smp_local_timer_interrupt(&regs);
-+
- 	irq_exit();
- }
- 
---- linux-2.6.9/include/asm-i386/crashdump.h.orig	2005-08-04 08:11:22.000000000 -0400
-+++ linux-2.6.9/include/asm-i386/crashdump.h	2005-08-04 08:27:04.000000000 -0400
-@@ -48,12 +48,14 @@ extern unsigned long next_ram_page (unsi
- 
- static inline void platform_init_stack(void **stackptr)
- {
-+#ifdef CONFIG_4KSTACKS
- 	*stackptr = (void *)kmalloc(sizeof(union irq_ctx), GFP_KERNEL);
- 	if (*stackptr)
- 		memset(*stackptr, 0, sizeof(union irq_ctx));
- 	else
- 		printk(KERN_WARNING
- 		       "crashdump: unable to allocate separate stack\n");
-+#endif
- }
- 
- typedef asmlinkage void (*crashdump_func_t)(struct pt_regs *, void *);
-@@ -62,6 +64,7 @@ static inline void platform_start_crashd
- 					   crashdump_func_t dumpfunc,
- 					   struct pt_regs *regs)
- {
-+#ifdef CONFIG_4KSTACKS
- 	u32 *dsp;
- 	union irq_ctx * curctx;
- 	union irq_ctx * dumpctx;
-@@ -90,6 +93,10 @@ static inline void platform_start_crashd
- 			: "memory", "cc", "edx", "ecx"
- 		);
- 	}
-+#else
-+	dumpfunc(regs, NULL);
-+#endif
-+
- }
- 
- #define platform_cleanup_stack(stackptr)	\
diff --git a/lustre/kernel_patches/patches/elevator-cfq.patch b/lustre/kernel_patches/patches/elevator-cfq.patch
deleted file mode 100644
index a13194ef64..0000000000
--- a/lustre/kernel_patches/patches/elevator-cfq.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/block/ll_rw_blk.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/block/ll_rw_blk.c	2005-06-28 01:53:39.000000000 -0600
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/block/ll_rw_blk.c	2005-06-28 01:58:45.000000000 -0600
-@@ -1380,12 +1380,12 @@
- static int __make_request(request_queue_t *, struct bio *);
- 
- static elevator_t *chosen_elevator =
--#if defined(CONFIG_IOSCHED_AS)
-+#if defined(CONFIG_IOSCHED_CFQ)
-+	&iosched_cfq;
-+#elif defined(CONFIG_IOSCHED_AS)
- 	&iosched_as;
- #elif defined(CONFIG_IOSCHED_DEADLINE)
- 	&iosched_deadline;
--#elif defined(CONFIG_IOSCHED_CFQ)
--	&iosched_cfq;
- #elif defined(CONFIG_IOSCHED_NOOP)
- 	&elevator_noop;
- #else
diff --git a/lustre/kernel_patches/patches/ext3-check-jbd-errors-2.6-sles10.patch b/lustre/kernel_patches/patches/ext3-check-jbd-errors-2.6-sles10.patch
deleted file mode 100644
index 3724fd9a68..0000000000
--- a/lustre/kernel_patches/patches/ext3-check-jbd-errors-2.6-sles10.patch
+++ /dev/null
@@ -1,83 +0,0 @@
-Index: linux-stage/include/linux/ext3_fs.h
-===================================================================
---- linux-stage.orig/include/linux/ext3_fs.h
-+++ linux-stage/include/linux/ext3_fs.h
-@@ -921,6 +921,7 @@ extern unsigned ext3_list_backups(struct
- 				  unsigned *five, unsigned *seven);
- 
- /* super.c */
-+extern void ext3_commit_super (struct super_block *, struct ext3_super_block *, int);
- extern void ext3_error (struct super_block *, const char *, const char *, ...)
- 	__attribute__ ((format (printf, 3, 4)));
- extern void __ext3_std_error (struct super_block *, const char *, int);
-Index: linux-stage/fs/ext3/super.c
-===================================================================
---- linux-stage.orig/fs/ext3/super.c
-+++ linux-stage/fs/ext3/super.c
-@@ -47,9 +47,6 @@ static int ext3_load_journal(struct supe
- 			     unsigned long journal_devnum);
- static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
- 			       int);
--static void ext3_commit_super (struct super_block * sb,
--			       struct ext3_super_block * es,
--			       int sync);
- static void ext3_mark_recovery_complete(struct super_block * sb,
- 					struct ext3_super_block * es);
- static void ext3_clear_journal_err(struct super_block * sb,
-@@ -2175,7 +2172,7 @@ static int ext3_create_journal(struct su
- 	return 0;
- }
- 
--static void ext3_commit_super (struct super_block * sb,
-+void ext3_commit_super (struct super_block * sb,
- 			       struct ext3_super_block * es,
- 			       int sync)
- {
-Index: linux-stage/fs/ext3/namei.c
-===================================================================
---- linux-stage.orig/fs/ext3/namei.c
-+++ linux-stage/fs/ext3/namei.c
-@@ -1591,7 +1591,7 @@ static int ext3_delete_entry (handle_t *
- 			      struct buffer_head * bh)
- {
- 	struct ext3_dir_entry_2 * de, * pde;
--	int i;
-+	int i, err;
- 
- 	i = 0;
- 	pde = NULL;
-@@ -1601,7 +1601,9 @@ static int ext3_delete_entry (handle_t *
- 			return -EIO;
- 		if (de == de_del)  {
- 			BUFFER_TRACE(bh, "get_write_access");
--			ext3_journal_get_write_access(handle, bh);
-+			err = ext3_journal_get_write_access(handle, bh);
-+			if (err)
-+				return err;
- 			if (pde)
- 				pde->rec_len =
- 					cpu_to_le16(le16_to_cpu(pde->rec_len) +
-Index: linux-stage/fs/ext3/inode.c
-===================================================================
---- linux-stage.orig/fs/ext3/inode.c
-+++ linux-stage/fs/ext3/inode.c
-@@ -1838,8 +1838,18 @@ ext3_clear_blocks(handle_t *handle, stru
- 		ext3_mark_inode_dirty(handle, inode);
- 		ext3_journal_test_restart(handle, inode);
- 		if (bh) {
-+			int err;
- 			BUFFER_TRACE(bh, "retaking write access");
--			ext3_journal_get_write_access(handle, bh);
-+			err = ext3_journal_get_write_access(handle, bh);
-+			if (err) {
-+				struct super_block *sb = inode->i_sb;
-+				struct ext3_super_block *es = EXT3_SB(sb)->s_es;
-+				printk (KERN_CRIT"EXT3-fs: can't continue truncate\n");
-+				EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
-+				es->s_state |= cpu_to_le16(EXT3_ERROR_FS);
-+				ext3_commit_super(sb, es, 1);
-+				return;
-+			}
- 		}
- 	}
- 
diff --git a/lustre/kernel_patches/patches/ext3-extents-fixes-2.6.9-rhel4.patch b/lustre/kernel_patches/patches/ext3-extents-fixes-2.6.9-rhel4.patch
deleted file mode 100644
index ffb9700950..0000000000
--- a/lustre/kernel_patches/patches/ext3-extents-fixes-2.6.9-rhel4.patch
+++ /dev/null
@@ -1,86 +0,0 @@
- - minor fixes
- - multiblock get_block() for direct I/O
-
-Index: linux-2.6.9-full/include/linux/ext3_extents.h
-===================================================================
---- linux-2.6.9-full.orig/include/linux/ext3_extents.h	2007-03-23 15:57:00.000000000 +0300
-+++ linux-2.6.9-full/include/linux/ext3_extents.h	2007-03-28 00:59:32.000000000 +0400
-@@ -205,7 +205,7 @@ typedef int (*ext_prepare_callback)(stru
- #define EXT_DEPTH(__tree__)	(EXT_ROOT_HDR(__tree__)->eh_depth)
- #define EXT_GENERATION(__tree__) EXT_HDR_GEN(EXT_ROOT_HDR(__tree__))
- 
--#define EXT_ASSERT(__x__) if (!(__x__)) BUG();
-+#define EXT_ASSERT(__x__) if (unlikely(!(__x__))) BUG();
- 
- #define EXT_CHECK_PATH(tree,path)					\
- {									\
-Index: linux-2.6.9-full/fs/ext3/extents.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/extents.c	2007-03-23 15:57:00.000000000 +0300
-+++ linux-2.6.9-full/fs/ext3/extents.c	2007-03-28 00:59:41.000000000 +0400
-@@ -895,6 +895,8 @@ repeat:
- 		/* if we found index with free entry, then use that
- 		 * entry: create all needed subtree and add new leaf */
- 		err = ext3_ext_split(handle, tree, path, newext, i);
-+		if (err)
-+			goto out;
- 
- 		/* refill path */
- 		ext3_ext_drop_refs(path);
-@@ -904,12 +906,16 @@ repeat:
- 	} else {
- 		/* tree is full, time to grow in depth */
- 		err = ext3_ext_grow_indepth(handle, tree, path, newext);
-+		if (err)
-+			goto out;
- 
- 		/* refill path */
- 		ext3_ext_drop_refs(path);
- 		path = ext3_ext_find_extent(tree, newext->ee_block, path);
--		if (IS_ERR(path))
-+		if (IS_ERR(path)) {
- 			err = PTR_ERR(path);
-+			goto out;
-+		}
- 
- 		/*
- 		 * only first (depth 0 -> 1) produces free space
-@@ -922,10 +928,8 @@ repeat:
- 		}
- 	}
- 
--	if (err)
--		return err;
--
--	return 0;
-+out:
-+	return err;
- }
- 
- /*
-@@ -1992,21 +1996,10 @@ static int ext3_new_block_cb(handle_t *h
- 	EXT_ASSERT(ex->ee_start);
- 	EXT_ASSERT(ex->ee_len);
- 	
--	/* reuse block from the extent to order data/metadata */
--	newblock = ex->ee_start++;
--	ex->ee_len--;
--	if (ex->ee_len == 0) {
--		ex->ee_len = 1;
--		/* allocate new block for the extent */
--		goal = ext3_ext_find_goal(inode, path, ex->ee_block);
--		ex->ee_start = ext3_new_block(handle, inode, goal, err);
--		ex->ee_start_hi = 0;
--		if (ex->ee_start == 0) {
--			/* error occured: restore old extent */
--			ex->ee_start = newblock;
--			return 0;
--		}
--	}
-+	/* allocate new block for the extent */
-+	goal = ext3_ext_find_goal(inode, path, ex->ee_block);
-+	newblock = ext3_new_block(handle, inode, goal, err);
-+
- 	return newblock;
- }
- 
diff --git a/lustre/kernel_patches/patches/ext3-extents-multiblock-directio-2.6.5-suse.patch b/lustre/kernel_patches/patches/ext3-extents-multiblock-directio-2.6.5-suse.patch
deleted file mode 100644
index 744cc45892..0000000000
--- a/lustre/kernel_patches/patches/ext3-extents-multiblock-directio-2.6.5-suse.patch
+++ /dev/null
@@ -1,157 +0,0 @@
-Index: linux-2.6.5-7.283-full/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.5-7.283-full.orig/include/linux/ext3_fs.h	2007-03-28 02:13:37.000000000 +0400
-+++ linux-2.6.5-7.283-full/include/linux/ext3_fs.h	2007-03-28 02:21:37.000000000 +0400
-@@ -815,7 +815,7 @@ extern struct inode_operations ext3_fast
- 
- /* extents.c */
- extern int ext3_ext_writepage_trans_blocks(struct inode *, int);
--extern int ext3_ext_get_block(handle_t *, struct inode *, long,
-+extern int ext3_ext_get_block(handle_t *, struct inode *, long, int,
- 			      struct buffer_head *, int, int);
- extern void ext3_ext_truncate(struct inode *, struct page *);
- extern void ext3_ext_init(struct super_block *);
-Index: linux-2.6.5-7.283-full/fs/ext3/extents.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/extents.c	2007-03-28 02:14:25.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/extents.c	2007-03-28 02:21:37.000000000 +0400
-@@ -2024,7 +2024,8 @@ void ext3_init_tree_desc(struct ext3_ext
- }
- 
- int ext3_ext_get_block(handle_t *handle, struct inode *inode,
--		       long iblock, struct buffer_head *bh_result,
-+		       long iblock, int max_blocks, 
-+		       struct buffer_head *bh_result,
- 		       int create, int extend_disksize)
- {
- 	struct ext3_ext_path *path = NULL;
-@@ -2032,6 +2033,11 @@ int ext3_ext_get_block(handle_t *handle,
- 	struct ext3_extent *ex;
- 	int goal, newblock, err = 0, depth;
- 	struct ext3_extents_tree tree;
-+	unsigned long next;
-+	int allocated = 0;
-+
-+	/* until we have multiblock allocation */
-+	max_blocks = 1;
- 
- 	__clear_bit(BH_New, &bh_result->b_state);
- 	ext3_init_tree_desc(&tree, inode);
-@@ -2051,6 +2057,9 @@ int ext3_ext_get_block(handle_t *handle,
- 		} else if (goal == EXT3_EXT_CACHE_EXTENT) {
- 			/* block is already allocated */
- 			newblock = iblock - newex.ee_block + newex.ee_start;
-+			/* number of remaining blocks in the extent */
-+			EXT_ASSERT(iblock >= newex.ee_block);
-+			allocated = newex.ee_len - (iblock - newex.ee_block);
- 			goto out;
- 		} else {
- 			EXT_ASSERT(0);
-@@ -2078,6 +2087,8 @@ int ext3_ext_get_block(handle_t *handle,
- 		/* if found exent covers block, simple return it */
- 		if (iblock >= ex->ee_block && iblock < ex->ee_block + ex->ee_len) {
- 			newblock = iblock - ex->ee_block + ex->ee_start;
-+			/* number of remaining blocks in the extent */
-+			allocated = ex->ee_len - (iblock - ex->ee_block);
- 			ext_debug(&tree, "%d fit into %d:%d -> %d\n",
- 				  (int) iblock, ex->ee_block, ex->ee_len,
- 				  newblock);
-@@ -2098,6 +2109,15 @@ int ext3_ext_get_block(handle_t *handle,
- 		goto out2;
- 	}
- 
-+	/* find next allocated block so that we know how many
-+	 * blocks we can allocate without ovelapping next extent */
-+	EXT_ASSERT(iblock >= ex->ee_block + ex->ee_len);
-+	next = ext3_ext_next_allocated_block(path);
-+	EXT_ASSERT(next > iblock);
-+	allocated = next - iblock;
-+	if (allocated > max_blocks)
-+		allocated = max_blocks;
-+
- 	/* allocate new block */
- 	goal = ext3_ext_find_goal(inode, path, iblock);
- 	newblock = ext3_new_block(handle, inode, goal, &err);
-@@ -2112,8 +2132,11 @@ int ext3_ext_get_block(handle_t *handle,
- 	newex.ee_start_hi = 0;
- 	newex.ee_len = 1;
- 	err = ext3_ext_insert_extent(handle, &tree, path, &newex);
--	if (err)
-+	if (err) {
-+		/* free data blocks we just allocated */
-+		ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len);
- 		goto out2;
-+	}
- 	
- 	if (extend_disksize && inode->i_size > EXT3_I(inode)->i_disksize)
- 		EXT3_I(inode)->i_disksize = inode->i_size;
-@@ -2125,10 +2148,13 @@ int ext3_ext_get_block(handle_t *handle,
- 	ext3_ext_put_in_cache(&tree, newex.ee_block, newex.ee_len,
- 			      newex.ee_start, EXT3_EXT_CACHE_EXTENT);
- out:
-+	if (allocated > max_blocks)
-+		allocated = max_blocks;
- 	ext3_ext_show_leaf(&tree, path);
- 	__set_bit(BH_Mapped, &bh_result->b_state);
- 	bh_result->b_bdev = inode->i_sb->s_bdev;
- 	bh_result->b_blocknr = newblock;
-+	bh_result->b_size = (allocated << inode->i_blkbits);
- out2:
- 	if (path) {
- 		ext3_ext_drop_refs(path);
-Index: linux-2.6.5-7.283-full/fs/ext3/inode.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/inode.c	2007-03-28 02:13:37.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/inode.c	2007-03-28 02:50:19.000000000 +0400
-@@ -800,13 +800,17 @@ changed:
- 
- static inline int
- ext3_get_block_wrap(handle_t *handle, struct inode *inode, long block,
--		    struct buffer_head *bh, int create, int extend_disksize)
-+			int max_blocks, struct buffer_head *bh, int create,
-+			int extend_disksize)
- {
-+	int ret;
- 	if (EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL)
--		return ext3_ext_get_block(handle, inode, block, bh, create,
--					  extend_disksize);
--	return ext3_get_block_handle(handle, inode, block, bh, create,
-+		return ext3_ext_get_block(handle, inode, block, max_blocks,
-+					bh, create, extend_disksize);
-+	ret = ext3_get_block_handle(handle, inode, block, bh, create,
- 				     extend_disksize);
-+	bh->b_size = (1 << inode->i_blkbits);
-+	return ret;
- }
- 
- static int ext3_get_block(struct inode *inode, sector_t iblock,
-@@ -819,7 +823,7 @@ static int ext3_get_block(struct inode *
- 		handle = ext3_journal_current_handle();
- 		J_ASSERT(handle != 0);
- 	}
--	ret = ext3_get_block_wrap(handle, inode, iblock,
-+	ret = ext3_get_block_wrap(handle, inode, iblock, 1,
- 				  bh_result, create, 1);
- 	return ret;
- }
-@@ -847,10 +851,8 @@ ext3_direct_io_get_blocks(struct inode *
- 		}
- 	}
- 	if (ret == 0)
--		ret = ext3_get_block_wrap(handle, inode, iblock,
-+		ret = ext3_get_block_wrap(handle, inode, iblock, max_blocks,
- 					  bh_result, create, 0);
--	if (ret == 0)
--		bh_result->b_size = (1 << inode->i_blkbits);
- 	return ret;
- }
- 
-@@ -869,7 +871,7 @@ struct buffer_head *ext3_getblk(handle_t
- 	dummy.b_state = 0;
- 	dummy.b_blocknr = -1000;
- 	buffer_trace_init(&dummy.b_history);
--	*errp = ext3_get_block_wrap(handle, inode, block, &dummy, create, 1);
-+	*errp = ext3_get_block_wrap(handle, inode, block, 1, &dummy, create, 1);
- 	if (!*errp && buffer_mapped(&dummy)) {
- 		struct buffer_head *bh;
- 		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
diff --git a/lustre/kernel_patches/patches/ext3-extents-multiblock-directio-2.6.9-rhel4.patch b/lustre/kernel_patches/patches/ext3-extents-multiblock-directio-2.6.9-rhel4.patch
deleted file mode 100644
index 726a473738..0000000000
--- a/lustre/kernel_patches/patches/ext3-extents-multiblock-directio-2.6.9-rhel4.patch
+++ /dev/null
@@ -1,149 +0,0 @@
---- linux-2.6.9-full/include/linux/ext3_fs.h	2007-03-23 15:57:00.000000000 +0300
-+++ linux-2.6.9-full/include/linux/ext3_fs.h	2007-02-16 17:16:23.000000000 +0300
-@@ -850,7 +850,7 @@ extern struct inode_operations ext3_fast
- 
- /* extents.c */
- extern int ext3_ext_writepage_trans_blocks(struct inode *, int);
--extern int ext3_ext_get_block(handle_t *, struct inode *, long,
-+extern int ext3_ext_get_block(handle_t *, struct inode *, long, int,
- 			      struct buffer_head *, int, int);
- extern void ext3_ext_truncate(struct inode *, struct page *);
- extern void ext3_ext_init(struct super_block *);
-
---- linux-2.6.9-full/fs/ext3/extents.c	2007-03-23 15:57:00.000000000 +0300
-+++ linux-2.6.9-full/fs/ext3/extents.c	2007-02-22 17:45:05.000000000 +0300
-@@ -2031,7 +2168,8 @@ void ext3_init_tree_desc(struct ext3_ext
- }
- 
- int ext3_ext_get_block(handle_t *handle, struct inode *inode,
--		       long iblock, struct buffer_head *bh_result,
-+		       long iblock, int max_blocks, 
-+		       struct buffer_head *bh_result,
- 		       int create, int extend_disksize)
- {
- 	struct ext3_ext_path *path = NULL;
-@@ -2039,6 +2177,11 @@ int ext3_ext_get_block(handle_t *handle,
- 	struct ext3_extent *ex;
- 	int goal, newblock, err = 0, depth;
- 	struct ext3_extents_tree tree;
-+	unsigned long next;
-+	int allocated = 0;
-+
-+	/* until we have multiblock allocation */
-+	max_blocks = 1;
- 
- 	clear_buffer_new(bh_result);
- 	ext3_init_tree_desc(&tree, inode);
-@@ -2058,6 +2201,9 @@ int ext3_ext_get_block(handle_t *handle,
- 		} else if (goal == EXT3_EXT_CACHE_EXTENT) {
- 			/* block is already allocated */
- 			newblock = iblock - newex.ee_block + newex.ee_start;
-+			/* number of remaining blocks in the extent */
-+			EXT_ASSERT(iblock >= newex.ee_block);
-+			allocated = newex.ee_len - (iblock - newex.ee_block);
- 			goto out;
- 		} else {
- 			EXT_ASSERT(0);
-@@ -2085,6 +2231,8 @@ int ext3_ext_get_block(handle_t *handle,
- 		/* if found exent covers block, simple return it */
- 		if (iblock >= ex->ee_block && iblock < ex->ee_block + ex->ee_len) {
- 			newblock = iblock - ex->ee_block + ex->ee_start;
-+			/* number of remaining blocks in the extent */
-+			allocated = ex->ee_len - (iblock - ex->ee_block);
- 			ext_debug(&tree, "%d fit into %d:%d -> %d\n",
- 				  (int) iblock, ex->ee_block, ex->ee_len,
- 				  newblock);
-@@ -2105,6 +2253,15 @@ int ext3_ext_get_block(handle_t *handle,
- 		goto out2;
- 	}
- 
-+	/* find next allocated block so that we know how many
-+	 * blocks we can allocate without ovelapping next extent */
-+	EXT_ASSERT(iblock >= ex->ee_block + ex->ee_len);
-+	next = ext3_ext_next_allocated_block(path);
-+	EXT_ASSERT(next > iblock);
-+	allocated = next - iblock;
-+	if (allocated > max_blocks)
-+		allocated = max_blocks;
-+
- 	/* allocate new block */
- 	goal = ext3_ext_find_goal(inode, path, iblock);
- 	newblock = ext3_new_block(handle, inode, goal, &err);
-@@ -2119,8 +2276,11 @@ int ext3_ext_get_block(handle_t *handle,
- 	newex.ee_start_hi = 0;
- 	newex.ee_len = 1;
- 	err = ext3_ext_insert_extent(handle, &tree, path, &newex);
--	if (err)
-+	if (err) {
-+		/* free data blocks we just allocated */
-+		ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len);
- 		goto out2;
-+	}
- 	
- 	if (extend_disksize && inode->i_size > EXT3_I(inode)->i_disksize)
- 		EXT3_I(inode)->i_disksize = inode->i_size;
-@@ -2132,8 +2292,11 @@ int ext3_ext_get_block(handle_t *handle,
- 	ext3_ext_put_in_cache(&tree, newex.ee_block, newex.ee_len,
- 			      newex.ee_start, EXT3_EXT_CACHE_EXTENT);
- out:
-+	if (allocated > max_blocks)
-+		allocated = max_blocks;
- 	ext3_ext_show_leaf(&tree, path);
- 	map_bh(bh_result, inode->i_sb, newblock);
-+	bh_result->b_size = (allocated << inode->i_blkbits);
- out2:
- 	if (path) {
- 		ext3_ext_drop_refs(path);
---- linux-2.6.9-full/fs/ext3/inode.c	2007-03-23 15:57:00.000000000 +0300
-+++ linux-2.6.9-full/fs/ext3/inode.c	2007-02-16 17:17:03.000000000 +0300
-@@ -798,13 +798,17 @@ changed:
- 
- static inline int
- ext3_get_block_wrap(handle_t *handle, struct inode *inode, long block,
--		    struct buffer_head *bh, int create, int extend_disksize)
-+			int max_blocks, struct buffer_head *bh, int create,
-+			int extend_disksize)
- {
-+	int ret;
- 	if (EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL)
--		return ext3_ext_get_block(handle, inode, block, bh, create,
--					  extend_disksize);
--	return ext3_get_block_handle(handle, inode, block, bh, create,
-+		return ext3_ext_get_block(handle, inode, block, max_blocks,
-+					bh, create, extend_disksize);
-+	ret = ext3_get_block_handle(handle, inode, block, bh, create,
- 				     extend_disksize);
-+	bh->b_size = (1 << inode->i_blkbits);
-+	return ret;
- }
- 
- static int ext3_get_block(struct inode *inode, sector_t iblock,
-@@ -817,7 +821,7 @@ static int ext3_get_block(struct inode *
- 		handle = ext3_journal_current_handle();
- 		J_ASSERT(handle != 0);
- 	}
--	ret = ext3_get_block_wrap(handle, inode, iblock,
-+	ret = ext3_get_block_wrap(handle, inode, iblock, 1,
- 				  bh_result, create, 1);
- 	return ret;
- }
-@@ -862,9 +866,8 @@ ext3_direct_io_get_blocks(struct inode *
- 
- get_block:
- 	if (ret == 0)
--		ret = ext3_get_block_wrap(handle, inode, iblock,
-+		ret = ext3_get_block_wrap(handle, inode, iblock, max_blocks,
- 					bh_result, create, 0);
--	bh_result->b_size = (1 << inode->i_blkbits);
- 	return ret;
- }
- 
-@@ -882,7 +885,7 @@ struct buffer_head *ext3_getblk(handle_t
- 	dummy.b_state = 0;
- 	dummy.b_blocknr = -1000;
- 	buffer_trace_init(&dummy.b_history);
--	*errp = ext3_get_block_wrap(handle, inode, block, &dummy, create, 1);
-+	*errp = ext3_get_block_wrap(handle, inode, block, 1, &dummy, create, 1);
- 	if (!*errp && buffer_mapped(&dummy)) {
- 		struct buffer_head *bh;
- 		bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
diff --git a/lustre/kernel_patches/patches/ext3-extents-search-2.6.9-rhel4.patch b/lustre/kernel_patches/patches/ext3-extents-search-2.6.9-rhel4.patch
deleted file mode 100644
index 2ad69c8c4c..0000000000
--- a/lustre/kernel_patches/patches/ext3-extents-search-2.6.9-rhel4.patch
+++ /dev/null
@@ -1,168 +0,0 @@
-Index: linux-2.6.9-full/include/linux/ext3_extents.h
-===================================================================
---- linux-2.6.9-full.orig/include/linux/ext3_extents.h	2007-03-23 15:57:00.000000000 +0300
-+++ linux-2.6.9-full/include/linux/ext3_extents.h	2007-03-26 22:08:16.000000000 +0400
-@@ -242,6 +242,8 @@ struct ext3_extent_tree_stats {
- 	int leaf_num;
- };
- 
-+extern int ext3_ext_search_left(struct ext3_extents_tree *, struct ext3_ext_path *, unsigned long *, unsigned long *);
-+extern int ext3_ext_search_right(struct ext3_extents_tree *, struct ext3_ext_path *, unsigned long *, unsigned long *);
- extern void ext3_init_tree_desc(struct ext3_extents_tree *, struct inode *);
- extern int ext3_extent_tree_init(handle_t *, struct ext3_extents_tree *);
- extern int ext3_ext_calc_credits_for_insert(struct ext3_extents_tree *, struct ext3_ext_path *);
-Index: linux-2.6.9-full/fs/ext3/extents.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/extents.c	2007-03-23 15:57:00.000000000 +0300
-+++ linux-2.6.9-full/fs/ext3/extents.c	2007-03-26 22:07:37.000000000 +0400
-@@ -929,6 +929,150 @@ repeat:
- }
- 
- /*
-+ * search the closest allocated block to the left for *logical
-+ * and returns it at @logical + it's physical address at @phys
-+ * if *logical is the smallest allocated block, the function
-+ * returns 0 at @phys
-+ * return value contains 0 (success) or error code
-+ */
-+int
-+ext3_ext_search_left(struct ext3_extents_tree *tree, struct ext3_ext_path *path,
-+			unsigned long *logical, unsigned long *phys)
-+{
-+	struct ext3_extent_idx *ix;
-+	struct ext3_extent *ex;
-+	int depth;
-+
-+	BUG_ON(path == NULL);
-+	depth = path->p_depth;
-+	*phys = 0;
-+
-+	if (depth == 0 && path->p_ext == NULL)
-+		return 0;
-+
-+	/* usually extent in the path covers blocks smaller
-+	 * then *logical, but it can be that extent is the
-+	 * first one in the file */
-+
-+	ex = path[depth].p_ext;
-+	if (*logical < ex->ee_block) {
-+		BUG_ON(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex);
-+		while (--depth >= 0) {
-+			ix = path[depth].p_idx;
-+			BUG_ON(ix != EXT_FIRST_INDEX(path[depth].p_hdr));
-+		}
-+		return 0;
-+	}
-+
-+	BUG_ON(*logical < ex->ee_block + ex->ee_len);
-+
-+	*logical = ex->ee_block + ex->ee_len - 1;
-+	*phys = ex->ee_start + ex->ee_len - 1;
-+	return 0;
-+}
-+EXPORT_SYMBOL(ext3_ext_search_left);
-+
-+/*
-+ * search the closest allocated block to the right for *logical
-+ * and returns it at @logical + it's physical address at @phys
-+ * if *logical is the smallest allocated block, the function
-+ * returns 0 at @phys
-+ * return value contains 0 (success) or error code
-+ */
-+int
-+ext3_ext_search_right(struct ext3_extents_tree *tree, struct ext3_ext_path *path,
-+			unsigned long *logical, unsigned long *phys)
-+{
-+	struct buffer_head *bh = NULL;
-+	struct ext3_extent_header *eh;
-+	struct ext3_extent_idx *ix;
-+	struct ext3_extent *ex;
-+	unsigned long block;
-+	int depth;
-+
-+	BUG_ON(path == NULL);
-+	depth = path->p_depth;
-+	*phys = 0;
-+
-+	if (depth == 0 && path->p_ext == NULL)
-+		return 0;
-+
-+	/* usually extent in the path covers blocks smaller
-+	 * then *logical, but it can be that extent is the
-+	 * first one in the file */
-+
-+	ex = path[depth].p_ext;
-+	if (*logical < ex->ee_block) {
-+		BUG_ON(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex);
-+		while (--depth >= 0) {
-+			ix = path[depth].p_idx;
-+			BUG_ON(ix != EXT_FIRST_INDEX(path[depth].p_hdr));
-+		}
-+		*logical = ex->ee_block;
-+		*phys = ex->ee_start;
-+		return 0;
-+	}
-+
-+	BUG_ON(*logical < ex->ee_block + ex->ee_len);
-+
-+	if (ex != EXT_LAST_EXTENT(path[depth].p_hdr)) {
-+		/* next allocated block in this leaf */
-+		ex++;
-+		*logical = ex->ee_block;
-+		*phys = ex->ee_start;
-+		return 0;
-+	}
-+
-+	/* go up and search for index to the right */
-+	while (--depth >= 0) {
-+		ix = path[depth].p_idx;
-+		if (ix != EXT_LAST_INDEX(path[depth].p_hdr))
-+			break;
-+	}
-+
-+	if (depth < 0) {
-+		/* we've gone up to the root and
-+		 * found no index to the right */
-+		return 0;
-+	}
-+
-+	/* we've found index to the right, let's
-+	 * follow it and find the closest allocated
-+	 * block to the right */
-+	ix++;
-+	block = ix->ei_leaf;
-+	while (++depth < path->p_depth) {
-+		bh = sb_bread(tree->inode->i_sb, block);
-+		if (bh == NULL)
-+			return -EIO;
-+		eh = EXT_BLOCK_HDR(bh);
-+		if (ext3_ext_check_header(eh)) {
-+			brelse(bh);
-+			return -EIO;
-+		}
-+		ix = EXT_FIRST_INDEX(eh);
-+		block = ix->ei_leaf;
-+		brelse(bh);
-+	}
-+
-+	bh = sb_bread(tree->inode->i_sb, block);
-+	if (bh == NULL)
-+		return -EIO;
-+	eh = EXT_BLOCK_HDR(bh);
-+	if (ext3_ext_check_header(eh)) {
-+		brelse(bh);
-+		return -EIO;
-+	}
-+	ex = EXT_FIRST_EXTENT(eh);
-+	*logical = ex->ee_block;
-+	*phys = ex->ee_start;
-+	brelse(bh);
-+	return 0;
-+
-+}
-+EXPORT_SYMBOL(ext3_ext_search_right);
-+
-+/*
-  * returns allocated block in subsequent extent or EXT_MAX_BLOCK
-  * NOTE: it consider block number from index entry as
-  * allocated block. thus, index entries have to be consistent
diff --git a/lustre/kernel_patches/patches/ext3-external-journal-2.6.9.patch b/lustre/kernel_patches/patches/ext3-external-journal-2.6.9.patch
deleted file mode 100644
index 7cc86f2f02..0000000000
--- a/lustre/kernel_patches/patches/ext3-external-journal-2.6.9.patch
+++ /dev/null
@@ -1,150 +0,0 @@
-Signed-off-by: Johann Lombardi <johann.lombardi@bull.net>
-
-Index: linux-2.6.9-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/super.c	2006-05-20 01:14:14.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/super.c	2006-05-20 01:17:10.000000000 +0400
-@@ -39,7 +39,8 @@
- #include "xattr.h"
- #include "acl.h"
- 
--static int ext3_load_journal(struct super_block *, struct ext3_super_block *);
-+static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
-+			     unsigned long journal_devnum);
- static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
- 			       int);
- static void ext3_commit_super (struct super_block * sb,
-@@ -591,7 +592,7 @@ enum {
- 	Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
- 	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
- 	Opt_reservation, Opt_noreservation, Opt_noload,
--	Opt_commit, Opt_journal_update, Opt_journal_inum,
-+	Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
- 	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,
-@@ -630,6 +631,7 @@ static match_table_t tokens = {
- 	{Opt_commit, "commit=%u"},
- 	{Opt_journal_update, "journal=update"},
- 	{Opt_journal_inum, "journal=%u"},
-+	{Opt_journal_dev, "journal_dev=%u"},
- 	{Opt_abort, "abort"},
- 	{Opt_data_journal, "data=journal"},
- 	{Opt_data_ordered, "data=ordered"},
-@@ -675,8 +677,9 @@ static unsigned long get_sb_block(void *
- 	return sb_block;
- }
- 
--static int parse_options (char * options, struct super_block *sb,
--			  unsigned long * inum, unsigned long *n_blocks_count, int is_remount)
-+static int parse_options (char *options, struct super_block *sb,
-+			  unsigned long *inum, unsigned long *journal_devnum, 
-+			  unsigned long *n_blocks_count, int is_remount)
- {
- 	struct ext3_sb_info *sbi = EXT3_SB(sb);
- 	char * p;
-@@ -816,6 +819,16 @@ static int parse_options (char * options
- 				return 0;
- 			*inum = option;
- 			break;
-+		case Opt_journal_dev:
-+			if (is_remount) {
-+				printk(KERN_ERR "EXT3-fs: cannot specify "
-+				       "journal on remount\n");
-+				return 0;
-+			}
-+			if (match_int(&args[0], &option))
-+				return 0;
-+			*journal_devnum = option;
-+			break;
- 		case Opt_noload:
- 			set_opt (sbi->s_mount_opt, NOLOAD);
- 			break;
-@@ -1278,6 +1291,7 @@ static int ext3_fill_super (struct super
- 	unsigned long logic_sb_block;
- 	unsigned long offset = 0;
- 	unsigned long journal_inum = 0;
-+	unsigned long journal_devnum = 0;
- 	unsigned long def_mount_opts;
- 	struct inode *root;
- 	int blocksize;
-@@ -1361,7 +1375,8 @@ static int ext3_fill_super (struct super
- 
- 	set_opt(sbi->s_mount_opt, RESERVATION);
- 
--	if (!parse_options ((char *) data, sb, &journal_inum, NULL, 0))
-+	if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, 
-+			    NULL, 0))
- 		goto failed_mount;
- 
- 	set_sb_time_gran(sb, 1000000000U);
-@@ -1567,7 +1582,7 @@ static int ext3_fill_super (struct super
- 	 */
- 	if (!test_opt(sb, NOLOAD) &&
- 	    EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
--		if (ext3_load_journal(sb, es))
-+		if (ext3_load_journal(sb, es, journal_devnum))
- 			goto failed_mount2;
- 	} else if (journal_inum) {
- 		if (ext3_create_journal(sb, es, journal_inum))
-@@ -1831,15 +1846,24 @@ out_bdev:
- 	return NULL;
- }
- 
--static int ext3_load_journal(struct super_block * sb,
--			     struct ext3_super_block * es)
-+static int ext3_load_journal(struct super_block *sb,
-+			     struct ext3_super_block *es,
-+			     unsigned long journal_devnum)
- {
- 	journal_t *journal;
- 	int journal_inum = le32_to_cpu(es->s_journal_inum);
--	dev_t journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
-+	dev_t journal_dev;
- 	int err = 0;
- 	int really_read_only;
- 
-+	if (journal_devnum &&
-+	    journal_devnum != le32_to_cpu(es->s_journal_dev)) {
-+		printk(KERN_INFO "EXT3-fs: external journal device major/minor "
-+			"numbers have changed\n");
-+		journal_dev = new_decode_dev(journal_devnum);
-+	} else
-+		journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
-+
- 	really_read_only = bdev_read_only(sb->s_bdev);
- 
- 	/*
-@@ -1898,6 +1922,16 @@ static int ext3_load_journal(struct supe
- 
- 	EXT3_SB(sb)->s_journal = journal;
- 	ext3_clear_journal_err(sb, es);
-+
-+	if (journal_devnum &&
-+	    journal_devnum != le32_to_cpu(es->s_journal_dev)) {
-+		es->s_journal_dev = cpu_to_le32(journal_devnum);
-+		sb->s_dirt = 1;
-+
-+		/* Make sure we flush the recovery flag to disk. */
-+		ext3_commit_super(sb, es, 1);
-+	}
-+
- 	return 0;
- }
- 
-@@ -2105,13 +2139,13 @@ int ext3_remount (struct super_block * s
- {
- 	struct ext3_super_block * es;
- 	struct ext3_sb_info *sbi = EXT3_SB(sb);
--	unsigned long tmp;
-+	unsigned long tmp1, tmp2;
- 	unsigned long n_blocks_count = 0;
- 
- 	/*
- 	 * Allow the "check" option to be passed as a remount option.
- 	 */
--	if (!parse_options(data, sb, &tmp, &n_blocks_count, 1))
-+	if (!parse_options(data, sb, &tmp1, &tmp2, &n_blocks_count, 1))
- 		return -EINVAL;
- 
- 	if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
diff --git a/lustre/kernel_patches/patches/ext3-filterdata-sles10.patch b/lustre/kernel_patches/patches/ext3-filterdata-sles10.patch
deleted file mode 100644
index 5f7c8c9b99..0000000000
--- a/lustre/kernel_patches/patches/ext3-filterdata-sles10.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-Index: linux-2.6.16.27-0.9-full/include/linux/ext3_fs_i.h
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/include/linux/ext3_fs_i.h	2007-03-28 16:03:20.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/include/linux/ext3_fs_i.h	2007-03-28 19:40:53.000000000 +0400
-@@ -139,6 +139,8 @@ struct ext3_inode_info {
- 	/* mballoc */
- 	struct list_head i_prealloc_list;
- 	spinlock_t i_prealloc_lock;
-+
-+	void *i_filterdata;
- };
- 
- #endif	/* _LINUX_EXT3_FS_I */
-Index: linux-2.6.16.27-0.9-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/super.c	2007-03-28 18:20:17.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/super.c	2007-03-28 19:40:53.000000000 +0400
-@@ -462,6 +462,7 @@ static struct inode *ext3_alloc_inode(st
- 	memset(&ei->i_cached_extent, 0, sizeof(ei->i_cached_extent));
- 	INIT_LIST_HEAD(&ei->i_prealloc_list);
- 	spin_lock_init(&ei->i_prealloc_lock);
-+	ei->i_filterdata = NULL;
- 	return &ei->vfs_inode;
- }
- 
diff --git a/lustre/kernel_patches/patches/ext3-htree-dot-2.6.5-suse.patch b/lustre/kernel_patches/patches/ext3-htree-dot-2.6.5-suse.patch
deleted file mode 100644
index e8ed1920fe..0000000000
--- a/lustre/kernel_patches/patches/ext3-htree-dot-2.6.5-suse.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/fs/ext3/namei.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/fs/ext3/namei.c	2005-04-04 05:06:46.000000000 -0600
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/fs/ext3/namei.c	2005-04-04 05:09:18.000000000 -0600
-@@ -926,8 +926,16 @@
- 	struct inode *dir = dentry->d_parent->d_inode;
- 
- 	sb = dir->i_sb;
--	if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err)))
--		return NULL;
-+	/* NFS may look up ".." - look at dx_root directory block */
-+	if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
-+		if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err)))
-+			return NULL;
-+	} else {
-+		frame = frames;
-+		frame->bh = NULL;			/* for dx_release() */
-+		frame->at = (struct dx_entry *)frames;	/* hack for zero entry*/
-+		dx_set_block(frame->at, 0);		/* dx_root block is 0 */
-+	}
- 	hash = hinfo.hash;
- 	do {
- 		block = dx_get_block(frame->at);
diff --git a/lustre/kernel_patches/patches/ext3-htree-path-ops.patch b/lustre/kernel_patches/patches/ext3-htree-path-ops.patch
deleted file mode 100644
index 9a2edbd3c4..0000000000
--- a/lustre/kernel_patches/patches/ext3-htree-path-ops.patch
+++ /dev/null
@@ -1,894 +0,0 @@
-Index: iam-src/fs/ext3/namei.c
-===================================================================
---- iam-src.orig/fs/ext3/namei.c	2006-02-12 16:43:57.000000000 +0300
-+++ iam-src/fs/ext3/namei.c	2006-02-12 23:22:12.000000000 +0300
-@@ -83,22 +83,21 @@ static struct buffer_head *ext3_append(h
- #define dxtrace(command)
- #endif
- 
--struct fake_dirent
--{
-+struct fake_dirent {
- 	__le32 inode;
- 	__le16 rec_len;
- 	u8 name_len;
- 	u8 file_type;
- };
- 
--struct dx_countlimit
--{
-+struct dx_countlimit {
- 	__le16 limit;
- 	__le16 count;
- };
- 
--struct dx_entry
--{
-+struct dx_entry; /* incomplete type */
-+
-+struct dx_entry_compat {
- 	__le32 hash;
- 	__le32 block;
- };
-@@ -109,8 +108,7 @@ struct dx_entry
-  * hash version mod 4 should never be 0.  Sincerely, the paranoia department.
-  */
- 
--struct dx_root
--{
-+struct dx_root {
- 	struct fake_dirent dot;
- 	char dot_name[4];
- 	struct fake_dirent dotdot;
-@@ -124,13 +122,13 @@ struct dx_root
- 		u8 unused_flags;
- 	}
- 	info;
--	struct dx_entry	entries[0];
-+	struct {} entries[0];
- };
- 
- struct dx_node
- {
- 	struct fake_dirent fake;
--	struct dx_entry	entries[0];
-+	struct {} entries[0];
- };
- 
- 
-@@ -147,38 +145,76 @@ struct dx_map_entry
- 	u32 offs;
- };
- 
-+struct dx_path;
-+struct dx_param {
-+	size_t       dpo_key_size;
-+	size_t       dpo_ptr_size;
-+	size_t       dpo_node_gap;
-+	size_t       dpo_root_gap;
-+
-+	u32 (*dpo_root_ptr)(struct dx_path *path);
-+	int (*dpo_node_check)(struct dx_path *path,
-+			      struct dx_frame *frame, void *cookie);
-+	int (*dpo_node_init)(struct dx_path *path,
-+			     struct buffer_head *bh, int root);
-+};
-+
- /*
-  * Structure to keep track of a path drilled through htree.
-  */
- struct dx_path {
--	struct inode    *dp_object;
--	struct dx_frame  dp_frames[DX_MAX_TREE_HEIGHT];
--	struct dx_frame *dp_frame;
-+	struct inode         *dp_object;
-+	struct dx_param      *dp_param;
-+	int                   dp_indirect;
-+	struct dx_frame       dp_frames[DX_MAX_TREE_HEIGHT];
-+	struct dx_frame      *dp_frame;
-+	void                 *dp_key_target;
-+	void                 *dp_key;
- };
- 
-+static u32 htree_root_ptr(struct dx_path *p);
-+static int htree_node_check(struct dx_path *path,
-+			    struct dx_frame *frame, void *cookie);
-+static int htree_node_init(struct dx_path *path,
-+			   struct buffer_head *bh, int root);
-+
-+static struct dx_param htree_compat_param = {
-+	.dpo_key_size = sizeof ((struct dx_map_entry *)NULL)->hash,
-+	.dpo_ptr_size = sizeof ((struct dx_map_entry *)NULL)->offs,
-+	.dpo_node_gap = offsetof(struct dx_node, entries),
-+	.dpo_root_gap = offsetof(struct dx_root, entries),
-+
-+	.dpo_root_ptr   = htree_root_ptr,
-+	.dpo_node_check = htree_node_check,
-+	.dpo_node_init  = htree_node_init
-+};
-+
-+
- #ifdef CONFIG_EXT3_INDEX
--static inline unsigned dx_get_block (struct dx_entry *entry);
--static void dx_set_block (struct dx_entry *entry, unsigned value);
--static inline unsigned dx_get_hash (struct dx_entry *entry);
--static void dx_set_hash (struct dx_entry *entry, unsigned value);
--static unsigned dx_get_count (struct dx_entry *entries);
--static unsigned dx_get_limit (struct dx_entry *entries);
--static void dx_set_count (struct dx_entry *entries, unsigned value);
--static void dx_set_limit (struct dx_entry *entries, unsigned value);
--static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
--static unsigned dx_node_limit (struct inode *dir);
--static struct dx_frame *dx_probe(struct dentry *dentry,
--				 struct inode *dir,
--				 struct dx_hash_info *hinfo,
--				 struct dx_path *path,
--				 int *err);
-+static inline unsigned dx_get_block(struct dx_path *p, struct dx_entry *entry);
-+static void dx_set_block(struct dx_path *p,
-+			 struct dx_entry *entry, unsigned value);
-+static inline void *dx_get_key(struct dx_path *p,
-+			       struct dx_entry *entry, void *key);
-+static void dx_set_key(struct dx_path *p, struct dx_entry *entry, void *key);
-+static unsigned dx_get_count(struct dx_entry *entries);
-+static unsigned dx_get_limit(struct dx_entry *entries);
-+static void dx_set_count(struct dx_entry *entries, unsigned value);
-+static void dx_set_limit(struct dx_entry *entries, unsigned value);
-+static unsigned dx_root_limit(struct dx_path *p);
-+static unsigned dx_node_limit(struct dx_path *p);
-+static int dx_probe(struct dentry *dentry,
-+		    struct inode *dir,
-+		    struct dx_hash_info *hinfo,
-+		    struct dx_path *path);
- static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
- 			struct dx_hash_info *hinfo, struct dx_map_entry map[]);
- static void dx_sort_map(struct dx_map_entry *map, unsigned count);
- static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to,
- 		struct dx_map_entry *offsets, int count);
- static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
--static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
-+static void dx_insert_block (struct dx_path *path,
-+			     struct dx_frame *frame, u32 hash, u32 block);
- static int ext3_htree_next_block(struct inode *dir, __u32 hash,
- 				 struct dx_path *path, __u32 *start_hash);
- static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
-@@ -186,29 +222,65 @@ static struct buffer_head * ext3_dx_find
- static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
- 			     struct inode *inode);
- 
-+static inline void dx_path_init(struct dx_path *path, struct inode *inode);
-+static inline void dx_path_fini(struct dx_path *path);
-+
-+
- /*
-  * Future: use high four bits of block for coalesce-on-delete flags
-  * Mask them off for now.
-  */
- 
--static inline unsigned dx_get_block (struct dx_entry *entry)
-+static inline void *entry_off(struct dx_entry *entry, ptrdiff_t off)
-+{
-+	return (void *)((char *)entry + off);
-+}
-+
-+static inline size_t dx_entry_size(struct dx_path *p)
- {
--	return le32_to_cpu(entry->block) & 0x00ffffff;
-+	return p->dp_param->dpo_key_size + p->dp_param->dpo_ptr_size;
- }
- 
--static inline void dx_set_block (struct dx_entry *entry, unsigned value)
-+static inline struct dx_entry *dx_entry_shift(struct dx_path *p,
-+					      struct dx_entry *entry, int shift)
- {
--	entry->block = cpu_to_le32(value);
-+	void *e = entry;
-+	return e + shift * dx_entry_size(p);
- }
- 
--static inline unsigned dx_get_hash (struct dx_entry *entry)
-+static inline ptrdiff_t dx_entry_diff(struct dx_path *p,
-+				      struct dx_entry *e1, struct dx_entry *e2)
- {
--	return le32_to_cpu(entry->hash);
-+	ptrdiff_t diff;
-+
-+	diff = (void *)e1 - (void *)e2;
-+	assert(diff / dx_entry_size(p) * dx_entry_size(p) == diff);
-+	return diff / dx_entry_size(p);
-+}
-+
-+static inline unsigned dx_get_block(struct dx_path *p, struct dx_entry *entry)
-+{
-+	return le32_to_cpu(*(u32 *)entry_off(entry, p->dp_param->dpo_key_size))
-+		& 0x00ffffff;
- }
- 
--static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
-+static inline void dx_set_block(struct dx_path *p,
-+				struct dx_entry *entry, unsigned value)
- {
--	entry->hash = cpu_to_le32(value);
-+	*(u32*)entry_off(entry, p->dp_param->dpo_key_size) = cpu_to_le32(value);
-+}
-+
-+static inline void *dx_get_key(struct dx_path *p,
-+			       struct dx_entry *entry, void *key)
-+{
-+	memcpy(key, entry, p->dp_param->dpo_key_size);
-+	return key;
-+}
-+
-+static inline void dx_set_key(struct dx_path *p,
-+			      struct dx_entry *entry, void *key)
-+{
-+	memcpy(entry, key, p->dp_param->dpo_key_size);
- }
- 
- static inline unsigned dx_get_count (struct dx_entry *entries)
-@@ -231,17 +303,123 @@ static inline void dx_set_limit (struct 
- 	((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
- }
- 
--static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
-+static inline unsigned dx_root_limit(struct dx_path *p)
- {
--	unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) -
--		EXT3_DIR_REC_LEN(2) - infosize;
--	return 0? 20: entry_space / sizeof(struct dx_entry);
-+	struct dx_param *param = p->dp_param;
-+	unsigned entry_space   = p->dp_object->i_sb->s_blocksize -
-+		param->dpo_root_gap;
-+	return entry_space / (param->dpo_key_size + param->dpo_ptr_size);
-+}
-+
-+static inline unsigned dx_node_limit(struct dx_path *p)
-+{
-+	struct dx_param *param = p->dp_param;
-+	unsigned entry_space   = p->dp_object->i_sb->s_blocksize -
-+		param->dpo_node_gap;
-+	return entry_space / (param->dpo_key_size + param->dpo_ptr_size);
-+}
-+
-+static inline int dx_index_is_compat(struct dx_path *path)
-+{
-+	return path->dp_param == &htree_compat_param;
-+}
-+
-+static struct dx_entry *dx_get_entries(struct dx_path *path, void *data,
-+				       int root)
-+{
-+	return data +
-+		(root ?
-+		 path->dp_param->dpo_root_gap : path->dp_param->dpo_node_gap);
-+}
-+
-+static struct dx_entry *dx_node_get_entries(struct dx_path *path,
-+					    struct dx_frame *frame)
-+{
-+	return dx_get_entries(path,
-+			      frame->bh->b_data, frame == path->dp_frames);
-+}
-+
-+static u32 htree_root_ptr(struct dx_path *path)
-+{
-+	return 0;
-+}
-+
-+struct htree_cookie {
-+	struct dx_hash_info *hinfo;
-+	struct dentry       *dentry;
-+};
-+
-+static int htree_node_check(struct dx_path *path, struct dx_frame *frame,
-+			    void *cookie)
-+{
-+	void *data;
-+	struct dx_entry *entries;
-+	struct super_block *sb;
-+
-+	data = frame->bh->b_data;
-+	entries = dx_node_get_entries(path, frame);
-+	sb = path->dp_object->i_sb;
-+	if (frame == path->dp_frames) {
-+		/* root node */
-+		struct dx_root *root;
-+		struct htree_cookie *hc = cookie;
-+
-+		root = data;
-+		if (root->info.hash_version != DX_HASH_TEA &&
-+		    root->info.hash_version != DX_HASH_HALF_MD4 &&
-+		    root->info.hash_version != DX_HASH_R5 &&
-+		    root->info.hash_version != DX_HASH_LEGACY) {
-+			ext3_warning(sb, __FUNCTION__,
-+				     "Unrecognised inode hash code %d",
-+				     root->info.hash_version);
-+			return ERR_BAD_DX_DIR;
-+		}
-+
-+		if (root->info.unused_flags & 1) {
-+			ext3_warning(sb, __FUNCTION__,
-+				     "Unimplemented inode hash flags: %#06x",
-+				     root->info.unused_flags);
-+			return ERR_BAD_DX_DIR;
-+		}
-+
-+		path->dp_indirect = root->info.indirect_levels;
-+		if (path->dp_indirect > DX_MAX_TREE_HEIGHT - 1) {
-+			ext3_warning(sb, __FUNCTION__,
-+				     "Unimplemented inode hash depth: %#06x",
-+				     root->info.indirect_levels);
-+			return ERR_BAD_DX_DIR;
-+		}
-+
-+		assert((char *)entries == (((char *)&root->info) +
-+					   root->info.info_length));
-+		assert(dx_get_limit(entries) == dx_root_limit(path));
-+
-+		hc->hinfo->hash_version = root->info.hash_version;
-+		hc->hinfo->seed = EXT3_SB(sb)->s_hash_seed;
-+		if (hc->dentry)
-+			ext3fs_dirhash(hc->dentry->d_name.name,
-+				       hc->dentry->d_name.len, hc->hinfo);
-+		path->dp_key_target = &hc->hinfo->hash;
-+	} else {
-+		/* non-root index */
-+		assert(entries == data + path->dp_param->dpo_node_gap);
-+		assert(dx_get_limit(entries) == dx_node_limit(path));
-+	}
-+	frame->entries = frame->at = entries;
-+	return 0;
- }
- 
--static inline unsigned dx_node_limit (struct inode *dir)
-+static int htree_node_init(struct dx_path *path,
-+			   struct buffer_head *bh, int root)
- {
--	unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0);
--	return 0? 22: entry_space / sizeof(struct dx_entry);
-+	struct dx_node *node;
-+
-+	assert(!root);
-+
-+	node = (void *)bh->b_data;
-+	node->fake.rec_len = cpu_to_le16(path->dp_object->i_sb->s_blocksize);
-+	node->fake.inode = 0;
-+	return 0;
- }
- 
- /*
-@@ -327,123 +505,101 @@ struct stats dx_show_entries(struct dx_h
- }
- #endif /* DX_DEBUG */
- 
--/*
-- * Probe for a directory leaf block to search.
-- *
-- * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
-- * error in the directory index, and the caller should fall back to
-- * searching the directory normally.  The callers of dx_probe **MUST**
-- * check for this error code, and make sure it never gets reflected
-- * back to userspace.
-- */
--static struct dx_frame *
--dx_probe(struct dentry *dentry, struct inode *dir,
--	 struct dx_hash_info *hinfo, struct dx_path *path, int *err)
--{
--	unsigned count, indirect;
--	struct dx_entry *at, *entries, *p, *q, *m;
--	struct dx_root *root;
--	struct buffer_head *bh;
--	struct dx_frame *frame = path->dp_frames;
--	u32 hash;
-+static int dx_lookup(struct dx_path *path, void *cookie)
-+{
-+	u32 ptr;
-+	int err;
-+	int i;
- 
--	frame->bh = NULL;
--	if (dentry)
--		dir = dentry->d_parent->d_inode;
--	if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
--		goto fail;
--	root = (struct dx_root *) bh->b_data;
--	if (root->info.hash_version != DX_HASH_TEA &&
--	    root->info.hash_version != DX_HASH_HALF_MD4 &&
--	    root->info.hash_version != DX_HASH_R5 &&
--	    root->info.hash_version != DX_HASH_LEGACY) {
--		ext3_warning(dir->i_sb, __FUNCTION__,
--			     "Unrecognised inode hash code %d", root->info.hash_version);
--		brelse(bh);
--		*err = ERR_BAD_DX_DIR;
--		goto fail;
--	}
--	hinfo->hash_version = root->info.hash_version;
--	hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed;
--	if (dentry)
--		ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
--	hash = hinfo->hash;
--
--	if (root->info.unused_flags & 1) {
--		ext3_warning(dir->i_sb, __FUNCTION__,
--			     "Unimplemented inode hash flags: %#06x",
--			     root->info.unused_flags);
--		brelse(bh);
--		*err = ERR_BAD_DX_DIR;
--		goto fail;
--	}
-+	struct dx_param *param;
-+	struct dx_frame *frame;
- 
--	if ((indirect = root->info.indirect_levels) > DX_MAX_TREE_HEIGHT - 1) {
--		ext3_warning(dir->i_sb, __FUNCTION__,
--			     "Unimplemented inode hash depth: %#06x",
--			     root->info.indirect_levels);
--		brelse(bh);
--		*err = ERR_BAD_DX_DIR;
--		goto fail;
--	}
-+	param = path->dp_param;
- 
--	entries = (struct dx_entry *) (((char *)&root->info) +
--				       root->info.info_length);
--	assert(dx_get_limit(entries) == dx_root_limit(dir,
--						      root->info.info_length));
--	dxtrace (printk("Look up %x", hash));
--	while (1)
--	{
-+	for (frame = path->dp_frames, i = 0,
-+	     ptr = param->dpo_root_ptr(path); i <= path->dp_indirect;
-+	     ptr = dx_get_block(path, frame->at), ++frame, ++i) {
-+		struct dx_entry *entries;
-+		struct dx_entry *p;
-+		struct dx_entry *q;
-+		struct dx_entry *m;
-+		unsigned count;
-+
-+		frame->bh = ext3_bread(NULL, path->dp_object, ptr, 0, &err);
-+		if (frame->bh == NULL) {
-+			err = -EIO;
-+			break;
-+		}
-+		err = param->dpo_node_check(path, frame, cookie);
-+		if (err != 0)
-+			break;
-+
-+		entries = frame->entries;
- 		count = dx_get_count(entries);
--		assert (count && count <= dx_get_limit(entries));
--		p = entries + 1;
--		q = entries + count - 1;
--		while (p <= q)
--		{
--			m = p + (q - p)/2;
-+		assert(count && count <= dx_get_limit(entries));
-+		p = dx_entry_shift(path, entries, 1);
-+		q = dx_entry_shift(path, entries, count - 1);
-+		while (p <= q) {
-+			m = dx_entry_shift(path,
-+					   p, dx_entry_diff(path, q, p) / 2);
- 			dxtrace(printk("."));
--			if (dx_get_hash(m) > hash)
--				q = m - 1;
-+			if (memcmp(dx_get_key(path, m, path->dp_key),
-+				   path->dp_key_target,
-+				   param->dpo_key_size) > 0)
-+				q = dx_entry_shift(path, m, -1);
- 			else
--				p = m + 1;
-+				p = dx_entry_shift(path, m, +1);
- 		}
- 
--		if (0) // linear search cross check
--		{
-+		frame->at = dx_entry_shift(path, p, -1);
-+		if (1) { // linear search cross check
- 			unsigned n = count - 1;
-+			struct dx_entry *at;
-+
- 			at = entries;
--			while (n--)
--			{
-+			while (n--) {
- 				dxtrace(printk(","));
--				if (dx_get_hash(++at) > hash)
--				{
--					at--;
-+				at = dx_entry_shift(path, at, +1);
-+				if (memcmp(dx_get_key(path, at, path->dp_key),
-+					   path->dp_key_target,
-+					   param->dpo_key_size) > 0) {
-+					at = dx_entry_shift(path, at, -1);
- 					break;
- 				}
- 			}
--			assert (at == p - 1);
-+			assert(at == frame->at);
- 		}
--
--		at = p - 1;
--		dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
--		frame->bh = bh;
--		frame->entries = entries;
--		frame->at = at;
--		if (!indirect--)
--			return path->dp_frame = frame;
--		if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
--			goto fail2;
--		at = entries = ((struct dx_node *) bh->b_data)->entries;
--		assert (dx_get_limit(entries) == dx_node_limit (dir));
--		frame++;
--	}
--fail2:
--	while (frame >= path->dp_frames) {
--		brelse(frame->bh);
--		frame--;
- 	}
--fail:
--	return NULL;
-+	if (err != 0)
-+		dx_path_fini(path);
-+	path->dp_frame = --frame;
-+	return err;
-+}
-+
-+/*
-+ * Probe for a directory leaf block to search.
-+ *
-+ * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
-+ * error in the directory index, and the caller should fall back to
-+ * searching the directory normally.  The callers of dx_probe **MUST**
-+ * check for this error code, and make sure it never gets reflected
-+ * back to userspace.
-+ */
-+static int dx_probe(struct dentry *dentry, struct inode *dir,
-+		    struct dx_hash_info *hinfo, struct dx_path *path)
-+{
-+	int err;
-+	__u32 hash_storage;
-+	struct htree_cookie hc = {
-+		.dentry = dentry,
-+		.hinfo  = hinfo
-+	};
-+
-+	assert(dx_index_is_compat(path));
-+	path->dp_key = &hash_storage;
-+	err = dx_lookup(path, &hc);
-+	assert(err != 0 || path->dp_frames[path->dp_indirect].bh != NULL);
-+	return err;
- }
- 
- static inline void dx_path_init(struct dx_path *path, struct inode *inode)
-@@ -458,8 +614,10 @@ static inline void dx_path_fini(struct d
- 	int i;
- 
- 	for (i = 0; i < ARRAY_SIZE(path->dp_frames); i--) {
--		if (path->dp_frames[i].bh != NULL)
-+		if (path->dp_frames[i].bh != NULL) {
- 			brelse(path->dp_frames[i].bh);
-+			path->dp_frames[i].bh = NULL;
-+		}
- 	}
- }
- 
-@@ -488,6 +646,8 @@ static int ext3_htree_next_block(struct 
- 	int err, num_frames = 0;
- 	__u32 bhash;
- 
-+	assert(dx_index_is_compat(path));
-+
- 	p = path->dp_frame;
- 	/*
- 	 * Find the next leaf page by incrementing the frame pointer.
-@@ -497,7 +657,9 @@ static int ext3_htree_next_block(struct 
- 	 * nodes need to be read.
- 	 */
- 	while (1) {
--		if (++(p->at) < p->entries + dx_get_count(p->entries))
-+		p->at = dx_entry_shift(path, p->at, +1);
-+		if (p->at < dx_entry_shift(path, p->entries,
-+					   dx_get_count(p->entries)))
- 			break;
- 		if (p == path->dp_frames)
- 			return 0;
-@@ -512,7 +674,7 @@ static int ext3_htree_next_block(struct 
- 	 * desired contiuation hash.  If it doesn't, return since
- 	 * there's no point to read in the successive index pages.
- 	 */
--	bhash = dx_get_hash(p->at);
-+	dx_get_key(path, p->at, &bhash);
- 	if (start_hash)
- 		*start_hash = bhash;
- 	if ((hash & 1) == 0) {
-@@ -524,12 +686,13 @@ static int ext3_htree_next_block(struct 
- 	 * block so no check is necessary
- 	 */
- 	while (num_frames--) {
--		if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at), 0, &err)))
-+		if (!(bh = ext3_bread(NULL, dir,
-+				      dx_get_block(path, p->at), 0, &err)))
- 			return err; /* Failure */
- 		++p;
- 		brelse (p->bh);
- 		p->bh = bh;
--		p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
-+		p->at = p->entries = dx_node_get_entries(path, p);
- 	}
- 	return 1;
- }
-@@ -609,6 +772,7 @@ int ext3_htree_fill_tree(struct file *di
- 		       start_minor_hash));
- 	dir = dir_file->f_dentry->d_inode;
- 	dx_path_init(&path, dir);
-+	path.dp_param = &htree_compat_param;
- 	if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {
- 		hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
- 		hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
-@@ -619,7 +783,8 @@ int ext3_htree_fill_tree(struct file *di
- 	}
- 	hinfo.hash = start_hash;
- 	hinfo.minor_hash = 0;
--	if (!dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, &path, &err))
-+	err = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, &path);
-+	if (err != 0)
- 		return err;
- 
- 	/* Add '.' and '..' from the htree header */
-@@ -634,7 +799,7 @@ int ext3_htree_fill_tree(struct file *di
- 	}
- 
- 	while (1) {
--		block = dx_get_block(path.dp_frame->at);
-+		block = dx_get_block(&path, path.dp_frame->at);
- 		ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo,
- 					     start_hash, start_minor_hash);
- 		if (ret < 0) {
-@@ -722,17 +887,19 @@ static void dx_sort_map (struct dx_map_e
- 	} while(more);
- }
- 
--static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
-+static void dx_insert_block(struct dx_path *path,
-+			    struct dx_frame *frame, u32 hash, u32 block)
- {
- 	struct dx_entry *entries = frame->entries;
--	struct dx_entry *old = frame->at, *new = old + 1;
-+	struct dx_entry *old = frame->at, *new = dx_entry_shift(path, old, +1);
- 	int count = dx_get_count(entries);
- 
- 	assert(count < dx_get_limit(entries));
--	assert(old < entries + count);
--	memmove(new + 1, new, (char *)(entries + count) - (char *)(new));
--	dx_set_hash(new, hash);
--	dx_set_block(new, block);
-+	assert(old < dx_entry_shift(path, entries, count));
-+	memmove(dx_entry_shift(path, new, 1), new,
-+		(char *)dx_entry_shift(path, entries, count) - (char *)new);
-+	dx_set_key(path, new, &hash);
-+	dx_set_block(path, new, block);
- 	dx_set_count(entries, count + 1);
- }
- #endif
-@@ -934,7 +1101,9 @@ static struct buffer_head * ext3_dx_find
- 	struct dx_hash_info	hinfo;
- 	u32 hash;
- 	struct dx_path path;
--	struct dx_entry dummy_dot;
-+	struct dx_entry_compat dummy_dot = {
-+		.block = 0
-+	};
- 	struct ext3_dir_entry_2 *de, *top;
- 	struct buffer_head *bh;
- 	unsigned long block;
-@@ -944,19 +1113,21 @@ static struct buffer_head * ext3_dx_find
- 	struct inode *dir = dentry->d_parent->d_inode;
- 
- 	dx_path_init(&path, dir);
-+	path.dp_param = &htree_compat_param;
-+	
- 	sb = dir->i_sb;
- 	/* NFS may look up ".." - look at dx_root directory block */
- 	if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
--		if (!(dx_probe(dentry, NULL, &hinfo, &path, err)))
-+		*err = dx_probe(dentry, NULL, &hinfo, &path);
-+		if (*err != 0)
- 			return NULL;
- 	} else {
--		path.dp_frame->bh = NULL;			/* for dx_path_fini() */
--		path.dp_frame->at = &dummy_dot;		/* hack for zero entry*/
--		dx_set_block(path.dp_frame->at, 0);	/* dx_root block is 0 */
-+		path.dp_frame->bh = NULL;		/* for dx_path_fini() */
-+		path.dp_frame->at = (void *)&dummy_dot;	/* hack for zero entry*/
- 	}
- 	hash = hinfo.hash;
- 	do {
--		block = dx_get_block(path.dp_frame->at);
-+		block = dx_get_block(&path, path.dp_frame->at);
- 		if (!(bh = ext3_bread (NULL,dir, block, 0, err)))
- 			goto errout;
- 		de = (struct ext3_dir_entry_2 *) bh->b_data;
-@@ -1115,10 +1286,11 @@ static struct ext3_dir_entry_2* dx_pack_
- 
- /* Allocate new node, and split leaf node @bh into it, inserting new pointer
-  * into parent node identified by @frame */
--static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
-+static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct dx_path *path,
- 			struct buffer_head **bh,struct dx_frame *frame,
- 			struct dx_hash_info *hinfo, int *error)
- {
-+	struct inode *dir = path->dp_object;
- 	unsigned blocksize = dir->i_sb->s_blocksize;
- 	unsigned count, continued;
- 	struct buffer_head *bh2;
-@@ -1180,7 +1352,7 @@ static struct ext3_dir_entry_2 *do_split
- 		swap(*bh, bh2);
- 		de = de2;
- 	}
--	dx_insert_block (frame, hash2 + continued, newblock);
-+	dx_insert_block(path, frame, hash2 + continued, newblock);
- 	err = ext3_journal_dirty_metadata (handle, bh2);
- 	if (err)
- 		goto journal_error;
-@@ -1315,6 +1487,7 @@ static int make_indexed_dir(handle_t *ha
- 	struct fake_dirent *fde;
- 
- 	dx_path_init(&path, dir);
-+	path.dp_param = &htree_compat_param;
- 	blocksize =  dir->i_sb->s_blocksize;
- 	dxtrace(printk("Creating index\n"));
- 	retval = ext3_journal_get_write_access(handle, bh);
-@@ -1350,10 +1523,10 @@ static int make_indexed_dir(handle_t *ha
- 	root->info.info_length = sizeof(root->info);
- 	root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
- 	root->info.hash_version = DX_HASH_R5;
--	entries = root->entries;
--	dx_set_block (entries, 1);
-+	entries = (void *)root->entries;
-+	dx_set_block (&path, entries, 1);
- 	dx_set_count (entries, 1);
--	dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
-+	dx_set_limit (entries, dx_root_limit(&path));
- 
- 	/* Initialize as for dx_probe */
- 	hinfo.hash_version = root->info.hash_version;
-@@ -1363,7 +1536,7 @@ static int make_indexed_dir(handle_t *ha
- 	path.dp_frame->at = entries;
- 	path.dp_frame->bh = bh;
- 	bh = bh2;
--	de = do_split(handle,dir, &bh, path.dp_frame, &hinfo, &retval);
-+	de = do_split(handle, &path, &bh, path.dp_frame, &hinfo, &retval);
- 	dx_path_fini(&path);
- 	if (!de)
- 		return retval;
-@@ -1446,8 +1619,8 @@ static int ext3_dx_add_entry(handle_t *h
- 			     struct inode *inode)
- {
- 	struct dx_path path;
-+	struct dx_param *param;
- 	struct dx_frame *frame, *safe;
--	struct dx_node *node2;
- 	struct dx_entry *entries;   /* old block contents */
- 	struct dx_entry *entries2;  /* new block contents */
- 	struct dx_hash_info hinfo;
-@@ -1463,7 +1636,10 @@ static int ext3_dx_add_entry(handle_t *h
- 	size_t isize;
- 
- 	dx_path_init(&path, dir);
--	if (!dx_probe(dentry, NULL, &hinfo, &path, &err))
-+	param = path.dp_param = &htree_compat_param;
-+
-+	err = dx_probe(dentry, NULL, &hinfo, &path);
-+	if (err != 0)
- 		return err;
- 	frame = path.dp_frame;
- 	entries = frame->entries;
-@@ -1471,7 +1647,8 @@ static int ext3_dx_add_entry(handle_t *h
- 	/* XXX nikita: global serialization! */
- 	isize = dir->i_size;
- 
--	if (!(bh = ext3_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
-+	if (!(bh = ext3_bread(handle, dir,
-+			      dx_get_block(&path, frame->at), 0, &err)))
- 		goto cleanup;
- 
- 	BUFFER_TRACE(bh, "get_write_access");
-@@ -1519,12 +1696,9 @@ static int ext3_dx_add_entry(handle_t *h
- 	 * transaction... */
- 	for (frame = safe + 1, i = 0; i < nr_splet; ++i, ++frame) {
- 		bh_new[i] = ext3_append (handle, dir, &newblock[i], &err);
--		if (!bh_new[i])
-+		if (!bh_new[i] ||
-+		    param->dpo_node_init(&path, bh_new[i], 0) != 0)
- 			goto cleanup;
--		node2 = (struct dx_node *)(bh_new[i]->b_data);
--		entries2 = node2->entries;
--		node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
--		node2->fake.inode = 0;
- 		BUFFER_TRACE(frame->bh, "get_write_access");
- 		err = ext3_journal_get_write_access(handle, frame->bh);
- 		if (err)
-@@ -1545,11 +1719,10 @@ static int ext3_dx_add_entry(handle_t *h
- 
- 		entries = frame->entries;
- 		count = dx_get_count(entries);
--		idx = frame->at - entries;
-+		idx = dx_entry_diff(&path, frame->at, entries);
- 
- 		bh2 = bh_new[i];
--		node2 = (struct dx_node *)(bh2->b_data);
--		entries2 = node2->entries;
-+		entries2 = dx_get_entries(&path, bh2->b_data, 0);
- 
- 		if (frame == path.dp_frames) {
- 			/* splitting root node. Tricky point:
-@@ -1571,19 +1744,19 @@ static int ext3_dx_add_entry(handle_t *h
- 			indirects = root->info.indirect_levels;
- 			dxtrace(printk("Creating new root %d\n", indirects));
- 			memcpy((char *) entries2, (char *) entries,
--			       count * sizeof(struct dx_entry));
--			dx_set_limit(entries2, dx_node_limit(dir));
-+			       count * dx_entry_size(&path));
-+			dx_set_limit(entries2, dx_node_limit(&path));
- 
- 			/* Set up root */
- 			dx_set_count(entries, 1);
--			dx_set_block(entries + 0, newblock[i]);
-+			dx_set_block(&path, entries, newblock[i]);
- 			root->info.indirect_levels = indirects + 1;
- 
- 			/* Shift frames in the path */
- 			memmove(frames + 2, frames + 1,
- 				(sizeof path.dp_frames) - 2 * sizeof frames[0]);
- 			/* Add new access path frame */
--			frames[1].at = entries2 + idx;
-+			frames[1].at = dx_entry_shift(&path, entries2, idx);
- 			frames[1].entries = entries = entries2;
- 			frames[1].bh = bh2;
- 			++ frame;
-@@ -1594,23 +1767,30 @@ static int ext3_dx_add_entry(handle_t *h
- 		} else {
- 			/* splitting non-root index node. */
- 			unsigned count1 = count/2, count2 = count - count1;
--			unsigned hash2 = dx_get_hash(entries + count1);
-+			unsigned hash2;
-+
-+			dx_get_key(&path,
-+				   dx_entry_shift(&path, entries, count1),
-+				   &hash2);
-+
- 			dxtrace(printk("Split index %i/%i\n", count1, count2));
- 
--			memcpy ((char *) entries2, (char *) (entries + count1),
--				count2 * sizeof(struct dx_entry));
-+			memcpy ((char *) entries2,
-+				(char *) dx_entry_shift(&path, entries, count1),
-+				count2 * dx_entry_size(&path));
- 			dx_set_count (entries, count1);
- 			dx_set_count (entries2, count2);
--			dx_set_limit (entries2, dx_node_limit(dir));
-+			dx_set_limit (entries2, dx_node_limit(&path));
- 
- 			/* Which index block gets the new entry? */
- 			if (idx >= count1) {
--				frame->at = entries2 + idx - count1;
-+				frame->at = dx_entry_shift(&path, entries2,
-+							   idx - count1);
- 				frame->entries = entries = entries2;
- 				swap(frame->bh, bh2);
- 				bh_new[i] = bh2;
- 			}
--			dx_insert_block (frame - 1, hash2, newblock[i]);
-+			dx_insert_block(&path, frame - 1, hash2, newblock[i]);
- 			dxtrace(dx_show_index ("node", frame->entries));
- 			dxtrace(dx_show_index ("node",
- 			       ((struct dx_node *) bh2->b_data)->entries));
-@@ -1619,7 +1799,7 @@ static int ext3_dx_add_entry(handle_t *h
- 				goto journal_error;
- 		}
- 	}
--	de = do_split(handle, dir, &bh, --frame, &hinfo, &err);
-+	de = do_split(handle, &path, &bh, --frame, &hinfo, &err);
- 	if (!de)
- 		goto cleanup;
- 	err = add_dirent_to_buf(handle, dentry, inode, de, bh);
diff --git a/lustre/kernel_patches/patches/ext3-inode-version-2.6-sles10.patch b/lustre/kernel_patches/patches/ext3-inode-version-2.6-sles10.patch
deleted file mode 100644
index 7b6b1b8890..0000000000
--- a/lustre/kernel_patches/patches/ext3-inode-version-2.6-sles10.patch
+++ /dev/null
@@ -1,426 +0,0 @@
-Index: linux-2.6.16-sles10/fs/ext3/inode.c
-===================================================================
---- linux-2.6.16-sles10.orig/fs/ext3/inode.c
-+++ linux-2.6.16-sles10/fs/ext3/inode.c
-@@ -2558,6 +2558,13 @@ void ext3_read_inode(struct inode * inod
- 	EXT3_INODE_GET_XTIME(i_atime, inode, raw_inode);
- 	EXT3_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
- 
-+	ei->i_fs_version = le32_to_cpu(raw_inode->i_disk_version);
-+	if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
-+		if (EXT3_FITS_IN_INODE(raw_inode, ei, i_version_hi))
-+			ei->i_fs_version |= (__u64)(le32_to_cpu(raw_inode->i_version_hi))
-+									 << 32;
-+	}
-+
- 	if (S_ISREG(inode->i_mode)) {
- 		inode->i_op = &ext3_file_inode_operations;
- 		inode->i_fop = &ext3_file_operations;
-@@ -2696,8 +2703,14 @@ static int ext3_do_update_inode(handle_t
- 	} else for (block = 0; block < EXT3_N_BLOCKS; block++)
- 		raw_inode->i_block[block] = ei->i_data[block];
- 
--	if (ei->i_extra_isize)
-+	raw_inode->i_disk_version = cpu_to_le32(ei->i_fs_version);
-+	if (ei->i_extra_isize) {
-+		if (EXT3_FITS_IN_INODE(raw_inode, ei, i_version_hi)) {
-+			raw_inode->i_version_hi = cpu_to_le32(ei->i_fs_version
-+									>> 32);
-+		}
- 		raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
-+	}
- 
- 	BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
- 	rc = ext3_journal_dirty_metadata(handle, bh);
-@@ -2971,10 +2984,32 @@ ext3_reserve_inode_write(handle_t *handl
- int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode)
- {
- 	struct ext3_iloc iloc;
--	int err;
-+	int err, ret;
-+	static int expand_message;
- 
- 	might_sleep();
- 	err = ext3_reserve_inode_write(handle, inode, &iloc);
-+	if (EXT3_I(inode)->i_extra_isize <
-+	    EXT3_SB(inode->i_sb)->s_want_extra_isize &&
-+	    !(EXT3_I(inode)->i_state & EXT3_STATE_NO_EXPAND)) {
-+		/* We need extra buffer credits since we may write into EA block
-+		 * with this same handle */
-+		if ((ext3_journal_extend(handle,
-+			     EXT3_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {
-+			ret = ext3_expand_extra_isize(inode,
-+  					EXT3_SB(inode->i_sb)->s_want_extra_isize,
-+					iloc, handle);
-+			if (ret) {
-+				EXT3_I(inode)->i_state |= EXT3_STATE_NO_EXPAND;
-+				if (!expand_message) {
-+					ext3_warning(inode->i_sb, __FUNCTION__,
-+					"Unable to expand inode %lu. Delete some"
-+					" EAs or run e2fsck.", inode->i_ino);
-+					expand_message = 1;
-+				}
-+			}
-+		}
-+	}
- 	if (!err)
- 		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
- 	return err;
-Index: linux-2.6.16-sles10/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.16-sles10.orig/include/linux/ext3_fs.h
-+++ linux-2.6.16-sles10/include/linux/ext3_fs.h
-@@ -205,6 +205,7 @@ struct ext3_group_desc
- #define EXT3_STATE_JDATA		0x00000001 /* journaled data exists */
- #define EXT3_STATE_NEW			0x00000002 /* inode is newly created */
- #define EXT3_STATE_XATTR		0x00000004 /* has in-inode xattrs */
-+#define EXT3_STATE_NO_EXPAND		0x00000008 /* No space for expansion */
- 
- /* Used to pass group descriptor data when online resize is done */
- struct ext3_new_group_input {
-@@ -281,7 +282,7 @@ struct ext3_inode {
- 	__le32	i_flags;	/* File flags */
- 	union {
- 		struct {
--			__u32  l_i_reserved1;
-+			__u32  l_i_version;
- 		} linux1;
- 		struct {
- 			__u32  h_i_translator;
-@@ -326,6 +327,7 @@ struct ext3_inode {
- 	__le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
- 	__le32  i_crtime;       /* File Creation time */
- 	__le32  i_crtime_extra; /* extra File Creation time (nsec << 2 | epoch) */
-+	__le32	i_version_hi;	/* high 32 bits for 64-bit version */
- };
- 
- #define i_size_high	i_dir_acl
-@@ -388,6 +390,8 @@ do {								     	 \
- 				      raw_inode->xtime ## _extra);       \
- } while (0)
- 
-+#define i_disk_version osd1.linux1.l_i_version
-+
- #if defined(__KERNEL__) || defined(__linux__)
- #define i_reserved1	osd1.linux1.l_i_reserved1
- #define i_frag		osd2.linux2.l_i_frag
-Index: linux-2.6.16-sles10/include/linux/ext3_fs_i.h
-===================================================================
---- linux-2.6.16-sles10.orig/include/linux/ext3_fs_i.h
-+++ linux-2.6.16-sles10/include/linux/ext3_fs_i.h
-@@ -20,6 +20,8 @@
- #include <linux/rbtree.h>
- #include <linux/seqlock.h>
- 
-+#define HAVE_DISK_INODE_VERSION
-+
- struct ext3_reserve_window {
- 	__u32			_rsv_start;	/* First byte reserved */
- 	__u32			_rsv_end;	/* Last byte reserved or 0 */
-@@ -138,6 +140,8 @@ struct ext3_inode_info {
- 	__u32 i_cached_extent[4];
- 
- 	void *i_filterdata;
-+
-+	__u64 i_fs_version;
- };
- 
- #endif	/* _LINUX_EXT3_FS_I */
-Index: linux-2.6.16-sles10/fs/ext3/xattr.c
-===================================================================
---- linux-2.6.16-sles10.orig/fs/ext3/xattr.c
-+++ linux-2.6.16-sles10/fs/ext3/xattr.c
-@@ -505,6 +505,20 @@ ext3_xattr_release_block(handle_t *handl
- 	}
- }
- 
-+static inline size_t ext3_xattr_free_space(struct ext3_xattr_entry *last,
-+				    size_t *min_offs, void *base, int *total)
-+{
-+	for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) {
-+		*total += EXT3_XATTR_LEN(last->e_name_len);
-+		if (!last->e_value_block && last->e_value_size) {
-+			size_t offs = le16_to_cpu(last->e_value_offs);
-+			if (offs < *min_offs)
-+				*min_offs = offs;
-+		}
-+	}
-+	return (*min_offs - ((void *)last - base) - sizeof(__u32));
-+}
-+
- struct ext3_xattr_info {
- 	int name_index;
- 	const char *name;
-@@ -1007,6 +1021,8 @@ ext3_xattr_set_handle(handle_t *handle, 
- 	if (!error) {
- 		ext3_xattr_update_super_block(handle, inode->i_sb);
- 		inode->i_ctime = ext3_current_time(inode);
-+		if (!value)
-+			EXT3_I(inode)->i_state &= ~EXT3_STATE_NO_EXPAND;
- 		ext3_mark_inode_dirty(handle, inode);
- 		/*
- 		 * The bh is consumed by ext3_mark_iloc_dirty, even with
-@@ -1059,6 +1075,249 @@ retry:
- 	return error;
- }
- 
-+static void ext3_xattr_shift_entries(struct ext3_xattr_entry *entry,
-+				     int value_offs_shift, void *to,
-+				     void *from, size_t n, int blocksize)
-+{
-+	struct ext3_xattr_entry *last = entry;
-+	int new_offs;
-+
-+	/* Adjust the value offsets of the entries */
-+	for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) {
-+		if (!last->e_value_block && last->e_value_size) {
-+			new_offs = le16_to_cpu(last->e_value_offs) +
-+							value_offs_shift;
-+			BUG_ON(new_offs + le32_to_cpu(last->e_value_size) >
-+			       blocksize);
-+			last->e_value_offs = cpu_to_le16(new_offs);
-+		}
-+	}
-+	/* Shift the entries by n bytes */
-+	memmove(to, from, n);
-+}
-+
-+/* Expand an inode by new_extra_isize bytes.
-+ * Returns 0 on success or negative error number on failure.
-+ */
-+int ext3_expand_extra_isize(struct inode *inode, int new_extra_isize,
-+			    struct ext3_iloc iloc, handle_t *handle)
-+{
-+	struct ext3_inode *raw_inode;
-+	struct ext3_xattr_ibody_header *header;
-+	struct ext3_xattr_entry *entry, *last, *first;
-+	struct buffer_head *bh = NULL;
-+	struct ext3_xattr_ibody_find *is = NULL;
-+	struct ext3_xattr_block_find *bs = NULL;
-+	char *buffer = NULL, *b_entry_name = NULL;
-+	size_t min_offs, free;
-+	int total_ino, total_blk;
-+	void *base, *start, *end;
-+	int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
-+	int s_min_extra_isize = EXT3_SB(inode->i_sb)->s_es->s_min_extra_isize;
-+
-+	down_write(&EXT3_I(inode)->xattr_sem);
-+
-+retry:
-+	if (EXT3_I(inode)->i_extra_isize >= new_extra_isize) {
-+		up_write(&EXT3_I(inode)->xattr_sem);
-+		return 0;
-+	}
-+
-+	raw_inode = ext3_raw_inode(&iloc);
-+
-+	header = IHDR(inode, raw_inode);
-+	entry = IFIRST(header);
-+
-+	/* No extended attributes present */
-+	if (!(EXT3_I(inode)->i_state & EXT3_STATE_XATTR) ||
-+	    header->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC)) {
-+		memset((void *)raw_inode + EXT3_GOOD_OLD_INODE_SIZE, 0,
-+		       new_extra_isize);
-+		EXT3_I(inode)->i_extra_isize = new_extra_isize;
-+		goto cleanup;
-+	}
-+
-+	/*
-+	 * Check if enough free space is available in the inode to shift the
-+	 * entries ahead by new_extra_isize.
-+	 */
-+
-+	base = start = entry;
-+	end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
-+	min_offs = end - base;
-+	last = entry;
-+	total_ino = sizeof(struct ext3_xattr_ibody_header);
-+
-+	free = ext3_xattr_free_space(last, &min_offs, base, &total_ino);
-+	if (free >= new_extra_isize) {
-+		entry = IFIRST(header);
-+		ext3_xattr_shift_entries(entry,	EXT3_I(inode)->i_extra_isize -
-+				new_extra_isize, (void *)raw_inode +
-+				EXT3_GOOD_OLD_INODE_SIZE + new_extra_isize,
-+				(void *)header, total_ino,
-+				inode->i_sb->s_blocksize);
-+		EXT3_I(inode)->i_extra_isize = new_extra_isize;
-+		error = 0;
-+		goto cleanup;
-+	}
-+
-+	/*
-+	 * Enough free space isn't available in the inode, check if
-+	 * EA block can hold new_extra_isize bytes.
-+	 */
-+	if (EXT3_I(inode)->i_file_acl) {
-+		bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
-+		error = -EIO;
-+		if (!bh)
-+			goto cleanup;
-+		if (ext3_xattr_check_block(bh)) {
-+			ext3_error(inode->i_sb, __FUNCTION__,
-+				"inode %lu: bad block %d", inode->i_ino,
-+				EXT3_I(inode)->i_file_acl);
-+			error = -EIO;
-+			goto cleanup;
-+		}
-+		base = BHDR(bh);
-+		first = BFIRST(bh);
-+		end = bh->b_data + bh->b_size;
-+		min_offs = end - base;
-+		free = ext3_xattr_free_space(first, &min_offs, base,
-+					     &total_blk);
-+		if (free < new_extra_isize) {
-+			if (!tried_min_extra_isize && s_min_extra_isize) {
-+				tried_min_extra_isize++;
-+				new_extra_isize = s_min_extra_isize;
-+				goto retry;
-+			}
-+			error = -1;
-+			goto cleanup;
-+		}
-+	} else {
-+		free = inode->i_sb->s_blocksize;
-+	}
-+
-+	while (new_extra_isize > 0) {
-+		size_t offs, size, entry_size;
-+		struct ext3_xattr_entry *small_entry = NULL;
-+		struct ext3_xattr_info i = {
-+			.value = NULL,
-+			.value_len = 0,
-+		};
-+		unsigned int total_size, shift_bytes, temp = ~0U;
-+
-+		is = (struct ext3_xattr_ibody_find *) kmalloc(sizeof(struct
-+					 ext3_xattr_ibody_find), GFP_KERNEL);
-+		bs = (struct ext3_xattr_block_find *) kmalloc(sizeof(struct
-+					 ext3_xattr_block_find), GFP_KERNEL);
-+		memset((void *)is, 0, sizeof(struct ext3_xattr_ibody_find));
-+		memset((void *)bs, 0, sizeof(struct ext3_xattr_block_find));
-+
-+		is->s.not_found = bs->s.not_found = -ENODATA;
-+		is->iloc.bh = NULL;
-+		bs->bh = NULL;
-+
-+		last = IFIRST(header);
-+		/* Find the entry best suited to be pushed into EA block */
-+		entry = NULL;
-+		for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) {
-+			total_size = EXT3_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
-+	    			    	EXT3_XATTR_LEN(last->e_name_len);
-+			if (total_size <= free && total_size < temp) {
-+				if (total_size < new_extra_isize) {
-+					small_entry = last;
-+				} else {
-+					entry = last;
-+					temp = total_size;
-+				}
-+			}
-+		}
-+
-+		if (entry == NULL) {
-+			if (small_entry) {
-+				entry = small_entry;
-+			} else {
-+				if (!tried_min_extra_isize &&
-+				    s_min_extra_isize) {
-+					tried_min_extra_isize++;
-+					new_extra_isize = s_min_extra_isize;
-+					goto retry;
-+				}
-+				error = -1;
-+				goto cleanup;
-+			}
-+		}
-+		offs = le16_to_cpu(entry->e_value_offs);
-+		size = le32_to_cpu(entry->e_value_size);
-+		entry_size = EXT3_XATTR_LEN(entry->e_name_len);
-+		i.name_index = entry->e_name_index,
-+		buffer = kmalloc(EXT3_XATTR_SIZE(size), GFP_KERNEL);
-+		b_entry_name = kmalloc(entry->e_name_len + 1, GFP_KERNEL);
-+		/* Save the entry name and the entry value */
-+		memcpy((void *)buffer, (void *)IFIRST(header) + offs,
-+		       EXT3_XATTR_SIZE(size));
-+		memcpy((void *)b_entry_name, (void *)entry->e_name,
-+		       entry->e_name_len);
-+		b_entry_name[entry->e_name_len] = '\0';
-+		i.name = b_entry_name;
-+
-+		error = ext3_get_inode_loc(inode, &is->iloc);
-+		if (error)
-+			goto cleanup;
-+
-+		error = ext3_xattr_ibody_find(inode, &i, is);
-+		if (error)
-+			goto cleanup;
-+
-+		/* Remove the chosen entry from the inode */
-+		error = ext3_xattr_ibody_set(handle, inode, &i, is);
-+
-+		entry = IFIRST(header);
-+		if (entry_size + EXT3_XATTR_SIZE(size) >= new_extra_isize)
-+			shift_bytes = new_extra_isize;
-+		else
-+			shift_bytes = entry_size + size;
-+		/* Adjust the offsets and shift the remaining entries ahead */
-+		ext3_xattr_shift_entries(entry, EXT3_I(inode)->i_extra_isize -
-+			shift_bytes, (void *)raw_inode +
-+			EXT3_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
-+			(void *)header, total_ino - entry_size,
-+			inode->i_sb->s_blocksize);
-+
-+		extra_isize += shift_bytes;
-+		new_extra_isize -= shift_bytes;
-+		EXT3_I(inode)->i_extra_isize = extra_isize;
-+
-+		i.name = b_entry_name;
-+		i.value = buffer;
-+		i.value_len = cpu_to_le32(size);
-+		error = ext3_xattr_block_find(inode, &i, bs);
-+		if (error)
-+			goto cleanup;
-+
-+		/* Add entry which was removed from the inode into the block */
-+		error = ext3_xattr_block_set(handle, inode, &i, bs);
-+		if (error)
-+			goto cleanup;
-+	}
-+
-+cleanup:
-+	if (b_entry_name)
-+		kfree(b_entry_name);
-+	if (buffer)
-+		kfree(buffer);
-+	if (is) {
-+		brelse(is->iloc.bh);
-+		kfree(is);
-+	}
-+	if (bs)
-+		kfree(bs);
-+	brelse(bh);
-+	up_write(&EXT3_I(inode)->xattr_sem);
-+	return error;
-+}
-+
-+
-+
- /*
-  * ext3_xattr_delete_inode()
-  *
-Index: linux-2.6.16-sles10/fs/ext3/xattr.h
-===================================================================
---- linux-2.6.16-sles10.orig/fs/ext3/xattr.h
-+++ linux-2.6.16-sles10/fs/ext3/xattr.h
-@@ -75,6 +75,9 @@ extern int ext3_xattr_set_handle(handle_
- extern void ext3_xattr_delete_inode(handle_t *, struct inode *);
- extern void ext3_xattr_put_super(struct super_block *);
- 
-+int ext3_expand_extra_isize(struct inode *inode, int new_extra_isize,
-+			    struct ext3_iloc iloc, handle_t *handle);
-+
- extern int init_ext3_xattr(void);
- extern void exit_ext3_xattr(void);
- 
diff --git a/lustre/kernel_patches/patches/ext3-inode-version-2.6.18-vanilla.patch b/lustre/kernel_patches/patches/ext3-inode-version-2.6.18-vanilla.patch
deleted file mode 100644
index 26f71acf45..0000000000
--- a/lustre/kernel_patches/patches/ext3-inode-version-2.6.18-vanilla.patch
+++ /dev/null
@@ -1,426 +0,0 @@
-Index: linux-2.6.18/fs/ext3/inode.c
-===================================================================
---- linux-2.6.18.orig/fs/ext3/inode.c
-+++ linux-2.6.18/fs/ext3/inode.c
-@@ -2703,6 +2703,13 @@ void ext3_read_inode(struct inode * inod
- 	EXT3_INODE_GET_XTIME(i_atime, inode, raw_inode);
- 	EXT3_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
- 
-+	ei->i_fs_version = le32_to_cpu(raw_inode->i_disk_version);
-+	if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
-+		if (EXT3_FITS_IN_INODE(raw_inode, ei, i_version_hi))
-+			ei->i_fs_version |= (__u64)(le32_to_cpu(raw_inode->i_version_hi))
-+									 << 32;
-+	}
-+
- 	if (S_ISREG(inode->i_mode)) {
- 		inode->i_op = &ext3_file_inode_operations;
- 		inode->i_fop = &ext3_file_operations;
-@@ -2841,8 +2848,14 @@ static int ext3_do_update_inode(handle_t
- 	} else for (block = 0; block < EXT3_N_BLOCKS; block++)
- 		raw_inode->i_block[block] = ei->i_data[block];
- 
--	if (ei->i_extra_isize)
-+	raw_inode->i_disk_version = cpu_to_le32(ei->i_fs_version);
-+	if (ei->i_extra_isize) {
-+		if (EXT3_FITS_IN_INODE(raw_inode, ei, i_version_hi)) {
-+			raw_inode->i_version_hi = cpu_to_le32(ei->i_fs_version
-+									>> 32);
-+		}
- 		raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
-+	}
- 
- 	BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
- 	rc = ext3_journal_dirty_metadata(handle, bh);
-@@ -3116,10 +3129,32 @@ ext3_reserve_inode_write(handle_t *handl
- int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode)
- {
- 	struct ext3_iloc iloc;
--	int err;
-+	int err, ret;
-+	static int expand_message;
- 
- 	might_sleep();
- 	err = ext3_reserve_inode_write(handle, inode, &iloc);
-+	if (EXT3_I(inode)->i_extra_isize <
-+	    EXT3_SB(inode->i_sb)->s_want_extra_isize &&
-+	    !(EXT3_I(inode)->i_state & EXT3_STATE_NO_EXPAND)) {
-+		/* We need extra buffer credits since we may write into EA block
-+		 * with this same handle */
-+		if ((ext3_journal_extend(handle,
-+			     EXT3_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {
-+			ret = ext3_expand_extra_isize(inode,
-+  					EXT3_SB(inode->i_sb)->s_want_extra_isize,
-+					iloc, handle);
-+			if (ret) {
-+				EXT3_I(inode)->i_state |= EXT3_STATE_NO_EXPAND;
-+				if (!expand_message) {
-+					ext3_warning(inode->i_sb, __FUNCTION__,
-+					"Unable to expand inode %lu. Delete some"
-+					" EAs or run e2fsck.", inode->i_ino);
-+					expand_message = 1;
-+				}
-+			}
-+		}
-+	}
- 	if (!err)
- 		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
- 	return err;
-Index: linux-2.6.18/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.18.orig/include/linux/ext3_fs.h
-+++ linux-2.6.18/include/linux/ext3_fs.h
-@@ -201,6 +201,7 @@ struct ext3_group_desc
- #define EXT3_STATE_JDATA		0x00000001 /* journaled data exists */
- #define EXT3_STATE_NEW			0x00000002 /* inode is newly created */
- #define EXT3_STATE_XATTR		0x00000004 /* has in-inode xattrs */
-+#define EXT3_STATE_NO_EXPAND		0x00000008 /* No space for expansion */
- 
- /* Used to pass group descriptor data when online resize is done */
- struct ext3_new_group_input {
-@@ -277,7 +278,7 @@ struct ext3_inode {
- 	__le32	i_flags;	/* File flags */
- 	union {
- 		struct {
--			__u32  l_i_reserved1;
-+			__u32  l_i_version;
- 		} linux1;
- 		struct {
- 			__u32  h_i_translator;
-@@ -322,6 +323,7 @@ struct ext3_inode {
- 	__le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
- 	__le32  i_crtime;       /* File Creation time */
- 	__le32  i_crtime_extra; /* extra File Creation time (nsec << 2 | epoch) */
-+	__le32	i_version_hi;	/* high 32 bits for 64-bit version */
- };
- 
- #define i_size_high	i_dir_acl
-@@ -384,6 +386,8 @@ do {									       \
- 				       raw_inode->xtime ## _extra);	       \
- } while (0)
- 
-+#define i_disk_version osd1.linux1.l_i_version
-+
- #if defined(__KERNEL__) || defined(__linux__)
- #define i_reserved1	osd1.linux1.l_i_reserved1
- #define i_frag		osd2.linux2.l_i_frag
-Index: linux-2.6.18/include/linux/ext3_fs_i.h
-===================================================================
---- linux-2.6.18.orig/include/linux/ext3_fs_i.h
-+++ linux-2.6.18/include/linux/ext3_fs_i.h
-@@ -21,6 +21,8 @@
- #include <linux/seqlock.h>
- #include <linux/mutex.h>
- 
-+#define HAVE_DISK_INODE_VERSION
-+
- /* data type for block offset of block group */
- typedef int ext3_grpblk_t;
- 
-@@ -147,6 +149,8 @@ struct ext3_inode_info {
- 	struct timespec i_crtime;
- 
- 	void *i_filterdata;
-+
-+	__u64 i_fs_version;
- };
- 
- #endif	/* _LINUX_EXT3_FS_I */
-Index: linux-2.6.18/fs/ext3/xattr.c
-===================================================================
---- linux-2.6.18.orig/fs/ext3/xattr.c
-+++ linux-2.6.18/fs/ext3/xattr.c
-@@ -505,6 +505,20 @@ ext3_xattr_release_block(handle_t *handl
- 	}
- }
- 
-+static inline size_t ext3_xattr_free_space(struct ext3_xattr_entry *last,
-+				    size_t *min_offs, void *base, int *total)
-+{
-+	for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) {
-+		*total += EXT3_XATTR_LEN(last->e_name_len);
-+		if (!last->e_value_block && last->e_value_size) {
-+			size_t offs = le16_to_cpu(last->e_value_offs);
-+			if (offs < *min_offs)
-+				*min_offs = offs;
-+		}
-+	}
-+	return (*min_offs - ((void *)last - base) - sizeof(__u32));
-+}
-+
- struct ext3_xattr_info {
- 	int name_index;
- 	const char *name;
-@@ -1008,6 +1022,8 @@ ext3_xattr_set_handle(handle_t *handle, 
- 	if (!error) {
- 		ext3_xattr_update_super_block(handle, inode->i_sb);
- 		inode->i_ctime = ext3_current_time(inode);
-+		if (!value)
-+			EXT3_I(inode)->i_state &= ~EXT3_STATE_NO_EXPAND;
- 		error = ext3_mark_iloc_dirty(handle, inode, &is.iloc);
- 		/*
- 		 * The bh is consumed by ext3_mark_iloc_dirty, even with
-@@ -1060,6 +1076,249 @@ retry:
- 	return error;
- }
- 
-+static void ext3_xattr_shift_entries(struct ext3_xattr_entry *entry,
-+				     int value_offs_shift, void *to,
-+				     void *from, size_t n, int blocksize)
-+{
-+	struct ext3_xattr_entry *last = entry;
-+	int new_offs;
-+
-+	/* Adjust the value offsets of the entries */
-+	for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) {
-+		if (!last->e_value_block && last->e_value_size) {
-+			new_offs = le16_to_cpu(last->e_value_offs) +
-+							value_offs_shift;
-+			BUG_ON(new_offs + le32_to_cpu(last->e_value_size) >
-+			       blocksize);
-+			last->e_value_offs = cpu_to_le16(new_offs);
-+		}
-+	}
-+	/* Shift the entries by n bytes */
-+	memmove(to, from, n);
-+}
-+
-+/* Expand an inode by new_extra_isize bytes.
-+ * Returns 0 on success or negative error number on failure.
-+ */
-+int ext3_expand_extra_isize(struct inode *inode, int new_extra_isize,
-+			    struct ext3_iloc iloc, handle_t *handle)
-+{
-+	struct ext3_inode *raw_inode;
-+	struct ext3_xattr_ibody_header *header;
-+	struct ext3_xattr_entry *entry, *last, *first;
-+	struct buffer_head *bh = NULL;
-+	struct ext3_xattr_ibody_find *is = NULL;
-+	struct ext3_xattr_block_find *bs = NULL;
-+	char *buffer = NULL, *b_entry_name = NULL;
-+	size_t min_offs, free;
-+	int total_ino, total_blk;
-+	void *base, *start, *end;
-+	int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
-+	int s_min_extra_isize = EXT3_SB(inode->i_sb)->s_es->s_min_extra_isize;
-+
-+	down_write(&EXT3_I(inode)->xattr_sem);
-+
-+retry:
-+	if (EXT3_I(inode)->i_extra_isize >= new_extra_isize) {
-+		up_write(&EXT3_I(inode)->xattr_sem);
-+		return 0;
-+	}
-+
-+	raw_inode = ext3_raw_inode(&iloc);
-+
-+	header = IHDR(inode, raw_inode);
-+	entry = IFIRST(header);
-+
-+	/* No extended attributes present */
-+	if (!(EXT3_I(inode)->i_state & EXT3_STATE_XATTR) ||
-+	    header->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC)) {
-+		memset((void *)raw_inode + EXT3_GOOD_OLD_INODE_SIZE, 0,
-+		       new_extra_isize);
-+		EXT3_I(inode)->i_extra_isize = new_extra_isize;
-+		goto cleanup;
-+	}
-+
-+	/*
-+	 * Check if enough free space is available in the inode to shift the
-+	 * entries ahead by new_extra_isize.
-+	 */
-+
-+	base = start = entry;
-+	end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
-+	min_offs = end - base;
-+	last = entry;
-+	total_ino = sizeof(struct ext3_xattr_ibody_header);
-+
-+	free = ext3_xattr_free_space(last, &min_offs, base, &total_ino);
-+	if (free >= new_extra_isize) {
-+		entry = IFIRST(header);
-+		ext3_xattr_shift_entries(entry,	EXT3_I(inode)->i_extra_isize -
-+				new_extra_isize, (void *)raw_inode +
-+				EXT3_GOOD_OLD_INODE_SIZE + new_extra_isize,
-+				(void *)header, total_ino,
-+				inode->i_sb->s_blocksize);
-+		EXT3_I(inode)->i_extra_isize = new_extra_isize;
-+		error = 0;
-+		goto cleanup;
-+	}
-+
-+	/*
-+	 * Enough free space isn't available in the inode, check if
-+	 * EA block can hold new_extra_isize bytes.
-+	 */
-+	if (EXT3_I(inode)->i_file_acl) {
-+		bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
-+		error = -EIO;
-+		if (!bh)
-+			goto cleanup;
-+		if (ext3_xattr_check_block(bh)) {
-+			ext3_error(inode->i_sb, __FUNCTION__,
-+				"inode %lu: bad block "E3FSBLK, inode->i_ino,
-+				EXT3_I(inode)->i_file_acl);
-+			error = -EIO;
-+			goto cleanup;
-+		}
-+		base = BHDR(bh);
-+		first = BFIRST(bh);
-+		end = bh->b_data + bh->b_size;
-+		min_offs = end - base;
-+		free = ext3_xattr_free_space(first, &min_offs, base,
-+					     &total_blk);
-+		if (free < new_extra_isize) {
-+			if (!tried_min_extra_isize && s_min_extra_isize) {
-+				tried_min_extra_isize++;
-+				new_extra_isize = s_min_extra_isize;
-+				goto retry;
-+			}
-+			error = -1;
-+			goto cleanup;
-+		}
-+	} else {
-+		free = inode->i_sb->s_blocksize;
-+	}
-+
-+	while (new_extra_isize > 0) {
-+		size_t offs, size, entry_size;
-+		struct ext3_xattr_entry *small_entry = NULL;
-+		struct ext3_xattr_info i = {
-+			.value = NULL,
-+			.value_len = 0,
-+		};
-+		unsigned int total_size, shift_bytes, temp = ~0U;
-+
-+		is = (struct ext3_xattr_ibody_find *) kmalloc(sizeof(struct
-+					 ext3_xattr_ibody_find), GFP_KERNEL);
-+		bs = (struct ext3_xattr_block_find *) kmalloc(sizeof(struct
-+					 ext3_xattr_block_find), GFP_KERNEL);
-+		memset((void *)is, 0, sizeof(struct ext3_xattr_ibody_find));
-+		memset((void *)bs, 0, sizeof(struct ext3_xattr_block_find));
-+
-+		is->s.not_found = bs->s.not_found = -ENODATA;
-+		is->iloc.bh = NULL;
-+		bs->bh = NULL;
-+
-+		last = IFIRST(header);
-+		/* Find the entry best suited to be pushed into EA block */
-+		entry = NULL;
-+		for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) {
-+			total_size = EXT3_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
-+	    			    	EXT3_XATTR_LEN(last->e_name_len);
-+			if (total_size <= free && total_size < temp) {
-+				if (total_size < new_extra_isize) {
-+					small_entry = last;
-+				} else {
-+					entry = last;
-+					temp = total_size;
-+				}
-+			}
-+		}
-+
-+		if (entry == NULL) {
-+			if (small_entry) {
-+				entry = small_entry;
-+			} else {
-+				if (!tried_min_extra_isize &&
-+				    s_min_extra_isize) {
-+					tried_min_extra_isize++;
-+					new_extra_isize = s_min_extra_isize;
-+					goto retry;
-+				}
-+				error = -1;
-+				goto cleanup;
-+			}
-+		}
-+		offs = le16_to_cpu(entry->e_value_offs);
-+		size = le32_to_cpu(entry->e_value_size);
-+		entry_size = EXT3_XATTR_LEN(entry->e_name_len);
-+		i.name_index = entry->e_name_index,
-+		buffer = kmalloc(EXT3_XATTR_SIZE(size), GFP_KERNEL);
-+		b_entry_name = kmalloc(entry->e_name_len + 1, GFP_KERNEL);
-+		/* Save the entry name and the entry value */
-+		memcpy((void *)buffer, (void *)IFIRST(header) + offs,
-+		       EXT3_XATTR_SIZE(size));
-+		memcpy((void *)b_entry_name, (void *)entry->e_name,
-+		       entry->e_name_len);
-+		b_entry_name[entry->e_name_len] = '\0';
-+		i.name = b_entry_name;
-+
-+		error = ext3_get_inode_loc(inode, &is->iloc);
-+		if (error)
-+			goto cleanup;
-+
-+		error = ext3_xattr_ibody_find(inode, &i, is);
-+		if (error)
-+			goto cleanup;
-+
-+		/* Remove the chosen entry from the inode */
-+		error = ext3_xattr_ibody_set(handle, inode, &i, is);
-+
-+		entry = IFIRST(header);
-+		if (entry_size + EXT3_XATTR_SIZE(size) >= new_extra_isize)
-+			shift_bytes = new_extra_isize;
-+		else
-+			shift_bytes = entry_size + size;
-+		/* Adjust the offsets and shift the remaining entries ahead */
-+		ext3_xattr_shift_entries(entry, EXT3_I(inode)->i_extra_isize -
-+			shift_bytes, (void *)raw_inode +
-+			EXT3_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
-+			(void *)header, total_ino - entry_size,
-+			inode->i_sb->s_blocksize);
-+
-+		extra_isize += shift_bytes;
-+		new_extra_isize -= shift_bytes;
-+		EXT3_I(inode)->i_extra_isize = extra_isize;
-+
-+		i.name = b_entry_name;
-+		i.value = buffer;
-+		i.value_len = cpu_to_le32(size);
-+		error = ext3_xattr_block_find(inode, &i, bs);
-+		if (error)
-+			goto cleanup;
-+
-+		/* Add entry which was removed from the inode into the block */
-+		error = ext3_xattr_block_set(handle, inode, &i, bs);
-+		if (error)
-+			goto cleanup;
-+	}
-+
-+cleanup:
-+	if (b_entry_name)
-+		kfree(b_entry_name);
-+	if (buffer)
-+		kfree(buffer);
-+	if (is) {
-+		brelse(is->iloc.bh);
-+		kfree(is);
-+	}
-+	if (bs)
-+		kfree(bs);
-+	brelse(bh);
-+	up_write(&EXT3_I(inode)->xattr_sem);
-+	return error;
-+}
-+
-+
-+
- /*
-  * ext3_xattr_delete_inode()
-  *
-Index: linux-2.6.18/fs/ext3/xattr.h
-===================================================================
---- linux-2.6.18.orig/fs/ext3/xattr.h
-+++ linux-2.6.18/fs/ext3/xattr.h
-@@ -74,6 +74,9 @@ extern int ext3_xattr_set_handle(handle_
- extern void ext3_xattr_delete_inode(handle_t *, struct inode *);
- extern void ext3_xattr_put_super(struct super_block *);
- 
-+int ext3_expand_extra_isize(struct inode *inode, int new_extra_isize,
-+			    struct ext3_iloc iloc, handle_t *handle);
-+
- extern int init_ext3_xattr(void);
- extern void exit_ext3_xattr(void);
- 
diff --git a/lustre/kernel_patches/patches/ext3-mballoc3-core.patch b/lustre/kernel_patches/patches/ext3-mballoc3-core.patch
deleted file mode 100644
index a6033d1d19..0000000000
--- a/lustre/kernel_patches/patches/ext3-mballoc3-core.patch
+++ /dev/null
@@ -1,4528 +0,0 @@
-Index: linux-2.6.9-full/include/linux/ext3_fs_sb.h
-===================================================================
---- linux-2.6.9-full.orig/include/linux/ext3_fs_sb.h	2006-05-18 23:57:04.000000000 +0400
-+++ linux-2.6.9-full/include/linux/ext3_fs_sb.h	2007-03-28 15:42:16.000000000 +0400
-@@ -81,6 +81,61 @@ struct ext3_sb_info {
- 	char *s_qf_names[MAXQUOTAS];		/* Names of quota files with journalled quota */
- 	int s_jquota_fmt;			/* Format of quota to use */
- #endif
-+
-+	/* for buddy allocator */
-+	struct ext3_group_info ***s_group_info;
-+	struct inode *s_buddy_cache;
-+	long s_blocks_reserved;
-+	spinlock_t s_reserve_lock;
-+	struct list_head s_active_transaction;
-+	struct list_head s_closed_transaction;
-+	struct list_head s_committed_transaction;
-+	spinlock_t s_md_lock;
-+	tid_t s_last_transaction;
-+	unsigned short *s_mb_offsets, *s_mb_maxs;
-+
-+	/* tunables */
-+	unsigned long s_mb_factor;
-+	unsigned long s_stripe;
-+	unsigned long s_mb_stream_request;
-+	unsigned long s_mb_max_to_scan;
-+	unsigned long s_mb_min_to_scan;
-+	unsigned long s_mb_max_groups_to_scan;
-+	unsigned long s_mb_stats;
-+	unsigned long s_mb_order2_reqs;
-+
-+	/* history to debug policy */
-+	struct ext3_mb_history *s_mb_history;
-+	int s_mb_history_cur;
-+	int s_mb_history_max;
-+	int s_mb_history_num;
-+	struct proc_dir_entry *s_mb_proc;
-+	spinlock_t s_mb_history_lock;
-+	int s_mb_history_filter;
-+
-+	/* stats for buddy allocator */
-+	spinlock_t s_mb_pa_lock;
-+	atomic_t s_bal_reqs;	/* number of reqs with len > 1 */
-+	atomic_t s_bal_success;	/* we found long enough chunks */
-+	atomic_t s_bal_allocated;	/* in blocks */
-+	atomic_t s_bal_ex_scanned;	/* total extents scanned */
-+	atomic_t s_bal_goals;	/* goal hits */
-+	atomic_t s_bal_breaks;	/* too long searches */
-+	atomic_t s_bal_2orders;	/* 2^order hits */
-+	spinlock_t s_bal_lock;
-+	unsigned long s_mb_buddies_generated;
-+	unsigned long long s_mb_generation_time;
-+	atomic_t s_mb_lost_chunks;
-+	atomic_t s_mb_preallocated;
-+	atomic_t s_mb_discarded;
-+
-+	/* locality groups */
-+	struct ext3_locality_group *s_locality_groups;
-+
- };
- 
-+#define EXT3_GROUP_INFO(sb, group)					   \
-+	EXT3_SB(sb)->s_group_info[(group) >> EXT3_DESC_PER_BLOCK_BITS(sb)] \
-+				 [(group) & (EXT3_DESC_PER_BLOCK(sb) - 1)]
-+
- #endif	/* _LINUX_EXT3_FS_SB */
-Index: linux-2.6.9-full/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.9-full.orig/include/linux/ext3_fs.h	2007-03-28 01:29:39.000000000 +0400
-+++ linux-2.6.9-full/include/linux/ext3_fs.h	2007-03-28 15:45:07.000000000 +0400
-@@ -57,6 +57,30 @@ struct statfs;
- #define ext3_debug(f, a...)	do {} while (0)
- #endif
- 
-+#define EXT3_MULTIBLOCK_ALLOCATOR	1
-+
-+#define EXT3_MB_HINT_MERGE		1	/* prefer goal again. length */
-+#define EXT3_MB_HINT_RESERVED		2	/* blocks already reserved */
-+#define EXT3_MB_HINT_METADATA		4	/* metadata is being allocated */
-+#define EXT3_MB_HINT_FIRST		8	/* first blocks in the file */
-+#define EXT3_MB_HINT_BEST		16	/* search for the best chunk */
-+#define EXT3_MB_HINT_DATA		32	/* data is being allocated */
-+#define EXT3_MB_HINT_NOPREALLOC		64	/* don't preallocate (for tails) */
-+#define EXT3_MB_HINT_GROUP_ALLOC	128	/* allocate for locality group */
-+#define EXT3_MB_HINT_GOAL_ONLY		256	/* allocate goal blocks or none */
-+
-+struct ext3_allocation_request {
-+	struct inode *inode;	/* target inode for block we're allocating */
-+	unsigned long logical;	/* logical block in target inode */
-+	unsigned long goal;	/* phys. target (a hint) */
-+	unsigned long lleft;	/* the closest logical allocated block to the left */
-+	unsigned long pleft;	/* phys. block for ^^^ */
-+	unsigned long lright;	/* the closest logical allocated block to the right */
-+	unsigned long pright;	/* phys. block for ^^^ */
-+	unsigned long len;	/* how many blocks we want to allocate */
-+	unsigned long flags;	/* flags. see above EXT3_MB_HINT_* */
-+};
-+
- /*
-  * Special inodes numbers
-  */
-@@ -404,6 +413,14 @@
- #define ext3_find_first_zero_bit	ext2_find_first_zero_bit
- #define ext3_find_next_zero_bit		ext2_find_next_zero_bit
- 
-+#ifndef ext2_find_next_le_bit
-+#ifdef __LITTLE_ENDIAN
-+#define ext2_find_next_le_bit(addr, size, off) find_next_bit((addr), (size), (off))
-+#else
-+#error "mballoc needs a patch for big-endian systems - CFS bug 10634"
-+#endif	/* __LITTLE_ENDIAN */
-+#endif	/* !ext2_find_next_le_bit */
-+
- /*
-  * Maximal mount counts between two filesystem checks
-  */
-@@ -763,6 +787,20 @@ extern unsigned long ext3_count_dirs (st
- extern void ext3_check_inodes_bitmap (struct super_block *);
- extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
- 
-+/* mballoc.c */
-+extern long ext3_mb_stats;
-+extern long ext3_mb_max_to_scan;
-+extern int ext3_mb_init(struct super_block *, int);
-+extern int ext3_mb_release(struct super_block *);
-+extern unsigned long ext3_mb_new_blocks(handle_t *, struct ext3_allocation_request *, int *);
-+extern int ext3_mb_reserve_blocks(struct super_block *, int);
-+extern void ext3_mb_release_blocks(struct super_block *, int);
-+extern void ext3_mb_release_blocks(struct super_block *, int);
-+extern void ext3_mb_discard_inode_preallocations(struct inode *);
-+extern int __init init_ext3_proc(void);
-+extern void exit_ext3_proc(void);
-+extern void ext3_mb_free_blocks(handle_t *, struct inode *, unsigned long, unsigned long, int, int *);
-+
- 
- /* inode.c */
- extern int ext3_block_truncate_page(handle_t *, struct page *,
-Index: linux-2.6.9-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/super.c	2007-03-28 01:29:38.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/super.c	2007-03-28 15:42:16.000000000 +0400
-@@ -394,6 +394,7 @@ void ext3_put_super (struct super_block 
- 	struct ext3_super_block *es = sbi->s_es;
- 	int i;
- 
-+	ext3_mb_release(sb);
- 	ext3_ext_release(sb);
- 	ext3_xattr_put_super(sb);
- 	journal_destroy(sbi->s_journal);
-@@ -463,6 +464,8 @@ static struct inode *ext3_alloc_inode(st
- 	ei->vfs_inode.i_version = 1;
- 	
- 	memset(&ei->i_cached_extent, 0, sizeof(ei->i_cached_extent));
-+	INIT_LIST_HEAD(&ei->i_prealloc_list);
-+	spin_lock_init(&ei->i_prealloc_lock);
- 	return &ei->vfs_inode;
- }
- 
-@@ -2433,7 +2436,13 @@ static struct file_system_type ext3_fs_t
- 
- static int __init init_ext3_fs(void)
- {
--	int err = init_ext3_xattr();
-+	int err;
-+
-+	err = init_ext3_proc();
-+	if (err)
-+		return err;
-+
-+	err = init_ext3_xattr();
- 	if (err)
- 		return err;
- 	err = init_inodecache();
-@@ -2455,6 +2464,7 @@ static void __exit exit_ext3_fs(void)
- 	unregister_filesystem(&ext3_fs_type);
- 	destroy_inodecache();
- 	exit_ext3_xattr();
-+	exit_ext3_proc();
- }
- 
- int ext3_prep_san_write(struct inode *inode, long *blocks,
-Index: linux-2.6.9-full/fs/ext3/mballoc.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/mballoc.c	2007-02-13 18:39:59.640066087 +0300
-+++ linux-2.6.9-full/fs/ext3/mballoc.c	2007-03-29 00:28:40.000000000 +0400
-@@ -0,0 +1,4342 @@
-+/*
-+ * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com
-+ * Written by Alex Tomas <alex@clusterfs.com>
-+ *
-+ * 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.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public Licens
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
-+ */
-+
-+
-+/*
-+ * mballoc.c contains the multiblocks allocation routines
-+ */
-+
-+#include <linux/time.h>
-+#include <linux/fs.h>
-+#include <linux/namei.h>
-+#include <linux/ext3_jbd.h>
-+#include <linux/jbd.h>
-+#include <linux/ext3_fs.h>
-+#include <linux/quotaops.h>
-+#include <linux/buffer_head.h>
-+#include <linux/module.h>
-+#include <linux/swap.h>
-+#include <linux/proc_fs.h>
-+#include <linux/pagemap.h>
-+#include <linux/seq_file.h>
-+#include <linux/version.h>
-+
-+/*
-+ * MUSTDO:
-+ *   - test ext3_ext_search_left() and ext3_ext_search_right()
-+ *   - search for metadata in few groups
-+ *
-+ * TODO v4:
-+ *   - normalization should take into account whether file is still open
-+ *   - discard preallocations if no free space left (policy?)
-+ *   - don't normalize tails
-+ *   - quota
-+ *   - reservation for superuser
-+ *
-+ * TODO v3:
-+ *   - bitmap read-ahead (proposed by Oleg Drokin aka green)
-+ *   - track min/max extents in each group for better group selection
-+ *   - mb_mark_used() may allocate chunk right after splitting buddy
-+ *   - tree of groups sorted by number of free blocks
-+ *   - error handling
-+ */
-+
-+/*
-+ * mballoc operates on the following data:
-+ *  - on-disk bitmap
-+ *  - in-core buddy (actually includes buddy and bitmap)
-+ *  - preallocation descriptors (PAs)
-+ *
-+ * there are two types of preallocations:
-+ *  - inode
-+ *    assiged to specific inode and can be used for this inode only.
-+ *    it describes part of inode's space preallocated to specific
-+ *    physical blocks. any block from that preallocated can be used
-+ *    independent. the descriptor just tracks number of blocks left
-+ *    unused. so, before taking some block from descriptor, one must
-+ *    make sure corresponded logical block isn't allocated yet. this
-+ *    also means that freeing any block within descriptor's range
-+ *    must discard all preallocated blocks.
-+ *  - locality group
-+ *    assigned to specific locality group which does not translate to
-+ *    permanent set of inodes: inode can join and leave group. space
-+ *    from this type of preallocation can be used for any inode. thus
-+ *    it's consumed from the beginning to the end.
-+ *
-+ * relation between them can be expressed as:
-+ *    in-core buddy = on-disk bitmap + preallocation descriptors
-+ *
-+ * this mean blocks mballoc considers used are:
-+ *  - allocated blocks (persistent)
-+ *  - preallocated blocks (non-persistent)
-+ *
-+ * consistency in mballoc world means that at any time a block is either
-+ * free or used in ALL structures. notice: "any time" should not be read
-+ * literally -- time is discrete and delimited by locks.
-+ *
-+ *  to keep it simple, we don't use block numbers, instead we count number of
-+ *  blocks: how many blocks marked used/free in on-disk bitmap, buddy and PA.
-+ *
-+ * all operations can be expressed as:
-+ *  - init buddy:			buddy = on-disk + PAs
-+ *  - new PA:				buddy += N; PA = N
-+ *  - use inode PA:			on-disk += N; PA -= N
-+ *  - discard inode PA			buddy -= on-disk - PA; PA = 0
-+ *  - use locality group PA		on-disk += N; PA -= N
-+ *  - discard locality group PA		buddy -= PA; PA = 0
-+ *  note: 'buddy -= on-disk - PA' is used to show that on-disk bitmap
-+ *        is used in real operation because we can't know actual used
-+ *        bits from PA, only from on-disk bitmap
-+ *
-+ * if we follow this strict logic, then all operations above should be atomic.
-+ * given some of them can block, we'd have to use something like semaphores
-+ * killing performance on high-end SMP hardware. let's try to relax it using
-+ * the following knowledge:
-+ *  1) if buddy is referenced, it's already initialized
-+ *  2) while block is used in buddy and the buddy is referenced,
-+ *     nobody can re-allocate that block
-+ *  3) we work on bitmaps and '+' actually means 'set bits'. if on-disk has
-+ *     bit set and PA claims same block, it's OK. IOW, one can set bit in
-+ *     on-disk bitmap if buddy has same bit set or/and PA covers corresponded
-+ *     block
-+ *
-+ * so, now we're building a concurrency table:
-+ *  - init buddy vs.
-+ *    - new PA
-+ *      blocks for PA are allocated in the buddy, buddy must be referenced
-+ *      until PA is linked to allocation group to avoid concurrent buddy init
-+ *    - use inode PA
-+ *      we need to make sure that either on-disk bitmap or PA has uptodate data
-+ *      given (3) we care that PA-=N operation doesn't interfere with init
-+ *    - discard inode PA
-+ *      the simplest way would be to have buddy initialized by the discard
-+ *    - use locality group PA
-+ *      again PA-=N must be serialized with init
-+ *    - discard locality group PA
-+ *      the simplest way would be to have buddy initialized by the discard
-+ *  - new PA vs.
-+ *    - use inode PA
-+ *      i_truncate_mutex serializes them
-+ *    - discard inode PA
-+ *      discard process must wait until PA isn't used by another process
-+ *    - use locality group PA
-+ *      some mutex should serialize them
-+ *    - discard locality group PA
-+ *      discard process must wait until PA isn't used by another process
-+ *  - use inode PA
-+ *    - use inode PA
-+ *      i_truncate_mutex or another mutex should serializes them
-+ *    - discard inode PA
-+ *      discard process must wait until PA isn't used by another process
-+ *    - use locality group PA
-+ *      nothing wrong here -- they're different PAs covering different blocks
-+ *    - discard locality group PA
-+ *      discard process must wait until PA isn't used by another process
-+ *
-+ * now we're ready to make few consequences:
-+ *  - PA is referenced and while it is no discard is possible
-+ *  - PA is referenced until block isn't marked in on-disk bitmap
-+ *  - PA changes only after on-disk bitmap
-+ *  - discard must not compete with init. either init is done before
-+ *    any discard or they're serialized somehow
-+ *  - buddy init as sum of on-disk bitmap and PAs is done atomically
-+ *
-+ * a special case when we've used PA to emptiness. no need to modify buddy
-+ * in this case, but we should care about concurrent init
-+ *
-+ */
-+
-+ /*
-+ * Logic in few words:
-+ *
-+ *  - allocation:
-+ *    load group
-+ *    find blocks
-+ *    mark bits in on-disk bitmap
-+ *    release group
-+ *
-+ *  - use preallocation:
-+ *    find proper PA (per-inode or group)
-+ *    load group
-+ *    mark bits in on-disk bitmap
-+ *    release group
-+ *    release PA
-+ *
-+ *  - free:
-+ *    load group
-+ *    mark bits in on-disk bitmap
-+ *    release group
-+ *
-+ *  - discard preallocations in group:
-+ *    mark PAs deleted
-+ *    move them onto local list
-+ *    load on-disk bitmap
-+ *    load group
-+ *    remove PA from object (inode or locality group)
-+ *    mark free blocks in-core
-+ *
-+ *  - discard inode's preallocations:
-+ */
-+
-+/*
-+ * Locking rules
-+ *
-+ * Locks:
-+ *  - bitlock on a group	(group)
-+ *  - object (inode/locality)	(object)
-+ *  - per-pa lock		(pa)
-+ *
-+ * Paths:
-+ *  - new pa
-+ *    object
-+ *    group
-+ *
-+ *  - find and use pa:
-+ *    pa
-+ *
-+ *  - release consumed pa:
-+ *    pa
-+ *    group
-+ *    object
-+ *
-+ *  - generate in-core bitmap:
-+ *    group
-+ *        pa
-+ *
-+ *  - discard all for given object (inode, locality group):
-+ *    object
-+ *        pa
-+ *    group
-+ *
-+ *  - discard all for given group:
-+ *    group
-+ *        pa
-+ *    group
-+ *        object
-+ *
-+ */
-+
-+/*
-+ * with AGGRESSIVE_CHECK allocator runs consistency checks over
-+ * structures. these checks slow things down a lot
-+ */
-+#define AGGRESSIVE_CHECK__
-+
-+/*
-+ * with DOUBLE_CHECK defined mballoc creates persistent in-core
-+ * bitmaps, maintains and uses them to check for double allocations
-+ */
-+#define DOUBLE_CHECK__
-+
-+/*
-+ */
-+#define MB_DEBUG__
-+#ifdef MB_DEBUG
-+#define mb_debug(fmt,a...)	printk(fmt, ##a)
-+#else
-+#define mb_debug(fmt,a...)
-+#endif
-+
-+/*
-+ * with EXT3_MB_HISTORY mballoc stores last N allocations in memory
-+ * and you can monitor it in /proc/fs/ext3/<dev>/mb_history
-+ */
-+#define EXT3_MB_HISTORY
-+#define EXT3_MB_HISTORY_ALLOC		1	/* allocation */
-+#define EXT3_MB_HISTORY_PREALLOC	2	/* preallocated blocks used */
-+#define EXT3_MB_HISTORY_DISCARD		4	/* preallocation discarded */
-+#define EXT3_MB_HISTORY_FREE		8	/* free */
-+
-+#define EXT3_MB_HISTORY_DEFAULT		(EXT3_MB_HISTORY_ALLOC | \
-+					 EXT3_MB_HISTORY_PREALLOC | \
-+					 EXT3_MB_HISTORY_DISCARD | \
-+					 EXT3_MB_HISTORY_FREE)
-+
-+/*
-+ * How long mballoc can look for a best extent (in found extents)
-+ */
-+#define MB_DEFAULT_MAX_TO_SCAN		200
-+
-+/*
-+ * How long mballoc must look for a best extent
-+ */
-+#define MB_DEFAULT_MIN_TO_SCAN		10
-+
-+/*
-+ * How many groups mballoc will scan looking for the best chunk
-+ */
-+#define MB_DEFAULT_MAX_GROUPS_TO_SCAN	5
-+
-+/*
-+ * with 'ext3_mb_stats' allocator will collect stats that will be
-+ * shown at umount. The collecting costs though!
-+ */
-+#define MB_DEFAULT_STATS		1
-+
-+/*
-+ * files smaller than MB_DEFAULT_STREAM_THRESHOLD are served
-+ * by the stream allocator, which purpose is to pack requests
-+ * as close each to other as possible to produce smooth I/O traffic
-+ */
-+#define MB_DEFAULT_STREAM_THRESHOLD	16	/* 64K */
-+
-+/*
-+ * for which requests use 2^N search using buddies
-+ */
-+#define MB_DEFAULT_ORDER2_REQS		8
-+
-+/*
-+ * default stripe size = 1MB
-+ */
-+#define MB_DEFAULT_STRIPE		256
-+
-+static kmem_cache_t *ext3_pspace_cachep = NULL;
-+
-+#ifdef EXT3_BB_MAX_BLOCKS
-+#undef EXT3_BB_MAX_BLOCKS
-+#endif
-+#define EXT3_BB_MAX_BLOCKS	30
-+
-+struct ext3_free_metadata {
-+	unsigned short group;
-+	unsigned short num;
-+	unsigned short blocks[EXT3_BB_MAX_BLOCKS];
-+	struct list_head list;
-+};
-+
-+struct ext3_group_info {
-+	unsigned long	bb_state;
-+	unsigned long 	bb_tid;
-+	struct ext3_free_metadata *bb_md_cur;
-+	unsigned short	bb_first_free;
-+	unsigned short	bb_free;
-+	unsigned short	bb_fragments;
-+	struct		list_head bb_prealloc_list;
-+#ifdef DOUBLE_CHECK
-+	void		*bb_bitmap;
-+#endif
-+	unsigned short	bb_counters[];
-+};
-+
-+#define EXT3_GROUP_INFO_NEED_INIT_BIT	0
-+#define EXT3_GROUP_INFO_LOCKED_BIT	1
-+
-+#define EXT3_MB_GRP_NEED_INIT(grp)	\
-+	(test_bit(EXT3_GROUP_INFO_NEED_INIT_BIT, &(grp)->bb_state))
-+
-+
-+struct ext3_prealloc_space {
-+	struct list_head	pa_inode_list;
-+	struct list_head	pa_group_list;
-+	union {
-+		struct list_head pa_tmp_list;
-+		struct rcu_head	pa_rcu;
-+	} u;
-+	spinlock_t		pa_lock;
-+	atomic_t		pa_count;
-+	unsigned		pa_deleted;
-+	unsigned long		pa_pstart;	/* phys. block */
-+	unsigned long		pa_lstart;	/* log. block */
-+	unsigned short		pa_len;		/* len of preallocated chunk */
-+	unsigned short		pa_free;	/* how many blocks are free */
-+	unsigned short		pa_linear;	/* consumed in one direction
-+						 * strictly, for group prealloc */
-+	spinlock_t		*pa_obj_lock;
-+	struct inode		*pa_inode;	/* hack, for history only */
-+};
-+
-+
-+struct ext3_free_extent {
-+	unsigned long fe_logical;
-+	unsigned long fe_start;
-+	unsigned long fe_group;
-+	unsigned long fe_len;
-+};
-+
-+/*
-+ * Locality group:
-+ *   we try to group all related changes together
-+ *   so that writeback can flush/allocate them together as well
-+ */
-+struct ext3_locality_group {
-+	/* for allocator */
-+	struct semaphore	lg_sem;		/* to serialize allocates */
-+	struct list_head	lg_prealloc_list;/* list of preallocations */
-+	spinlock_t		lg_prealloc_lock;
-+};
-+
-+struct ext3_allocation_context {
-+	struct inode *ac_inode;
-+	struct super_block *ac_sb;
-+
-+	/* original request */
-+	struct ext3_free_extent ac_o_ex;
-+
-+	/* goal request (after normalization) */
-+	struct ext3_free_extent ac_g_ex;
-+
-+	/* the best found extent */
-+	struct ext3_free_extent ac_b_ex;
-+
-+	/* copy of the bext found extent taken before preallocation efforts */
-+	struct ext3_free_extent ac_f_ex;
-+
-+	/* number of iterations done. we have to track to limit searching */
-+	unsigned long ac_ex_scanned;
-+	__u16 ac_groups_scanned;
-+	__u16 ac_found;
-+	__u16 ac_tail;
-+	__u16 ac_buddy;
-+	__u16 ac_flags;		/* allocation hints */
-+	__u8 ac_status;
-+	__u8 ac_criteria;
-+	__u8 ac_repeats;
-+	__u8 ac_2order;		/* if request is to allocate 2^N blocks and
-+				 * N > 0, the field stores N, otherwise 0 */
-+	__u8 ac_op;		/* operation, for history only */
-+	struct page *ac_bitmap_page;
-+	struct page *ac_buddy_page;
-+	struct ext3_prealloc_space *ac_pa;
-+	struct ext3_locality_group *ac_lg;
-+};
-+
-+#define AC_STATUS_CONTINUE	1
-+#define AC_STATUS_FOUND		2
-+#define AC_STATUS_BREAK		3
-+
-+struct ext3_mb_history {
-+	struct ext3_free_extent orig;	/* orig allocation */
-+	struct ext3_free_extent goal;	/* goal allocation */
-+	struct ext3_free_extent result;	/* result allocation */
-+	unsigned pid;
-+	unsigned ino;
-+	__u16 found;	/* how many extents have been found */
-+	__u16 groups;	/* how many groups have been scanned */
-+	__u16 tail;	/* what tail broke some buddy */
-+	__u16 buddy;	/* buddy the tail ^^^ broke */
-+	__u16 flags;
-+	__u8 cr:3;	/* which phase the result extent was found at */
-+	__u8 op:4;
-+	__u8 merged:1;
-+};
-+
-+struct ext3_buddy {
-+	struct page *bd_buddy_page;
-+	void *bd_buddy;
-+	struct page *bd_bitmap_page;
-+	void *bd_bitmap;
-+	struct ext3_group_info *bd_info;
-+	struct super_block *bd_sb;
-+	__u16 bd_blkbits;
-+	__u16 bd_group;
-+};
-+#define EXT3_MB_BITMAP(e3b)	((e3b)->bd_bitmap)
-+#define EXT3_MB_BUDDY(e3b)	((e3b)->bd_buddy)
-+
-+#ifndef EXT3_MB_HISTORY
-+#define ext3_mb_store_history(ac)
-+#else
-+static void ext3_mb_store_history(struct ext3_allocation_context *ac);
-+#endif
-+
-+#define in_range(b, first, len)	((b) >= (first) && (b) <= (first) + (len) - 1)
-+
-+static struct proc_dir_entry *proc_root_ext3;
-+
-+int ext3_create (struct inode *, struct dentry *, int, struct nameidata *);
-+struct buffer_head * read_block_bitmap(struct super_block *, unsigned int);
-+unsigned long ext3_new_blocks_old(handle_t *handle, struct inode *inode,
-+			unsigned long goal, unsigned long *count, int *errp);
-+void ext3_mb_release_blocks(struct super_block *, int);
-+void ext3_mb_poll_new_transaction(struct super_block *, handle_t *);
-+void ext3_mb_free_committed_blocks(struct super_block *);
-+void ext3_mb_generate_from_pa(struct super_block *sb, void *bitmap, int group);
-+void ext3_mb_free_consumed_preallocations(struct ext3_allocation_context *ac);
-+void ext3_mb_return_to_preallocation(struct inode *inode, struct ext3_buddy *e3b,
-+					sector_t block, int count);
-+void ext3_mb_show_ac(struct ext3_allocation_context *ac);
-+void ext3_mb_check_with_pa(struct ext3_buddy *e3b, int first, int count);
-+void ext3_mb_put_pa(struct ext3_allocation_context *, struct super_block *, struct ext3_prealloc_space *pa);
-+int ext3_mb_init_per_dev_proc(struct super_block *sb);
-+int ext3_mb_destroy_per_dev_proc(struct super_block *sb);
-+
-+/*
-+ * Calculate the block group number and offset, given a block number
-+ */
-+static void ext3_get_group_no_and_offset(struct super_block *sb,
-+					unsigned long blocknr,
-+					unsigned long *blockgrpp,
-+					unsigned long *offsetp)
-+{
-+	struct ext3_super_block *es = EXT3_SB(sb)->s_es;
-+	unsigned long offset;
-+
-+	blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
-+	offset = blocknr % EXT3_BLOCKS_PER_GROUP(sb);
-+	blocknr = blocknr / EXT3_BLOCKS_PER_GROUP(sb);
-+	if (offsetp)
-+		*offsetp = offset;
-+	if (blockgrpp)
-+	        *blockgrpp = blocknr;
-+
-+}
-+
-+static inline void
-+ext3_lock_group(struct super_block *sb, int group)
-+{
-+	bit_spin_lock(EXT3_GROUP_INFO_LOCKED_BIT,
-+		      &EXT3_GROUP_INFO(sb, group)->bb_state);
-+}
-+
-+static inline void
-+ext3_unlock_group(struct super_block *sb, int group)
-+{
-+	bit_spin_unlock(EXT3_GROUP_INFO_LOCKED_BIT,
-+			&EXT3_GROUP_INFO(sb, group)->bb_state);
-+}
-+
-+static inline int
-+ext3_is_group_locked(struct super_block *sb, int group)
-+{
-+	return bit_spin_is_locked(EXT3_GROUP_INFO_LOCKED_BIT,
-+					&EXT3_GROUP_INFO(sb, group)->bb_state);
-+}
-+
-+unsigned long ext3_grp_offs_to_block(struct super_block *sb,
-+					struct ext3_free_extent *fex)
-+{
-+	unsigned long block;
-+
-+	block = (unsigned long) fex->fe_group * EXT3_BLOCKS_PER_GROUP(sb)
-+			+ fex->fe_start
-+			+ le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
-+	return block;
-+}
-+
-+#if BITS_PER_LONG == 64
-+#define mb_correct_addr_and_bit(bit,addr)		\
-+{							\
-+	bit += ((unsigned long) addr & 7UL) << 3;	\
-+	addr = (void *) ((unsigned long) addr & ~7UL);	\
-+}
-+#elif BITS_PER_LONG == 32
-+#define mb_correct_addr_and_bit(bit,addr)		\
-+{							\
-+	bit += ((unsigned long) addr & 3UL) << 3;	\
-+	addr = (void *) ((unsigned long) addr & ~3UL);	\
-+}
-+#else
-+#error "how many bits you are?!"
-+#endif
-+
-+static inline int mb_test_bit(int bit, void *addr)
-+{
-+	mb_correct_addr_and_bit(bit,addr);
-+	return ext2_test_bit(bit, addr);
-+}
-+
-+static inline void mb_set_bit(int bit, void *addr)
-+{
-+	mb_correct_addr_and_bit(bit,addr);
-+	ext2_set_bit(bit, addr);
-+}
-+
-+static inline void mb_set_bit_atomic(int bit, void *addr)
-+{
-+	mb_correct_addr_and_bit(bit,addr);
-+	ext2_set_bit_atomic(NULL, bit, addr);
-+}
-+
-+static inline void mb_clear_bit(int bit, void *addr)
-+{
-+	mb_correct_addr_and_bit(bit,addr);
-+	ext2_clear_bit(bit, addr);
-+}
-+
-+static inline void mb_clear_bit_atomic(int bit, void *addr)
-+{
-+	mb_correct_addr_and_bit(bit,addr);
-+	ext2_clear_bit_atomic(NULL, bit, addr);
-+}
-+
-+static inline int mb_find_next_zero_bit(void *addr, int max, int start)
-+{
-+	int fix;
-+#if BITS_PER_LONG == 64
-+	fix = ((unsigned long) addr & 7UL) << 3;
-+	addr = (void *) ((unsigned long) addr & ~7UL);
-+#elif BITS_PER_LONG == 32
-+	fix = ((unsigned long) addr & 3UL) << 3;
-+	addr = (void *) ((unsigned long) addr & ~3UL);
-+#else
-+#error "how many bits you are?!"
-+#endif
-+	max += fix;
-+	start += fix;
-+	return ext2_find_next_zero_bit(addr, max, start) - fix;
-+}
-+
-+static inline int mb_find_next_bit(void *addr, int max, int start)
-+{
-+	int fix;
-+#if BITS_PER_LONG == 64
-+	fix = ((unsigned long) addr & 7UL) << 3;
-+	addr = (void *) ((unsigned long) addr & ~7UL);
-+#elif BITS_PER_LONG == 32
-+	fix = ((unsigned long) addr & 3UL) << 3;
-+	addr = (void *) ((unsigned long) addr & ~3UL);
-+#else
-+#error "how many bits you are?!"
-+#endif
-+	max += fix;
-+	start += fix;
-+
-+#ifdef __BIG_ENDIAN
-+#else
-+	return find_next_bit(addr, max, start) - fix;
-+#endif
-+}
-+
-+static inline void *mb_find_buddy(struct ext3_buddy *e3b, int order, int *max)
-+{
-+	char *bb;
-+
-+	BUG_ON(EXT3_MB_BITMAP(e3b) == EXT3_MB_BUDDY(e3b));
-+	BUG_ON(max == NULL);
-+
-+	if (order > e3b->bd_blkbits + 1) {
-+		*max = 0;
-+		return NULL;
-+	}
-+
-+	/* at order 0 we see each particular block */
-+	*max = 1 << (e3b->bd_blkbits + 3);
-+	if (order == 0)
-+		return EXT3_MB_BITMAP(e3b);
-+
-+	bb = EXT3_MB_BUDDY(e3b) + EXT3_SB(e3b->bd_sb)->s_mb_offsets[order];
-+	*max = EXT3_SB(e3b->bd_sb)->s_mb_maxs[order];
-+
-+	return bb;
-+}
-+
-+#ifdef DOUBLE_CHECK
-+void mb_free_blocks_double(struct ext3_buddy *e3b, int first, int count)
-+{
-+	int i;
-+	if (unlikely(e3b->bd_info->bb_bitmap == NULL))
-+		return;
-+	BUG_ON(!ext3_is_group_locked(e3b->bd_sb, e3b->bd_group));
-+	for (i = 0; i < count; i++) {
-+		BUG_ON(!mb_test_bit(first + i, e3b->bd_info->bb_bitmap));
-+		mb_clear_bit(first + i, e3b->bd_info->bb_bitmap);
-+	}
-+}
-+
-+void mb_mark_used_double(struct ext3_buddy *e3b, int first, int count)
-+{
-+	int i;
-+	if (unlikely(e3b->bd_info->bb_bitmap == NULL))
-+		return;
-+	BUG_ON(!ext3_is_group_locked(e3b->bd_sb, e3b->bd_group));
-+	for (i = 0; i < count; i++) {
-+		BUG_ON(mb_test_bit(first + i, e3b->bd_info->bb_bitmap));
-+		mb_set_bit(first + i, e3b->bd_info->bb_bitmap);
-+	}
-+}
-+
-+void mb_cmp_bitmaps(struct ext3_buddy *e3b, void *bitmap)
-+{
-+	if (memcmp(e3b->bd_info->bb_bitmap, bitmap, e3b->bd_sb->s_blocksize)) {
-+		unsigned char *b1, *b2;
-+		int i;
-+		b1 = (unsigned char *) e3b->bd_info->bb_bitmap;
-+		b2 = (unsigned char *) bitmap;
-+		for (i = 0; i < e3b->bd_sb->s_blocksize; i++) {
-+			if (b1[i] != b2[i]) {
-+				printk("corruption in group %u at byte %u(%u): "
-+				       "%x in copy != %x on disk/prealloc\n",
-+					e3b->bd_group, i, i * 8, b1[i], b2[i]);
-+				BUG();
-+			}
-+		}
-+	}
-+}
-+
-+#else
-+#define mb_free_blocks_double(a,b,c)
-+#define mb_mark_used_double(a,b,c)
-+#define mb_cmp_bitmaps(a,b)
-+#endif
-+
-+#ifdef AGGRESSIVE_CHECK
-+
-+#define MB_CHECK_ASSERT(assert)						\
-+do {									\
-+	if (!(assert)) {						\
-+		printk (KERN_EMERG					\
-+			"Assertion failure in %s() at %s:%d: \"%s\"\n",	\
-+			function, file, line, # assert);		\
-+		BUG();							\
-+	}								\
-+} while (0)
-+
-+static int __mb_check_buddy(struct ext3_buddy *e3b, char *file,
-+				const char *function, int line)
-+{
-+	struct super_block *sb = e3b->bd_sb;
-+	int order = e3b->bd_blkbits + 1;
-+	int max, max2, i, j, k, count;
-+	struct ext3_group_info *grp;
-+	int fragments = 0, fstart;
-+	struct list_head *cur;
-+	void *buddy, *buddy2;
-+
-+	if (!test_opt(sb, MBALLOC))
-+		return 0;
-+
-+	{
-+		static int mb_check_counter = 0;
-+		if (mb_check_counter++ % 100 != 0)
-+			return 0;
-+	}
-+
-+	while (order > 1) {
-+		buddy = mb_find_buddy(e3b, order, &max);
-+		MB_CHECK_ASSERT(buddy);
-+		buddy2 = mb_find_buddy(e3b, order - 1, &max2);
-+		MB_CHECK_ASSERT(buddy2);
-+		MB_CHECK_ASSERT(buddy != buddy2);
-+		MB_CHECK_ASSERT(max * 2 == max2);
-+
-+		count = 0;
-+		for (i = 0; i < max; i++) {
-+
-+			if (mb_test_bit(i, buddy)) {
-+				/* only single bit in buddy2 may be 1 */
-+				if (!mb_test_bit(i << 1, buddy2))
-+					MB_CHECK_ASSERT(mb_test_bit((i<<1)+1, buddy2));
-+				else if (!mb_test_bit((i << 1) + 1, buddy2))
-+					MB_CHECK_ASSERT(mb_test_bit(i << 1, buddy2));
-+				continue;
-+			}
-+
-+			/* both bits in buddy2 must be 0 */
-+			MB_CHECK_ASSERT(mb_test_bit(i << 1, buddy2));
-+			MB_CHECK_ASSERT(mb_test_bit((i << 1) + 1, buddy2));
-+
-+			for (j = 0; j < (1 << order); j++) {
-+				k = (i * (1 << order)) + j;
-+				MB_CHECK_ASSERT(!mb_test_bit(k, EXT3_MB_BITMAP(e3b)));
-+			}
-+			count++;
-+		}
-+		MB_CHECK_ASSERT(e3b->bd_info->bb_counters[order] == count);
-+		order--;
-+	}
-+
-+	fstart = -1;
-+	buddy = mb_find_buddy(e3b, 0, &max);
-+	for (i = 0; i < max; i++) {
-+		if (!mb_test_bit(i, buddy)) {
-+			MB_CHECK_ASSERT(i >= e3b->bd_info->bb_first_free);
-+			if (fstart == -1) {
-+				fragments++;
-+				fstart = i;
-+			}
-+			continue;
-+		}
-+		fstart = -1;
-+		/* check used bits only */
-+		for (j = 0; j < e3b->bd_blkbits + 1; j++) {
-+			buddy2 = mb_find_buddy(e3b, j, &max2);
-+			k = i >> j;
-+			MB_CHECK_ASSERT(k < max2);
-+			MB_CHECK_ASSERT(mb_test_bit(k, buddy2));
-+		}
-+	}
-+	MB_CHECK_ASSERT(!EXT3_MB_GRP_NEED_INIT(e3b->bd_info));
-+	MB_CHECK_ASSERT(e3b->bd_info->bb_fragments == fragments);
-+
-+	grp = EXT3_GROUP_INFO(sb, e3b->bd_group);
-+	buddy = mb_find_buddy(e3b, 0, &max);
-+	list_for_each(cur, &grp->bb_prealloc_list) {
-+		unsigned long groupnr;
-+		struct ext3_prealloc_space *pa;
-+		pa = list_entry(cur, struct ext3_prealloc_space, group_list);
-+		ext3_get_group_no_and_offset(sb, pa->pstart, &groupnr, &k);
-+		MB_CHECK_ASSERT(groupnr == e3b->bd_group);
-+		for (i = 0; i < pa->len; i++)
-+			MB_CHECK_ASSERT(mb_test_bit(k + i, buddy));
-+	}
-+	return 0;
-+}
-+#undef MB_CHECK_ASSERT
-+#define mb_check_buddy(e3b) __mb_check_buddy(e3b,__FILE__,__FUNCTION__,__LINE__)
-+#else
-+#define mb_check_buddy(e3b)
-+#endif
-+
-+/* find most significant bit */
-+static int inline fmsb(unsigned short word)
-+{
-+	int order;
-+
-+	if (word > 255) {
-+		order = 7;
-+		word >>= 8;
-+	} else {
-+		order = -1;
-+	}
-+
-+	do {
-+		order++;
-+		word >>= 1;
-+	} while (word != 0);
-+
-+	return order;
-+}
-+
-+static void inline
-+ext3_mb_mark_free_simple(struct super_block *sb, void *buddy, unsigned first,
-+				int len, struct ext3_group_info *grp)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	unsigned short min, max, chunk, border;
-+
-+	BUG_ON(len >= EXT3_BLOCKS_PER_GROUP(sb));
-+
-+	border = 2 << sb->s_blocksize_bits;
-+
-+	while (len > 0) {
-+		/* find how many blocks can be covered since this position */
-+		max = ffs(first | border) - 1;
-+
-+		/* find how many blocks of power 2 we need to mark */
-+		min = fmsb(len);
-+
-+		if (max < min)
-+			min = max;
-+		chunk = 1 << min;
-+
-+		/* mark multiblock chunks only */
-+		grp->bb_counters[min]++;
-+		if (min > 0)
-+			mb_clear_bit(first >> min, buddy + sbi->s_mb_offsets[min]);
-+
-+		len -= chunk;
-+		first += chunk;
-+	}
-+}
-+
-+static void
-+ext3_mb_generate_buddy(struct super_block *sb, void *buddy, void *bitmap,
-+			int group)
-+{
-+	struct ext3_group_info *grp = EXT3_GROUP_INFO(sb, group);
-+	unsigned short max = EXT3_BLOCKS_PER_GROUP(sb);
-+	unsigned short i = 0, first, len;
-+	unsigned free = 0, fragments = 0;
-+	unsigned long long period = get_cycles();
-+
-+	/* initialize buddy from bitmap which is aggregation
-+	 * of on-disk bitmap and preallocations */
-+	i = mb_find_next_zero_bit(bitmap, max, 0);
-+	grp->bb_first_free = i;
-+	while (i < max) {
-+		fragments++;
-+		first = i;
-+		i = ext2_find_next_le_bit(bitmap, max, i);
-+		len = i - first;
-+		free += len;
-+		if (len > 1)
-+			ext3_mb_mark_free_simple(sb, buddy, first, len, grp);
-+		else
-+			grp->bb_counters[0]++;
-+		if (i < max)
-+			i = mb_find_next_zero_bit(bitmap, max, i);
-+	}
-+	grp->bb_fragments = fragments;
-+
-+	if (free != grp->bb_free) {
-+		printk("EXT3-fs: group %u: %u blocks in bitmap, %u in gd\n",
-+			group, free, grp->bb_free);
-+		grp->bb_free = free;
-+	}
-+
-+	clear_bit(EXT3_GROUP_INFO_NEED_INIT_BIT, &grp->bb_state);
-+
-+	period = get_cycles() - period;
-+	spin_lock(&EXT3_SB(sb)->s_bal_lock);
-+	EXT3_SB(sb)->s_mb_buddies_generated++;
-+	EXT3_SB(sb)->s_mb_generation_time += period;
-+	spin_unlock(&EXT3_SB(sb)->s_bal_lock);
-+}
-+
-+static int ext3_mb_init_cache(struct page *page, char *incore)
-+{
-+	int blocksize, blocks_per_page, groups_per_page;
-+	int err = 0, i, first_group, first_block;
-+	struct super_block *sb;
-+	struct buffer_head *bhs;
-+	struct buffer_head **bh;
-+	struct inode *inode;
-+	char *data, *bitmap;
-+
-+	mb_debug("init page %lu\n", page->index);
-+
-+	inode = page->mapping->host;
-+	sb = inode->i_sb;
-+	blocksize = 1 << inode->i_blkbits;
-+	blocks_per_page = PAGE_CACHE_SIZE / blocksize;
-+
-+	groups_per_page = blocks_per_page >> 1;
-+	if (groups_per_page == 0)
-+		groups_per_page = 1;
-+
-+	/* allocate buffer_heads to read bitmaps */
-+	if (groups_per_page > 1) {
-+		err = -ENOMEM;
-+		i = sizeof(struct buffer_head *) * groups_per_page;
-+		bh = kmalloc(i, GFP_NOFS);
-+		if (bh == NULL)
-+			goto out;
-+		memset(bh, 0, i);
-+	} else
-+		bh = &bhs;
-+
-+	first_group = page->index * blocks_per_page / 2;
-+
-+	/* read all groups the page covers into the cache */
-+	for (i = 0; i < groups_per_page; i++) {
-+		struct ext3_group_desc * desc;
-+
-+		if (first_group + i >= EXT3_SB(sb)->s_groups_count)
-+			break;
-+
-+		err = -EIO;
-+		desc = ext3_get_group_desc(sb, first_group + i, NULL);
-+		if (desc == NULL)
-+			goto out;
-+
-+		err = -ENOMEM;
-+		bh[i] = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap));
-+		if (bh[i] == NULL)
-+			goto out;
-+
-+		if (buffer_uptodate(bh[i]))
-+			continue;
-+
-+		lock_buffer(bh[i]);
-+		if (buffer_uptodate(bh[i])) {
-+			unlock_buffer(bh[i]);
-+			continue;
-+		}
-+
-+		get_bh(bh[i]);
-+		bh[i]->b_end_io = end_buffer_read_sync;
-+		submit_bh(READ, bh[i]);
-+		mb_debug("read bitmap for group %u\n", first_group + i);
-+	}
-+
-+	/* wait for I/O completion */
-+	for (i = 0; i < groups_per_page && bh[i]; i++)
-+		wait_on_buffer(bh[i]);
-+
-+	err = -EIO;
-+	for (i = 0; i < groups_per_page && bh[i]; i++)
-+		if (!buffer_uptodate(bh[i]))
-+			goto out;
-+
-+	first_block = page->index * blocks_per_page;
-+	for (i = 0; i < blocks_per_page; i++) {
-+		int group;
-+
-+		group = (first_block + i) >> 1;
-+		if (group >= EXT3_SB(sb)->s_groups_count)
-+			break;
-+
-+		data = page_address(page) + (i * blocksize);
-+		bitmap = bh[group - first_group]->b_data;
-+
-+		if ((first_block + i) & 1) {
-+			/* this is block of buddy */
-+			BUG_ON(incore == NULL);
-+			mb_debug("put buddy for group %u in page %lu/%x\n",
-+				group, page->index, i * blocksize);
-+			memset(data, 0xff, blocksize);
-+			EXT3_GROUP_INFO(sb, group)->bb_fragments = 0;
-+			memset(EXT3_GROUP_INFO(sb, group)->bb_counters, 0,
-+			       sizeof(unsigned short)*(sb->s_blocksize_bits+2));
-+			ext3_mb_generate_buddy(sb, data, incore, group);
-+			incore = NULL;
-+		} else {
-+			/* this is block of bitmap */
-+			BUG_ON(incore != NULL);
-+			mb_debug("put bitmap for group %u in page %lu/%x\n",
-+				group, page->index, i * blocksize);
-+
-+			/* see comments in ext3_mb_put_pa() */
-+			ext3_lock_group(sb, group);
-+			memcpy(data, bitmap, blocksize);
-+
-+			/* mark all preallocated blocks used in in-core bitmap */
-+			ext3_mb_generate_from_pa(sb, data, group);
-+			ext3_unlock_group(sb, group);
-+
-+			incore = data;
-+		}
-+	}
-+	SetPageUptodate(page);
-+
-+out:
-+	if (bh) {
-+		for (i = 0; i < groups_per_page && bh[i]; i++)
-+			brelse(bh[i]);
-+		if (bh != &bhs)
-+			kfree(bh);
-+	}
-+	return err;
-+}
-+
-+static int ext3_mb_load_buddy(struct super_block *sb, int group,
-+		struct ext3_buddy *e3b)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	struct inode *inode = sbi->s_buddy_cache;
-+	int blocks_per_page, block, pnum, poff;
-+	struct page *page;
-+
-+	mb_debug("load group %u\n", group);
-+
-+	blocks_per_page = PAGE_CACHE_SIZE / sb->s_blocksize;
-+
-+	e3b->bd_blkbits = sb->s_blocksize_bits;
-+	e3b->bd_info = EXT3_GROUP_INFO(sb, group);
-+	e3b->bd_sb = sb;
-+	e3b->bd_group = group;
-+	e3b->bd_buddy_page = NULL;
-+	e3b->bd_bitmap_page = NULL;
-+
-+	block = group * 2;
-+	pnum = block / blocks_per_page;
-+	poff = block % blocks_per_page;
-+
-+	/* we could use find_or_create_page(), but it locks page
-+	 * what we'd like to avoid in fast path ... */
-+	page = find_get_page(inode->i_mapping, pnum);
-+	if (page == NULL || !PageUptodate(page)) {
-+		if (page)
-+			page_cache_release(page);
-+		page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
-+		if (page) {
-+			BUG_ON(page->mapping != inode->i_mapping);
-+			if (!PageUptodate(page)) {
-+				ext3_mb_init_cache(page, NULL);
-+				mb_cmp_bitmaps(e3b, page_address(page) +
-+					       (poff * sb->s_blocksize));
-+			}
-+			unlock_page(page);
-+		}
-+	}
-+	if (page == NULL || !PageUptodate(page))
-+		goto err;
-+	e3b->bd_bitmap_page = page;
-+	e3b->bd_bitmap = page_address(page) + (poff * sb->s_blocksize);
-+	mark_page_accessed(page);
-+
-+	block++;
-+	pnum = block / blocks_per_page;
-+	poff = block % blocks_per_page;
-+
-+	page = find_get_page(inode->i_mapping, pnum);
-+	if (page == NULL || !PageUptodate(page)) {
-+		if (page)
-+			page_cache_release(page);
-+		page = find_or_create_page(inode->i_mapping, pnum, GFP_NOFS);
-+		if (page) {
-+			BUG_ON(page->mapping != inode->i_mapping);
-+			if (!PageUptodate(page))
-+				ext3_mb_init_cache(page, e3b->bd_bitmap);
-+
-+			unlock_page(page);
-+		}
-+	}
-+	if (page == NULL || !PageUptodate(page))
-+		goto err;
-+	e3b->bd_buddy_page = page;
-+	e3b->bd_buddy = page_address(page) + (poff * sb->s_blocksize);
-+	mark_page_accessed(page);
-+
-+	BUG_ON(e3b->bd_bitmap_page == NULL);
-+	BUG_ON(e3b->bd_buddy_page == NULL);
-+
-+	return 0;
-+
-+err:
-+	if (e3b->bd_bitmap_page)
-+		page_cache_release(e3b->bd_bitmap_page);
-+	if (e3b->bd_buddy_page)
-+		page_cache_release(e3b->bd_buddy_page);
-+	e3b->bd_buddy = NULL;
-+	e3b->bd_bitmap = NULL;
-+	return -EIO;
-+}
-+
-+static void ext3_mb_release_desc(struct ext3_buddy *e3b)
-+{
-+	if (e3b->bd_bitmap_page)
-+		page_cache_release(e3b->bd_bitmap_page);
-+	if (e3b->bd_buddy_page)
-+		page_cache_release(e3b->bd_buddy_page);
-+}
-+
-+
-+static int mb_find_order_for_block(struct ext3_buddy *e3b, int block)
-+{
-+	int order = 1;
-+	void *bb;
-+
-+	BUG_ON(EXT3_MB_BITMAP(e3b) == EXT3_MB_BUDDY(e3b));
-+	BUG_ON(block >= (1 << (e3b->bd_blkbits + 3)));
-+
-+	bb = EXT3_MB_BUDDY(e3b);
-+	while (order <= e3b->bd_blkbits + 1) {
-+		block = block >> 1;
-+		if (!mb_test_bit(block, bb)) {
-+			/* this block is part of buddy of order 'order' */
-+			return order;
-+		}
-+		bb += 1 << (e3b->bd_blkbits - order);
-+		order++;
-+	}
-+	return 0;
-+}
-+
-+static inline void mb_clear_bits(void *bm, int cur, int len)
-+{
-+	__u32 *addr;
-+
-+	len = cur + len;
-+	while (cur < len) {
-+		if ((cur & 31) == 0 && (len - cur) >= 32) {
-+			/* fast path: clear whole word at once */
-+			addr = bm + (cur >> 3);
-+			*addr = 0;
-+			cur += 32;
-+			continue;
-+		}
-+		mb_clear_bit_atomic(cur, bm);
-+		cur++;
-+	}
-+}
-+
-+static inline void mb_set_bits(void *bm, int cur, int len)
-+{
-+	__u32 *addr;
-+
-+	len = cur + len;
-+	while (cur < len) {
-+		if ((cur & 31) == 0 && (len - cur) >= 32) {
-+			/* fast path: clear whole word at once */
-+			addr = bm + (cur >> 3);
-+			*addr = 0xffffffff;
-+			cur += 32;
-+			continue;
-+		}
-+		mb_set_bit_atomic(cur, bm);
-+		cur++;
-+	}
-+}
-+
-+static int mb_free_blocks(struct ext3_buddy *e3b, int first, int count)
-+{
-+	int block = 0, max = 0, order;
-+	void *buddy, *buddy2;
-+
-+	BUG_ON(first + count > (e3b->bd_sb->s_blocksize << 3));
-+	BUG_ON(!ext3_is_group_locked(e3b->bd_sb, e3b->bd_group));
-+	mb_check_buddy(e3b);
-+	mb_free_blocks_double(e3b, first, count);
-+
-+	e3b->bd_info->bb_free += count;
-+	if (first < e3b->bd_info->bb_first_free)
-+		e3b->bd_info->bb_first_free = first;
-+
-+	/* let's maintain fragments counter */
-+	if (first != 0)
-+		block = !mb_test_bit(first - 1, EXT3_MB_BITMAP(e3b));
-+	if (first + count < EXT3_SB(e3b->bd_sb)->s_mb_maxs[0])
-+		max = !mb_test_bit(first + count, EXT3_MB_BITMAP(e3b));
-+	if (block && max)
-+		e3b->bd_info->bb_fragments--;
-+	else if (!block && !max)
-+		e3b->bd_info->bb_fragments++;
-+
-+	/* let's maintain buddy itself */
-+	while (count-- > 0) {
-+		block = first++;
-+		order = 0;
-+
-+		BUG_ON(!mb_test_bit(block, EXT3_MB_BITMAP(e3b)));
-+		mb_clear_bit(block, EXT3_MB_BITMAP(e3b));
-+		e3b->bd_info->bb_counters[order]++;
-+
-+		/* start of the buddy */
-+		buddy = mb_find_buddy(e3b, order, &max);
-+
-+		do {
-+			block &= ~1UL;
-+			if (mb_test_bit(block, buddy) ||
-+					mb_test_bit(block + 1, buddy))
-+				break;
-+
-+			/* both the buddies are free, try to coalesce them */
-+			buddy2 = mb_find_buddy(e3b, order + 1, &max);
-+
-+			if (!buddy2)
-+				break;
-+
-+			if (order > 0) {
-+				/* for special purposes, we don't set
-+				 * free bits in bitmap */
-+				mb_set_bit(block, buddy);
-+				mb_set_bit(block + 1, buddy);
-+			}
-+			e3b->bd_info->bb_counters[order]--;
-+			e3b->bd_info->bb_counters[order]--;
-+
-+			block = block >> 1;
-+			order++;
-+			e3b->bd_info->bb_counters[order]++;
-+
-+			mb_clear_bit(block, buddy2);
-+			buddy = buddy2;
-+		} while (1);
-+	}
-+	mb_check_buddy(e3b);
-+
-+	return 0;
-+}
-+
-+static int mb_find_extent(struct ext3_buddy *e3b, int order, int block,
-+				int needed, struct ext3_free_extent *ex)
-+{
-+	int next = block, max, ord;
-+	void *buddy;
-+
-+	BUG_ON(!ext3_is_group_locked(e3b->bd_sb, e3b->bd_group));
-+	BUG_ON(ex == NULL);
-+
-+	buddy = mb_find_buddy(e3b, order, &max);
-+	BUG_ON(buddy == NULL);
-+	BUG_ON(block >= max);
-+	if (mb_test_bit(block, buddy)) {
-+		ex->fe_len = 0;
-+		ex->fe_start = 0;
-+		ex->fe_group = 0;
-+		return 0;
-+	}
-+
-+	if (likely(order == 0)) {
-+		/* find actual order */
-+		order = mb_find_order_for_block(e3b, block);
-+		block = block >> order;
-+	}
-+
-+	ex->fe_len = 1 << order;
-+	ex->fe_start = block << order;
-+	ex->fe_group = e3b->bd_group;
-+
-+	/* calc difference from given start */
-+	next = next - ex->fe_start;
-+	ex->fe_len -= next;
-+	ex->fe_start += next;
-+
-+	while (needed > ex->fe_len && (buddy = mb_find_buddy(e3b, order, &max))) {
-+
-+		if (block + 1 >= max)
-+			break;
-+
-+		next = (block + 1) * (1 << order);
-+		if (mb_test_bit(next, EXT3_MB_BITMAP(e3b)))
-+			break;
-+
-+		ord = mb_find_order_for_block(e3b, next);
-+
-+		order = ord;
-+		block = next >> order;
-+		ex->fe_len += 1 << order;
-+	}
-+
-+	BUG_ON(ex->fe_start + ex->fe_len > (1 << (e3b->bd_blkbits + 3)));
-+	return ex->fe_len;
-+}
-+
-+static int mb_mark_used(struct ext3_buddy *e3b, struct ext3_free_extent *ex)
-+{
-+	int ord, mlen = 0, max = 0, cur;
-+	int start = ex->fe_start;
-+	int len = ex->fe_len;
-+	unsigned ret = 0;
-+	int len0 = len;
-+	void *buddy;
-+
-+	BUG_ON(start + len > (e3b->bd_sb->s_blocksize << 3));
-+	BUG_ON(e3b->bd_group != ex->fe_group);
-+	BUG_ON(!ext3_is_group_locked(e3b->bd_sb, e3b->bd_group));
-+	mb_check_buddy(e3b);
-+	mb_mark_used_double(e3b, start, len);
-+
-+	e3b->bd_info->bb_free -= len;
-+	if (e3b->bd_info->bb_first_free == start)
-+		e3b->bd_info->bb_first_free += len;
-+
-+	/* let's maintain fragments counter */
-+	if (start != 0)
-+		mlen = !mb_test_bit(start - 1, EXT3_MB_BITMAP(e3b));
-+	if (start + len < EXT3_SB(e3b->bd_sb)->s_mb_maxs[0])
-+		max = !mb_test_bit(start + len, EXT3_MB_BITMAP(e3b));
-+	if (mlen && max)
-+		e3b->bd_info->bb_fragments++;
-+	else if (!mlen && !max)
-+		e3b->bd_info->bb_fragments--;
-+
-+	/* let's maintain buddy itself */
-+	while (len) {
-+		ord = mb_find_order_for_block(e3b, start);
-+
-+		if (((start >> ord) << ord) == start && len >= (1 << ord)) {
-+			/* the whole chunk may be allocated at once! */
-+			mlen = 1 << ord;
-+			buddy = mb_find_buddy(e3b, ord, &max);
-+			BUG_ON((start >> ord) >= max);
-+			mb_set_bit(start >> ord, buddy);
-+			e3b->bd_info->bb_counters[ord]--;
-+			start += mlen;
-+			len -= mlen;
-+			BUG_ON(len < 0);
-+			continue;
-+		}
-+
-+		/* store for history */
-+		if (ret == 0)
-+			ret = len | (ord << 16);
-+
-+		/* we have to split large buddy */
-+		BUG_ON(ord <= 0);
-+		buddy = mb_find_buddy(e3b, ord, &max);
-+		mb_set_bit(start >> ord, buddy);
-+		e3b->bd_info->bb_counters[ord]--;
-+
-+		ord--;
-+		cur = (start >> ord) & ~1U;
-+		buddy = mb_find_buddy(e3b, ord, &max);
-+		mb_clear_bit(cur, buddy);
-+		mb_clear_bit(cur + 1, buddy);
-+		e3b->bd_info->bb_counters[ord]++;
-+		e3b->bd_info->bb_counters[ord]++;
-+	}
-+
-+	mb_set_bits(EXT3_MB_BITMAP(e3b), ex->fe_start, len0);
-+	mb_check_buddy(e3b);
-+
-+	return ret;
-+}
-+
-+/*
-+ * Must be called under group lock!
-+ */
-+static void ext3_mb_use_best_found(struct ext3_allocation_context *ac,
-+					struct ext3_buddy *e3b)
-+{
-+	unsigned long ret;
-+
-+	BUG_ON(ac->ac_b_ex.fe_group != e3b->bd_group);
-+	BUG_ON(ac->ac_status == AC_STATUS_FOUND);
-+
-+	ac->ac_b_ex.fe_len = min(ac->ac_b_ex.fe_len, ac->ac_g_ex.fe_len);
-+	ac->ac_b_ex.fe_logical = ac->ac_g_ex.fe_logical;
-+	ret = mb_mark_used(e3b, &ac->ac_b_ex);
-+
-+	/* preallocation can change ac_b_ex, thus we store actually
-+	 * allocated blocks for history */
-+	ac->ac_f_ex = ac->ac_b_ex;
-+
-+	ac->ac_status = AC_STATUS_FOUND;
-+	ac->ac_tail = ret & 0xffff;
-+	ac->ac_buddy = ret >> 16;
-+
-+	/* XXXXXXX: SUCH A HORRIBLE **CK */
-+	ac->ac_bitmap_page = e3b->bd_bitmap_page;
-+	get_page(ac->ac_bitmap_page);
-+	ac->ac_buddy_page = e3b->bd_buddy_page;
-+	get_page(ac->ac_buddy_page);
-+}
-+
-+/*
-+ * regular allocator, for general purposes allocation
-+ */
-+
-+void ext3_mb_check_limits(struct ext3_allocation_context *ac,
-+					struct ext3_buddy *e3b,
-+					int finish_group)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(ac->ac_sb);
-+	struct ext3_free_extent *bex = &ac->ac_b_ex;
-+	struct ext3_free_extent *gex = &ac->ac_g_ex;
-+	struct ext3_free_extent ex;
-+	int max;
-+
-+	/*
-+	 * We don't want to scan for a whole year
-+	 */
-+	if (ac->ac_found > sbi->s_mb_max_to_scan &&
-+			!(ac->ac_flags & EXT3_MB_HINT_FIRST)) {
-+		ac->ac_status = AC_STATUS_BREAK;
-+		return;
-+	}
-+
-+	/*
-+	 * Haven't found good chunk so far, let's continue
-+	 */
-+	if (bex->fe_len < gex->fe_len)
-+		return;
-+
-+	if ((finish_group || ac->ac_found > sbi->s_mb_min_to_scan)
-+			&& bex->fe_group == e3b->bd_group) {
-+		/* recheck chunk's availability - we don't know
-+		 * when it was found (within this lock-unlock
-+		 * period or not) */
-+		max = mb_find_extent(e3b, 0, bex->fe_start, gex->fe_len, &ex);
-+		if (max >= gex->fe_len) {
-+			ext3_mb_use_best_found(ac, e3b);
-+			return;
-+		}
-+	}
-+}
-+
-+/*
-+ * The routine checks whether found extent is good enough. If it is,
-+ * then the extent gets marked used and flag is set to the context
-+ * to stop scanning. Otherwise, the extent is compared with the
-+ * previous found extent and if new one is better, then it's stored
-+ * in the context. Later, the best found extent will be used, if
-+ * mballoc can't find good enough extent.
-+ *
-+ * FIXME: real allocation policy is to be designed yet!
-+ */
-+static void ext3_mb_measure_extent(struct ext3_allocation_context *ac,
-+					struct ext3_free_extent *ex,
-+					struct ext3_buddy *e3b)
-+{
-+	struct ext3_free_extent *bex = &ac->ac_b_ex;
-+	struct ext3_free_extent *gex = &ac->ac_g_ex;
-+
-+	BUG_ON(ex->fe_len <= 0);
-+	BUG_ON(ex->fe_len >= (1 << ac->ac_sb->s_blocksize_bits) * 8);
-+	BUG_ON(ex->fe_start >= (1 << ac->ac_sb->s_blocksize_bits) * 8);
-+	BUG_ON(ac->ac_status != AC_STATUS_CONTINUE);
-+
-+	ac->ac_found++;
-+
-+	/*
-+	 * The special case - take what you catch first
-+	 */
-+	if (unlikely(ac->ac_flags & EXT3_MB_HINT_FIRST)) {
-+		*bex = *ex;
-+		ext3_mb_use_best_found(ac, e3b);
-+		return;
-+	}
-+
-+	/*
-+	 * Let's check whether the chuck is good enough
-+	 */
-+	if (ex->fe_len == gex->fe_len) {
-+		*bex = *ex;
-+		ext3_mb_use_best_found(ac, e3b);
-+		return;
-+	}
-+
-+	/*
-+	 * If this is first found extent, just store it in the context
-+	 */
-+	if (bex->fe_len == 0) {
-+		*bex = *ex;
-+		return;
-+	}
-+
-+	/*
-+	 * If new found extent is better, store it in the context
-+	 */
-+	if (bex->fe_len < gex->fe_len) {
-+		/* if the request isn't satisfied, any found extent
-+		 * larger than previous best one is better */
-+		if (ex->fe_len > bex->fe_len)
-+			*bex = *ex;
-+	} else if (ex->fe_len > gex->fe_len) {
-+		/* if the request is satisfied, then we try to find
-+		 * an extent that still satisfy the request, but is
-+		 * smaller than previous one */
-+		*bex = *ex;
-+	}
-+
-+	ext3_mb_check_limits(ac, e3b, 0);
-+}
-+
-+static int ext3_mb_try_best_found(struct ext3_allocation_context *ac,
-+					struct ext3_buddy *e3b)
-+{
-+	struct ext3_free_extent ex = ac->ac_b_ex;
-+	int group = ex.fe_group, max, err;
-+
-+	BUG_ON(ex.fe_len <= 0);
-+	err = ext3_mb_load_buddy(ac->ac_sb, group, e3b);
-+	if (err)
-+		return err;
-+
-+	ext3_lock_group(ac->ac_sb, group);
-+	max = mb_find_extent(e3b, 0, ex.fe_start, ex.fe_len, &ex);
-+
-+	if (max > 0) {
-+		ac->ac_b_ex = ex;
-+		ext3_mb_use_best_found(ac, e3b);
-+	}
-+
-+	ext3_unlock_group(ac->ac_sb, group);
-+	ext3_mb_release_desc(e3b);
-+
-+	return 0;
-+}
-+
-+static int ext3_mb_find_by_goal(struct ext3_allocation_context *ac,
-+				struct ext3_buddy *e3b)
-+{
-+	int group = ac->ac_g_ex.fe_group, max, err;
-+	struct ext3_sb_info *sbi = EXT3_SB(ac->ac_sb);
-+	struct ext3_super_block *es = sbi->s_es;
-+	struct ext3_free_extent ex;
-+
-+	err = ext3_mb_load_buddy(ac->ac_sb, group, e3b);
-+	if (err)
-+		return err;
-+
-+	ext3_lock_group(ac->ac_sb, group);
-+	max = mb_find_extent(e3b, 0, ac->ac_g_ex.fe_start,
-+			     ac->ac_g_ex.fe_len, &ex);
-+
-+	if (max >= ac->ac_g_ex.fe_len && ac->ac_g_ex.fe_len == sbi->s_stripe) {
-+		unsigned long start;
-+		start = (e3b->bd_group * EXT3_BLOCKS_PER_GROUP(ac->ac_sb) +
-+			ex.fe_start + le32_to_cpu(es->s_first_data_block));
-+		if (start % sbi->s_stripe == 0) {
-+			ac->ac_found++;
-+			ac->ac_b_ex = ex;
-+			ext3_mb_use_best_found(ac, e3b);
-+		}
-+	} else if (max >= ac->ac_g_ex.fe_len) {
-+		BUG_ON(ex.fe_len <= 0);
-+		BUG_ON(ex.fe_group != ac->ac_g_ex.fe_group);
-+		BUG_ON(ex.fe_start != ac->ac_g_ex.fe_start);
-+		ac->ac_found++;
-+		ac->ac_b_ex = ex;
-+		ext3_mb_use_best_found(ac, e3b);
-+	} else if (max > 0 && (ac->ac_flags & EXT3_MB_HINT_MERGE)) {
-+		/* Sometimes, caller may want to merge even small
-+		 * number of blocks to an existing extent */
-+		BUG_ON(ex.fe_len <= 0);
-+		BUG_ON(ex.fe_group != ac->ac_g_ex.fe_group);
-+		BUG_ON(ex.fe_start != ac->ac_g_ex.fe_start);
-+		ac->ac_found++;
-+		ac->ac_b_ex = ex;
-+		ext3_mb_use_best_found(ac, e3b);
-+	}
-+	ext3_unlock_group(ac->ac_sb, group);
-+	ext3_mb_release_desc(e3b);
-+
-+	return 0;
-+}
-+
-+/*
-+ * The routine scans buddy structures (not bitmap!) from given order
-+ * to max order and tries to find big enough chunk to satisfy the req
-+ */
-+static void ext3_mb_simple_scan_group(struct ext3_allocation_context *ac,
-+					struct ext3_buddy *e3b)
-+{
-+	struct super_block *sb = ac->ac_sb;
-+	struct ext3_group_info *grp = e3b->bd_info;
-+	void *buddy;
-+	int i, k, max;
-+
-+	BUG_ON(ac->ac_2order <= 0);
-+	for (i = ac->ac_2order; i <= sb->s_blocksize_bits + 1; i++) {
-+		if (grp->bb_counters[i] == 0)
-+			continue;
-+
-+		buddy = mb_find_buddy(e3b, i, &max);
-+		BUG_ON(buddy == NULL);
-+
-+		k = mb_find_next_zero_bit(buddy, max, 0);
-+		BUG_ON(k >= max);
-+
-+		ac->ac_found++;
-+
-+		ac->ac_b_ex.fe_len = 1 << i;
-+		ac->ac_b_ex.fe_start = k << i;
-+		ac->ac_b_ex.fe_group = e3b->bd_group;
-+
-+		ext3_mb_use_best_found(ac, e3b);
-+
-+		BUG_ON(ac->ac_b_ex.fe_len != ac->ac_g_ex.fe_len);
-+
-+		if (EXT3_SB(sb)->s_mb_stats)
-+			atomic_inc(&EXT3_SB(sb)->s_bal_2orders);
-+
-+		break;
-+	}
-+}
-+
-+/*
-+ * The routine scans the group and measures all found extents.
-+ * In order to optimize scanning, caller must pass number of
-+ * free blocks in the group, so the routine can know upper limit.
-+ */
-+static void ext3_mb_complex_scan_group(struct ext3_allocation_context *ac,
-+					struct ext3_buddy *e3b)
-+{
-+	struct super_block *sb = ac->ac_sb;
-+	void *bitmap = EXT3_MB_BITMAP(e3b);
-+	struct ext3_free_extent ex;
-+	int i, free;
-+
-+	free = e3b->bd_info->bb_free;
-+	BUG_ON(free <= 0);
-+
-+	i = e3b->bd_info->bb_first_free;
-+
-+	while (free && ac->ac_status == AC_STATUS_CONTINUE) {
-+		i = mb_find_next_zero_bit(bitmap, sb->s_blocksize * 8, i);
-+		if (i >= sb->s_blocksize * 8) {
-+			BUG_ON(free != 0);
-+			break;
-+		}
-+
-+		mb_find_extent(e3b, 0, i, ac->ac_g_ex.fe_len, &ex);
-+		BUG_ON(ex.fe_len <= 0);
-+		BUG_ON(free < ex.fe_len);
-+
-+		ext3_mb_measure_extent(ac, &ex, e3b);
-+
-+		i += ex.fe_len;
-+		free -= ex.fe_len;
-+	}
-+
-+	ext3_mb_check_limits(ac, e3b, 1);
-+}
-+
-+/*
-+ * This is a special case for storages like raid5
-+ * we try to find stripe-aligned chunks for stripe-size requests
-+ */
-+static void ext3_mb_scan_aligned(struct ext3_allocation_context *ac,
-+				 struct ext3_buddy *e3b)
-+{
-+	struct super_block *sb = ac->ac_sb;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	void *bitmap = EXT3_MB_BITMAP(e3b);
-+	struct ext3_free_extent ex;
-+	unsigned long i, max;
-+
-+	BUG_ON(sbi->s_stripe == 0);
-+
-+	/* find first stripe-aligned block */
-+	i = e3b->bd_group * EXT3_BLOCKS_PER_GROUP(sb)
-+		+ le32_to_cpu(sbi->s_es->s_first_data_block);
-+	i = ((i + sbi->s_stripe - 1) / sbi->s_stripe) * sbi->s_stripe;
-+	i = (i - le32_to_cpu(sbi->s_es->s_first_data_block))
-+			% EXT3_BLOCKS_PER_GROUP(sb);
-+
-+	while (i < sb->s_blocksize * 8) {
-+		if (!mb_test_bit(i, bitmap)) {
-+			max = mb_find_extent(e3b, 0, i, sbi->s_stripe, &ex);
-+			if (max >= sbi->s_stripe) {
-+				ac->ac_found++;
-+				ac->ac_b_ex = ex;
-+				ext3_mb_use_best_found(ac, e3b);
-+				break;
-+			}
-+		}
-+		i += sbi->s_stripe;
-+	}
-+}
-+
-+static int ext3_mb_good_group(struct ext3_allocation_context *ac,
-+				int group, int cr)
-+{
-+	struct ext3_group_info *grp = EXT3_GROUP_INFO(ac->ac_sb, group);
-+	unsigned free, fragments, i, bits;
-+
-+	BUG_ON(cr < 0 || cr >= 4);
-+	BUG_ON(EXT3_MB_GRP_NEED_INIT(grp));
-+
-+	free = grp->bb_free;
-+	fragments = grp->bb_fragments;
-+	if (free == 0)
-+		return 0;
-+	if (fragments == 0)
-+		return 0;
-+
-+	switch (cr) {
-+		case 0:
-+			BUG_ON(ac->ac_2order == 0);
-+			bits = ac->ac_sb->s_blocksize_bits + 1;
-+			for (i = ac->ac_2order; i <= bits; i++)
-+				if (grp->bb_counters[i] > 0)
-+					return 1;
-+			break;
-+		case 1:
-+			if ((free / fragments) >= ac->ac_g_ex.fe_len)
-+				return 1;
-+			break;
-+		case 2:
-+			if (free >= ac->ac_g_ex.fe_len)
-+				return 1;
-+			break;
-+		case 3:
-+			return 1;
-+		default:
-+			BUG();
-+	}
-+
-+	return 0;
-+}
-+
-+int ext3_mb_regular_allocator(struct ext3_allocation_context *ac)
-+{
-+	int group, i, cr, err = 0;
-+	struct ext3_sb_info *sbi;
-+	struct super_block *sb;
-+	struct ext3_buddy e3b;
-+
-+	sb = ac->ac_sb;
-+	sbi = EXT3_SB(sb);
-+	BUG_ON(ac->ac_status == AC_STATUS_FOUND);
-+
-+	/* first, try the goal */
-+	err = ext3_mb_find_by_goal(ac, &e3b);
-+	if (err || ac->ac_status == AC_STATUS_FOUND)
-+		goto out;
-+
-+	if (unlikely(ac->ac_flags & EXT3_MB_HINT_GOAL_ONLY))
-+		goto out;
-+
-+	i = ffs(ac->ac_g_ex.fe_len);
-+	ac->ac_2order = 0;
-+	if (i >= sbi->s_mb_order2_reqs) {
-+		i--;
-+		if ((ac->ac_g_ex.fe_len & (~(1 << i))) == 0)
-+			ac->ac_2order = i;
-+	}
-+
-+	group = ac->ac_g_ex.fe_group;
-+
-+	/* Let's just scan groups to find more-less suitable blocks */
-+	cr = ac->ac_2order ? 0 : 1;
-+repeat:
-+	for (; cr < 4 && ac->ac_status == AC_STATUS_CONTINUE; cr++) {
-+		ac->ac_criteria = cr;
-+		for (i = 0; i < EXT3_SB(sb)->s_groups_count; group++, i++) {
-+			struct ext3_group_info *grp;
-+
-+			if (group == EXT3_SB(sb)->s_groups_count)
-+				group = 0;
-+
-+			/* quick check to skip empty groups */
-+			grp = EXT3_GROUP_INFO(ac->ac_sb, group);
-+			if (grp->bb_free == 0)
-+				continue;
-+
-+			if (EXT3_MB_GRP_NEED_INIT(EXT3_GROUP_INFO(sb, group))) {
-+				/* we need full data about the group
-+				 * to make a good selection */
-+				err = ext3_mb_load_buddy(sb, group, &e3b);
-+				if (err)
-+					goto out;
-+				ext3_mb_release_desc(&e3b);
-+			}
-+
-+			/* check is group good for our criteries */
-+			if (!ext3_mb_good_group(ac, group, cr))
-+				continue;
-+
-+			err = ext3_mb_load_buddy(sb, group, &e3b);
-+			if (err)
-+				goto out;
-+
-+			ext3_lock_group(sb, group);
-+			if (!ext3_mb_good_group(ac, group, cr)) {
-+				/* someone did allocation from this group */
-+				ext3_unlock_group(sb, group);
-+				ext3_mb_release_desc(&e3b);
-+				continue;
-+			}
-+
-+			ac->ac_groups_scanned++;
-+			if (cr == 0)
-+				ext3_mb_simple_scan_group(ac, &e3b);
-+			else if (cr == 1 && ac->ac_g_ex.fe_len == sbi->s_stripe)
-+				ext3_mb_scan_aligned(ac, &e3b);
-+			else
-+				ext3_mb_complex_scan_group(ac, &e3b);
-+
-+			ext3_unlock_group(sb, group);
-+			ext3_mb_release_desc(&e3b);
-+
-+			if (ac->ac_status != AC_STATUS_CONTINUE)
-+				break;
-+		}
-+	}
-+
-+	if (ac->ac_b_ex.fe_len > 0 && ac->ac_status != AC_STATUS_FOUND &&
-+	    !(ac->ac_flags & EXT3_MB_HINT_FIRST)) {
-+		/*
-+		 * We've been searching too long. Let's try to allocate
-+		 * the best chunk we've found so far
-+		 */
-+
-+		ext3_mb_try_best_found(ac, &e3b);
-+		if (ac->ac_status != AC_STATUS_FOUND) {
-+			/*
-+			 * Someone more lucky has already allocated it.
-+			 * The only thing we can do is just take first
-+			 * found block(s)
-+			printk(KERN_DEBUG "EXT3-fs: someone won our chunk\n");
-+			 */
-+			ac->ac_b_ex.fe_group = 0;
-+			ac->ac_b_ex.fe_start = 0;
-+			ac->ac_b_ex.fe_len = 0;
-+			ac->ac_status = AC_STATUS_CONTINUE;
-+			ac->ac_flags |= EXT3_MB_HINT_FIRST;
-+			cr = 3;
-+			atomic_inc(&sbi->s_mb_lost_chunks);
-+			goto repeat;
-+		}
-+	}
-+out:
-+	return err;
-+}
-+
-+#ifdef EXT3_MB_HISTORY
-+struct ext3_mb_proc_session {
-+	struct ext3_mb_history *history;
-+	struct super_block *sb;
-+	int start;
-+	int max;
-+};
-+
-+static void *ext3_mb_history_skip_empty(struct ext3_mb_proc_session *s,
-+					struct ext3_mb_history *hs,
-+					int first)
-+{
-+	if (hs == s->history + s->max)
-+		hs = s->history;
-+	if (!first && hs == s->history + s->start)
-+		return NULL;
-+	while (hs->orig.fe_len == 0) {
-+		hs++;
-+		if (hs == s->history + s->max)
-+			hs = s->history;
-+		if (hs == s->history + s->start)
-+			return NULL;
-+	}
-+	return hs;
-+}
-+
-+static void *ext3_mb_seq_history_start(struct seq_file *seq, loff_t *pos)
-+{
-+	struct ext3_mb_proc_session *s = seq->private;
-+	struct ext3_mb_history *hs;
-+	int l = *pos;
-+
-+	if (l == 0)
-+		return SEQ_START_TOKEN;
-+	hs = ext3_mb_history_skip_empty(s, s->history + s->start, 1);
-+	if (!hs)
-+		return NULL;
-+	while (--l && (hs = ext3_mb_history_skip_empty(s, ++hs, 0)) != NULL);
-+	return hs;
-+}
-+
-+static void *ext3_mb_seq_history_next(struct seq_file *seq, void *v, loff_t *pos)
-+{
-+	struct ext3_mb_proc_session *s = seq->private;
-+	struct ext3_mb_history *hs = v;
-+
-+	++*pos;
-+	if (v == SEQ_START_TOKEN)
-+		return ext3_mb_history_skip_empty(s, s->history + s->start, 1);
-+	else
-+		return ext3_mb_history_skip_empty(s, ++hs, 0);
-+}
-+
-+static int ext3_mb_seq_history_show(struct seq_file *seq, void *v)
-+{
-+	char buf[25], buf2[25], buf3[25], *fmt;
-+	struct ext3_mb_history *hs = v;
-+
-+	if (v == SEQ_START_TOKEN) {
-+		seq_printf(seq, "%-5s %-8s %-23s %-23s %-23s %-5s "
-+				"%-5s %-2s %-5s %-5s %-5s %-6s\n",
-+			   "pid", "inode", "original", "goal", "result","found",
-+			   "grps", "cr", "flags", "merge", "tail", "broken");
-+		return 0;
-+	}
-+
-+	if (hs->op == EXT3_MB_HISTORY_ALLOC) {
-+		fmt = "%-5u %-8u %-23s %-23s %-23s %-5u %-5u %-2u "
-+			"%-5u %-5s %-5u %-6u\n";
-+		sprintf(buf2, "%lu/%lu/%lu@%lu", hs->result.fe_group,
-+			hs->result.fe_start, hs->result.fe_len,
-+			hs->result.fe_logical);
-+		sprintf(buf, "%lu/%lu/%lu@%lu", hs->orig.fe_group,
-+			hs->orig.fe_start, hs->orig.fe_len,
-+			hs->orig.fe_logical);
-+		sprintf(buf3, "%lu/%lu/%lu@%lu", hs->goal.fe_group,
-+			hs->goal.fe_start, hs->goal.fe_len,
-+			hs->goal.fe_logical);
-+		seq_printf(seq, fmt, hs->pid, hs->ino, buf, buf3, buf2,
-+				hs->found, hs->groups, hs->cr, hs->flags,
-+				hs->merged ? "M" : "", hs->tail,
-+				hs->buddy ? 1 << hs->buddy : 0);
-+	} else if (hs->op == EXT3_MB_HISTORY_PREALLOC) {
-+		fmt = "%-5u %-8u %-23s %-23s %-23s\n";
-+		sprintf(buf2, "%lu/%lu/%lu@%lu", hs->result.fe_group,
-+			hs->result.fe_start, hs->result.fe_len,
-+			hs->result.fe_logical);
-+		sprintf(buf, "%lu/%lu/%lu@%lu", hs->orig.fe_group,
-+			hs->orig.fe_start, hs->orig.fe_len,
-+			hs->orig.fe_logical);
-+		seq_printf(seq, fmt, hs->pid, hs->ino, buf, "", buf2);
-+	} else if (hs->op == EXT3_MB_HISTORY_DISCARD) {
-+		sprintf(buf2, "%lu/%lu/%lu", hs->result.fe_group,
-+			hs->result.fe_start, hs->result.fe_len);
-+		seq_printf(seq, "%-5u %-8u %-23s discard\n",
-+				hs->pid, hs->ino, buf2);
-+	} else if (hs->op == EXT3_MB_HISTORY_FREE) {
-+		sprintf(buf2, "%lu/%lu/%lu", hs->result.fe_group,
-+			hs->result.fe_start, hs->result.fe_len);
-+		seq_printf(seq, "%-5u %-8u %-23s free\n",
-+				hs->pid, hs->ino, buf2);
-+	}
-+	return 0;
-+}
-+
-+static void ext3_mb_seq_history_stop(struct seq_file *seq, void *v)
-+{
-+}
-+
-+static struct seq_operations ext3_mb_seq_history_ops = {
-+	.start  = ext3_mb_seq_history_start,
-+	.next   = ext3_mb_seq_history_next,
-+	.stop   = ext3_mb_seq_history_stop,
-+	.show   = ext3_mb_seq_history_show,
-+};
-+
-+static int ext3_mb_seq_history_open(struct inode *inode, struct file *file)
-+{
-+	struct super_block *sb = PDE(inode)->data;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	struct ext3_mb_proc_session *s;
-+	int rc, size;
-+
-+	s = kmalloc(sizeof(*s), GFP_KERNEL);
-+	if (s == NULL)
-+		return -ENOMEM;
-+	s->sb = sb;
-+	size = sizeof(struct ext3_mb_history) * sbi->s_mb_history_max;
-+	s->history = kmalloc(size, GFP_KERNEL);
-+	if (s->history == NULL) {
-+		kfree(s);
-+		return -ENOMEM;
-+	}
-+
-+	spin_lock(&sbi->s_mb_history_lock);
-+	memcpy(s->history, sbi->s_mb_history, size);
-+	s->max = sbi->s_mb_history_max;
-+	s->start = sbi->s_mb_history_cur % s->max;
-+	spin_unlock(&sbi->s_mb_history_lock);
-+
-+	rc = seq_open(file, &ext3_mb_seq_history_ops);
-+	if (rc == 0) {
-+		struct seq_file *m = (struct seq_file *)file->private_data;
-+		m->private = s;
-+	} else {
-+		kfree(s->history);
-+		kfree(s);
-+	}
-+	return rc;
-+
-+}
-+
-+static int ext3_mb_seq_history_release(struct inode *inode, struct file *file)
-+{
-+	struct seq_file *seq = (struct seq_file *)file->private_data;
-+	struct ext3_mb_proc_session *s = seq->private;
-+	kfree(s->history);
-+	kfree(s);
-+	return seq_release(inode, file);
-+}
-+
-+static ssize_t ext3_mb_seq_history_write(struct file *file,
-+				const char __user *buffer,
-+				size_t count, loff_t *ppos)
-+{
-+	struct seq_file *seq = (struct seq_file *)file->private_data;
-+	struct ext3_mb_proc_session *s = seq->private;
-+	struct super_block *sb = s->sb;
-+	char str[32];
-+	int value;
-+
-+	if (count >= sizeof(str)) {
-+		printk(KERN_ERR "EXT3-fs: %s string too long, max %u bytes\n",
-+				"mb_history", (int)sizeof(str));
-+		return -EOVERFLOW;
-+	}
-+
-+	if (copy_from_user(str, buffer, count))
-+		return -EFAULT;
-+
-+	value = simple_strtol(str, NULL, 0);
-+	if (value < 0)
-+		return -ERANGE;
-+	EXT3_SB(sb)->s_mb_history_filter = value;
-+
-+	return count;
-+}
-+
-+static struct file_operations ext3_mb_seq_history_fops = {
-+	.owner		= THIS_MODULE,
-+	.open		= ext3_mb_seq_history_open,
-+	.read		= seq_read,
-+	.write		= ext3_mb_seq_history_write,
-+	.llseek		= seq_lseek,
-+	.release	= ext3_mb_seq_history_release,
-+};
-+
-+static void *ext3_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)
-+{
-+	struct super_block *sb = seq->private;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	long group;
-+
-+	if (*pos < 0 || *pos >= sbi->s_groups_count)
-+		return NULL;
-+
-+	group = *pos + 1;
-+	return (void *) group;
-+}
-+
-+static void *ext3_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos)
-+{
-+	struct super_block *sb = seq->private;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	long group;
-+
-+	++*pos;
-+	if (*pos < 0 || *pos >= sbi->s_groups_count)
-+		return NULL;
-+	group = *pos + 1;
-+	return (void *) group;;
-+}
-+
-+static int ext3_mb_seq_groups_show(struct seq_file *seq, void *v)
-+{
-+	struct super_block *sb = seq->private;
-+	long group = (long) v;
-+	int i, err;
-+	struct ext3_buddy e3b;
-+	struct sg {
-+		struct ext3_group_info info;
-+		unsigned short counters[16];
-+	} sg;
-+
-+	group--;
-+	if (group == 0)
-+		seq_printf(seq, "#%-5s: %-5s %-5s %-5s "
-+				"[ %-5s %-5s %-5s %-5s %-5s %-5s %-5s "
-+				  "%-5s %-5s %-5s %-5s %-5s %-5s %-5s ]\n",
-+			   "group", "free", "frags", "first",
-+			   "2^0", "2^1", "2^2", "2^3", "2^4", "2^5","2^6",
-+			   "2^7", "2^8", "2^9", "2^10", "2^11", "2^12", "2^13");
-+
-+	i = (sb->s_blocksize_bits + 2) * sizeof(sg.info.bb_counters[0]) +
-+		sizeof(struct ext3_group_info);
-+	err = ext3_mb_load_buddy(sb, group, &e3b);
-+	if (err) {
-+		seq_printf(seq, "#%-5lu: I/O error\n", group);
-+		return 0;
-+	}
-+	ext3_lock_group(sb, group);
-+	memcpy(&sg, EXT3_GROUP_INFO(sb, group), i);
-+	ext3_unlock_group(sb, group);
-+	ext3_mb_release_desc(&e3b);
-+
-+	seq_printf(seq, "#%-5lu: %-5u %-5u %-5u [", group, sg.info.bb_free,
-+			sg.info.bb_fragments, sg.info.bb_first_free);
-+	for (i = 0; i <= 13; i++)
-+		seq_printf(seq, " %-5u", i <= sb->s_blocksize_bits + 1 ?
-+				sg.info.bb_counters[i] : 0);
-+	seq_printf(seq, " ]\n");
-+
-+	return 0;
-+}
-+
-+static void ext3_mb_seq_groups_stop(struct seq_file *seq, void *v)
-+{
-+}
-+
-+static struct seq_operations ext3_mb_seq_groups_ops = {
-+	.start  = ext3_mb_seq_groups_start,
-+	.next   = ext3_mb_seq_groups_next,
-+	.stop   = ext3_mb_seq_groups_stop,
-+	.show   = ext3_mb_seq_groups_show,
-+};
-+
-+static int ext3_mb_seq_groups_open(struct inode *inode, struct file *file)
-+{
-+	struct super_block *sb = PDE(inode)->data;
-+	int rc;
-+
-+	rc = seq_open(file, &ext3_mb_seq_groups_ops);
-+	if (rc == 0) {
-+		struct seq_file *m = (struct seq_file *)file->private_data;
-+		m->private = sb;
-+	}
-+	return rc;
-+
-+}
-+
-+static struct file_operations ext3_mb_seq_groups_fops = {
-+	.owner		= THIS_MODULE,
-+	.open		= ext3_mb_seq_groups_open,
-+	.read		= seq_read,
-+	.llseek		= seq_lseek,
-+	.release	= seq_release,
-+};
-+
-+static void ext3_mb_history_release(struct super_block *sb)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+
-+	remove_proc_entry("mb_groups", sbi->s_mb_proc);
-+	remove_proc_entry("mb_history", sbi->s_mb_proc);
-+
-+	if (sbi->s_mb_history)
-+		kfree(sbi->s_mb_history);
-+}
-+
-+static void ext3_mb_history_init(struct super_block *sb)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	int i;
-+
-+	if (sbi->s_mb_proc != NULL) {
-+		struct proc_dir_entry *p;
-+		p = create_proc_entry("mb_history", S_IRUGO, sbi->s_mb_proc);
-+		if (p) {
-+			p->proc_fops = &ext3_mb_seq_history_fops;
-+			p->data = sb;
-+		}
-+		p = create_proc_entry("mb_groups", S_IRUGO, sbi->s_mb_proc);
-+		if (p) {
-+			p->proc_fops = &ext3_mb_seq_groups_fops;
-+			p->data = sb;
-+		}
-+	}
-+
-+	sbi->s_mb_history_max = 1000;
-+	sbi->s_mb_history_cur = 0;
-+	spin_lock_init(&sbi->s_mb_history_lock);
-+	i = sbi->s_mb_history_max * sizeof(struct ext3_mb_history);
-+	sbi->s_mb_history = kmalloc(i, GFP_KERNEL);
-+	memset(sbi->s_mb_history, 0, i);
-+	/* if we can't allocate history, then we simple won't use it */
-+}
-+
-+static void
-+ext3_mb_store_history(struct ext3_allocation_context *ac)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(ac->ac_sb);
-+	struct ext3_mb_history h;
-+
-+	if (likely(sbi->s_mb_history == NULL))
-+		return;
-+
-+	if (!(ac->ac_op & sbi->s_mb_history_filter))
-+		return;
-+
-+	h.op = ac->ac_op;
-+	h.pid = current->pid;
-+	h.ino = ac->ac_inode ? ac->ac_inode->i_ino : 0;
-+	h.orig = ac->ac_o_ex;
-+	h.result = ac->ac_b_ex;
-+	h.flags = ac->ac_flags;
-+	h.merged = 0;
-+	if (ac->ac_op == EXT3_MB_HISTORY_ALLOC) {
-+		if (ac->ac_g_ex.fe_start == ac->ac_b_ex.fe_start &&
-+				ac->ac_g_ex.fe_group == ac->ac_b_ex.fe_group)
-+			h.merged = 1;
-+		h.goal = ac->ac_g_ex;
-+		h.result = ac->ac_f_ex;
-+	}
-+
-+	spin_lock(&sbi->s_mb_history_lock);
-+	memcpy(sbi->s_mb_history + sbi->s_mb_history_cur, &h, sizeof(h));
-+	if (++sbi->s_mb_history_cur >= sbi->s_mb_history_max)
-+		sbi->s_mb_history_cur = 0;
-+	spin_unlock(&sbi->s_mb_history_lock);
-+}
-+
-+#else
-+#define ext3_mb_history_release(sb)
-+#define ext3_mb_history_init(sb)
-+#endif
-+
-+int ext3_mb_init_backend(struct super_block *sb)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	int i, j, len, metalen;
-+	int num_meta_group_infos =
-+		(sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) >>
-+			EXT3_DESC_PER_BLOCK_BITS(sb);
-+	struct ext3_group_info **meta_group_info;
-+
-+	/* An 8TB filesystem with 64-bit pointers requires a 4096 byte
-+	 * kmalloc. A 128kb malloc should suffice for a 256TB filesystem.
-+	 * So a two level scheme suffices for now. */
-+	sbi->s_group_info = kmalloc(sizeof(*sbi->s_group_info) *
-+				    num_meta_group_infos, GFP_KERNEL);
-+	if (sbi->s_group_info == NULL) {
-+		printk(KERN_ERR "EXT3-fs: can't allocate buddy meta group\n");
-+		return -ENOMEM;
-+	}
-+	sbi->s_buddy_cache = new_inode(sb);
-+	if (sbi->s_buddy_cache == NULL) {
-+		printk(KERN_ERR "EXT3-fs: can't get new inode\n");
-+		goto err_freesgi;
-+	}
-+	EXT3_I(sbi->s_buddy_cache)->i_disksize = 0;
-+
-+	metalen = sizeof(*meta_group_info) << EXT3_DESC_PER_BLOCK_BITS(sb);
-+	for (i = 0; i < num_meta_group_infos; i++) {
-+		if ((i + 1) == num_meta_group_infos)
-+			metalen = sizeof(*meta_group_info) *
-+				(sbi->s_groups_count -
-+					(i << EXT3_DESC_PER_BLOCK_BITS(sb)));
-+		meta_group_info = kmalloc(metalen, GFP_KERNEL);
-+		if (meta_group_info == NULL) {
-+			printk(KERN_ERR "EXT3-fs: can't allocate mem for a "
-+			       "buddy group\n");
-+			goto err_freemeta;
-+		}
-+		sbi->s_group_info[i] = meta_group_info;
-+	}
-+
-+	/*
-+	 * calculate needed size. if change bb_counters size,
-+	 * don't forget about ext3_mb_generate_buddy()
-+	 */
-+	len = sizeof(struct ext3_group_info);
-+	len += sizeof(unsigned short) * (sb->s_blocksize_bits + 2);
-+	for (i = 0; i < sbi->s_groups_count; i++) {
-+		struct ext3_group_desc * desc;
-+
-+		meta_group_info =
-+			sbi->s_group_info[i >> EXT3_DESC_PER_BLOCK_BITS(sb)];
-+		j = i & (EXT3_DESC_PER_BLOCK(sb) - 1);
-+
-+		meta_group_info[j] = kmalloc(len, GFP_KERNEL);
-+		if (meta_group_info[j] == NULL) {
-+			printk(KERN_ERR "EXT3-fs: can't allocate buddy mem\n");
-+			i--;
-+			goto err_freebuddy;
-+		}
-+		desc = ext3_get_group_desc(sb, i, NULL);
-+		if (desc == NULL) {
-+			printk(KERN_ERR"EXT3-fs: can't read descriptor %u\n",i);
-+			goto err_freebuddy;
-+		}
-+		memset(meta_group_info[j], 0, len);
-+		set_bit(EXT3_GROUP_INFO_NEED_INIT_BIT,
-+			&meta_group_info[j]->bb_state);
-+
-+		/* initialize bb_free to be able to skip
-+		 * empty groups without initialization */
-+		meta_group_info[j]->bb_free =
-+			le16_to_cpu(desc->bg_free_blocks_count);
-+
-+		INIT_LIST_HEAD(&meta_group_info[j]->bb_prealloc_list);
-+
-+#ifdef DOUBLE_CHECK
-+		{
-+			struct buffer_head *bh;
-+			meta_group_info[j]->bb_bitmap =
-+				kmalloc(sb->s_blocksize, GFP_KERNEL);
-+			BUG_ON(meta_group_info[j]->bb_bitmap == NULL);
-+			bh = read_block_bitmap(sb, i);
-+			BUG_ON(bh == NULL);
-+			memcpy(meta_group_info[j]->bb_bitmap, bh->b_data,
-+					sb->s_blocksize);
-+			brelse(bh);
-+		}
-+#endif
-+
-+	}
-+
-+	return 0;
-+
-+err_freebuddy:
-+	while (i >= 0) {
-+		kfree(EXT3_GROUP_INFO(sb, i));
-+		i--;
-+	}
-+	i = num_meta_group_infos;
-+err_freemeta:
-+	while (--i >= 0)
-+		kfree(sbi->s_group_info[i]);
-+	iput(sbi->s_buddy_cache);
-+err_freesgi:
-+	kfree(sbi->s_group_info);
-+	return -ENOMEM;
-+}
-+
-+int ext3_mb_init(struct super_block *sb, int needs_recovery)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	unsigned i, offset, max;
-+
-+	if (!test_opt(sb, MBALLOC))
-+		return 0;
-+
-+	i = (sb->s_blocksize_bits + 2) * sizeof(unsigned short);
-+
-+	sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL);
-+	if (sbi->s_mb_offsets == NULL) {
-+		clear_opt(sbi->s_mount_opt, MBALLOC);
-+		return -ENOMEM;
-+	}
-+	sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL);
-+	if (sbi->s_mb_maxs == NULL) {
-+		clear_opt(sbi->s_mount_opt, MBALLOC);
-+		kfree(sbi->s_mb_maxs);
-+		return -ENOMEM;
-+	}
-+
-+	/* order 0 is regular bitmap */
-+	sbi->s_mb_maxs[0] = sb->s_blocksize << 3;
-+	sbi->s_mb_offsets[0] = 0;
-+
-+	i = 1;
-+	offset = 0;
-+	max = sb->s_blocksize << 2;
-+	do {
-+		sbi->s_mb_offsets[i] = offset;
-+		sbi->s_mb_maxs[i] = max;
-+		offset += 1 << (sb->s_blocksize_bits - i);
-+		max = max >> 1;
-+		i++;
-+	} while (i <= sb->s_blocksize_bits + 1);
-+
-+	/* init file for buddy data */
-+	if ((i = ext3_mb_init_backend(sb))) {
-+		clear_opt(sbi->s_mount_opt, MBALLOC);
-+		kfree(sbi->s_mb_offsets);
-+		kfree(sbi->s_mb_maxs);
-+		return i;
-+	}
-+
-+	spin_lock_init(&sbi->s_md_lock);
-+	INIT_LIST_HEAD(&sbi->s_active_transaction);
-+	INIT_LIST_HEAD(&sbi->s_closed_transaction);
-+	INIT_LIST_HEAD(&sbi->s_committed_transaction);
-+	spin_lock_init(&sbi->s_bal_lock);
-+
-+	sbi->s_mb_max_to_scan = MB_DEFAULT_MAX_TO_SCAN;
-+	sbi->s_mb_min_to_scan = MB_DEFAULT_MIN_TO_SCAN;
-+	sbi->s_mb_max_groups_to_scan = MB_DEFAULT_MAX_GROUPS_TO_SCAN;
-+	sbi->s_mb_stats = MB_DEFAULT_STATS;
-+	sbi->s_mb_stream_request = MB_DEFAULT_STREAM_THRESHOLD;
-+	sbi->s_mb_order2_reqs = MB_DEFAULT_ORDER2_REQS;
-+	sbi->s_mb_history_filter = EXT3_MB_HISTORY_DEFAULT;
-+
-+	i = sizeof(struct ext3_locality_group) * NR_CPUS;
-+	sbi->s_locality_groups = kmalloc(i, GFP_NOFS);
-+	if (sbi->s_locality_groups == NULL) {
-+		clear_opt(sbi->s_mount_opt, MBALLOC);
-+		kfree(sbi->s_mb_offsets);
-+		kfree(sbi->s_mb_maxs);
-+		return -ENOMEM;
-+	}
-+	for (i = 0; i < NR_CPUS; i++) {
-+		struct ext3_locality_group *lg;
-+		lg = &sbi->s_locality_groups[i];
-+		sema_init(&lg->lg_sem, 1);
-+		INIT_LIST_HEAD(&lg->lg_prealloc_list);
-+		spin_lock_init(&lg->lg_prealloc_lock);
-+	}
-+
-+	ext3_mb_init_per_dev_proc(sb);
-+	ext3_mb_history_init(sb);
-+
-+	printk("EXT3-fs: mballoc enabled\n");
-+	return 0;
-+}
-+
-+void ext3_mb_cleanup_pa(struct ext3_group_info *grp)
-+{
-+	struct ext3_prealloc_space *pa;
-+	struct list_head *cur, *tmp;
-+	int count = 0;
-+
-+	list_for_each_safe(cur, tmp, &grp->bb_prealloc_list) {
-+		pa = list_entry(cur, struct ext3_prealloc_space, pa_group_list);
-+		list_del_rcu(&pa->pa_group_list);
-+		count++;
-+		kfree(pa);
-+	}
-+	if (count)
-+		mb_debug("mballoc: %u PAs left\n", count);
-+
-+}
-+
-+int ext3_mb_release(struct super_block *sb)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	int i, num_meta_group_infos;
-+
-+	if (!test_opt(sb, MBALLOC))
-+		return 0;
-+
-+	/* release freed, non-committed blocks */
-+	spin_lock(&sbi->s_md_lock);
-+	list_splice_init(&sbi->s_closed_transaction,
-+			&sbi->s_committed_transaction);
-+	list_splice_init(&sbi->s_active_transaction,
-+			&sbi->s_committed_transaction);
-+	spin_unlock(&sbi->s_md_lock);
-+	ext3_mb_free_committed_blocks(sb);
-+
-+	if (sbi->s_group_info) {
-+		for (i = 0; i < sbi->s_groups_count; i++) {
-+#ifdef DOUBLE_CHECK
-+			if (EXT3_GROUP_INFO(sb, i)->bb_bitmap)
-+				kfree(EXT3_GROUP_INFO(sb, i)->bb_bitmap);
-+#endif
-+			ext3_mb_cleanup_pa(EXT3_GROUP_INFO(sb, i));
-+			kfree(EXT3_GROUP_INFO(sb, i));
-+		}
-+		num_meta_group_infos = (sbi->s_groups_count +
-+				EXT3_DESC_PER_BLOCK(sb) - 1) >>
-+			EXT3_DESC_PER_BLOCK_BITS(sb);
-+		for (i = 0; i < num_meta_group_infos; i++)
-+			kfree(sbi->s_group_info[i]);
-+		kfree(sbi->s_group_info);
-+	}
-+	if (sbi->s_mb_offsets)
-+		kfree(sbi->s_mb_offsets);
-+	if (sbi->s_mb_maxs)
-+		kfree(sbi->s_mb_maxs);
-+	if (sbi->s_buddy_cache)
-+		iput(sbi->s_buddy_cache);
-+	if (sbi->s_mb_stats) {
-+		printk("EXT3-fs: mballoc: %u blocks %u reqs (%u success)\n",
-+				atomic_read(&sbi->s_bal_allocated),
-+				atomic_read(&sbi->s_bal_reqs),
-+				atomic_read(&sbi->s_bal_success));
-+		printk("EXT3-fs: mballoc: %u extents scanned, %u goal hits, "
-+				"%u 2^N hits, %u breaks, %u lost\n",
-+				atomic_read(&sbi->s_bal_ex_scanned),
-+				atomic_read(&sbi->s_bal_goals),
-+				atomic_read(&sbi->s_bal_2orders),
-+				atomic_read(&sbi->s_bal_breaks),
-+				atomic_read(&sbi->s_mb_lost_chunks));
-+		printk("EXT3-fs: mballoc: %lu generated and it took %Lu\n",
-+				sbi->s_mb_buddies_generated++,
-+				sbi->s_mb_generation_time);
-+		printk("EXT3-fs: mballoc: %u preallocated, %u discarded\n",
-+				atomic_read(&sbi->s_mb_preallocated),
-+				atomic_read(&sbi->s_mb_discarded));
-+	}
-+
-+	if (sbi->s_locality_groups)
-+		kfree(sbi->s_locality_groups);
-+
-+	ext3_mb_history_release(sb);
-+	ext3_mb_destroy_per_dev_proc(sb);
-+
-+	return 0;
-+}
-+
-+void ext3_mb_free_committed_blocks(struct super_block *sb)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	int err, i, count = 0, count2 = 0;
-+	struct ext3_free_metadata *md;
-+	struct ext3_buddy e3b;
-+
-+	if (list_empty(&sbi->s_committed_transaction))
-+		return;
-+
-+	/* there is committed blocks to be freed yet */
-+	do {
-+		/* get next array of blocks */
-+		md = NULL;
-+		spin_lock(&sbi->s_md_lock);
-+		if (!list_empty(&sbi->s_committed_transaction)) {
-+			md = list_entry(sbi->s_committed_transaction.next,
-+					struct ext3_free_metadata, list);
-+			list_del(&md->list);
-+		}
-+		spin_unlock(&sbi->s_md_lock);
-+
-+		if (md == NULL)
-+			break;
-+
-+		mb_debug("gonna free %u blocks in group %u (0x%p):",
-+				md->num, md->group, md);
-+
-+		err = ext3_mb_load_buddy(sb, md->group, &e3b);
-+		/* we expect to find existing buddy because it's pinned */
-+		BUG_ON(err != 0);
-+
-+		/* there are blocks to put in buddy to make them really free */
-+		count += md->num;
-+		count2++;
-+		ext3_lock_group(sb, md->group);
-+		for (i = 0; i < md->num; i++) {
-+			mb_debug(" %u", md->blocks[i]);
-+			err = mb_free_blocks(&e3b, md->blocks[i], 1);
-+			BUG_ON(err != 0);
-+		}
-+		mb_debug("\n");
-+		ext3_unlock_group(sb, md->group);
-+
-+		/* balance refcounts from ext3_mb_free_metadata() */
-+		page_cache_release(e3b.bd_buddy_page);
-+		page_cache_release(e3b.bd_bitmap_page);
-+
-+		kfree(md);
-+		ext3_mb_release_desc(&e3b);
-+
-+	} while (md);
-+
-+	mb_debug("freed %u blocks in %u structures\n", count, count2);
-+}
-+
-+#define EXT3_ROOT			"ext3"
-+#define EXT3_MB_STATS_NAME		"stats"
-+#define EXT3_MB_MAX_TO_SCAN_NAME	"max_to_scan"
-+#define EXT3_MB_MIN_TO_SCAN_NAME	"min_to_scan"
-+#define EXT3_MB_ORDER2_REQ		"order2_req"
-+#define EXT3_MB_STREAM_REQ		"stream_req"
-+
-+static int ext3_mb_stats_read(char *page, char **start, off_t off,
-+		int count, int *eof, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	int len;
-+
-+	*eof = 1;
-+	if (off != 0)
-+		return 0;
-+
-+	len = sprintf(page, "%ld\n", sbi->s_mb_stats);
-+	*start = page;
-+	return len;
-+}
-+
-+static int ext3_mb_stats_write(struct file *file, const char *buffer,
-+		unsigned long count, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	char str[32];
-+
-+	if (count >= sizeof(str)) {
-+		printk(KERN_ERR "EXT3-fs: %s string too long, max %u bytes\n",
-+				EXT3_MB_STATS_NAME, (int)sizeof(str));
-+		return -EOVERFLOW;
-+	}
-+
-+	if (copy_from_user(str, buffer, count))
-+		return -EFAULT;
-+
-+	/* Only set to 0 or 1 respectively; zero->0; non-zero->1 */
-+	sbi->s_mb_stats = (simple_strtol(str, NULL, 0) != 0);
-+	return count;
-+}
-+
-+static int ext3_mb_max_to_scan_read(char *page, char **start, off_t off,
-+		int count, int *eof, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	int len;
-+
-+	*eof = 1;
-+	if (off != 0)
-+		return 0;
-+
-+	len = sprintf(page, "%ld\n", sbi->s_mb_max_to_scan);
-+	*start = page;
-+	return len;
-+}
-+
-+static int ext3_mb_max_to_scan_write(struct file *file, const char *buffer,
-+		unsigned long count, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	char str[32];
-+	long value;
-+
-+	if (count >= sizeof(str)) {
-+		printk(KERN_ERR "EXT3-fs: %s string too long, max %u bytes\n",
-+				EXT3_MB_MAX_TO_SCAN_NAME, (int)sizeof(str));
-+		return -EOVERFLOW;
-+	}
-+
-+	if (copy_from_user(str, buffer, count))
-+		return -EFAULT;
-+
-+	/* Only set to 0 or 1 respectively; zero->0; non-zero->1 */
-+	value = simple_strtol(str, NULL, 0);
-+	if (value <= 0)
-+		return -ERANGE;
-+
-+	sbi->s_mb_max_to_scan = value;
-+
-+	return count;
-+}
-+
-+static int ext3_mb_min_to_scan_read(char *page, char **start, off_t off,
-+		int count, int *eof, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	int len;
-+
-+	*eof = 1;
-+	if (off != 0)
-+		return 0;
-+
-+	len = sprintf(page, "%ld\n", sbi->s_mb_min_to_scan);
-+	*start = page;
-+	return len;
-+}
-+
-+static int ext3_mb_order2_req_write(struct file *file, const char *buffer,
-+		unsigned long count, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	char str[32];
-+	long value;
-+
-+	if (count >= sizeof(str)) {
-+		printk(KERN_ERR "EXT3-fs: %s string too long, max %u bytes\n",
-+				EXT3_MB_MIN_TO_SCAN_NAME, (int)sizeof(str));
-+		return -EOVERFLOW;
-+	}
-+
-+	if (copy_from_user(str, buffer, count))
-+		return -EFAULT;
-+
-+	/* Only set to 0 or 1 respectively; zero->0; non-zero->1 */
-+	value = simple_strtol(str, NULL, 0);
-+	if (value <= 0)
-+		return -ERANGE;
-+
-+	sbi->s_mb_order2_reqs = value;
-+
-+	return count;
-+}
-+
-+static int ext3_mb_order2_req_read(char *page, char **start, off_t off,
-+		int count, int *eof, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	int len;
-+
-+	*eof = 1;
-+	if (off != 0)
-+		return 0;
-+
-+	len = sprintf(page, "%ld\n", sbi->s_mb_order2_reqs);
-+	*start = page;
-+	return len;
-+}
-+
-+static int ext3_mb_min_to_scan_write(struct file *file, const char *buffer,
-+		unsigned long count, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	char str[32];
-+	long value;
-+
-+	if (count >= sizeof(str)) {
-+		printk(KERN_ERR "EXT3-fs: %s string too long, max %u bytes\n",
-+				EXT3_MB_MIN_TO_SCAN_NAME, (int)sizeof(str));
-+		return -EOVERFLOW;
-+	}
-+
-+	if (copy_from_user(str, buffer, count))
-+		return -EFAULT;
-+
-+	/* Only set to 0 or 1 respectively; zero->0; non-zero->1 */
-+	value = simple_strtol(str, NULL, 0);
-+	if (value <= 0)
-+		return -ERANGE;
-+
-+	sbi->s_mb_min_to_scan = value;
-+
-+	return count;
-+}
-+
-+static int ext3_mb_stream_req_read(char *page, char **start, off_t off,
-+		int count, int *eof, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	int len;
-+
-+	*eof = 1;
-+	if (off != 0)
-+		return 0;
-+
-+	len = sprintf(page, "%ld\n", sbi->s_mb_stream_request);
-+	*start = page;
-+	return len;
-+}
-+
-+static int ext3_mb_stream_req_write(struct file *file, const char *buffer,
-+		unsigned long count, void *data)
-+{
-+	struct ext3_sb_info *sbi = data;
-+	char str[32];
-+	long value;
-+
-+	if (count >= sizeof(str)) {
-+		printk(KERN_ERR "EXT3-fs: %s string too long, max %u bytes\n",
-+				EXT3_MB_STREAM_REQ, (int)sizeof(str));
-+		return -EOVERFLOW;
-+	}
-+
-+	if (copy_from_user(str, buffer, count))
-+		return -EFAULT;
-+
-+	/* Only set to 0 or 1 respectively; zero->0; non-zero->1 */
-+	value = simple_strtol(str, NULL, 0);
-+	if (value <= 0)
-+		return -ERANGE;
-+
-+	sbi->s_mb_stream_request = value;
-+
-+	return count;
-+}
-+
-+int ext3_mb_init_per_dev_proc(struct super_block *sb)
-+{
-+	mode_t mode = S_IFREG | S_IRUGO | S_IWUSR;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	struct proc_dir_entry *proc;
-+	char devname[64], *name;
-+
-+	snprintf(devname, sizeof(devname) - 1, "%s",
-+		bdevname(sb->s_bdev, devname));
-+	sbi->s_mb_proc = proc_mkdir(devname, proc_root_ext3);
-+
-+	name = EXT3_MB_STATS_NAME;
-+	proc = create_proc_entry(name, mode, sbi->s_mb_proc);
-+	if (proc == NULL)
-+		goto err_out;
-+	proc->data = sbi;
-+	proc->read_proc  = ext3_mb_stats_read;
-+	proc->write_proc = ext3_mb_stats_write;
-+
-+	name = EXT3_MB_MAX_TO_SCAN_NAME;
-+	proc = create_proc_entry(name, mode, sbi->s_mb_proc);
-+	if (proc == NULL)
-+		goto err_out;
-+	proc->data = sbi;
-+	proc->read_proc  = ext3_mb_max_to_scan_read;
-+	proc->write_proc = ext3_mb_max_to_scan_write;
-+
-+	name = EXT3_MB_MIN_TO_SCAN_NAME;
-+	proc = create_proc_entry(name, mode, sbi->s_mb_proc);
-+	if (proc == NULL)
-+		goto err_out;
-+	proc->data = sbi;
-+	proc->read_proc  = ext3_mb_min_to_scan_read;
-+	proc->write_proc = ext3_mb_min_to_scan_write;
-+
-+	name = EXT3_MB_ORDER2_REQ;
-+	proc = create_proc_entry(name, mode, sbi->s_mb_proc);
-+	if (proc == NULL)
-+		goto err_out;
-+	proc->data = sbi;
-+	proc->read_proc  = ext3_mb_order2_req_read;
-+	proc->write_proc = ext3_mb_order2_req_write;
-+
-+	name = EXT3_MB_STREAM_REQ;
-+	proc = create_proc_entry(name, mode, sbi->s_mb_proc);
-+	if (proc == NULL)
-+		goto err_out;
-+	proc->data = sbi;
-+	proc->read_proc  = ext3_mb_stream_req_read;
-+	proc->write_proc = ext3_mb_stream_req_write;
-+
-+	return 0;
-+
-+err_out:
-+	printk(KERN_ERR "EXT3-fs: Unable to create %s\n", name);
-+	remove_proc_entry(EXT3_MB_STREAM_REQ, sbi->s_mb_proc);
-+	remove_proc_entry(EXT3_MB_ORDER2_REQ, sbi->s_mb_proc);
-+	remove_proc_entry(EXT3_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc);
-+	remove_proc_entry(EXT3_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc);
-+	remove_proc_entry(EXT3_MB_STATS_NAME, sbi->s_mb_proc);
-+	remove_proc_entry(devname, proc_root_ext3);
-+	sbi->s_mb_proc = NULL;
-+
-+	return -ENOMEM;
-+}
-+
-+int ext3_mb_destroy_per_dev_proc(struct super_block *sb)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	char devname[64];
-+
-+	if (sbi->s_mb_proc == NULL)
-+		return -EINVAL;
-+
-+	snprintf(devname, sizeof(devname) - 1, "%s",
-+		bdevname(sb->s_bdev, devname));
-+	remove_proc_entry(EXT3_MB_STREAM_REQ, sbi->s_mb_proc);
-+	remove_proc_entry(EXT3_MB_ORDER2_REQ, sbi->s_mb_proc);
-+	remove_proc_entry(EXT3_MB_MIN_TO_SCAN_NAME, sbi->s_mb_proc);
-+	remove_proc_entry(EXT3_MB_MAX_TO_SCAN_NAME, sbi->s_mb_proc);
-+	remove_proc_entry(EXT3_MB_STATS_NAME, sbi->s_mb_proc);
-+	remove_proc_entry(devname, proc_root_ext3);
-+
-+	return 0;
-+}
-+
-+int __init init_ext3_proc(void)
-+{
-+	ext3_pspace_cachep =
-+		kmem_cache_create("ext3_prealloc_space",
-+				     sizeof(struct ext3_prealloc_space),
-+				     0, SLAB_RECLAIM_ACCOUNT, NULL, NULL);
-+	if (ext3_pspace_cachep == NULL)
-+		return -ENOMEM;
-+
-+	proc_root_ext3 = proc_mkdir(EXT3_ROOT, proc_root_fs);
-+	if (proc_root_ext3 == NULL)
-+		printk(KERN_ERR "EXT3-fs: Unable to create %s\n", EXT3_ROOT);
-+
-+	return 0;
-+}
-+
-+void exit_ext3_proc(void)
-+{
-+	/* XXX: synchronize_rcu(); */
-+	kmem_cache_destroy(ext3_pspace_cachep);
-+	remove_proc_entry(EXT3_ROOT, proc_root_fs);
-+}
-+
-+
-+/*
-+ * Check quota and mark choosed space (ac->ac_b_ex) non-free in bitmaps
-+ * Returns 0 if success or error code
-+ */
-+int ext3_mb_mark_diskspace_used(struct ext3_allocation_context *ac, handle_t *handle)
-+{
-+	struct buffer_head *bitmap_bh = NULL;
-+	struct ext3_super_block *es;
-+	struct ext3_group_desc *gdp;
-+	struct buffer_head *gdp_bh;
-+	struct ext3_sb_info *sbi;
-+	struct super_block *sb;
-+	sector_t block;
-+	int len, err;
-+
-+	BUG_ON(ac->ac_status != AC_STATUS_FOUND);
-+	BUG_ON(ac->ac_b_ex.fe_len <= 0);
-+
-+	sb = ac->ac_sb;
-+	sbi = EXT3_SB(sb);
-+	es = sbi->s_es;
-+
-+	ext3_debug("using block group %d(%d)\n", ac->ac_b_group.group,
-+			gdp->bg_free_blocks_count);
-+
-+	/* time to check quota, we can't do this before because
-+	 * having quota spent on preallocated-unused-yet blocks
-+	 * would be wrong */
-+	len = ac->ac_b_ex.fe_len;
-+	while (len && DQUOT_ALLOC_BLOCK(ac->ac_inode, len)) len--;
-+	if (ac->ac_b_ex.fe_len != len) {
-+		/* some blocks can't be allocated due to quota
-+		 * we have to return them back */
-+		BUG();
-+	}
-+	err = -EDQUOT;
-+	if (len == 0)
-+		goto out_err;
-+
-+	err = -EIO;
-+	bitmap_bh = read_block_bitmap(sb, ac->ac_b_ex.fe_group);
-+	if (!bitmap_bh)
-+		goto out_err;
-+
-+	err = ext3_journal_get_write_access(handle, bitmap_bh);
-+	if (err)
-+		goto out_err;
-+
-+	err = -EIO;
-+	gdp = ext3_get_group_desc(sb, ac->ac_b_ex.fe_group, &gdp_bh);
-+	if (!gdp)
-+		goto out_err;
-+
-+	err = ext3_journal_get_write_access(handle, gdp_bh);
-+	if (err)
-+		goto out_err;
-+
-+	block = ac->ac_b_ex.fe_group * EXT3_BLOCKS_PER_GROUP(sb)
-+		+ ac->ac_b_ex.fe_start
-+		+ le32_to_cpu(es->s_first_data_block);
-+
-+	if (block == le32_to_cpu(gdp->bg_block_bitmap) ||
-+			block == le32_to_cpu(gdp->bg_inode_bitmap) ||
-+			in_range(block, le32_to_cpu(gdp->bg_inode_table),
-+				EXT3_SB(sb)->s_itb_per_group))
-+		ext3_error(sb, __FUNCTION__,
-+			   "Allocating block in system zone - block = %lu",
-+			   (unsigned long) block);
-+#ifdef AGGRESSIVE_CHECK
-+	{
-+		int i;
-+		for (i = 0; i < ac->ac_b_ex.fe_len; i++) {
-+			BUG_ON(mb_test_bit(ac->ac_b_ex.fe_start + i,
-+						bitmap_bh->b_data));
-+		}
-+	}
-+#endif
-+	mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len);
-+
-+	spin_lock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
-+	gdp->bg_free_blocks_count =
-+		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)
-+				- ac->ac_b_ex.fe_len);
-+	spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
-+	percpu_counter_mod(&sbi->s_freeblocks_counter, - ac->ac_b_ex.fe_len);
-+
-+	err = ext3_journal_dirty_metadata(handle, bitmap_bh);
-+	if (err)
-+		goto out_err;
-+	err = ext3_journal_dirty_metadata(handle, gdp_bh);
-+
-+out_err:
-+	sb->s_dirt = 1;
-+	brelse(bitmap_bh);
-+	return err;
-+}
-+
-+/*
-+ * here we normalize request for locality group
-+ * XXX: should we try to preallocate more than the group has now?
-+ */
-+void ext3_mb_normalize_group_request(struct ext3_allocation_context *ac)
-+{
-+	struct super_block *sb = ac->ac_sb;
-+	struct ext3_locality_group *lg = ac->ac_lg;
-+
-+	BUG_ON(lg == NULL);
-+	if (EXT3_SB(sb)->s_stripe)
-+		ac->ac_g_ex.fe_len = EXT3_SB(sb)->s_stripe;
-+	else
-+		ac->ac_g_ex.fe_len = (1024 * 1024) >> sb->s_blocksize_bits;
-+
-+	mb_debug("#%u: goal %u blocks for locality group\n",
-+		current->pid, ac->ac_g_ex.fe_len);
-+}
-+
-+/*
-+ * Normalization means making request better in terms of
-+ * size and alignment
-+ */
-+void ext3_mb_normalize_request(struct ext3_allocation_context *ac,
-+				struct ext3_allocation_request *ar)
-+{
-+	struct ext3_inode_info *ei = EXT3_I(ac->ac_inode);
-+	loff_t start, end, size, orig_size, orig_start;
-+	struct list_head *cur;
-+	int bsbits;
-+
-+	/* do normalize only data requests, metadata requests
-+	   do not need preallocation */
-+	if (!(ac->ac_flags & EXT3_MB_HINT_DATA))
-+		return;
-+
-+	/* sometime caller may want exact blocks */
-+	if (unlikely(ac->ac_flags & EXT3_MB_HINT_GOAL_ONLY))
-+		return;
-+
-+	/* caller may indicate that preallocation isn't
-+	 * required (it's a tail, for example) */
-+	if (ac->ac_flags & EXT3_MB_HINT_NOPREALLOC)
-+		return;
-+
-+	if (ac->ac_flags & EXT3_MB_HINT_GROUP_ALLOC)
-+		return ext3_mb_normalize_group_request(ac);
-+
-+	bsbits = ac->ac_sb->s_blocksize_bits;
-+
-+	/* first, let's learn actual file size
-+	 * given current request is allocated */
-+	size = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len;
-+	size = size << bsbits;
-+	if (size < i_size_read(ac->ac_inode))
-+		size = i_size_read(ac->ac_inode);
-+
-+	/* first, try to predict filesize */
-+	/* XXX: should this table be tunable? */
-+	start = 0;
-+	if (size <= 16 * 1024) {
-+		size = 16 * 1024;
-+	} else if (size <= 32 * 1024) {
-+		size = 32 * 1024;
-+	} else if (size <= 64 * 1024) {
-+		size = 64 * 1024;
-+	} else if (size <= 128 * 1024) {
-+		size = 128 * 1024;
-+	} else if (size <= 256 * 1024) {
-+		size = 256 * 1024;
-+	} else if (size <= 512 * 1024) {
-+		size = 512 * 1024;
-+	} else if (size <= 1024 * 1024) {
-+		size = 1024 * 1024;
-+	} else if (size < 4 * 1024 * 1024) {
-+		start = ac->ac_o_ex.fe_logical << bsbits;
-+		start = (start / (1024 * 1024)) * (1024 * 1024);
-+		size = 1024 * 1024;
-+	} else if (size < 8 * 1024 * 1024) {
-+		start = ac->ac_o_ex.fe_logical << bsbits;
-+		start = (start / (4 * (1024 * 1024))) * 4 * (1024 * 1024);
-+		size = 4 * 1024 * 1024;
-+	} else if (ac->ac_o_ex.fe_len < ((8 << 20) >> bsbits)) {
-+		start = ac->ac_o_ex.fe_logical;
-+		start = start << bsbits;
-+		start = (start / (8 * (1024 * 1024))) * 8 * (1024 * 1024);
-+		size = 8 * 1024 * 1024;
-+	} else {
-+		start = ac->ac_o_ex.fe_logical;
-+		start = start << bsbits;
-+		size = ac->ac_o_ex.fe_len << bsbits;
-+	}
-+	orig_size = size = size >> bsbits;
-+	orig_start = start = start >> bsbits;
-+
-+	/* don't cover already allocated blocks in selected range */
-+	if (ar->pleft && start <= ar->lleft) {
-+		size -= ar->lleft + 1 - start;
-+		start = ar->lleft + 1;
-+	}
-+	if (ar->pright && start + size - 1 >= ar->lright)
-+		size -= start + size - ar->lright;
-+
-+	end = start + size;
-+
-+	/* check we don't cross already preallocated blocks */
-+	rcu_read_lock();
-+	list_for_each_rcu(cur, &ei->i_prealloc_list) {
-+		struct ext3_prealloc_space *pa;
-+		unsigned long pa_end;
-+
-+		pa = list_entry(cur, struct ext3_prealloc_space, pa_inode_list);
-+		pa_end = pa->pa_lstart + pa->pa_len;
-+
-+		/* PA must not overlap original request */
-+		BUG_ON(!(ac->ac_o_ex.fe_logical >= pa_end ||
-+			ac->ac_o_ex.fe_logical < pa->pa_lstart));
-+
-+		/* skip PA normalized request doesn't overlap with */
-+		if (pa->pa_lstart >= end)
-+			continue;
-+		if (pa_end <= start)
-+			continue;
-+		BUG_ON(pa->pa_lstart <= start && pa_end >= end);
-+
-+		if (pa_end <= ac->ac_o_ex.fe_logical) {
-+			BUG_ON(pa_end < start);
-+			start = pa_end;
-+		}
-+
-+		if (pa->pa_lstart > ac->ac_o_ex.fe_logical) {
-+			BUG_ON(pa->pa_lstart > end);
-+			end = pa->pa_lstart;
-+		}
-+	}
-+	rcu_read_unlock();
-+	size = end - start;
-+
-+	/* XXX: extra loop to check we really don't overlap preallocations */
-+	rcu_read_lock();
-+	list_for_each_rcu(cur, &ei->i_prealloc_list) {
-+		struct ext3_prealloc_space *pa;
-+		unsigned long pa_end;
-+		pa = list_entry(cur, struct ext3_prealloc_space, pa_inode_list);
-+		pa_end = pa->pa_lstart + pa->pa_len;
-+		BUG_ON(!(start >= pa_end || end <= pa->pa_lstart));
-+	}
-+	rcu_read_unlock();
-+
-+	if (start + size <= ac->ac_o_ex.fe_logical &&
-+			start > ac->ac_o_ex.fe_logical) {
-+		printk("start %lu, size %lu, fe_logical %lu\n",
-+			(unsigned long) start, (unsigned long) size,
-+			(unsigned long) ac->ac_o_ex.fe_logical);
-+	}
-+	BUG_ON(start + size <= ac->ac_o_ex.fe_logical &&
-+			start > ac->ac_o_ex.fe_logical);
-+
-+	/* now prepare goal request */
-+	BUG_ON(size <= 0 || size >= EXT3_BLOCKS_PER_GROUP(ac->ac_sb));
-+	if (size < ac->ac_o_ex.fe_len) {
-+		/* XXX: don't normalize tails? */
-+	}
-+
-+	/* XXX: is it better to align blocks WRT to logical placement
-+	 * or satisfy big request as is */
-+	ac->ac_g_ex.fe_logical = start;
-+	ac->ac_g_ex.fe_len = size;
-+
-+	mb_debug("goal: %u(was %u) blocks at %u\n", (unsigned) size,
-+		(unsigned) orig_size, (unsigned) start);
-+}
-+
-+void ext3_mb_collect_stats(struct ext3_allocation_context *ac)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(ac->ac_sb);
-+
-+	if (sbi->s_mb_stats && ac->ac_g_ex.fe_len > 1) {
-+		atomic_inc(&sbi->s_bal_reqs);
-+		atomic_add(ac->ac_b_ex.fe_len, &sbi->s_bal_allocated);
-+		if (ac->ac_o_ex.fe_len >= ac->ac_g_ex.fe_len)
-+			atomic_inc(&sbi->s_bal_success);
-+		atomic_add(ac->ac_found, &sbi->s_bal_ex_scanned);
-+		if (ac->ac_g_ex.fe_start == ac->ac_b_ex.fe_start &&
-+				ac->ac_g_ex.fe_group == ac->ac_b_ex.fe_group)
-+			atomic_inc(&sbi->s_bal_goals);
-+		if (ac->ac_found > sbi->s_mb_max_to_scan)
-+			atomic_inc(&sbi->s_bal_breaks);
-+	}
-+
-+	ext3_mb_store_history(ac);
-+}
-+
-+/*
-+ * use blocks preallocated to inode
-+ */
-+void ext3_mb_use_inode_pa(struct ext3_allocation_context *ac,
-+				struct ext3_prealloc_space *pa)
-+{
-+	unsigned long start, len;
-+
-+	/* found preallocated blocks, use them */
-+	start = pa->pa_pstart + (ac->ac_o_ex.fe_logical - pa->pa_lstart);
-+	len = min(pa->pa_pstart + pa->pa_len, start + ac->ac_o_ex.fe_len);
-+	len = len - start;
-+	ext3_get_group_no_and_offset(ac->ac_sb, start, &ac->ac_b_ex.fe_group,
-+					&ac->ac_b_ex.fe_start);
-+	ac->ac_b_ex.fe_len = len;
-+	ac->ac_status = AC_STATUS_FOUND;
-+	ac->ac_pa = pa;
-+
-+	BUG_ON(start < pa->pa_pstart);
-+	BUG_ON(start + len > pa->pa_pstart + pa->pa_len);
-+	BUG_ON(pa->pa_free < len);
-+	pa->pa_free -= len;
-+
-+	mb_debug("use %lu/%lu from inode pa %p\n", start, len, pa);
-+}
-+
-+/*
-+ * use blocks preallocated to locality group
-+ */
-+void ext3_mb_use_group_pa(struct ext3_allocation_context *ac,
-+				struct ext3_prealloc_space *pa)
-+{
-+	unsigned len = ac->ac_o_ex.fe_len;
-+
-+	ext3_get_group_no_and_offset(ac->ac_sb, pa->pa_pstart,
-+					&ac->ac_b_ex.fe_group,
-+					&ac->ac_b_ex.fe_start);
-+	ac->ac_b_ex.fe_len = len;
-+	ac->ac_status = AC_STATUS_FOUND;
-+	ac->ac_pa = pa;
-+
-+	/* we don't correct pa_pstart or pa_plen here to avoid
-+	 * possible race when tte group is being loaded concurrently
-+	 * instead we correct pa later, after blocks are marked
-+	 * in on-disk bitmap -- see ext3_mb_release_context() */
-+	mb_debug("use %lu/%lu from group pa %p\n", pa->pa_lstart-len, len, pa);
-+}
-+
-+/*
-+ * search goal blocks in preallocated space
-+ */
-+int ext3_mb_use_preallocated(struct ext3_allocation_context *ac)
-+{
-+	struct ext3_inode_info *ei = EXT3_I(ac->ac_inode);
-+	struct ext3_locality_group *lg;
-+	struct ext3_prealloc_space *pa;
-+	struct list_head *cur;
-+
-+	/* only data can be preallocated */
-+	if (!(ac->ac_flags & EXT3_MB_HINT_DATA))
-+		return 0;
-+
-+	/* first, try per-file preallocation */
-+	rcu_read_lock();
-+	list_for_each_rcu(cur, &ei->i_prealloc_list) {
-+		pa = list_entry(cur, struct ext3_prealloc_space, pa_inode_list);
-+
-+		/* all fields in this condition don't change,
-+		 * so we can skip locking for them */
-+		if (ac->ac_o_ex.fe_logical < pa->pa_lstart ||
-+			ac->ac_o_ex.fe_logical >= pa->pa_lstart + pa->pa_len)
-+			continue;
-+
-+		/* found preallocated blocks, use them */
-+		spin_lock(&pa->pa_lock);
-+		if (pa->pa_deleted == 0 && pa->pa_free) {
-+			atomic_inc(&pa->pa_count);
-+			ext3_mb_use_inode_pa(ac, pa);
-+			spin_unlock(&pa->pa_lock);
-+			ac->ac_criteria = 10;
-+			rcu_read_unlock();
-+			return 1;
-+		}
-+		spin_unlock(&pa->pa_lock);
-+	}
-+	rcu_read_unlock();
-+
-+	/* can we use group allocation? */
-+	if (!(ac->ac_flags & EXT3_MB_HINT_GROUP_ALLOC))
-+		return 0;
-+
-+	/* inode may have no locality group for some reason */
-+	lg = ac->ac_lg;
-+	if (lg == NULL)
-+		return 0;
-+
-+	rcu_read_lock();
-+	list_for_each_rcu(cur, &lg->lg_prealloc_list) {
-+		pa = list_entry(cur, struct ext3_prealloc_space, pa_inode_list);
-+		spin_lock(&pa->pa_lock);
-+		if (pa->pa_deleted == 0 && pa->pa_free >= ac->ac_o_ex.fe_len) {
-+			atomic_inc(&pa->pa_count);
-+			ext3_mb_use_group_pa(ac, pa);
-+			spin_unlock(&pa->pa_lock);
-+			ac->ac_criteria = 20;
-+			rcu_read_unlock();
-+			return 1;
-+		}
-+		spin_unlock(&pa->pa_lock);
-+	}
-+	rcu_read_unlock();
-+
-+	return 0;
-+}
-+
-+/*
-+ * the function goes through all preallocation in this group and marks them
-+ * used in in-core bitmap. buddy must be generated from this bitmap
-+ */
-+void ext3_mb_generate_from_pa(struct super_block *sb, void *bitmap, int group)
-+{
-+	struct ext3_group_info *grp = EXT3_GROUP_INFO(sb, group);
-+	struct ext3_prealloc_space *pa;
-+	struct list_head *cur;
-+	unsigned long groupnr;
-+	unsigned long start;
-+	int preallocated = 0, count = 0, len;
-+
-+ 	/* all form of preallocation discards first load group,
-+	 * so the only competing code is preallocation use.
-+	 * we don't need any locking here
-+	 * notice we do NOT ignore preallocations with pa_deleted
-+	 * otherwise we could leave used blocks available for
-+	 * allocation in buddy when concurrent ext3_mb_put_pa()
-+	 * is dropping preallocation
-+	 */
-+	list_for_each_rcu(cur, &grp->bb_prealloc_list) {
-+		pa = list_entry(cur, struct ext3_prealloc_space, pa_group_list);
-+		spin_lock(&pa->pa_lock);
-+		ext3_get_group_no_and_offset(sb, pa->pa_pstart, &groupnr, &start);
-+		len = pa->pa_len;
-+		spin_unlock(&pa->pa_lock);
-+		BUG_ON(groupnr != group);
-+		mb_set_bits(bitmap, start, len);
-+		preallocated += len;
-+		count++;
-+	}
-+	mb_debug("prellocated %u for group %u\n", preallocated, group);
-+}
-+
-+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,5)
-+static void ext3_mb_pa_callback(struct rcu_head *head)
-+{
-+	struct ext3_prealloc_space *pa;
-+	pa = container_of(head, struct ext3_prealloc_space, u.pa_rcu);
-+	kmem_cache_free(ext3_pspace_cachep, pa);
-+}
-+#define mb_call_rcu(__pa)	call_rcu(&(__pa)->u.pa_rcu, ext3_mb_pa_callback)
-+#else
-+static void ext3_mb_pa_callback(void *pa)
-+{
-+	kmem_cache_free(ext3_pspace_cachep, pa);
-+}
-+#define mb_call_rcu(__pa)	call_rcu(&(__pa)->u.pa_rcu, ext3_mb_pa_callback, pa)
-+#endif
-+
-+/*
-+ * drops a reference to preallocated space descriptor
-+ * if this was the last reference and the space is consumed
-+ */
-+void ext3_mb_put_pa(struct ext3_allocation_context *ac,
-+			struct super_block *sb, struct ext3_prealloc_space *pa)
-+{
-+	unsigned long grp;
-+
-+	if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0)
-+		return;
-+
-+	/* in this short window concurrent discard can set pa_deleted */
-+	spin_lock(&pa->pa_lock);
-+	if (pa->pa_deleted == 0) {
-+		spin_unlock(&pa->pa_lock);
-+		return;
-+	}
-+
-+	pa->pa_deleted = 1;
-+	spin_unlock(&pa->pa_lock);
-+
-+	/* -1 is to protect from crossing allocation group */
-+	ext3_get_group_no_and_offset(sb, pa->pa_pstart - 1, &grp, NULL);
-+
-+	/*
-+	 * possible race:
-+	 *
-+	 *  P1 (buddy init)			P2 (regular allocation)
-+	 *					find block B in PA
-+	 *  copy on-disk bitmap to buddy
-+	 *  					mark B in on-disk bitmap
-+	 *					drop PA from group
-+	 *  mark all PAs in buddy
-+	 *
-+	 * thus, P1 initializes buddy with B available. to prevent this
-+	 * we make "copy" and "mark all PAs" atomic and serialize "drop PA"
-+	 * against that pair
-+	 */
-+	ext3_lock_group(sb, grp);
-+	list_del_rcu(&pa->pa_group_list);
-+	ext3_unlock_group(sb, grp);
-+
-+	spin_lock(pa->pa_obj_lock);
-+	list_del_rcu(&pa->pa_inode_list);
-+	spin_unlock(pa->pa_obj_lock);
-+
-+	mb_call_rcu(pa);
-+}
-+
-+/*
-+ * creates new preallocated space for given inode
-+ */
-+int ext3_mb_new_inode_pa(struct ext3_allocation_context *ac)
-+{
-+	struct super_block *sb = ac->ac_sb;
-+	struct ext3_prealloc_space *pa;
-+	struct ext3_group_info *grp;
-+	struct ext3_inode_info *ei;
-+
-+	/* preallocate only when found space is larger then requested */
-+	BUG_ON(ac->ac_o_ex.fe_len >= ac->ac_b_ex.fe_len);
-+	BUG_ON(ac->ac_status != AC_STATUS_FOUND);
-+	BUG_ON(!S_ISREG(ac->ac_inode->i_mode));
-+
-+	pa = kmem_cache_alloc(ext3_pspace_cachep, SLAB_NOFS);
-+	if (pa == NULL)
-+		return -ENOMEM;
-+
-+	if (ac->ac_b_ex.fe_len < ac->ac_g_ex.fe_len) {
-+		int winl, wins, win, offs;
-+
-+		/* we can't allocate as much as normalizer wants.
-+		 * so, found space must get proper lstart
-+		 * to cover original request */
-+		BUG_ON(ac->ac_g_ex.fe_logical > ac->ac_o_ex.fe_logical);
-+		BUG_ON(ac->ac_g_ex.fe_len < ac->ac_o_ex.fe_len);
-+
-+		/* we're limited by original request in that
-+		 * logical block must be covered any way
-+		 * winl is window we can move our chunk within */
-+		winl = ac->ac_o_ex.fe_logical - ac->ac_g_ex.fe_logical;
-+
-+		/* also, we should cover whole original request */
-+		wins = ac->ac_b_ex.fe_len - ac->ac_o_ex.fe_len;
-+
-+		/* the smallest one defines real window */
-+		win = min(winl, wins);
-+
-+		offs = ac->ac_o_ex.fe_logical % ac->ac_b_ex.fe_len;
-+		if (offs && offs < win)
-+			win = offs;
-+
-+		ac->ac_b_ex.fe_logical = ac->ac_o_ex.fe_logical - win;
-+		BUG_ON(ac->ac_o_ex.fe_logical < ac->ac_b_ex.fe_logical);
-+		BUG_ON(ac->ac_o_ex.fe_len > ac->ac_b_ex.fe_len);
-+	}
-+
-+	/* preallocation can change ac_b_ex, thus we store actually
-+	 * allocated blocks for history */
-+	ac->ac_f_ex = ac->ac_b_ex;
-+
-+	pa->pa_lstart = ac->ac_b_ex.fe_logical;
-+	pa->pa_pstart = ext3_grp_offs_to_block(sb, &ac->ac_b_ex);
-+	pa->pa_len = ac->ac_b_ex.fe_len;
-+	pa->pa_free = pa->pa_len;
-+	atomic_set(&pa->pa_count, 1);
-+	spin_lock_init(&pa->pa_lock);
-+	pa->pa_deleted = 0;
-+	pa->pa_linear = 0;
-+
-+	mb_debug("new inode pa %p: %lu/%lu for %lu\n", pa,
-+			pa->pa_pstart, pa->pa_len, pa->pa_lstart);
-+
-+	ext3_mb_use_inode_pa(ac, pa);
-+	atomic_add(pa->pa_free, &EXT3_SB(sb)->s_mb_preallocated);
-+
-+	ei = EXT3_I(ac->ac_inode);
-+	grp = EXT3_GROUP_INFO(sb, ac->ac_b_ex.fe_group);
-+
-+	pa->pa_obj_lock = &ei->i_prealloc_lock;
-+	pa->pa_inode = ac->ac_inode;
-+
-+	ext3_lock_group(sb, ac->ac_b_ex.fe_group);
-+	list_add_rcu(&pa->pa_group_list, &grp->bb_prealloc_list);
-+	ext3_unlock_group(sb, ac->ac_b_ex.fe_group);
-+
-+	spin_lock(pa->pa_obj_lock);
-+	list_add_rcu(&pa->pa_inode_list, &ei->i_prealloc_list);
-+	spin_unlock(pa->pa_obj_lock);
-+
-+	return 0;
-+}
-+
-+/*
-+ * creates new preallocated space for locality group inodes belongs to
-+ */
-+int ext3_mb_new_group_pa(struct ext3_allocation_context *ac)
-+{
-+	struct super_block *sb = ac->ac_sb;
-+	struct ext3_locality_group *lg;
-+	struct ext3_prealloc_space *pa;
-+	struct ext3_group_info *grp;
-+
-+	/* preallocate only when found space is larger then requested */
-+	BUG_ON(ac->ac_o_ex.fe_len >= ac->ac_b_ex.fe_len);
-+	BUG_ON(ac->ac_status != AC_STATUS_FOUND);
-+	BUG_ON(!S_ISREG(ac->ac_inode->i_mode));
-+
-+	BUG_ON(ext3_pspace_cachep == NULL);
-+	pa = kmem_cache_alloc(ext3_pspace_cachep, SLAB_NOFS);
-+	if (pa == NULL)
-+		return -ENOMEM;
-+
-+	/* preallocation can change ac_b_ex, thus we store actually
-+	 * allocated blocks for history */
-+	ac->ac_f_ex = ac->ac_b_ex;
-+
-+	pa->pa_pstart = ext3_grp_offs_to_block(sb, &ac->ac_b_ex);
-+	pa->pa_lstart = pa->pa_pstart;
-+	pa->pa_len = ac->ac_b_ex.fe_len;
-+	pa->pa_free = pa->pa_len;
-+	atomic_set(&pa->pa_count, 1);
-+	spin_lock_init(&pa->pa_lock);
-+	pa->pa_deleted = 0;
-+	pa->pa_linear = 1;
-+
-+	mb_debug("new group pa %p: %lu/%lu for %lu\n", pa,
-+			pa->pa_pstart, pa->pa_len, pa->pa_lstart);
-+
-+	ext3_mb_use_group_pa(ac, pa);
-+	atomic_add(pa->pa_free, &EXT3_SB(sb)->s_mb_preallocated);
-+
-+	grp = EXT3_GROUP_INFO(sb, ac->ac_b_ex.fe_group);
-+	lg = ac->ac_lg;
-+	BUG_ON(lg == NULL);
-+
-+	pa->pa_obj_lock = &lg->lg_prealloc_lock;
-+	pa->pa_inode = NULL;
-+
-+	ext3_lock_group(sb, ac->ac_b_ex.fe_group);
-+	list_add_rcu(&pa->pa_group_list, &grp->bb_prealloc_list);
-+	ext3_unlock_group(sb, ac->ac_b_ex.fe_group);
-+
-+	spin_lock(pa->pa_obj_lock);
-+	list_add_tail_rcu(&pa->pa_inode_list, &lg->lg_prealloc_list);
-+	spin_unlock(pa->pa_obj_lock);
-+
-+	return 0;
-+}
-+
-+int ext3_mb_new_preallocation(struct ext3_allocation_context *ac)
-+{
-+	int err;
-+
-+	if (ac->ac_flags & EXT3_MB_HINT_GROUP_ALLOC)
-+		err = ext3_mb_new_group_pa(ac);
-+	else
-+		err = ext3_mb_new_inode_pa(ac);
-+	return err;
-+}
-+
-+/*
-+ * finds all unused blocks in on-disk bitmap, frees them in
-+ * in-core bitmap and buddy.
-+ * @pa must be unlinked from inode and group lists, so that
-+ * nobody else can find/use it.
-+ * the caller MUST hold group/inode locks.
-+ * TODO: optimize the case when there are no in-core structures yet
-+ */
-+int ext3_mb_release_inode_pa(struct ext3_buddy *e3b,
-+				struct buffer_head *bitmap_bh,
-+				struct ext3_prealloc_space *pa)
-+{
-+	struct ext3_allocation_context ac;
-+	struct super_block *sb = e3b->bd_sb;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	unsigned long bit, end, next, group;
-+	sector_t start;
-+	int err = 0, free = 0;
-+
-+	BUG_ON(pa->pa_deleted == 0);
-+	ext3_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
-+	BUG_ON(group != e3b->bd_group);
-+	end = bit + pa->pa_len;
-+
-+	ac.ac_sb = sb;
-+	ac.ac_inode = pa->pa_inode;
-+	ac.ac_op = EXT3_MB_HISTORY_DISCARD;
-+
-+	while (bit < end) {
-+		bit = mb_find_next_zero_bit(bitmap_bh->b_data, end, bit);
-+		if (bit >= end)
-+			break;
-+		next = mb_find_next_bit(bitmap_bh->b_data, end, bit);
-+		if (next > end)
-+			next = end;
-+		start = group * EXT3_BLOCKS_PER_GROUP(sb) + bit +
-+				le32_to_cpu(sbi->s_es->s_first_data_block);
-+		mb_debug("    free preallocated %u/%u in group %u\n",
-+				(unsigned) start, (unsigned) next - bit,
-+				(unsigned) group);
-+		free += next - bit;
-+
-+		ac.ac_b_ex.fe_group = group;
-+		ac.ac_b_ex.fe_start = bit;
-+		ac.ac_b_ex.fe_len = next - bit;
-+		ac.ac_b_ex.fe_logical = 0;
-+		ext3_mb_store_history(&ac);
-+
-+		mb_free_blocks(e3b, bit, next - bit);
-+		bit = next + 1;
-+	}
-+	if (free != pa->pa_free) {
-+		printk("pa %p: logic %lu, phys. %lu, len %lu\n",
-+			pa, (unsigned long) pa->pa_lstart,
-+			(unsigned long) pa->pa_pstart,
-+			(unsigned long) pa->pa_len);
-+		printk("free %u, pa_free %u\n", free, pa->pa_free);
-+	}
-+	BUG_ON(free != pa->pa_free);
-+	atomic_add(free, &sbi->s_mb_discarded);
-+
-+	return err;
-+}
-+
-+int ext3_mb_release_group_pa(struct ext3_buddy *e3b,
-+				struct ext3_prealloc_space *pa)
-+{
-+	struct ext3_allocation_context ac;
-+	struct super_block *sb = e3b->bd_sb;
-+	unsigned long bit, group;
-+
-+	ac.ac_op = EXT3_MB_HISTORY_DISCARD;
-+
-+	BUG_ON(pa->pa_deleted == 0);
-+	ext3_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit);
-+	BUG_ON(group != e3b->bd_group);
-+	mb_free_blocks(e3b, bit, pa->pa_len);
-+	atomic_add(pa->pa_len, &EXT3_SB(sb)->s_mb_discarded);
-+
-+	ac.ac_sb = sb;
-+	ac.ac_inode = NULL;
-+	ac.ac_b_ex.fe_group = group;
-+	ac.ac_b_ex.fe_start = bit;
-+	ac.ac_b_ex.fe_len = pa->pa_len;
-+	ac.ac_b_ex.fe_logical = 0;
-+	ext3_mb_store_history(&ac);
-+
-+	return 0;
-+}
-+
-+/*
-+ * releases all preallocations in given group
-+ *
-+ * first, we need to decide discard policy:
-+ * - when do we discard
-+ *   1) ENOSPC
-+ * - how many do we discard
-+ *   1) how many requested
-+ */
-+int ext3_mb_discard_group_preallocations(struct super_block *sb,
-+						int group, int needed)
-+{
-+	struct ext3_group_info *grp = EXT3_GROUP_INFO(sb, group);
-+	struct buffer_head *bitmap_bh = NULL;
-+	struct ext3_prealloc_space *pa, *tmp;
-+	struct list_head list;
-+	struct ext3_buddy e3b;
-+	int err, busy, free = 0;
-+
-+	mb_debug("discard preallocation for group %lu\n", group);
-+
-+	if (list_empty(&grp->bb_prealloc_list))
-+		return 0;
-+
-+	bitmap_bh = read_block_bitmap(sb, group);
-+	if (bitmap_bh == NULL) {
-+		/* error handling here */
-+		ext3_mb_release_desc(&e3b);
-+		BUG_ON(bitmap_bh == NULL);
-+	}
-+
-+	err = ext3_mb_load_buddy(sb, group, &e3b);
-+	BUG_ON(err != 0); /* error handling here */
-+
-+	if (needed == 0)
-+		needed = EXT3_BLOCKS_PER_GROUP(sb) + 1;
-+
-+	grp = EXT3_GROUP_INFO(sb, group);
-+	INIT_LIST_HEAD(&list);
-+
-+repeat:
-+	busy = 0;
-+	ext3_lock_group(sb, group);
-+	list_for_each_entry_safe (pa, tmp, &grp->bb_prealloc_list, pa_group_list) {
-+		spin_lock(&pa->pa_lock);
-+		if (atomic_read(&pa->pa_count)) {
-+			spin_unlock(&pa->pa_lock);
-+			printk("uh! busy PA\n");
-+			dump_stack();
-+			busy = 1;
-+			continue;
-+		}
-+		if (pa->pa_deleted) {
-+			spin_unlock(&pa->pa_lock);
-+			continue;
-+		}
-+
-+		/* seems this one can be freed ... */
-+		pa->pa_deleted = 1;
-+
-+		/* we can trust pa_free ... */
-+		free += pa->pa_free;
-+
-+		spin_unlock(&pa->pa_lock);
-+
-+		list_del_rcu(&pa->pa_group_list);
-+		list_add(&pa->u.pa_tmp_list, &list);
-+	}
-+
-+	/* if we still need more blocks and some PAs were used, try again */
-+	if (free < needed && busy)
-+		goto repeat;
-+
-+	/* found anything to free? */
-+	if (list_empty(&list)) {
-+		BUG_ON(free != 0);
-+		goto out;
-+	}
-+
-+	/* now free all selected PAs */
-+	list_for_each_entry_safe(pa, tmp, &list, u.pa_tmp_list) {
-+
-+		/* remove from object (inode or locality group) */
-+		spin_lock(pa->pa_obj_lock);
-+		list_del_rcu(&pa->pa_inode_list);
-+		spin_unlock(pa->pa_obj_lock);
-+
-+		if (pa->pa_linear)
-+			ext3_mb_release_group_pa(&e3b, pa);
-+		else
-+			ext3_mb_release_inode_pa(&e3b, bitmap_bh, pa);
-+
-+		list_del(&pa->u.pa_tmp_list);
-+		mb_call_rcu(pa);
-+	}
-+
-+out:
-+	ext3_unlock_group(sb, group);
-+	ext3_mb_release_desc(&e3b);
-+	brelse(bitmap_bh);
-+	return free;
-+}
-+
-+/*
-+ * releases all non-used preallocated blocks for given inode
-+ */
-+void ext3_mb_discard_inode_preallocations(struct inode *inode)
-+{
-+	struct ext3_inode_info *ei = EXT3_I(inode);
-+	struct super_block *sb = inode->i_sb;
-+	struct buffer_head *bitmap_bh = NULL;
-+	struct ext3_prealloc_space *pa, *tmp;
-+	unsigned long group = 0;
-+	struct list_head list;
-+	struct ext3_buddy e3b;
-+	int err;
-+
-+	if (!test_opt(sb, MBALLOC) || !S_ISREG(inode->i_mode)) {
-+		/*BUG_ON(!list_empty(&ei->i_prealloc_list));*/
-+		return;
-+	}
-+
-+	mb_debug("discard preallocation for inode %lu\n", inode->i_ino);
-+
-+	INIT_LIST_HEAD(&list);
-+
-+repeat:
-+	/* first, collect all pa's in the inode */
-+	spin_lock(&ei->i_prealloc_lock);
-+	while (!list_empty(&ei->i_prealloc_list)) {
-+		pa = list_entry(ei->i_prealloc_list.next,
-+				struct ext3_prealloc_space, pa_inode_list);
-+		BUG_ON(pa->pa_obj_lock != &ei->i_prealloc_lock);
-+		spin_lock(&pa->pa_lock);
-+		if (atomic_read(&pa->pa_count)) {
-+			/* this shouldn't happen often - nobody should
-+			 * use preallocation while we're discarding it */
-+			spin_unlock(&pa->pa_lock);
-+			spin_unlock(&ei->i_prealloc_lock);
-+			printk("uh-oh! used pa while discarding\n");
-+			dump_stack();
-+			current->state = TASK_UNINTERRUPTIBLE;
-+			schedule_timeout(HZ);
-+			goto repeat;
-+
-+		}
-+		if (pa->pa_deleted == 0) {
-+			pa->pa_deleted = 1;
-+			spin_unlock(&pa->pa_lock);
-+			list_del_rcu(&pa->pa_inode_list);
-+			list_add(&pa->u.pa_tmp_list, &list);
-+			continue;
-+		}
-+
-+		/* someone is deleting pa right now */
-+		spin_unlock(&pa->pa_lock);
-+		spin_unlock(&ei->i_prealloc_lock);
-+
-+		/* we have to wait here because pa_deleted
-+		 * doesn't mean pa is already unlinked from
-+		 * the list. as we might be called from
-+		 * ->clear_inode() the inode will get freed
-+		 * and concurrent thread which is unlinking
-+		 * pa from inode's list may access already
-+		 * freed memory, bad-bad-bad */
-+
-+		/* XXX: if this happens too often, we can
-+		 * add a flag to force wait only in case
-+		 * of ->clear_inode(), but not in case of
-+		 * regular truncate */
-+		printk("uh-oh! some one just deleted it\n");
-+		dump_stack();
-+		current->state = TASK_UNINTERRUPTIBLE;
-+		schedule_timeout(HZ);
-+		goto repeat;
-+	}
-+	spin_unlock(&ei->i_prealloc_lock);
-+
-+	list_for_each_entry_safe(pa, tmp, &list, u.pa_tmp_list) {
-+		BUG_ON(pa->pa_linear != 0);
-+		ext3_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL);
-+
-+		err = ext3_mb_load_buddy(sb, group, &e3b);
-+		BUG_ON(err != 0); /* error handling here */
-+
-+		bitmap_bh = read_block_bitmap(sb, group);
-+		if (bitmap_bh == NULL) {
-+			/* error handling here */
-+			ext3_mb_release_desc(&e3b);
-+			BUG_ON(bitmap_bh == NULL);
-+		}
-+
-+		ext3_lock_group(sb, group);
-+		list_del_rcu(&pa->pa_group_list);
-+		ext3_mb_release_inode_pa(&e3b, bitmap_bh, pa);
-+		ext3_unlock_group(sb, group);
-+
-+		ext3_mb_release_desc(&e3b);
-+		brelse(bitmap_bh);
-+
-+		list_del(&pa->u.pa_tmp_list);
-+		mb_call_rcu(pa);
-+	}
-+}
-+
-+/*
-+ * finds all preallocated spaces and return blocks being freed to them
-+ * if preallocated space becomes full (no block is used from the space)
-+ * then the function frees space in buddy
-+ * XXX: at the moment, truncate (which is the only way to free blocks)
-+ * discards all preallocations
-+ */
-+void ext3_mb_return_to_preallocation(struct inode *inode, struct ext3_buddy *e3b,
-+					sector_t block, int count)
-+{
-+	BUG_ON(!list_empty(&EXT3_I(inode)->i_prealloc_list));
-+}
-+
-+void ext3_mb_show_ac(struct ext3_allocation_context *ac)
-+{
-+#if 0
-+	struct super_block *sb = ac->ac_sb;
-+	int i;
-+
-+	printk(KERN_ERR "EXT3-fs: can't allocate: status %d flags %d\n",
-+			ac->ac_status, ac->ac_flags);
-+	printk(KERN_ERR "EXT3-fs: orig %lu/%lu/%lu@%lu, goal %lu/%lu/%lu@%lu, "
-+			"best %lu/%lu/%lu@%lu cr %d\n",
-+			ac->ac_o_ex.fe_group, ac->ac_o_ex.fe_start,
-+			ac->ac_o_ex.fe_len, ac->ac_o_ex.fe_logical,
-+			ac->ac_g_ex.fe_group, ac->ac_g_ex.fe_start,
-+			ac->ac_g_ex.fe_len, ac->ac_g_ex.fe_logical,
-+			ac->ac_b_ex.fe_group, ac->ac_b_ex.fe_start,
-+			ac->ac_b_ex.fe_len, ac->ac_b_ex.fe_logical,
-+			ac->ac_criteria);
-+	printk(KERN_ERR "EXT3-fs: %lu scanned, %d found\n", ac->ac_ex_scanned,
-+		ac->ac_found);
-+	printk("EXT3-fs: groups: ");
-+	for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
-+		struct ext3_group_info *grp = EXT3_GROUP_INFO(sb, i);
-+		struct ext3_prealloc_space *pa;
-+		unsigned long start;
-+		struct list_head *cur;
-+		list_for_each_rcu(cur, &grp->bb_prealloc_list) {
-+			pa = list_entry(cur, struct ext3_prealloc_space,
-+					pa_group_list);
-+			spin_lock(&pa->pa_lock);
-+			ext3_get_group_no_and_offset(sb, pa->pa_pstart, NULL, &start);
-+			spin_unlock(&pa->pa_lock);
-+			printk("PA:%u:%lu:%u ", i, start, pa->pa_len);
-+		}
-+
-+		if (grp->bb_free == 0)
-+			continue;
-+		printk("%d: %d/%d ", i, grp->bb_free, grp->bb_fragments);
-+	}
-+	printk("\n");
-+	//dump_stack();
-+#endif
-+}
-+
-+void ext3_mb_group_or_file(struct ext3_allocation_context *ac)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(ac->ac_sb);
-+	int bsbits = ac->ac_sb->s_blocksize_bits;
-+	loff_t size, isize;
-+
-+	if (!(ac->ac_flags & EXT3_MB_HINT_DATA))
-+		return;
-+
-+	size = ac->ac_o_ex.fe_logical + ac->ac_o_ex.fe_len;
-+	isize = i_size_read(ac->ac_inode) >> bsbits;
-+	if (size < isize)
-+		size = isize;
-+
-+	/* don't use group allocation for large files */
-+	if (size >= sbi->s_mb_stream_request)
-+		return;
-+
-+	if (unlikely(ac->ac_flags & EXT3_MB_HINT_GOAL_ONLY))
-+		return;
-+
-+	BUG_ON(ac->ac_lg != NULL);
-+	ac->ac_lg = &sbi->s_locality_groups[smp_processor_id()];
-+
-+	/* we're going to use group allocation */
-+	ac->ac_flags |= EXT3_MB_HINT_GROUP_ALLOC;
-+
-+	/* serialize all allocations in the group */
-+	down(&ac->ac_lg->lg_sem);
-+}
-+
-+int ext3_mb_initialize_context(struct ext3_allocation_context *ac,
-+				struct ext3_allocation_request *ar)
-+{
-+	struct super_block *sb = ar->inode->i_sb;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	struct ext3_super_block *es = sbi->s_es;
-+	unsigned long group, len, goal;
-+	unsigned long block;
-+
-+	/* we can't allocate > group size */
-+	len = ar->len;
-+	if (len >= EXT3_BLOCKS_PER_GROUP(sb) - 10)
-+		len = EXT3_BLOCKS_PER_GROUP(sb) - 10;
-+
-+	/* start searching from the goal */
-+	goal = ar->goal;
-+	if (goal < le32_to_cpu(es->s_first_data_block) ||
-+			goal >= le32_to_cpu(es->s_blocks_count))
-+		goal = le32_to_cpu(es->s_first_data_block);
-+	ext3_get_group_no_and_offset(sb, goal, &group, &block);
-+
-+	/* set up allocation goals */
-+	ac->ac_b_ex.fe_logical = ar->logical;
-+	ac->ac_b_ex.fe_group = 0;
-+	ac->ac_b_ex.fe_start = 0;
-+	ac->ac_b_ex.fe_len = 0;
-+	ac->ac_status = AC_STATUS_CONTINUE;
-+	ac->ac_groups_scanned = 0;
-+	ac->ac_ex_scanned = 0;
-+	ac->ac_found = 0;
-+	ac->ac_sb = sb;
-+	ac->ac_inode = ar->inode;
-+	ac->ac_o_ex.fe_logical = ar->logical;
-+	ac->ac_o_ex.fe_group = group;
-+	ac->ac_o_ex.fe_start = block;
-+	ac->ac_o_ex.fe_len = len;
-+	ac->ac_g_ex.fe_logical = ar->logical;
-+	ac->ac_g_ex.fe_group = group;
-+	ac->ac_g_ex.fe_start = block;
-+	ac->ac_g_ex.fe_len = len;
-+	ac->ac_f_ex.fe_len = 0;
-+	ac->ac_flags = ar->flags;
-+	ac->ac_2order = 0;
-+	ac->ac_criteria = 0;
-+	ac->ac_pa = NULL;
-+	ac->ac_bitmap_page = NULL;
-+	ac->ac_buddy_page = NULL;
-+	ac->ac_lg = NULL;
-+
-+	/* we have to define context: we'll we work with a file or
-+	 * locality group. this is a policy, actually */
-+	ext3_mb_group_or_file(ac);
-+
-+	mb_debug("init ac: %u blocks @ %llu, goal %llu, flags %x, 2^%d, "
-+			"left: %llu/%llu, right %llu/%llu to %swritable\n",
-+			(unsigned) ar->len, (unsigned) ar->logical,
-+			(unsigned) ar->goal, ac->ac_flags, ac->ac_2order,
-+			(unsigned) ar->lleft, (unsigned) ar->pleft,
-+			(unsigned) ar->lright, (unsigned) ar->pright,
-+			atomic_read(&ar->inode->i_writecount) ? "" : "non-");
-+	return 0;
-+
-+}
-+
-+/*
-+ * release all resource we used in allocation
-+ */
-+int ext3_mb_release_context(struct ext3_allocation_context *ac)
-+{
-+	if (ac->ac_pa) {
-+		if (ac->ac_pa->pa_linear) {
-+			/* see comment in ext3_mb_use_group_pa() */
-+			spin_lock(&ac->ac_pa->pa_lock);
-+			ac->ac_pa->pa_pstart += ac->ac_b_ex.fe_len;
-+			ac->ac_pa->pa_lstart += ac->ac_b_ex.fe_len;
-+			ac->ac_pa->pa_free -= ac->ac_b_ex.fe_len;
-+			ac->ac_pa->pa_len -= ac->ac_b_ex.fe_len;
-+			spin_unlock(&ac->ac_pa->pa_lock);
-+		}
-+		ext3_mb_put_pa(ac, ac->ac_sb, ac->ac_pa);
-+	}
-+	if (ac->ac_bitmap_page)
-+		page_cache_release(ac->ac_bitmap_page);
-+	if (ac->ac_buddy_page)
-+		page_cache_release(ac->ac_buddy_page);
-+	if (ac->ac_flags & EXT3_MB_HINT_GROUP_ALLOC)
-+		up(&ac->ac_lg->lg_sem);
-+	ext3_mb_collect_stats(ac);
-+	return 0;
-+}
-+
-+int ext3_mb_discard_preallocations(struct super_block *sb, int needed)
-+{
-+	int i, ret, freed = 0;
-+
-+	for (i = 0; i < EXT3_SB(sb)->s_groups_count && needed > 0; i++) {
-+		ret = ext3_mb_discard_group_preallocations(sb, i, needed);
-+		freed += ret;
-+		needed -= ret;
-+	}
-+
-+	return freed;
-+}
-+
-+/*
-+ * Main entry point into mballoc to allocate blocks
-+ * it tries to use preallocation first, then falls back
-+ * to usual allocation
-+ */
-+unsigned long ext3_mb_new_blocks(handle_t *handle,
-+				 struct ext3_allocation_request *ar, int *errp)
-+{
-+	struct ext3_allocation_context ac;
-+	struct ext3_sb_info *sbi;
-+	struct super_block *sb;
-+	unsigned long block;
-+	int err, freed;
-+
-+	sb = ar->inode->i_sb;
-+	sbi = EXT3_SB(sb);
-+
-+	if (!test_opt(sb, MBALLOC)) {
-+		static int ext3_mballoc_warning = 0;
-+		if (ext3_mballoc_warning++ == 0)
-+			printk(KERN_ERR "EXT3-fs: multiblock request with "
-+					"mballoc disabled!\n");
-+		ar->len = 1;
-+		err = ext3_new_block_old(handle, ar->inode, ar->goal, errp);
-+		return err;
-+	}
-+
-+	ext3_mb_poll_new_transaction(sb, handle);
-+
-+	if ((err = ext3_mb_initialize_context(&ac, ar)))
-+		return err;
-+
-+	ac.ac_op = EXT3_MB_HISTORY_PREALLOC;
-+	if (!ext3_mb_use_preallocated(&ac)) {
-+
-+		ac.ac_op = EXT3_MB_HISTORY_ALLOC;
-+		ext3_mb_normalize_request(&ac, ar);
-+
-+repeat:
-+		/* allocate space in core */
-+		ext3_mb_regular_allocator(&ac);
-+
-+		/* as we've just preallocated more space than
-+		 * user requested orinally, we store allocated
-+		 * space in a special descriptor */
-+		if (ac.ac_status == AC_STATUS_FOUND &&
-+				ac.ac_o_ex.fe_len < ac.ac_b_ex.fe_len)
-+			ext3_mb_new_preallocation(&ac);
-+	}
-+
-+	if (likely(ac.ac_status == AC_STATUS_FOUND)) {
-+		ext3_mb_mark_diskspace_used(&ac, handle);
-+		*errp = 0;
-+		block = ext3_grp_offs_to_block(sb, &ac.ac_b_ex);
-+		ar->len = ac.ac_b_ex.fe_len;
-+	} else {
-+		freed  = ext3_mb_discard_preallocations(sb, ac.ac_o_ex.fe_len);
-+		if (freed)
-+			goto repeat;
-+		*errp = -ENOSPC;
-+		ac.ac_b_ex.fe_len = 0;
-+		block = 0;
-+		ext3_mb_show_ac(&ac);
-+	}
-+
-+	ext3_mb_release_context(&ac);
-+
-+	return block;
-+}
-+EXPORT_SYMBOL(ext3_mb_new_blocks);
-+
-+int ext3_new_block(handle_t *handle, struct inode *inode,
-+		   unsigned long goal, int *errp)
-+{
-+	struct ext3_allocation_request ar;
-+	unsigned long ret;
-+
-+	if (!test_opt(inode->i_sb, MBALLOC)) {
-+		ret = ext3_new_block_old(handle, inode, goal, errp);
-+		return ret;
-+	}
-+
-+	ar.inode = inode;
-+	ar.goal = goal;
-+	ar.len = 1;
-+	ar.logical = 0;
-+	ar.lleft = 0;
-+	ar.pleft = 0;
-+	ar.lright = 0;
-+	ar.pright = 0;
-+	ar.flags = 0;
-+	ret = ext3_mb_new_blocks(handle, &ar, errp);
-+	return ret;
-+}
-+
-+void ext3_mb_poll_new_transaction(struct super_block *sb, handle_t *handle)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+
-+	if (sbi->s_last_transaction == handle->h_transaction->t_tid)
-+		return;
-+
-+	/* new transaction! time to close last one and free blocks for
-+	 * committed transaction. we know that only transaction can be
-+	 * active, so previos transaction can be being logged and we
-+	 * know that transaction before previous is known to be already
-+	 * logged. this means that now we may free blocks freed in all
-+	 * transactions before previous one. hope I'm clear enough ... */
-+
-+	spin_lock(&sbi->s_md_lock);
-+	if (sbi->s_last_transaction != handle->h_transaction->t_tid) {
-+		mb_debug("new transaction %lu, old %lu\n",
-+				(unsigned long) handle->h_transaction->t_tid,
-+				(unsigned long) sbi->s_last_transaction);
-+		list_splice_init(&sbi->s_closed_transaction,
-+				&sbi->s_committed_transaction);
-+		list_splice_init(&sbi->s_active_transaction,
-+				&sbi->s_closed_transaction);
-+		sbi->s_last_transaction = handle->h_transaction->t_tid;
-+	}
-+	spin_unlock(&sbi->s_md_lock);
-+
-+	ext3_mb_free_committed_blocks(sb);
-+}
-+
-+int ext3_mb_free_metadata(handle_t *handle, struct ext3_buddy *e3b,
-+			  int group, int block, int count)
-+{
-+	struct ext3_group_info *db = e3b->bd_info;
-+	struct super_block *sb = e3b->bd_sb;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+	struct ext3_free_metadata *md;
-+	int i;
-+
-+	BUG_ON(e3b->bd_bitmap_page == NULL);
-+	BUG_ON(e3b->bd_buddy_page == NULL);
-+
-+	ext3_lock_group(sb, group);
-+	for (i = 0; i < count; i++) {
-+		md = db->bb_md_cur;
-+		if (md && db->bb_tid != handle->h_transaction->t_tid) {
-+			db->bb_md_cur = NULL;
-+			md = NULL;
-+		}
-+
-+		if (md == NULL) {
-+			ext3_unlock_group(sb, group);
-+			md = kmalloc(sizeof(*md), GFP_KERNEL);
-+			if (md == NULL)
-+				return -ENOMEM;
-+			md->num = 0;
-+			md->group = group;
-+
-+			ext3_lock_group(sb, group);
-+			if (db->bb_md_cur == NULL) {
-+				spin_lock(&sbi->s_md_lock);
-+				list_add(&md->list, &sbi->s_active_transaction);
-+				spin_unlock(&sbi->s_md_lock);
-+				/* protect buddy cache from being freed,
-+				 * otherwise we'll refresh it from
-+				 * on-disk bitmap and lose not-yet-available
-+				 * blocks */
-+				page_cache_get(e3b->bd_buddy_page);
-+				page_cache_get(e3b->bd_bitmap_page);
-+				db->bb_md_cur = md;
-+				db->bb_tid = handle->h_transaction->t_tid;
-+				mb_debug("new md 0x%p for group %u\n",
-+						md, md->group);
-+			} else {
-+				kfree(md);
-+				md = db->bb_md_cur;
-+			}
-+		}
-+
-+		BUG_ON(md->num >= EXT3_BB_MAX_BLOCKS);
-+		md->blocks[md->num] = block + i;
-+		md->num++;
-+		if (md->num == EXT3_BB_MAX_BLOCKS) {
-+			/* no more space, put full container on a sb's list */
-+			db->bb_md_cur = NULL;
-+		}
-+	}
-+	ext3_unlock_group(sb, group);
-+	return 0;
-+}
-+
-+/*
-+ * Main entry point into mballoc to free blocks
-+ */
-+void ext3_mb_free_blocks(handle_t *handle, struct inode *inode,
-+			unsigned long block, unsigned long count,
-+			int metadata, int *freed)
-+{
-+	struct buffer_head *bitmap_bh = NULL;
-+	struct super_block *sb = inode->i_sb;
-+	struct ext3_allocation_context ac;
-+	struct ext3_group_desc *gdp;
-+	struct ext3_super_block *es;
-+	unsigned long bit, overflow;
-+	struct buffer_head *gd_bh;
-+	unsigned long block_group;
-+	struct ext3_sb_info *sbi;
-+	struct ext3_buddy e3b;
-+	int err = 0, ret;
-+
-+	*freed = 0;
-+
-+	ext3_mb_poll_new_transaction(sb, handle);
-+
-+	sbi = EXT3_SB(sb);
-+	es = EXT3_SB(sb)->s_es;
-+	if (block < le32_to_cpu(es->s_first_data_block) ||
-+	    block + count < block ||
-+	    block + count > le32_to_cpu(es->s_blocks_count)) {
-+		ext3_error (sb, __FUNCTION__,
-+			    "Freeing blocks not in datazone - "
-+			    "block = %lu, count = %lu", block, count);
-+		goto error_return;
-+	}
-+
-+	ext3_debug("freeing block %lu\n", block);
-+
-+	ac.ac_op = EXT3_MB_HISTORY_FREE;
-+	ac.ac_inode = inode;
-+	ac.ac_sb = sb;
-+
-+do_more:
-+	overflow = 0;
-+	ext3_get_group_no_and_offset(sb, block, &block_group, &bit);
-+
-+	/*
-+	 * Check to see if we are freeing blocks across a group
-+	 * boundary.
-+	 */
-+	if (bit + count > EXT3_BLOCKS_PER_GROUP(sb)) {
-+		overflow = bit + count - EXT3_BLOCKS_PER_GROUP(sb);
-+		count -= overflow;
-+	}
-+	brelse(bitmap_bh);
-+	bitmap_bh = read_block_bitmap(sb, block_group);
-+	if (!bitmap_bh)
-+		goto error_return;
-+	gdp = ext3_get_group_desc (sb, block_group, &gd_bh);
-+	if (!gdp)
-+		goto error_return;
-+
-+	if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
-+	    in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
-+	    in_range (block, le32_to_cpu(gdp->bg_inode_table),
-+		      EXT3_SB(sb)->s_itb_per_group) ||
-+	    in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
-+		      EXT3_SB(sb)->s_itb_per_group))
-+		ext3_error(sb, __FUNCTION__,
-+			   "Freeing blocks in system zone - "
-+			   "Block = %lu, count = %lu", block, count);
-+
-+	BUFFER_TRACE(bitmap_bh, "getting write access");
-+	err = ext3_journal_get_write_access(handle, bitmap_bh);
-+	if (err)
-+		goto error_return;
-+
-+	/*
-+	 * We are about to modify some metadata.  Call the journal APIs
-+	 * to unshare ->b_data if a currently-committing transaction is
-+	 * using it
-+	 */
-+	BUFFER_TRACE(gd_bh, "get_write_access");
-+	err = ext3_journal_get_write_access(handle, gd_bh);
-+	if (err)
-+		goto error_return;
-+
-+	err = ext3_mb_load_buddy(sb, block_group, &e3b);
-+	if (err)
-+		goto error_return;
-+
-+#ifdef AGGRESSIVE_CHECK
-+	{
-+		int i;
-+		for (i = 0; i < count; i++)
-+			BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data));
-+	}
-+#endif
-+	mb_clear_bits(bitmap_bh->b_data, bit, count);
-+
-+	/* We dirtied the bitmap block */
-+	BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
-+	err = ext3_journal_dirty_metadata(handle, bitmap_bh);
-+
-+	ac.ac_b_ex.fe_group = block_group;
-+	ac.ac_b_ex.fe_start = bit;
-+	ac.ac_b_ex.fe_len = count;
-+	ext3_mb_store_history(&ac);
-+
-+	if (metadata) {
-+		/* blocks being freed are metadata. these blocks shouldn't
-+		 * be used until this transaction is committed */
-+		ext3_mb_free_metadata(handle, &e3b, block_group, bit, count);
-+	} else {
-+		ext3_lock_group(sb, block_group);
-+		err = mb_free_blocks(&e3b, bit, count);
-+		ext3_mb_return_to_preallocation(inode, &e3b, block, count);
-+		ext3_unlock_group(sb, block_group);
-+		BUG_ON(err != 0);
-+	}
-+
-+	spin_lock(sb_bgl_lock(sbi, block_group));
-+	gdp->bg_free_blocks_count =
-+		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count);
-+	spin_unlock(sb_bgl_lock(sbi, block_group));
-+	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
-+
-+	ext3_mb_release_desc(&e3b);
-+
-+	*freed += count;
-+
-+	/* And the group descriptor block */
-+	BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
-+	ret = ext3_journal_dirty_metadata(handle, gd_bh);
-+	if (!err) err = ret;
-+
-+	if (overflow && !err) {
-+		block += count;
-+		count = overflow;
-+		goto do_more;
-+	}
-+	sb->s_dirt = 1;
-+error_return:
-+	brelse(bitmap_bh);
-+	ext3_std_error(sb, err);
-+	return;
-+}
diff --git a/lustre/kernel_patches/patches/ext3-mballoc3-rhel4.patch b/lustre/kernel_patches/patches/ext3-mballoc3-rhel4.patch
deleted file mode 100644
index 910df7c0d0..0000000000
--- a/lustre/kernel_patches/patches/ext3-mballoc3-rhel4.patch
+++ /dev/null
@@ -1,396 +0,0 @@
-Index: linux-2.6.9-full/include/linux/ext3_fs_i.h
-===================================================================
---- linux-2.6.9-full.orig/include/linux/ext3_fs_i.h	2007-03-28 01:29:38.000000000 +0400
-+++ linux-2.6.9-full/include/linux/ext3_fs_i.h	2007-03-28 15:45:41.000000000 +0400
-@@ -130,6 +130,10 @@ struct ext3_inode_info {
- 	struct inode vfs_inode;
- 
- 	__u32 i_cached_extent[4];
-+
-+	/* mballoc */
-+	struct list_head i_prealloc_list;
-+	spinlock_t i_prealloc_lock;
- };
- 
- #endif	/* _LINUX_EXT3_FS_I */
-Index: linux-2.6.9-full/include/linux/ext3_fs_sb.h
-===================================================================
---- linux-2.6.9-full.orig/include/linux/ext3_fs_sb.h	2007-03-28 15:42:16.000000000 +0400
-+++ linux-2.6.9-full/include/linux/ext3_fs_sb.h	2007-03-28 15:45:41.000000000 +0400
-@@ -23,9 +23,16 @@
- #define EXT_INCLUDE
- #include <linux/blockgroup_lock.h>
- #include <linux/percpu_counter.h>
-+#include <linux/list.h>
- #endif
- #endif
- #include <linux/rbtree.h>
-+#include <linux/proc_fs.h>
-+
-+struct ext3_buddy_group_blocks;
-+struct ext3_locality_group;
-+struct ext3_mb_history;
-+#define EXT3_BB_MAX_BLOCKS
- 
- /*
-  * third extended-fs super-block data in memory
-Index: linux-2.6.9-full/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.9-full.orig/include/linux/ext3_fs.h	2007-03-28 15:45:07.000000000 +0400
-+++ linux-2.6.9-full/include/linux/ext3_fs.h	2007-03-28 15:45:41.000000000 +0400
-@@ -389,6 +389,7 @@ struct ext3_inode {
- #define EXT3_MOUNT_IOPEN_NOPRIV		0x100000/* Make iopen world-readable */
- #define EXT3_MOUNT_EXTENTS		0x200000/* Extents support */
- #define EXT3_MOUNT_EXTDEBUG		0x400000/* Extents debug */
-+#define EXT3_MOUNT_MBALLOC		0x800000/* Buddy allocation support */
- 
- /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
- #ifndef clear_opt
-@@ -749,8 +750,9 @@ struct dir_private_info {
- extern int ext3_bg_has_super(struct super_block *sb, int group);
- extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
- extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
-+extern int ext3_new_block_old (handle_t *, struct inode *, unsigned long, int *);
- extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
--			      unsigned long);
-+			      unsigned long, int);
- extern void ext3_free_blocks_sb (handle_t *, struct super_block *,
- 				 unsigned long, unsigned long, int *);
- extern unsigned long ext3_count_free_blocks (struct super_block *);
-Index: linux-2.6.9-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/super.c	2007-03-28 15:42:16.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/super.c	2007-03-28 15:45:41.000000000 +0400
-@@ -600,6 +600,7 @@ enum {
- 	Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
- 	Opt_iopen, Opt_noiopen, Opt_iopen_nopriv,
- 	Opt_extents, Opt_noextents, Opt_extdebug,
-+	Opt_mballoc, Opt_nomballoc, Opt_stripe,
- };
- 
- static match_table_t tokens = {
-@@ -653,6 +654,9 @@ static match_table_t tokens = {
- 	{Opt_noextents, "noextents"},
- 	{Opt_extdebug, "extdebug"},
- 	{Opt_barrier, "barrier=%u"},
-+	{Opt_mballoc, "mballoc"},
-+	{Opt_nomballoc, "nomballoc"},
-+	{Opt_stripe, "stripe=%u"},
- 	{Opt_err, NULL},
- 	{Opt_resize, "resize"},
- };
-@@ -965,6 +969,19 @@ clear_qf_name:
- 		case Opt_extdebug:
- 			set_opt (sbi->s_mount_opt, EXTDEBUG);
- 			break;
-+		case Opt_mballoc:
-+			set_opt(sbi->s_mount_opt, MBALLOC);
-+			break;
-+		case Opt_nomballoc:
-+			clear_opt(sbi->s_mount_opt, MBALLOC);
-+			break;
-+		case Opt_stripe:
-+			if (match_int(&args[0], &option))
-+				return 0;
-+			if (option < 0)
-+				return 0;
-+			sbi->s_stripe = option;
-+			break;
- 		default:
- 			printk (KERN_ERR
- 				"EXT3-fs: Unrecognized mount option \"%s\" "
-@@ -1654,6 +1671,7 @@ static int ext3_fill_super (struct super
- 		ext3_count_dirs(sb));
- 
- 	ext3_ext_init(sb);
-+	ext3_mb_init(sb, needs_recovery);
- 
- 	return 0;
- 
-Index: linux-2.6.9-full/fs/ext3/extents.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/extents.c	2007-03-28 01:29:41.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/extents.c	2007-03-28 15:45:41.000000000 +0400
-@@ -779,7 +779,7 @@ cleanup:
- 		for (i = 0; i < depth; i++) {
- 			if (!ablocks[i])
- 				continue;
--			ext3_free_blocks(handle, tree->inode, ablocks[i], 1);
-+			ext3_free_blocks(handle, tree->inode, ablocks[i], 1, 1);
- 		}
- 	}
- 	kfree(ablocks);
-@@ -1586,7 +1586,7 @@ int ext3_ext_rm_idx(handle_t *handle, st
- 		  path->p_idx->ei_leaf);
- 	bh = sb_find_get_block(tree->inode->i_sb, path->p_idx->ei_leaf);
- 	ext3_forget(handle, 1, tree->inode, bh, path->p_idx->ei_leaf);
--	ext3_free_blocks(handle, tree->inode, path->p_idx->ei_leaf, 1);
-+	ext3_free_blocks(handle, tree->inode, path->p_idx->ei_leaf, 1, 1);
- 	return err;
- }
- 
-@@ -2071,10 +2071,12 @@ ext3_remove_blocks(struct ext3_extents_t
- 	int needed = ext3_remove_blocks_credits(tree, ex, from, to);
- 	handle_t *handle = ext3_journal_start(tree->inode, needed);
- 	struct buffer_head *bh;
--	int i;
-+	int i, metadata = 0;
- 
- 	if (IS_ERR(handle))
- 		return PTR_ERR(handle);
-+	if (S_ISDIR(tree->inode->i_mode) || S_ISLNK(tree->inode->i_mode))
-+		metadata = 1;
- 	if (from >= ex->ee_block && to == ex->ee_block + ex->ee_len - 1) {
- 		/* tail removal */
- 		unsigned long num, start;
-@@ -2086,7 +2088,7 @@ ext3_remove_blocks(struct ext3_extents_t
- 			bh = sb_find_get_block(tree->inode->i_sb, start + i);
- 			ext3_forget(handle, 0, tree->inode, bh, start + i);
- 		}
--		ext3_free_blocks(handle, tree->inode, start, num);
-+		ext3_free_blocks(handle, tree->inode, start, num, metadata);
- 	} else if (from == ex->ee_block && to <= ex->ee_block + ex->ee_len - 1) {
- 		printk("strange request: removal %lu-%lu from %u:%u\n",
- 		       from, to, ex->ee_block, ex->ee_len);
-@@ -2177,11 +2179,8 @@ int ext3_ext_get_block(handle_t *handle,
- 	struct ext3_extent *ex;
- 	int goal, newblock, err = 0, depth;
- 	struct ext3_extents_tree tree;
--	unsigned long next;
--	int allocated = 0;
--
--	/* until we have multiblock allocation */
--	max_blocks = 1;
-+	unsigned long allocated = 0;
-+	struct ext3_allocation_request ar;
- 
- 	clear_buffer_new(bh_result);
- 	ext3_init_tree_desc(&tree, inode);
-@@ -2253,18 +2252,33 @@ int ext3_ext_get_block(handle_t *handle,
- 		goto out2;
- 	}
- 
-+	/* find neighbour allocated blocks */
-+	ar.lleft = iblock;
-+	err = ext3_ext_search_left(&tree, path, &ar.lleft, &ar.pleft);
-+	if (err)
-+		goto out2;
-+	ar.lright = iblock;
-+	err = ext3_ext_search_right(&tree, path, &ar.lright, &ar.pright);
-+	if (err)
-+		goto out2;
-+
- 	/* find next allocated block so that we know how many
- 	 * blocks we can allocate without ovelapping next extent */
--	EXT_ASSERT(iblock >= ex->ee_block + ex->ee_len);
--	next = ext3_ext_next_allocated_block(path);
--	EXT_ASSERT(next > iblock);
--	allocated = next - iblock;
-+	EXT_ASSERT(ar.pright == 0 || ar.lright > iblock);
-+	if (ar.pright == 0)
-+		allocated = EXT_MAX_BLOCK - iblock;
-+	else
-+		allocated = ar.lright - iblock;
- 	if (allocated > max_blocks)
- 		allocated = max_blocks;
- 
- 	/* allocate new block */
--	goal = ext3_ext_find_goal(inode, path, iblock);
--	newblock = ext3_new_block(handle, inode, goal, &err);
-+	ar.inode = inode;
-+	ar.goal = ext3_ext_find_goal(inode, path, iblock);
-+	ar.logical = iblock;
-+	ar.len = allocated;
-+	ar.flags = EXT3_MB_HINT_DATA;
-+	newblock = ext3_mb_new_blocks(handle, &ar, &err);
- 	if (!newblock)
- 		goto out2;
- 	ext_debug(&tree, "allocate new block: goal %d, found %d\n",
-@@ -2274,11 +2288,14 @@ int ext3_ext_get_block(handle_t *handle,
- 	newex.ee_block = iblock;
- 	newex.ee_start = newblock;
- 	newex.ee_start_hi = 0;
--	newex.ee_len = 1;
-+	newex.ee_len = ar.len;
- 	err = ext3_ext_insert_extent(handle, &tree, path, &newex);
- 	if (err) {
- 		/* free data blocks we just allocated */
--		ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len);
-+		/* not a good idea to call discard here directly,
-+		 * but otherwise we'd need to call it every free() */
-+		ext3_mb_discard_inode_preallocations(inode);
-+		ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len, 0);
- 		goto out2;
- 	}
- 	
-@@ -2287,6 +2304,7 @@ int ext3_ext_get_block(handle_t *handle,
- 
- 	/* previous routine could use block we allocated */
- 	newblock = newex.ee_start;
-+	allocated = newex.ee_len;
- 	set_buffer_new(bh_result);
- 
- 	ext3_ext_put_in_cache(&tree, newex.ee_block, newex.ee_len,
-@@ -2339,6 +2357,9 @@ void ext3_ext_truncate(struct inode * in
- 	down(&EXT3_I(inode)->truncate_sem);
- 	ext3_ext_invalidate_cache(&tree);
- 
-+	/* it's important to discard preallocations under truncate_sem */
-+	ext3_mb_discard_inode_preallocations(inode);
-+
- 	/* 
- 	 * TODO: optimization is possible here
- 	 * probably we need not scaning at all,
-Index: linux-2.6.9-full/fs/ext3/Makefile
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/Makefile	2007-03-28 01:29:38.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/Makefile	2007-03-28 15:45:41.000000000 +0400
-@@ -6,7 +6,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o
- 
- ext3-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
- 	   ioctl.o namei.o super.o symlink.o hash.o resize.o \
--	   extents.o
-+	   extents.o mballoc.o
- 
- ext3-$(CONFIG_EXT3_FS_XATTR)	 += xattr.o xattr_user.o xattr_trusted.o
- ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
-Index: linux-2.6.9-full/fs/ext3/xattr.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/xattr.c	2006-05-18 23:57:04.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/xattr.c	2007-03-28 15:45:41.000000000 +0400
-@@ -1281,7 +1281,7 @@ ext3_xattr_set_handle2(handle_t *handle,
- 			new_bh = sb_getblk(sb, block);
- 			if (!new_bh) {
- getblk_failed:
--				ext3_free_blocks(handle, inode, block, 1);
-+				ext3_free_blocks(handle, inode, block, 1, 1);
- 				error = -EIO;
- 				goto cleanup;
- 			}
-@@ -1328,7 +1328,7 @@ getblk_failed:
- 			if (ce)
- 				mb_cache_entry_free(ce);
- 			ea_bdebug(old_bh, "freeing");
--			ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1);
-+			ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1, 1);
- 
- 			/* ext3_forget() calls bforget() for us, but we
- 			   let our caller release old_bh, so we need to
-@@ -1427,7 +1427,7 @@ ext3_xattr_delete_inode(handle_t *handle
- 	if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
- 		if (ce)
- 			mb_cache_entry_free(ce);
--		ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1);
-+		ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1, 1);
- 		get_bh(bh);
- 		ext3_forget(handle, 1, inode, bh, EXT3_I(inode)->i_file_acl);
- 	} else {
-Index: linux-2.6.9-full/fs/ext3/balloc.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/balloc.c	2006-03-10 18:20:03.000000000 +0300
-+++ linux-2.6.9-full/fs/ext3/balloc.c	2007-03-28 15:45:41.000000000 +0400
-@@ -79,7 +79,7 @@ struct ext3_group_desc * ext3_get_group_
-  *
-  * Return buffer_head on success or NULL in case of failure.
-  */
--static struct buffer_head *
-+struct buffer_head *
- read_block_bitmap(struct super_block *sb, unsigned int block_group)
- {
- 	struct ext3_group_desc * desc;
-@@ -267,6 +267,8 @@ void ext3_discard_reservation(struct ino
- 	struct reserve_window_node *rsv = &ei->i_rsv_window;
- 	spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock;
- 
-+	ext3_mb_discard_inode_preallocations(inode);
-+
- 	if (!rsv_is_empty(&rsv->rsv_window)) {
- 		spin_lock(rsv_lock);
- 		if (!rsv_is_empty(&rsv->rsv_window))
-@@ -451,21 +453,25 @@ error_return:
- 	return;
- }
- 
--/* Free given blocks, update quota and i_blocks field */
--void ext3_free_blocks(handle_t *handle, struct inode *inode,
--			unsigned long block, unsigned long count)
-+void ext3_free_blocks(handle_t *handle, struct inode * inode,
-+		unsigned long block, unsigned long count, int metadata)
- {
--	struct super_block * sb;
--	int dquot_freed_blocks;
-+	struct super_block *sb;
-+	int freed;
-+
-+	/* this isn't the right place to decide whether block is metadata
-+	 * inode.c/extents.c knows better, but for safety ... */
-+	if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) ||
-+			ext3_should_journal_data(inode))
-+		metadata = 1;
- 
- 	sb = inode->i_sb;
--	if (!sb) {
--		printk ("ext3_free_blocks: nonexistent device");
--		return;
--	}
--	ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks);
--	if (dquot_freed_blocks)
--		DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
-+	if (!test_opt(sb, MBALLOC) || !EXT3_SB(sb)->s_group_info)
-+		ext3_free_blocks_sb(handle, sb, block, count, &freed);
-+	else
-+		ext3_mb_free_blocks(handle, inode, block, count, metadata, &freed);
-+	if (freed)
-+		DQUOT_FREE_BLOCK(inode, freed);
- 	return;
- }
- 
-@@ -1131,7 +1137,7 @@ int ext3_should_retry_alloc(struct super
-  * bitmap, and then for any free bit if that fails.
-  * This function also updates quota and i_blocks field.
-  */
--int ext3_new_block(handle_t *handle, struct inode *inode,
-+int ext3_new_block_old(handle_t *handle, struct inode *inode,
- 			unsigned long goal, int *errp)
- {
- 	struct buffer_head *bitmap_bh = NULL;
-Index: linux-2.6.9-full/fs/ext3/inode.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/inode.c	2007-03-28 01:29:39.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/inode.c	2007-03-28 15:45:41.000000000 +0400
-@@ -572,7 +572,7 @@ static int ext3_alloc_branch(handle_t *h
- 		ext3_journal_forget(handle, branch[i].bh);
- 	}
- 	for (i = 0; i < keys; i++)
--		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1);
-+		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1, 0);
- 	return err;
- }
- 
-@@ -673,7 +673,7 @@ err_out:
- 	if (err == -EAGAIN)
- 		for (i = 0; i < num; i++)
- 			ext3_free_blocks(handle, inode, 
--					 le32_to_cpu(where[i].key), 1);
-+					 le32_to_cpu(where[i].key), 1, 0);
- 	return err;
- }
- 
-@@ -1834,7 +1834,7 @@ ext3_clear_blocks(handle_t *handle, stru
- 		}
- 	}
- 
--	ext3_free_blocks(handle, inode, block_to_free, count);
-+	ext3_free_blocks(handle, inode, block_to_free, count, 0);
- }
- 
- /**
-@@ -2007,7 +2007,7 @@ static void ext3_free_branches(handle_t 
- 				ext3_journal_test_restart(handle, inode);
- 			}
- 
--			ext3_free_blocks(handle, inode, nr, 1);
-+			ext3_free_blocks(handle, inode, nr, 1, 1);
- 
- 			if (parent_bh) {
- 				/*
diff --git a/lustre/kernel_patches/patches/ext3-mballoc3-sles10.patch b/lustre/kernel_patches/patches/ext3-mballoc3-sles10.patch
deleted file mode 100644
index 373f0c6680..0000000000
--- a/lustre/kernel_patches/patches/ext3-mballoc3-sles10.patch
+++ /dev/null
@@ -1,377 +0,0 @@
-Index: linux-2.6.16.27-0.9-full/include/linux/ext3_fs_i.h
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/include/linux/ext3_fs_i.h	2007-03-28 05:12:50.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/include/linux/ext3_fs_i.h	2007-03-28 16:03:20.000000000 +0400
-@@ -135,6 +135,10 @@ struct ext3_inode_info {
- 	struct inode vfs_inode;
- 
- 	__u32 i_cached_extent[4];
-+
-+	/* mballoc */
-+	struct list_head i_prealloc_list;
-+	spinlock_t i_prealloc_lock;
- };
- 
- #endif	/* _LINUX_EXT3_FS_I */
-Index: linux-2.6.16.27-0.9-full/include/linux/ext3_fs_sb.h
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/include/linux/ext3_fs_sb.h	2007-03-28 16:03:19.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/include/linux/ext3_fs_sb.h	2007-03-28 16:03:20.000000000 +0400
-@@ -21,8 +21,15 @@
- #include <linux/wait.h>
- #include <linux/blockgroup_lock.h>
- #include <linux/percpu_counter.h>
-+#include <linux/list.h>
- #endif
- #include <linux/rbtree.h>
-+#include <linux/proc_fs.h>
-+
-+struct ext3_buddy_group_blocks;
-+struct ext3_locality_group;
-+struct ext3_mb_history;
-+#define EXT3_BB_MAX_BLOCKS
- 
- /*
-  * third extended-fs super-block data in memory
-Index: linux-2.6.16.27-0.9-full/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/include/linux/ext3_fs.h	2007-03-28 16:03:19.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/include/linux/ext3_fs.h	2007-03-28 16:03:20.000000000 +0400
-@@ -407,6 +407,7 @@ struct ext3_inode {
- #define EXT3_MOUNT_IOPEN_NOPRIV		0x800000/* Make iopen world-readable */
- #define EXT3_MOUNT_EXTENTS		0x1000000/* Extents support */
- #define EXT3_MOUNT_EXTDEBUG		0x2000000/* Extents debug */
-+#define EXT3_MOUNT_MBALLOC		0x4000000/* Buddy allocation support */
- 
- /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
- #ifndef clear_opt
-@@ -767,8 +768,9 @@ struct dir_private_info {
- extern int ext3_bg_has_super(struct super_block *sb, int group);
- extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
- extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
-+extern int ext3_new_block_old (handle_t *, struct inode *, unsigned long, int *);
- extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
--			      unsigned long);
-+			      unsigned long, int);
- extern void ext3_free_blocks_sb (handle_t *, struct super_block *,
- 				 unsigned long, unsigned long, int *);
- extern unsigned long ext3_count_free_blocks (struct super_block *);
-Index: linux-2.6.16.27-0.9-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/super.c	2007-03-28 16:03:19.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/super.c	2007-03-28 16:03:20.000000000 +0400
-@@ -688,6 +688,7 @@ enum {
- 	Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
- 	Opt_iopen, Opt_noiopen, Opt_iopen_nopriv,
- 	Opt_extents, Opt_noextents, Opt_extdebug,
-+	Opt_mballoc, Opt_nomballoc, Opt_stripe,
- 	Opt_grpquota
- };
- 
-@@ -743,6 +744,9 @@ static match_table_t tokens = {
- 	{Opt_noextents, "noextents"},
- 	{Opt_extdebug, "extdebug"},
- 	{Opt_barrier, "barrier=%u"},
-+	{Opt_mballoc, "mballoc"},
-+	{Opt_nomballoc, "nomballoc"},
-+	{Opt_stripe, "stripe=%u"},
- 	{Opt_err, NULL},
- 	{Opt_resize, "resize"},
- };
-@@ -1092,6 +1096,19 @@ clear_qf_name:
- 		case Opt_extdebug:
- 			set_opt (sbi->s_mount_opt, EXTDEBUG);
- 			break;
-+		case Opt_mballoc:
-+			set_opt(sbi->s_mount_opt, MBALLOC);
-+			break;
-+		case Opt_nomballoc:
-+			clear_opt(sbi->s_mount_opt, MBALLOC);
-+			break;
-+		case Opt_stripe:
-+			if (match_int(&args[0], &option))
-+				return 0;
-+			if (option < 0)
-+				return 0;
-+			sbi->s_stripe = option;
-+			break;
- 		default:
- 			printk (KERN_ERR
- 				"EXT3-fs: Unrecognized mount option \"%s\" "
-@@ -1819,6 +1836,7 @@ static int ext3_fill_super (struct super
- 		ext3_count_dirs(sb));
- 
- 	ext3_ext_init(sb);
-+	ext3_mb_init(sb, needs_recovery);
- 	lock_kernel();
- 	return 0;
- 
-Index: linux-2.6.16.27-0.9-full/fs/ext3/extents.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/extents.c	2007-03-28 05:13:39.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/extents.c	2007-03-28 16:03:20.000000000 +0400
-@@ -779,7 +779,7 @@ cleanup:
- 		for (i = 0; i < depth; i++) {
- 			if (!ablocks[i])
- 				continue;
--			ext3_free_blocks(handle, tree->inode, ablocks[i], 1);
-+			ext3_free_blocks(handle, tree->inode, ablocks[i], 1, 1);
- 		}
- 	}
- 	kfree(ablocks);
-@@ -1586,7 +1586,7 @@ int ext3_ext_rm_idx(handle_t *handle, st
- 		  path->p_idx->ei_leaf);
- 	bh = sb_find_get_block(tree->inode->i_sb, path->p_idx->ei_leaf);
- 	ext3_forget(handle, 1, tree->inode, bh, path->p_idx->ei_leaf);
--	ext3_free_blocks(handle, tree->inode, path->p_idx->ei_leaf, 1);
-+	ext3_free_blocks(handle, tree->inode, path->p_idx->ei_leaf, 1, 1);
- 	return err;
- }
- 
-@@ -2071,10 +2071,12 @@ ext3_remove_blocks(struct ext3_extents_t
- 	int needed = ext3_remove_blocks_credits(tree, ex, from, to);
- 	handle_t *handle = ext3_journal_start(tree->inode, needed);
- 	struct buffer_head *bh;
--	int i;
-+	int i, metadata = 0;
- 
- 	if (IS_ERR(handle))
- 		return PTR_ERR(handle);
-+	if (S_ISDIR(tree->inode->i_mode) || S_ISLNK(tree->inode->i_mode))
-+		metadata = 1;
- 	if (from >= ex->ee_block && to == ex->ee_block + ex->ee_len - 1) {
- 		/* tail removal */
- 		unsigned long num, start;
-@@ -2086,7 +2088,7 @@ ext3_remove_blocks(struct ext3_extents_t
- 			bh = sb_find_get_block(tree->inode->i_sb, start + i);
- 			ext3_forget(handle, 0, tree->inode, bh, start + i);
- 		}
--		ext3_free_blocks(handle, tree->inode, start, num);
-+		ext3_free_blocks(handle, tree->inode, start, num, metadata);
- 	} else if (from == ex->ee_block && to <= ex->ee_block + ex->ee_len - 1) {
- 		printk("strange request: removal %lu-%lu from %u:%u\n",
- 		       from, to, ex->ee_block, ex->ee_len);
-@@ -2177,11 +2179,8 @@ int ext3_ext_get_block(handle_t *handle,
- 	struct ext3_extent *ex;
- 	int goal, newblock, err = 0, depth;
- 	struct ext3_extents_tree tree;
--	unsigned long next;
--	int allocated = 0;
--
--	/* until we have multiblock allocation */
--	max_blocks = 1;
-+	unsigned long allocated = 0;
-+	struct ext3_allocation_request ar;
- 
- 	clear_buffer_new(bh_result);
- 	ext3_init_tree_desc(&tree, inode);
-@@ -2253,18 +2252,33 @@ int ext3_ext_get_block(handle_t *handle,
- 		goto out2;
- 	}
- 
-+	/* find neighbour allocated blocks */
-+	ar.lleft = iblock;
-+	err = ext3_ext_search_left(&tree, path, &ar.lleft, &ar.pleft);
-+	if (err)
-+		goto out2;
-+	ar.lright = iblock;
-+	err = ext3_ext_search_right(&tree, path, &ar.lright, &ar.pright);
-+	if (err)
-+		goto out2;
-+
- 	/* find next allocated block so that we know how many
- 	 * blocks we can allocate without ovelapping next extent */
--	EXT_ASSERT(iblock >= ex->ee_block + ex->ee_len);
--	next = ext3_ext_next_allocated_block(path);
--	EXT_ASSERT(next > iblock);
--	allocated = next - iblock;
-+	EXT_ASSERT(ar.pright == 0 || ar.lright > iblock);
-+	if (ar.pright == 0)
-+		allocated = EXT_MAX_BLOCK - iblock;
-+	else
-+		allocated = ar.lright - iblock;
- 	if (allocated > max_blocks)
- 		allocated = max_blocks;
- 
- 	/* allocate new block */
--	goal = ext3_ext_find_goal(inode, path, iblock);
--	newblock = ext3_new_block(handle, inode, goal, &err);
-+	ar.inode = inode;
-+	ar.goal = ext3_ext_find_goal(inode, path, iblock);
-+	ar.logical = iblock;
-+	ar.len = allocated;
-+	ar.flags = EXT3_MB_HINT_DATA;
-+	newblock = ext3_mb_new_blocks(handle, &ar, &err);
- 	if (!newblock)
- 		goto out2;
- 	ext_debug(&tree, "allocate new block: goal %d, found %d\n",
-@@ -2274,11 +2288,14 @@ int ext3_ext_get_block(handle_t *handle,
- 	newex.ee_block = iblock;
- 	newex.ee_start = newblock;
- 	newex.ee_start_hi = 0;
--	newex.ee_len = 1;
-+	newex.ee_len = ar.len;
- 	err = ext3_ext_insert_extent(handle, &tree, path, &newex);
- 	if (err) {
- 		/* free data blocks we just allocated */
--		ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len);
-+		/* not a good idea to call discard here directly,
-+		 * but otherwise we'd need to call it every free() */
-+		ext3_mb_discard_inode_preallocations(inode);
-+		ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len, 0);
- 		goto out2;
- 	}
- 	
-@@ -2287,6 +2304,7 @@ int ext3_ext_get_block(handle_t *handle,
- 
- 	/* previous routine could use block we allocated */
- 	newblock = newex.ee_start;
-+	allocated = newex.ee_len;
- 	set_buffer_new(bh_result);
- 
- 	ext3_ext_put_in_cache(&tree, newex.ee_block, newex.ee_len,
-@@ -2339,6 +2357,9 @@ void ext3_ext_truncate(struct inode * in
- 	down(&EXT3_I(inode)->truncate_sem);
- 	ext3_ext_invalidate_cache(&tree);
- 
-+	/* it's important to discard preallocations under truncate_sem */
-+	ext3_mb_discard_inode_preallocations(inode);
-+
- 	/* 
- 	 * TODO: optimization is possible here
- 	 * probably we need not scaning at all,
-Index: linux-2.6.16.27-0.9-full/fs/ext3/Makefile
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/Makefile	2007-03-28 05:12:50.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/Makefile	2007-03-28 16:03:20.000000000 +0400
-@@ -6,7 +6,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o
- 
- ext3-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
- 	   ioctl.o namei.o super.o symlink.o hash.o resize.o \
--	   extents.o
-+	   extents.o mballoc.o
- 
- ext3-$(CONFIG_EXT3_FS_XATTR)	 += xattr.o xattr_user.o xattr_trusted.o
- ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
-Index: linux-2.6.16.27-0.9-full/fs/ext3/xattr.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/xattr.c	2007-03-13 02:56:52.000000000 +0300
-+++ linux-2.6.16.27-0.9-full/fs/ext3/xattr.c	2007-03-28 16:03:20.000000000 +0400
-@@ -484,7 +484,7 @@ ext3_xattr_release_block(handle_t *handl
- 		ea_bdebug(bh, "refcount now=0; freeing");
- 		if (ce)
- 			mb_cache_entry_free(ce);
--		ext3_free_blocks(handle, inode, bh->b_blocknr, 1);
-+		ext3_free_blocks(handle, inode, bh->b_blocknr, 1, 1);
- 		get_bh(bh);
- 		ext3_forget(handle, 1, inode, bh, bh->b_blocknr);
- 	} else {
-@@ -804,7 +804,7 @@ inserted:
- 			new_bh = sb_getblk(sb, block);
- 			if (!new_bh) {
- getblk_failed:
--				ext3_free_blocks(handle, inode, block, 1);
-+				ext3_free_blocks(handle, inode, block, 1, 1);
- 				error = -EIO;
- 				goto cleanup;
- 			}
-Index: linux-2.6.16.27-0.9-full/fs/ext3/balloc.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/balloc.c	2007-03-13 02:56:52.000000000 +0300
-+++ linux-2.6.16.27-0.9-full/fs/ext3/balloc.c	2007-03-28 16:03:20.000000000 +0400
-@@ -80,7 +80,7 @@ struct ext3_group_desc * ext3_get_group_
-  *
-  * Return buffer_head on success or NULL in case of failure.
-  */
--static struct buffer_head *
-+struct buffer_head *
- read_block_bitmap(struct super_block *sb, unsigned int block_group)
- {
- 	struct ext3_group_desc * desc;
-@@ -296,6 +296,8 @@ void ext3_discard_reservation(struct ino
- 	struct ext3_reserve_window_node *rsv;
- 	spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock;
- 
-+	ext3_mb_discard_inode_preallocations(inode);
-+
- 	if (!block_i)
- 		return;
- 
-@@ -491,21 +493,25 @@ error_return:
- 	return;
- }
- 
--/* Free given blocks, update quota and i_blocks field */
--void ext3_free_blocks(handle_t *handle, struct inode *inode,
--			unsigned long block, unsigned long count)
-+void ext3_free_blocks(handle_t *handle, struct inode * inode,
-+		unsigned long block, unsigned long count, int metadata)
- {
--	struct super_block * sb;
--	int dquot_freed_blocks;
-+	struct super_block *sb;
-+	int freed;
-+
-+	/* this isn't the right place to decide whether block is metadata
-+	 * inode.c/extents.c knows better, but for safety ... */
-+	if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) ||
-+			ext3_should_journal_data(inode))
-+		metadata = 1;
- 
- 	sb = inode->i_sb;
--	if (!sb) {
--		printk ("ext3_free_blocks: nonexistent device");
--		return;
--	}
--	ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks);
--	if (dquot_freed_blocks)
--		DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
-+	if (!test_opt(sb, MBALLOC) || !EXT3_SB(sb)->s_group_info)
-+		ext3_free_blocks_sb(handle, sb, block, count, &freed);
-+	else
-+		ext3_mb_free_blocks(handle, inode, block, count, metadata, &freed);
-+	if (freed)
-+		DQUOT_FREE_BLOCK(inode, freed);
- 	return;
- }
- 
-@@ -1154,7 +1160,7 @@ int ext3_should_retry_alloc(struct super
-  * bitmap, and then for any free bit if that fails.
-  * This function also updates quota and i_blocks field.
-  */
--int ext3_new_block(handle_t *handle, struct inode *inode,
-+int ext3_new_block_old(handle_t *handle, struct inode *inode,
- 			unsigned long goal, int *errp)
- {
- 	struct buffer_head *bitmap_bh = NULL;
-Index: linux-2.6.16.27-0.9-full/fs/ext3/inode.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/inode.c	2007-03-28 05:13:38.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/inode.c	2007-03-28 16:03:20.000000000 +0400
-@@ -568,7 +568,7 @@ static int ext3_alloc_branch(handle_t *h
- 		ext3_journal_forget(handle, branch[i].bh);
- 	}
- 	for (i = 0; i < keys; i++)
--		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1);
-+		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1, 0);
- 	return err;
- }
- 
-@@ -1865,7 +1865,7 @@ ext3_clear_blocks(handle_t *handle, stru
- 		}
- 	}
- 
--	ext3_free_blocks(handle, inode, block_to_free, count);
-+	ext3_free_blocks(handle, inode, block_to_free, count, 0);
- }
- 
- /**
-@@ -2038,7 +2038,7 @@ static void ext3_free_branches(handle_t 
- 				ext3_journal_test_restart(handle, inode);
- 			}
- 
--			ext3_free_blocks(handle, inode, nr, 1);
-+			ext3_free_blocks(handle, inode, nr, 1, 1);
- 
- 			if (parent_bh) {
- 				/*
diff --git a/lustre/kernel_patches/patches/ext3-mballoc3-suse.patch b/lustre/kernel_patches/patches/ext3-mballoc3-suse.patch
deleted file mode 100644
index dd07148688..0000000000
--- a/lustre/kernel_patches/patches/ext3-mballoc3-suse.patch
+++ /dev/null
@@ -1,397 +0,0 @@
-Index: linux-2.6.5-7.283-full/include/linux/ext3_fs_i.h
-===================================================================
---- linux-2.6.5-7.283-full.orig/include/linux/ext3_fs_i.h	2007-03-28 02:13:37.000000000 +0400
-+++ linux-2.6.5-7.283-full/include/linux/ext3_fs_i.h	2007-03-28 15:46:02.000000000 +0400
-@@ -131,6 +131,10 @@ struct ext3_inode_info {
- 	struct inode vfs_inode;
- 
- 	struct ext3_ext_cache i_cached_extent;
-+
-+	/* mballoc */
-+	struct list_head i_prealloc_list;
-+	spinlock_t i_prealloc_lock;
- };
- 
- #endif	/* _LINUX_EXT3_FS_I */
-Index: linux-2.6.5-7.283-full/include/linux/ext3_fs_sb.h
-===================================================================
---- linux-2.6.5-7.283-full.orig/include/linux/ext3_fs_sb.h	2007-03-28 15:46:00.000000000 +0400
-+++ linux-2.6.5-7.283-full/include/linux/ext3_fs_sb.h	2007-03-28 15:46:02.000000000 +0400
-@@ -23,9 +23,16 @@
- #define EXT_INCLUDE
- #include <linux/blockgroup_lock.h>
- #include <linux/percpu_counter.h>
-+#include <linux/list.h>
- #endif
- #endif
- #include <linux/rbtree.h>
-+#include <linux/proc_fs.h>
-+
-+struct ext3_buddy_group_blocks;
-+struct ext3_locality_group;
-+struct ext3_mb_history;
-+#define EXT3_BB_MAX_BLOCKS
- 
- /*
-  * third extended-fs super-block data in memory
-Index: linux-2.6.5-7.283-full/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.5-7.283-full.orig/include/linux/ext3_fs.h	2007-03-28 15:46:00.000000000 +0400
-+++ linux-2.6.5-7.283-full/include/linux/ext3_fs.h	2007-03-28 15:46:02.000000000 +0400
-@@ -363,6 +363,7 @@ struct ext3_inode {
- #define EXT3_MOUNT_IOPEN_NOPRIV		0x100000/* Make iopen world-readable */
- #define EXT3_MOUNT_EXTENTS		0x200000/* Extents support */
- #define EXT3_MOUNT_EXTDEBUG		0x400000/* Extents debug */
-+#define EXT3_MOUNT_MBALLOC		0x800000/* Buddy allocation support */
- 
- /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
- #ifndef clear_opt
-@@ -723,8 +724,9 @@ struct dir_private_info {
- extern int ext3_bg_has_super(struct super_block *sb, int group);
- extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
- extern int ext3_new_block (handle_t *, struct inode *, unsigned long, int *);
-+extern int ext3_new_block_old (handle_t *, struct inode *, unsigned long, int *);
- extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
--			      unsigned long);
-+			      unsigned long, int);
- extern unsigned long ext3_count_free_blocks (struct super_block *);
- extern void ext3_check_blocks_bitmap (struct super_block *);
- extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
-Index: linux-2.6.5-7.283-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/super.c	2007-03-28 15:46:00.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/super.c	2007-03-28 15:46:02.000000000 +0400
-@@ -622,6 +622,7 @@ enum {
- 	Opt_err,
- 	Opt_iopen, Opt_noiopen, Opt_iopen_nopriv,
- 	Opt_extents, Opt_noextents, Opt_extdebug,
-+	Opt_mballoc, Opt_nomballoc, Opt_stripe,
- };
- 
- static match_table_t tokens = {
-@@ -669,6 +670,9 @@ static match_table_t tokens = {
- 	{Opt_noextents, "noextents"},
- 	{Opt_extdebug, "extdebug"},
- 	{Opt_barrier, "barrier=%u"},
-+	{Opt_mballoc, "mballoc"},
-+	{Opt_nomballoc, "nomballoc"},
-+	{Opt_stripe, "stripe=%u"},
- 	{Opt_err, NULL}
- };
- 
-@@ -893,6 +897,19 @@ static int parse_options (char * options
- 		case Opt_extdebug:
- 			set_opt (sbi->s_mount_opt, EXTDEBUG);
- 			break;
-+		case Opt_mballoc:
-+			set_opt(sbi->s_mount_opt, MBALLOC);
-+			break;
-+		case Opt_nomballoc:
-+			clear_opt(sbi->s_mount_opt, MBALLOC);
-+			break;
-+		case Opt_stripe:
-+			if (match_int(&args[0], &option))
-+				return 0;
-+			if (option < 0)
-+				return 0;
-+			sbi->s_stripe = option;
-+			break;
- 		default:
- 			printk (KERN_ERR
- 				"EXT3-fs: Unrecognized mount option \"%s\" "
-@@ -1548,6 +1565,7 @@ static int ext3_fill_super (struct super
- 		ext3_count_dirs(sb));
- 
- 	ext3_ext_init(sb);
-+	ext3_mb_init(sb, needs_recovery);
- 
- 	return 0;
- 
-Index: linux-2.6.5-7.283-full/fs/ext3/extents.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/extents.c	2007-03-28 03:18:19.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/extents.c	2007-03-28 15:46:02.000000000 +0400
-@@ -779,7 +779,7 @@ cleanup:
- 		for (i = 0; i < depth; i++) {
- 			if (!ablocks[i])
- 				continue;
--			ext3_free_blocks(handle, tree->inode, ablocks[i], 1);
-+			ext3_free_blocks(handle, tree->inode, ablocks[i], 1, 1);
- 		}
- 	}
- 	kfree(ablocks);
-@@ -1586,7 +1586,7 @@ int ext3_ext_rm_idx(handle_t *handle, st
- 		  path->p_idx->ei_leaf);
- 	bh = sb_find_get_block(tree->inode->i_sb, path->p_idx->ei_leaf);
- 	ext3_forget(handle, 1, tree->inode, bh, path->p_idx->ei_leaf);
--	ext3_free_blocks(handle, tree->inode, path->p_idx->ei_leaf, 1);
-+	ext3_free_blocks(handle, tree->inode, path->p_idx->ei_leaf, 1, 1);
- 	return err;
- }
- 
-@@ -2071,10 +2071,12 @@ ext3_remove_blocks(struct ext3_extents_t
- 	int needed = ext3_remove_blocks_credits(tree, ex, from, to);
- 	handle_t *handle = ext3_journal_start(tree->inode, needed);
- 	struct buffer_head *bh;
--	int i;
-+	int i, metadata = 0;
- 
- 	if (IS_ERR(handle))
- 		return PTR_ERR(handle);
-+	if (S_ISDIR(tree->inode->i_mode) || S_ISLNK(tree->inode->i_mode))
-+		metadata = 1;
- 	if (from >= ex->ee_block && to == ex->ee_block + ex->ee_len - 1) {
- 		/* tail removal */
- 		unsigned long num, start;
-@@ -2086,7 +2088,7 @@ ext3_remove_blocks(struct ext3_extents_t
- 			bh = sb_find_get_block(tree->inode->i_sb, start + i);
- 			ext3_forget(handle, 0, tree->inode, bh, start + i);
- 		}
--		ext3_free_blocks(handle, tree->inode, start, num);
-+		ext3_free_blocks(handle, tree->inode, start, num, metadata);
- 	} else if (from == ex->ee_block && to <= ex->ee_block + ex->ee_len - 1) {
- 		printk("strange request: removal %lu-%lu from %u:%u\n",
- 		       from, to, ex->ee_block, ex->ee_len);
-@@ -2177,11 +2179,8 @@ int ext3_ext_get_block(handle_t *handle,
- 	struct ext3_extent *ex;
- 	int goal, newblock, err = 0, depth;
- 	struct ext3_extents_tree tree;
--	unsigned long next;
--	int allocated = 0;
--
--	/* until we have multiblock allocation */
--	max_blocks = 1;
-+	unsigned long allocated = 0;
-+	struct ext3_allocation_request ar;
- 
- 	__clear_bit(BH_New, &bh_result->b_state);
- 	ext3_init_tree_desc(&tree, inode);
-@@ -2253,18 +2252,33 @@ int ext3_ext_get_block(handle_t *handle,
- 		goto out2;
- 	}
- 
-+	/* find neighbour allocated blocks */
-+	ar.lleft = iblock;
-+	err = ext3_ext_search_left(&tree, path, &ar.lleft, &ar.pleft);
-+	if (err)
-+		goto out2;
-+	ar.lright = iblock;
-+	err = ext3_ext_search_right(&tree, path, &ar.lright, &ar.pright);
-+	if (err)
-+		goto out2;
-+
- 	/* find next allocated block so that we know how many
- 	 * blocks we can allocate without ovelapping next extent */
--	EXT_ASSERT(iblock >= ex->ee_block + ex->ee_len);
--	next = ext3_ext_next_allocated_block(path);
--	EXT_ASSERT(next > iblock);
--	allocated = next - iblock;
-+	EXT_ASSERT(ar.pright == 0 || ar.lright > iblock);
-+	if (ar.pright == 0)
-+		allocated = EXT_MAX_BLOCK - iblock;
-+	else
-+		allocated = ar.lright - iblock;
- 	if (allocated > max_blocks)
- 		allocated = max_blocks;
- 
- 	/* allocate new block */
--	goal = ext3_ext_find_goal(inode, path, iblock);
--	newblock = ext3_new_block(handle, inode, goal, &err);
-+	ar.inode = inode;
-+	ar.goal = ext3_ext_find_goal(inode, path, iblock);
-+	ar.logical = iblock;
-+	ar.len = allocated;
-+	ar.flags = EXT3_MB_HINT_DATA;
-+	newblock = ext3_mb_new_blocks(handle, &ar, &err);
- 	if (!newblock)
- 		goto out2;
- 	ext_debug(&tree, "allocate new block: goal %d, found %d\n",
-@@ -2274,11 +2288,14 @@ int ext3_ext_get_block(handle_t *handle,
- 	newex.ee_block = iblock;
- 	newex.ee_start = newblock;
- 	newex.ee_start_hi = 0;
--	newex.ee_len = 1;
-+	newex.ee_len = ar.len;
- 	err = ext3_ext_insert_extent(handle, &tree, path, &newex);
- 	if (err) {
- 		/* free data blocks we just allocated */
--		ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len);
-+		/* not a good idea to call discard here directly,
-+		 * but otherwise we'd need to call it every free() */
-+		ext3_mb_discard_inode_preallocations(inode);
-+		ext3_free_blocks(handle, inode, newex.ee_start, newex.ee_len, 0);
- 		goto out2;
- 	}
- 	
-@@ -2287,6 +2304,7 @@ int ext3_ext_get_block(handle_t *handle,
- 
- 	/* previous routine could use block we allocated */
- 	newblock = newex.ee_start;
-+	allocated = newex.ee_len;
- 	__set_bit(BH_New, &bh_result->b_state);
- 
- 	ext3_ext_put_in_cache(&tree, newex.ee_block, newex.ee_len,
-@@ -2341,6 +2359,9 @@ void ext3_ext_truncate(struct inode * in
- 	down(&EXT3_I(inode)->truncate_sem);
- 	ext3_ext_invalidate_cache(&tree);
- 
-+	/* it's important to discard preallocations under truncate_sem */
-+	ext3_mb_discard_inode_preallocations(inode);
-+
- 	/* 
- 	 * TODO: optimization is possible here
- 	 * probably we need not scaning at all,
-Index: linux-2.6.5-7.283-full/fs/ext3/Makefile
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/Makefile	2007-03-28 15:27:39.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/Makefile	2007-03-28 15:46:02.000000000 +0400
-@@ -6,7 +6,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o
- 
- ext3-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
- 	   ioctl.o namei.o super.o symlink.o hash.o \
--	   extents.o
-+	   extents.o mballoc.o
- 
- ext3-$(CONFIG_EXT3_FS_XATTR)	 += xattr.o xattr_user.o xattr_trusted.o
- ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
-Index: linux-2.6.5-7.283-full/fs/ext3/xattr.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/xattr.c	2007-03-28 02:13:37.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/xattr.c	2007-03-28 15:46:02.000000000 +0400
-@@ -1371,7 +1371,7 @@ ext3_xattr_set_handle2(handle_t *handle,
- 			new_bh = sb_getblk(sb, block);
- 			if (!new_bh) {
- getblk_failed:
--				ext3_free_blocks(handle, inode, block, 1);
-+				ext3_free_blocks(handle, inode, block, 1, 1);
- 				error = -EIO;
- 				goto cleanup;
- 			}
-@@ -1411,7 +1411,7 @@ getblk_failed:
- 		if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {
- 			/* Free the old block. */
- 			ea_bdebug(old_bh, "freeing");
--			ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1);
-+			ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1, 1);
- 
- 			/* ext3_forget() calls bforget() for us, but we
- 			   let our caller release old_bh, so we need to
-@@ -1519,7 +1519,7 @@ ext3_xattr_delete_inode(handle_t *handle
- 			mb_cache_entry_free(ce);
- 			ce = NULL;
- 		}
--		ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1);
-+		ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1, 1);
- 		get_bh(bh);
- 		ext3_forget(handle, 1, inode, bh, EXT3_I(inode)->i_file_acl);
- 	} else {
-Index: linux-2.6.5-7.283-full/fs/ext3/balloc.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/balloc.c	2006-12-01 18:39:48.000000000 +0300
-+++ linux-2.6.5-7.283-full/fs/ext3/balloc.c	2007-03-28 15:46:02.000000000 +0400
-@@ -78,7 +78,7 @@ struct ext3_group_desc * ext3_get_group_
-  *
-  * Return buffer_head on success or NULL in case of failure.
-  */
--static struct buffer_head *
-+struct buffer_head *
- read_block_bitmap(struct super_block *sb, unsigned int block_group)
- {
- 	struct ext3_group_desc * desc;
-@@ -266,6 +266,8 @@ void ext3_discard_reservation(struct ino
- 	struct reserve_window_node *rsv = &ei->i_rsv_window;
- 	spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock;
- 
-+	ext3_mb_discard_inode_preallocations(inode);
-+
- 	if (!rsv_is_empty(&rsv->rsv_window)) {
- 		spin_lock(rsv_lock);
- 		rsv_window_remove(inode->i_sb, rsv);
-@@ -274,7 +276,7 @@ void ext3_discard_reservation(struct ino
- }
- 
- /* Free given blocks, update quota and i_blocks field */
--void ext3_free_blocks(handle_t *handle, struct inode *inode,
-+void ext3_free_blocks_old(handle_t *handle, struct inode *inode,
- 			unsigned long block, unsigned long count)
- {
- 	struct buffer_head *bitmap_bh = NULL;
-@@ -456,6 +458,29 @@ error_return:
- 	return;
- }
- 
-+void ext3_free_blocks(handle_t *handle, struct inode * inode,
-+		unsigned long block, unsigned long count, int metadata)
-+{
-+	struct super_block *sb;
-+	int freed;
-+
-+	/* this isn't the right place to decide whether block is metadata
-+	 * inode.c/extents.c knows better, but for safety ... */
-+	if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) ||
-+			ext3_should_journal_data(inode))
-+		metadata = 1;
-+
-+	sb = inode->i_sb;
-+	if (!test_opt(sb, MBALLOC) || !EXT3_SB(sb)->s_group_info)
-+		ext3_free_blocks_old(handle, inode, block, count);
-+	else {
-+		ext3_mb_free_blocks(handle, inode, block, count, metadata, &freed);
-+		if (freed)
-+			DQUOT_FREE_BLOCK(inode, freed);
-+	}
-+	return;
-+}
-+
- /*
-  * For ext3 allocations, we must not reuse any blocks which are
-  * allocated in the bitmap buffer's "last committed data" copy.  This
-@@ -1142,7 +1167,7 @@ int ext3_should_retry_alloc(struct super
-  * bitmap, and then for any free bit if that fails.
-  * This function also updates quota and i_blocks field.
-  */
--int ext3_new_block(handle_t *handle, struct inode *inode,
-+int ext3_new_block_old(handle_t *handle, struct inode *inode,
- 			unsigned long goal, int *errp)
- {
- 	struct buffer_head *bitmap_bh = NULL;
-Index: linux-2.6.5-7.283-full/fs/ext3/inode.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/inode.c	2007-03-28 02:50:19.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/inode.c	2007-03-28 15:46:02.000000000 +0400
-@@ -574,7 +574,7 @@ static int ext3_alloc_branch(handle_t *h
- 		ext3_journal_forget(handle, branch[i].bh);
- 	}
- 	for (i = 0; i < keys; i++)
--		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1);
-+		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1, 0);
- 	return err;
- }
- 
-@@ -675,7 +675,7 @@ err_out:
- 	if (err == -EAGAIN)
- 		for (i = 0; i < num; i++)
- 			ext3_free_blocks(handle, inode, 
--					 le32_to_cpu(where[i].key), 1);
-+					 le32_to_cpu(where[i].key), 1, 0);
- 	return err;
- }
- 
-@@ -1839,7 +1839,7 @@ ext3_clear_blocks(handle_t *handle, stru
- 		}
- 	}
- 
--	ext3_free_blocks(handle, inode, block_to_free, count);
-+	ext3_free_blocks(handle, inode, block_to_free, count, 0);
- }
- 
- /**
-@@ -2010,7 +2010,7 @@ static void ext3_free_branches(handle_t 
- 				ext3_journal_test_restart(handle, inode);
- 			}
- 
--			ext3_free_blocks(handle, inode, nr, 1);
-+			ext3_free_blocks(handle, inode, nr, 1, 1);
- 
- 			if (parent_bh) {
- 				/*
diff --git a/lustre/kernel_patches/patches/ext3-multi-mount-protection-2.6-fc5.patch b/lustre/kernel_patches/patches/ext3-multi-mount-protection-2.6-fc5.patch
deleted file mode 100644
index 0c41b47614..0000000000
--- a/lustre/kernel_patches/patches/ext3-multi-mount-protection-2.6-fc5.patch
+++ /dev/null
@@ -1,381 +0,0 @@
-Index: mmp/fs/ext3/al.h
-===================================================================
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ mmp/fs/ext3/al.h	2006-07-24 10:39:26.000000000 +0800
-@@ -0,0 +1,11 @@
-+/*
-+ * (C) 2006  Qi Yong <qiyong@clusterfs.com>
-+ */
-+
-+#define	ALIVE_MAGIC	0xA1153C29
-+struct alive_struct {
-+	__le32	al_magic;
-+	__le32	al_seq;
-+	__le32	al_time;
-+	char	al_nodename[65];
-+};
-Index: mmp/fs/ext3/namei.c
-===================================================================
---- mmp.orig/fs/ext3/namei.c	2006-07-24 10:34:41.000000000 +0800
-+++ mmp/fs/ext3/namei.c	2006-07-24 10:39:26.000000000 +0800
-@@ -805,7 +805,7 @@ static inline int search_dirblock(struct
-  * The returned buffer_head has ->b_count elevated.  The caller is expected
-  * to brelse() it when appropriate.
-  */
--static struct buffer_head * ext3_find_entry (struct dentry *dentry,
-+struct buffer_head * ext3_find_entry (struct dentry *dentry,
- 					struct ext3_dir_entry_2 ** res_dir)
- {
- 	struct super_block * sb;
-Index: mmp/fs/ext3/super.c
-===================================================================
---- mmp.orig/fs/ext3/super.c	2006-07-24 10:34:41.000000000 +0800
-+++ mmp/fs/ext3/super.c	2006-07-24 10:45:19.000000000 +0800
-@@ -36,12 +36,14 @@
- #include <linux/namei.h>
- #include <linux/quotaops.h>
- #include <linux/seq_file.h>
-+#include <linux/kthread.h>
- 
- #include <asm/uaccess.h>
- 
- #include "xattr.h"
- #include "acl.h"
- #include "namei.h"
-+#include "al.h"
- 
- static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
- 			     unsigned long journal_devnum);
-@@ -62,6 +64,8 @@ static int ext3_statfs (struct super_blo
- static void ext3_unlockfs(struct super_block *sb);
- static void ext3_write_super (struct super_block * sb);
- static void ext3_write_super_lockfs(struct super_block *sb);
-+struct buffer_head * ext3_find_entry (struct dentry *dentry,
-+					struct ext3_dir_entry_2 ** res_dir);
- 
- /* 
-  * Wrappers for journal_start/end.
-@@ -435,6 +439,9 @@ static void ext3_put_super (struct super
- 		invalidate_bdev(sbi->journal_bdev, 0);
- 		ext3_blkdev_remove(sbi);
- 	}
-+	if (sbi->s_alive_tsk)
-+		kthread_stop(sbi->s_alive_tsk);
-+
- 	sb->s_fs_info = NULL;
- 	kfree(sbi);
- 	return;
-@@ -1369,6 +1376,261 @@ static unsigned long descriptor_loc(stru
- 	return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
- }
- 
-+static int write_alive(struct buffer_head * bh)
-+{
-+	lock_buffer(bh);
-+	bh->b_end_io = end_buffer_write_sync;
-+	get_bh(bh);
-+	submit_bh(WRITE, bh);
-+	wait_on_buffer(bh);
-+	if (unlikely(!buffer_uptodate(bh)))
-+		return 1;
-+	return 0;
-+}
-+
-+static int read_alive_again(struct buffer_head * bh)
-+{
-+	lock_buffer(bh);
-+	bh->b_end_io = end_buffer_read_sync;
-+	get_bh(bh);
-+	submit_bh(READ, bh);
-+	wait_on_buffer(bh);
-+	if (!buffer_uptodate(bh)) {
-+		brelse(bh);
-+		return 1;
-+	}
-+	return 0;
-+}
-+
-+/*
-+ * The caller must have a ref on the buffer_head.
-+ */
-+static int kalived(void *data)
-+{
-+	struct buffer_head * bh;
-+	struct alive_struct * alive;
-+	char b[BDEVNAME_SIZE];
-+	u32 seq = 0;
-+
-+	bh = (struct buffer_head *)data;
-+	bdevname(bh->b_bdev, b);
-+
-+	alive = (struct alive_struct *)(bh->b_data);
-+	alive->al_magic = cpu_to_le32(ALIVE_MAGIC);
-+	alive->al_time = cpu_to_le32(get_seconds());
-+
-+	down_read(&uts_sem);
-+	memcpy(alive->al_nodename, system_utsname.nodename, 65);
-+	up_read(&uts_sem);
-+
-+	while (!kthread_should_stop()) {
-+		if (++seq == 0)
-+			++seq;
-+
-+		alive->al_seq = cpu_to_le32(seq);
-+		alive->al_time = cpu_to_le32(get_seconds());
-+
-+		if (unlikely(write_alive(bh))) {
-+			/* panic here? */
-+			printk(KERN_ERR "Alive (device %s): "
-+				"can't write alive block\n", b);
-+			continue;
-+		}
-+
-+		schedule_timeout_interruptible(5 * HZ);
-+	}
-+
-+	alive->al_seq = 0;
-+	alive->al_time = cpu_to_le32(get_seconds());
-+
-+	if (unlikely(write_alive(bh)))
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't reset alive block\n", b);
-+	brelse(bh);
-+	return 0;
-+}
-+
-+static unsigned long get_alive_ino(struct super_block *sb)
-+{
-+	unsigned long	ino = 0;
-+	struct dentry	alive;
-+	struct dentry	* root;
-+	struct inode	* root_inode;
-+	struct ext3_dir_entry_2 * de;
-+	struct buffer_head	* bh;
-+
-+	root_inode = iget(sb, EXT3_ROOT_INO);
-+	root = d_alloc_root(root_inode);
-+	if (!root) {
-+		printk(KERN_ERR "Alive (device %s): get root inode failed\n",
-+			sb->s_id);
-+		iput(root_inode);
-+		goto out;
-+	}
-+
-+	alive.d_name.name = ".alive";
-+	alive.d_name.len = 6;
-+	alive.d_parent = root;
-+
-+	bh = ext3_find_entry(&alive, &de);
-+	dput(root);
-+
-+	if (!bh) {
-+		printk(KERN_WARNING "Alive (device %s): alive lookup failed\n",
-+			sb->s_id);
-+		goto out;
-+	}
-+
-+	ino = le32_to_cpu(de->inode);
-+	brelse (bh);
-+	pr_debug("Alive (device %s): alive_ino=%lu\n", sb->s_id, ino);
-+out:
-+	return ino;
-+}
-+
-+/* check alive file */
-+static int check_alive(struct super_block *sb, struct ext3_sb_info *sbi)
-+{
-+	unsigned long		ino;
-+	struct buffer_head	* bh;
-+	struct ext3_inode_info	* ei;
-+	struct inode		* alive_inode;
-+	struct alive_struct	* alive;
-+	u32 alive_block;
-+	u32 seq;
-+
-+	ino = get_alive_ino(sb);
-+	if (!ino)
-+		goto failed;
-+
-+	alive_inode = iget(sb, ino);
-+	if (!alive_inode) {
-+		iput(alive_inode);
-+		printk(KERN_ERR "Alive (device %s): get alive inode failed\n",
-+			sb->s_id);
-+		goto failed;
-+	}
-+	if (!alive_inode->i_nlink) {
-+		make_bad_inode(alive_inode);
-+		iput(alive_inode);
-+		printk(KERN_ERR "Alive (device %s): alive inode is deleted\n",
-+			sb->s_id);
-+		goto failed;
-+	}
-+	if (!S_ISREG(alive_inode->i_mode)) {
-+		iput(alive_inode);
-+		printk(KERN_ERR "Alive (device %s): invalid alive inode\n",
-+			sb->s_id);
-+		goto failed;
-+	}
-+	if (EXT3_I(alive_inode)->i_flags & EXT3_EXTENTS_FL) {
-+		iput(alive_inode);
-+		printk(KERN_ERR "Alive (device %s): invalid alive inode, "
-+			"in extents format\n", sb->s_id);
-+		goto failed;
-+	}
-+
-+	ei = EXT3_I(alive_inode);
-+	alive_block = ei->i_data[0];
-+	iput(alive_inode);
-+
-+	pr_debug("Alive (device %s): read in alive block #%u\n",
-+			sb->s_id, alive_block);
-+
-+	/* first read */
-+	bh = sb_bread(sb, alive_block);
-+	if (!bh) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't read alive block #%u\n", sb->s_id, alive_block);
-+		goto failed;
-+	}
-+
-+	alive = (struct alive_struct *)(bh->b_data);
-+	if (le32_to_cpu(alive->al_magic) != ALIVE_MAGIC) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"magic mismatch\n", sb->s_id);
-+		brelse(bh);
-+		goto failed;
-+	}
-+
-+	seq = le32_to_cpu(alive->al_seq);
-+	pr_debug("Alive (device %s): seq=%u\n", sb->s_id, seq);
-+	pr_info ("Alive (device %s): last touched by node: %s, "
-+		"%li seconds ago\n", sb->s_id, alive->al_nodename,
-+		get_seconds() - le32_to_cpu(alive->al_time));
-+
-+	if (seq == 0)
-+		goto skip;
-+
-+	/* wait 8s */
-+	pr_info("Alive (device %s): wait for 8 seconds...\n", sb->s_id);
-+	schedule_timeout_uninterruptible(HZ * 8);
-+
-+	/* read again */
-+	if (read_alive_again(bh)) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't read alive block #%u\n",
-+			sb->s_id, alive_block);
-+		goto failed;
-+	}
-+
-+	alive = (struct alive_struct *)(bh->b_data);
-+	pr_debug("Alive (device %s): seq=%u\n",
-+		sb->s_id, le32_to_cpu(alive->al_seq));
-+
-+	if (seq != le32_to_cpu(alive->al_seq)) {
-+		printk(KERN_WARNING "Alive (device %s): "
-+			"still active on node %s\n",
-+			sb->s_id, alive->al_nodename);
-+		brelse(bh);
-+		goto failed;
-+	}
-+skip:
-+	/* write a new random seq */
-+	get_random_bytes(&seq, sizeof(u32));
-+	alive->al_seq = cpu_to_le32(seq);
-+	if (unlikely(write_alive(bh))) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't write alive block\n", sb->s_id);
-+		goto failed;
-+	}
-+	pr_debug("Alive (device %s): write random seq=%u\n", sb->s_id, seq);
-+
-+	/* wait 6s */
-+	pr_info("Alive (device %s): wait for 6 seconds...\n", sb->s_id);
-+	schedule_timeout_uninterruptible(HZ * 6);
-+
-+	/* read again */
-+	if (read_alive_again(bh)) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't read alive block #%u\n",
-+			sb->s_id, alive_block);
-+		goto failed;
-+	}
-+
-+	alive = (struct alive_struct *)(bh->b_data);
-+	pr_debug("Alive (device %s): seq=%u\n",
-+		sb->s_id, le32_to_cpu(alive->al_seq));
-+
-+	if (seq != le32_to_cpu(alive->al_seq)) {
-+		printk(KERN_WARNING "Alive (device %s): "
-+			"still active on node %s\n",
-+			sb->s_id, alive->al_nodename);
-+		brelse(bh);
-+		goto failed;
-+	}
-+
-+	/* succeed */
-+	pr_info("Alive (device %s): alive check passed!\n", sb->s_id);
-+	sbi->s_alive_tsk = kthread_run(kalived, bh, "kalived");
-+	return 0;
-+
-+failed:
-+	printk(KERN_WARNING "Alive (device %s): alive check failed!\n",
-+		sb->s_id);
-+	return 1;
-+}
-+
- 
- static int ext3_fill_super (struct super_block *sb, void *data, int silent)
- {
-@@ -1668,6 +1930,10 @@ static int ext3_fill_super (struct super
- 			  EXT3_HAS_INCOMPAT_FEATURE(sb,
- 				    EXT3_FEATURE_INCOMPAT_RECOVER));
- 
-+	if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_ALIVE))
-+		if (check_alive(sb, sbi))
-+			goto failed_mount2;
-+
- 	/*
- 	 * The first inode we look at is the journal inode.  Don't try
- 	 * root first: it may be modified in the journal!
-@@ -1785,6 +2051,8 @@ cantfind_ext3:
- 
- failed_mount3:
- 	journal_destroy(sbi->s_journal);
-+	if (sbi->s_alive_tsk)
-+		kthread_stop(sbi->s_alive_tsk);
- failed_mount2:
- 	for (i = 0; i < db_count; i++)
- 		brelse(sbi->s_group_desc[i]);
-Index: mmp/include/linux/ext3_fs.h
-===================================================================
---- mmp.orig/include/linux/ext3_fs.h	2006-07-24 10:34:41.000000000 +0800
-+++ mmp/include/linux/ext3_fs.h	2006-07-24 10:39:26.000000000 +0800
-@@ -581,12 +581,14 @@ static inline struct ext3_inode_info *EX
- #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008 /* Journal device */
- #define EXT3_FEATURE_INCOMPAT_META_BG		0x0010
- #define EXT3_FEATURE_INCOMPAT_EXTENTS		0x0040 /* extents support */
-+#define EXT3_FEATURE_INCOMPAT_ALIVE		0x0080
- 
- #define EXT3_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
- #define EXT3_FEATURE_INCOMPAT_SUPP	(EXT3_FEATURE_INCOMPAT_FILETYPE| \
- 					 EXT3_FEATURE_INCOMPAT_RECOVER| \
- 					 EXT3_FEATURE_INCOMPAT_META_BG| \
--					 EXT3_FEATURE_INCOMPAT_EXTENTS)
-+					 EXT3_FEATURE_INCOMPAT_EXTENTS| \
-+					 EXT3_FEATURE_INCOMPAT_ALIVE)
- #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
- 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
- 					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
-Index: mmp/include/linux/ext3_fs_sb.h
-===================================================================
---- mmp.orig/include/linux/ext3_fs_sb.h	2006-07-24 10:34:41.000000000 +0800
-+++ mmp/include/linux/ext3_fs_sb.h	2006-07-24 10:39:26.000000000 +0800
-@@ -86,6 +86,7 @@ struct ext3_sb_info {
- 	char *s_qf_names[MAXQUOTAS];		/* Names of quota files with journalled quota */
- 	int s_jquota_fmt;			/* Format of quota to use */
- #endif
-+	struct task_struct * s_alive_tsk;
- 
- 	/* for buddy allocator */
- 	struct ext3_group_info **s_group_info;
diff --git a/lustre/kernel_patches/patches/ext3-multi-mount-protection-2.6.18-vanilla.patch b/lustre/kernel_patches/patches/ext3-multi-mount-protection-2.6.18-vanilla.patch
deleted file mode 100644
index 989ca26c45..0000000000
--- a/lustre/kernel_patches/patches/ext3-multi-mount-protection-2.6.18-vanilla.patch
+++ /dev/null
@@ -1,381 +0,0 @@
-Index: mmp/fs/ext3/al.h
-===================================================================
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ mmp/fs/ext3/al.h	2006-07-18 20:43:51.000000000 +0800
-@@ -0,0 +1,11 @@
-+/*
-+ * (C) 2006  Qi Yong <qiyong@clusterfs.com>
-+ */
-+
-+#define	ALIVE_MAGIC	0xA1153C29
-+struct alive_struct {
-+	__le32	al_magic;
-+	__le32	al_seq;
-+	__le32	al_time;
-+	char	al_nodename[65];
-+};
-Index: mmp/fs/ext3/namei.c
-===================================================================
---- mmp.orig/fs/ext3/namei.c	2006-07-18 20:43:51.000000000 +0800
-+++ mmp/fs/ext3/namei.c	2006-07-18 20:43:51.000000000 +0800
-@@ -805,7 +805,7 @@ static inline int search_dirblock(struct
-  * The returned buffer_head has ->b_count elevated.  The caller is expected
-  * to brelse() it when appropriate.
-  */
--static struct buffer_head * ext3_find_entry (struct dentry *dentry,
-+struct buffer_head * ext3_find_entry (struct dentry *dentry,
- 					struct ext3_dir_entry_2 ** res_dir)
- {
- 	struct super_block * sb;
-Index: mmp/fs/ext3/super.c
-===================================================================
---- mmp.orig/fs/ext3/super.c	2006-07-18 20:43:51.000000000 +0800
-+++ mmp/fs/ext3/super.c	2006-07-18 23:49:54.000000000 +0800
-@@ -35,12 +35,14 @@
- #include <linux/namei.h>
- #include <linux/quotaops.h>
- #include <linux/seq_file.h>
-+#include <linux/kthread.h>
- 
- #include <asm/uaccess.h>
- 
- #include "xattr.h"
- #include "acl.h"
- #include "namei.h"
-+#include "al.h"
- 
- static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
- 			     unsigned long journal_devnum);
-@@ -61,6 +63,8 @@ static int ext3_statfs (struct dentry * 
- static void ext3_unlockfs(struct super_block *sb);
- static void ext3_write_super (struct super_block * sb);
- static void ext3_write_super_lockfs(struct super_block *sb);
-+struct buffer_head * ext3_find_entry (struct dentry *dentry,
-+					struct ext3_dir_entry_2 ** res_dir);
- 
- /* 
-  * Wrappers for journal_start/end.
-@@ -434,6 +438,9 @@ static void ext3_put_super (struct super
- 		invalidate_bdev(sbi->journal_bdev, 0);
- 		ext3_blkdev_remove(sbi);
- 	}
-+	if (sbi->s_alive_tsk)
-+		kthread_stop(sbi->s_alive_tsk);
-+
- 	sb->s_fs_info = NULL;
- 	kfree(sbi);
- 	return;
-@@ -1374,6 +1381,261 @@ static ext3_fsblk_t descriptor_loc(struc
- 	return (has_super + ext3_group_first_block_no(sb, bg));
- }
- 
-+static int write_alive(struct buffer_head * bh)
-+{
-+	lock_buffer(bh);
-+	bh->b_end_io = end_buffer_write_sync;
-+	get_bh(bh);
-+	submit_bh(WRITE, bh);
-+	wait_on_buffer(bh);
-+	if (unlikely(!buffer_uptodate(bh)))
-+		return 1;
-+	return 0;
-+}
-+
-+static int read_alive_again(struct buffer_head * bh)
-+{
-+	lock_buffer(bh);
-+	bh->b_end_io = end_buffer_read_sync;
-+	get_bh(bh);
-+	submit_bh(READ, bh);
-+	wait_on_buffer(bh);
-+	if (!buffer_uptodate(bh)) {
-+		brelse(bh);
-+		return 1;
-+	}
-+	return 0;
-+}
-+
-+/*
-+ * The caller must have a ref on the buffer_head.
-+ */
-+static int kalived(void *data)
-+{
-+	struct buffer_head * bh;
-+	struct alive_struct * alive;
-+	char b[BDEVNAME_SIZE];
-+	u32 seq = 0;
-+
-+	bh = (struct buffer_head *)data;
-+	bdevname(bh->b_bdev, b);
-+
-+	alive = (struct alive_struct *)(bh->b_data);
-+	alive->al_magic = cpu_to_le32(ALIVE_MAGIC);
-+	alive->al_time = cpu_to_le32(get_seconds());
-+
-+	down_read(&uts_sem);
-+	memcpy(alive->al_nodename, system_utsname.nodename, 65);
-+	up_read(&uts_sem);
-+
-+	while (!kthread_should_stop()) {
-+		if (++seq == 0)
-+			++seq;
-+
-+		alive->al_seq = cpu_to_le32(seq);
-+		alive->al_time = cpu_to_le32(get_seconds());
-+
-+		if (unlikely(write_alive(bh))) {
-+			/* panic here? */
-+			printk(KERN_ERR "Alive (device %s): "
-+				"can't write alive block\n", b);
-+			continue;
-+		}
-+
-+		schedule_timeout_interruptible(5 * HZ);
-+	}
-+
-+	alive->al_seq = 0;
-+	alive->al_time = cpu_to_le32(get_seconds());
-+
-+	if (unlikely(write_alive(bh)))
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't reset alive block\n", b);
-+	brelse(bh);
-+	return 0;
-+}
-+
-+static unsigned long get_alive_ino(struct super_block *sb)
-+{
-+	unsigned long	ino = 0;
-+	struct dentry	alive;
-+	struct dentry	* root;
-+	struct inode	* root_inode;
-+	struct ext3_dir_entry_2 * de;
-+	struct buffer_head	* bh;
-+
-+	root_inode = iget(sb, EXT3_ROOT_INO);
-+	root = d_alloc_root(root_inode);
-+	if (!root) {
-+		printk(KERN_ERR "Alive (device %s): get root inode failed\n",
-+			sb->s_id);
-+		iput(root_inode);
-+		goto out;
-+	}
-+
-+	alive.d_name.name = ".alive";
-+	alive.d_name.len = 6;
-+	alive.d_parent = root;
-+
-+	bh = ext3_find_entry(&alive, &de);
-+	dput(root);
-+
-+	if (!bh) {
-+		printk(KERN_WARNING "Alive (device %s): alive lookup failed\n",
-+			sb->s_id);
-+		goto out;
-+	}
-+
-+	ino = le32_to_cpu(de->inode);
-+	brelse (bh);
-+	pr_debug("Alive (device %s): alive_ino=%lu\n", sb->s_id, ino);
-+out:
-+	return ino;
-+}
-+
-+/* check alive file */
-+static int check_alive(struct super_block *sb, struct ext3_sb_info *sbi)
-+{
-+	unsigned long		ino;
-+	struct buffer_head	* bh;
-+	struct ext3_inode_info	* ei;
-+	struct inode		* alive_inode;
-+	struct alive_struct	* alive;
-+	u32 alive_block;
-+	u32 seq;
-+
-+	ino = get_alive_ino(sb);
-+	if (!ino)
-+		goto failed;
-+
-+	alive_inode = iget(sb, ino);
-+	if (!alive_inode) {
-+		iput(alive_inode);
-+		printk(KERN_ERR "Alive (device %s): get alive inode failed\n",
-+			sb->s_id);
-+		goto failed;
-+	}
-+	if (!alive_inode->i_nlink) {
-+		make_bad_inode(alive_inode);
-+		iput(alive_inode);
-+		printk(KERN_ERR "Alive (device %s): alive inode is deleted\n",
-+			sb->s_id);
-+		goto failed;
-+	}
-+	if (!S_ISREG(alive_inode->i_mode)) {
-+		iput(alive_inode);
-+		printk(KERN_ERR "Alive (device %s): invalid alive inode\n",
-+			sb->s_id);
-+		goto failed;
-+	}
-+	if (EXT3_I(alive_inode)->i_flags & EXT3_EXTENTS_FL) {
-+		iput(alive_inode);
-+		printk(KERN_ERR "Alive (device %s): invalid alive inode, "
-+			"in extents format\n", sb->s_id);
-+		goto failed;
-+	}
-+
-+	ei = EXT3_I(alive_inode);
-+	alive_block = ei->i_data[0];
-+	iput(alive_inode);
-+
-+	pr_debug("Alive (device %s): read in alive block #%u\n",
-+			sb->s_id, alive_block);
-+
-+	/* first read */
-+	bh = sb_bread(sb, alive_block);
-+	if (!bh) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't read alive block #%u\n", sb->s_id, alive_block);
-+		goto failed;
-+	}
-+
-+	alive = (struct alive_struct *)(bh->b_data);
-+	if (le32_to_cpu(alive->al_magic) != ALIVE_MAGIC) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"magic mismatch\n", sb->s_id);
-+		brelse(bh);
-+		goto failed;
-+	}
-+
-+	seq = le32_to_cpu(alive->al_seq);
-+	pr_debug("Alive (device %s): seq=%u\n", sb->s_id, seq);
-+	pr_info ("Alive (device %s): last touched by node: %s, "
-+		"%li seconds ago\n", sb->s_id, alive->al_nodename,
-+		get_seconds() - le32_to_cpu(alive->al_time));
-+
-+	if (seq == 0)
-+		goto skip;
-+
-+	/* wait 8s */
-+	pr_info("Alive (device %s): wait for 8 seconds...\n", sb->s_id);
-+	schedule_timeout_uninterruptible(HZ * 8);
-+
-+	/* read again */
-+	if (read_alive_again(bh)) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't read alive block #%u\n",
-+			sb->s_id, alive_block);
-+		goto failed;
-+	}
-+
-+	alive = (struct alive_struct *)(bh->b_data);
-+	pr_debug("Alive (device %s): seq=%u\n",
-+		sb->s_id, le32_to_cpu(alive->al_seq));
-+
-+	if (seq != le32_to_cpu(alive->al_seq)) {
-+		printk(KERN_WARNING "Alive (device %s): "
-+			"still active on node %s\n",
-+			sb->s_id, alive->al_nodename);
-+		brelse(bh);
-+		goto failed;
-+	}
-+skip:
-+	/* write a new random seq */
-+	get_random_bytes(&seq, sizeof(u32));
-+	alive->al_seq = cpu_to_le32(seq);
-+	if (unlikely(write_alive(bh))) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't write alive block\n", sb->s_id);
-+		goto failed;
-+	}
-+	pr_debug("Alive (device %s): write random seq=%u\n", sb->s_id, seq);
-+
-+	/* wait 6s */
-+	pr_info("Alive (device %s): wait for 6 seconds...\n", sb->s_id);
-+	schedule_timeout_uninterruptible(HZ * 6);
-+
-+	/* read again */
-+	if (read_alive_again(bh)) {
-+		printk(KERN_ERR "Alive (device %s): "
-+			"can't read alive block #%u\n",
-+			sb->s_id, alive_block);
-+		goto failed;
-+	}
-+
-+	alive = (struct alive_struct *)(bh->b_data);
-+	pr_debug("Alive (device %s): seq=%u\n",
-+		sb->s_id, le32_to_cpu(alive->al_seq));
-+
-+	if (seq != le32_to_cpu(alive->al_seq)) {
-+		printk(KERN_WARNING "Alive (device %s): "
-+			"still active on node %s\n",
-+			sb->s_id, alive->al_nodename);
-+		brelse(bh);
-+		goto failed;
-+	}
-+
-+	/* succeed */
-+	pr_info("Alive (device %s): alive check passed!\n", sb->s_id);
-+	sbi->s_alive_tsk = kthread_run(kalived, bh, "kalived");
-+	return 0;
-+
-+failed:
-+	printk(KERN_WARNING "Alive (device %s): alive check failed!\n",
-+		sb->s_id);
-+	return 1;
-+}
-+
- 
- static int ext3_fill_super (struct super_block *sb, void *data, int silent)
- {
-@@ -1688,6 +1950,10 @@ static int ext3_fill_super (struct super
- 			  EXT3_HAS_INCOMPAT_FEATURE(sb,
- 				    EXT3_FEATURE_INCOMPAT_RECOVER));
- 
-+	if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_ALIVE))
-+		if (check_alive(sb, sbi))
-+			goto failed_mount2;
-+
- 	/*
- 	 * The first inode we look at is the journal inode.  Don't try
- 	 * root first: it may be modified in the journal!
-@@ -1796,6 +2062,8 @@ failed_mount3:
- 	percpu_counter_destroy(&sbi->s_freeblocks_counter);
- 	percpu_counter_destroy(&sbi->s_freeinodes_counter);
- 	percpu_counter_destroy(&sbi->s_dirs_counter);
-+	if (sbi->s_alive_tsk)
-+		kthread_stop(sbi->s_alive_tsk);
- failed_mount2:
- 	for (i = 0; i < db_count; i++)
- 		brelse(sbi->s_group_desc[i]);
-Index: mmp/include/linux/ext3_fs.h
-===================================================================
---- mmp.orig/include/linux/ext3_fs.h	2006-07-18 20:43:51.000000000 +0800
-+++ mmp/include/linux/ext3_fs.h	2006-07-18 20:43:52.000000000 +0800
-@@ -579,12 +579,14 @@ static inline struct ext3_inode_info *EX
- #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008 /* Journal device */
- #define EXT3_FEATURE_INCOMPAT_META_BG		0x0010
- #define EXT3_FEATURE_INCOMPAT_EXTENTS		0x0040 /* extents support */
-+#define EXT3_FEATURE_INCOMPAT_ALIVE		0x0080
- 
- #define EXT3_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
- #define EXT3_FEATURE_INCOMPAT_SUPP	(EXT3_FEATURE_INCOMPAT_FILETYPE| \
- 					 EXT3_FEATURE_INCOMPAT_RECOVER| \
- 					 EXT3_FEATURE_INCOMPAT_META_BG| \
--					 EXT3_FEATURE_INCOMPAT_EXTENTS)
-+					 EXT3_FEATURE_INCOMPAT_EXTENTS| \
-+					 EXT3_FEATURE_INCOMPAT_ALIVE)
- #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
- 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
- 					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
-Index: mmp/include/linux/ext3_fs_sb.h
-===================================================================
---- mmp.orig/include/linux/ext3_fs_sb.h	2006-07-18 20:43:51.000000000 +0800
-+++ mmp/include/linux/ext3_fs_sb.h	2006-07-18 20:43:52.000000000 +0800
-@@ -86,6 +86,7 @@ struct ext3_sb_info {
- 	char *s_qf_names[MAXQUOTAS];		/* Names of quota files with journalled quota */
- 	int s_jquota_fmt;			/* Format of quota to use */
- #endif
-+	struct task_struct * s_alive_tsk;
- 
- 	/* for buddy allocator */
- 	struct ext3_group_info **s_group_info;
diff --git a/lustre/kernel_patches/patches/ext3-statfs-2.6.12.patch b/lustre/kernel_patches/patches/ext3-statfs-2.6.12.patch
deleted file mode 100644
index ad7d79b1cd..0000000000
--- a/lustre/kernel_patches/patches/ext3-statfs-2.6.12.patch
+++ /dev/null
@@ -1,177 +0,0 @@
-Index: linux-2.6.12/fs/ext3/super.c
-===================================================================
---- linux-2.6.12.orig/fs/ext3/super.c	2005-06-17 13:48:29.000000000 -0600
-+++ linux-2.6.12/fs/ext3/super.c	2005-11-25 05:59:47.000000000 -0700
-@@ -2165,13 +2165,13 @@
- {
- 	struct ext3_super_block *es = EXT3_SB(sb)->s_es;
- 	unsigned long overhead;
--	int i;
- 
- 	if (test_opt (sb, MINIX_DF))
- 		overhead = 0;
- 	else {
--		unsigned long ngroups;
--		ngroups = EXT3_SB(sb)->s_groups_count;
-+		unsigned long ngroups = EXT3_SB(sb)->s_groups_count, group;
-+		unsigned long three = 1, five = 5, seven = 7;
-+		unsigned long metabg = -1UL;
- 		smp_rmb();
- 
- 		/*
-@@ -2189,11 +2188,14 @@
- 		 * block group descriptors.  If the sparse superblocks
- 		 * feature is turned on, then not all groups have this.
- 		 */
--		for (i = 0; i < ngroups; i++) {
--			overhead += ext3_bg_has_super(sb, i) +
--				ext3_bg_num_gdb(sb, i);
--			cond_resched();
--		}
-+		overhead += 1 + EXT3_SB(sb)->s_gdb_count; /* group 0 */
-+		if (EXT3_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_META_BG))
-+			metabg =le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg);
-+
-+		while ((group = ext3_list_backups(sb, &three, &five, &seven)) <
-+		       ngroups) /* sb + group descriptors backups */
-+			overhead += 1 + (group >= metabg ? 1 :
-+					 EXT3_SB(sb)->s_gdb_count);
- 
- 		/*
- 		 * Every block group has an inode bitmap, a block
-@@ -2205,12 +2204,16 @@
- 	buf->f_type = EXT3_SUPER_MAGIC;
- 	buf->f_bsize = sb->s_blocksize;
- 	buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;
--	buf->f_bfree = ext3_count_free_blocks (sb);
-+	buf->f_bfree = percpu_counter_read(&EXT3_SB(sb)->s_freeblocks_counter);
-+	if (buf->f_bfree < 0)
-+		buf->f_bfree = 0;
- 	buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
- 	if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
- 		buf->f_bavail = 0;
- 	buf->f_files = le32_to_cpu(es->s_inodes_count);
--	buf->f_ffree = ext3_count_free_inodes (sb);
-+	buf->f_ffree = percpu_counter_read(&EXT3_SB(sb)->s_freeinodes_counter);
-+	if (buf->f_ffree < 0)
-+		buf->f_ffree = 0;
- 	buf->f_namelen = EXT3_NAME_LEN;
- 	return 0;
- }
-Index: linux-2.6.12/fs/ext3/resize.c
-===================================================================
---- linux-2.6.12.orig/fs/ext3/resize.c	2005-11-24 15:17:06.000000000 -0700
-+++ linux-2.6.12/fs/ext3/resize.c	2005-11-25 06:01:01.000000000 -0700
-@@ -285,17 +285,17 @@
-  * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
-  * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
-  */
--static unsigned ext3_list_backups(struct super_block *sb, unsigned *three,
--				  unsigned *five, unsigned *seven)
-+unsigned long ext3_list_backups(struct super_block *sb, unsigned long *three,
-+				unsigned long *five, unsigned long *seven)
- {
--	unsigned *min = three;
-+	unsigned long metabg = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg);
-+	unsigned long *min = three, ret;
- 	int mult = 3;
--	unsigned ret;
- 
- 	if (!EXT3_HAS_RO_COMPAT_FEATURE(sb,
- 					EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
--		ret = *min;
--		*min += 1;
-+		ret = *three;
-+		*three += 1;
- 		return ret;
- 	}
- 
-@@ -308,8 +307,26 @@
- 		mult = 7;
- 	}
- 
--	ret = *min;
--	*min *= mult;
-+	if (EXT3_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_META_BG) &&
-+	    *min >= metabg * EXT3_DESC_PER_BLOCK(sb)) {
-+		ret = *min;
-+		switch (ret & (EXT3_DESC_PER_BLOCK(sb) - 1)) {
-+		case 0:
-+			*three = ret + 1;
-+			break;
-+		case 1:
-+			*three = ret + EXT3_DESC_PER_BLOCK(sb) - 2;
-+			break;
-+		default:
-+			*three = (ret | (EXT3_DESC_PER_BLOCK(sb) - 1)) + 1;
-+			break;
-+		}
-+		*five = -1UL;
-+		*seven = -1UL;
-+	} else {
-+		ret = *min;
-+		*min *= mult;
-+	}
- 
- 	return ret;
- }
-@@ -324,17 +337,17 @@
- {
- 	const unsigned long blk = primary->b_blocknr;
- 	const unsigned long end = EXT3_SB(sb)->s_groups_count;
--	unsigned three = 1;
--	unsigned five = 5;
--	unsigned seven = 7;
--	unsigned grp;
-+	unsigned long three = 1;
-+	unsigned long five = 5;
-+	unsigned long seven = 7;
-+	unsigned long grp;
- 	__u32 *p = (__u32 *)primary->b_data;
- 	int gdbackups = 0;
- 
- 	while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
- 		if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){
- 			ext3_warning(sb, __FUNCTION__,
--				     "reserved GDT %ld missing grp %d (%ld)\n",
-+				     "reserved GDT %ld missing grp %ld (%ld)\n",
- 				     blk, grp,
- 				     grp * EXT3_BLOCKS_PER_GROUP(sb) + blk);
- 			return -EINVAL;
-@@ -618,10 +631,8 @@
- 	struct ext3_sb_info *sbi = EXT3_SB(sb);
- 	const unsigned long last = sbi->s_groups_count;
- 	const int bpg = EXT3_BLOCKS_PER_GROUP(sb);
--	unsigned three = 1;
--	unsigned five = 5;
--	unsigned seven = 7;
--	unsigned group;
-+	unsigned long three = 1, five = 5, seven = 7;
-+	unsigned long group;
- 	int rest = sb->s_blocksize - size;
- 	handle_t *handle;
- 	int err = 0, err2;
-@@ -672,7 +683,7 @@
- exit_err:
- 	if (err) {
- 		ext3_warning(sb, __FUNCTION__,
--			     "can't update backup for group %d (err %d), "
-+			     "can't update backup for group %ld (err %d), "
- 			     "forcing fsck on next reboot\n", group, err);
- 		sbi->s_mount_state &= ~EXT3_VALID_FS;
- 		sbi->s_es->s_state &= ~cpu_to_le16(EXT3_VALID_FS);
-Index: linux-2.6.12/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.12.orig/include/linux/ext3_fs.h	2005-06-17 13:48:29.000000000 -0600
-+++ linux-2.6.12/include/linux/ext3_fs.h	2005-11-25 05:59:47.000000000 -0700
-@@ -788,6 +788,10 @@
- extern int ext3_group_extend(struct super_block *sb,
- 				struct ext3_super_block *es,
- 				unsigned long n_blocks_count);
-+extern unsigned long ext3_list_backups(struct super_block *sb,
-+				       unsigned long *three,
-+				       unsigned long *five,
-+				       unsigned long *seven);
- 
- /* super.c */
- extern void ext3_error (struct super_block *, const char *, const char *, ...)
diff --git a/lustre/kernel_patches/patches/ext3-uninit-2.6-sles10.patch b/lustre/kernel_patches/patches/ext3-uninit-2.6-sles10.patch
deleted file mode 100644
index 62b1f50a90..0000000000
--- a/lustre/kernel_patches/patches/ext3-uninit-2.6-sles10.patch
+++ /dev/null
@@ -1,674 +0,0 @@
-Add support for the uninit_groups feature to the kernel.
-
-Keep a high water mark of used inodes for each group to improve e2fsck time.
-Block and inode bitmaps can be uninitialized on disk via a flag in the
-group descriptor to avoid reading or scanning them at e2fsck time.
-A checksum of each group descriptor is used to ensure that corruption in
-the group descriptor's bit flags does not cause incorrect operation.
-
-Index: linux-2.6.16.27-0.9-full/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/include/linux/ext3_fs.h	2007-03-28 18:20:16.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/include/linux/ext3_fs.h	2007-03-28 18:30:06.000000000 +0400
-@@ -153,16 +153,22 @@ struct ext3_allocation_request {
-  */
- struct ext3_group_desc
- {
--	__le32	bg_block_bitmap;		/* Blocks bitmap block */
--	__le32	bg_inode_bitmap;		/* Inodes bitmap block */
-+	__le32	bg_block_bitmap;	/* Blocks bitmap block */
-+	__le32	bg_inode_bitmap;	/* Inodes bitmap block */
- 	__le32	bg_inode_table;		/* Inodes table block */
- 	__le16	bg_free_blocks_count;	/* Free blocks count */
- 	__le16	bg_free_inodes_count;	/* Free inodes count */
- 	__le16	bg_used_dirs_count;	/* Directories count */
--	__u16	bg_pad;
--	__le32	bg_reserved[3];
-+	__le16  bg_flags;		/* EXT3_BG_flags (UNINIT, etc) */
-+	__le32	bg_reserved[2];		/* Likely block/inode bitmap checksum */
-+	__le16	bg_itable_unused;	/* Unused inodes count */
-+	__le16	bg_checksum;		/* crc16(sb_uuid+group+desc) */
- };
- 
-+#define EXT3_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not in use */
-+#define EXT3_BG_BLOCK_UNINIT	0x0002 /* Block bitmap not in use */
-+#define EXT3_BG_INODE_ZEROED	0x0004 /* On-disk itable initialized to zero */
-+
- /*
-  * Macro-instructions used to manage group descriptors
-  */
-@@ -590,6 +596,7 @@ static inline struct ext3_inode_info *EX
- #define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
- #define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
- #define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
-+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010
- #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK	0x0020
- 
- #define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
-@@ -606,6 +613,7 @@ static inline struct ext3_inode_info *EX
- 					 EXT3_FEATURE_INCOMPAT_EXTENTS)
- #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
- 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
-+					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
- 					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
- 					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
- 
-Index: linux-2.6.16.27-0.9-full/fs/ext3/resize.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/resize.c	2007-03-13 02:56:52.000000000 +0300
-+++ linux-2.6.16.27-0.9-full/fs/ext3/resize.c	2007-03-28 18:30:06.000000000 +0400
-@@ -19,6 +19,7 @@
- #include <linux/errno.h>
- #include <linux/slab.h>
- 
-+#include "group.h"
- 
- #define outside(b, first, last)	((b) < (first) || (b) >= (last))
- #define inside(b, first, last)	((b) >= (first) && (b) < (last))
-@@ -818,6 +819,7 @@ int ext3_group_add(struct super_block *s
- 	gdp->bg_inode_table = cpu_to_le32(input->inode_table);
- 	gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);
- 	gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb));
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, input->group, gdp);
- 
- 	/*
- 	 * Make the new blocks and inodes valid next.  We do this before
-Index: linux-2.6.16.27-0.9-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/super.c	2007-03-28 18:25:51.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/super.c	2007-03-28 18:30:06.000000000 +0400
-@@ -42,6 +42,7 @@
- #include "xattr.h"
- #include "acl.h"
- #include "namei.h"
-+#include "group.h"
- 
- static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
- 			     unsigned long journal_devnum);
-@@ -1221,6 +1222,90 @@ static int ext3_setup_super(struct super
- 	return res;
- }
- 
-+#if !defined(CONFIG_CRC16) && !defined(CONFIG_CRC16_MODULE)
-+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
-+__u16 const crc16_table[256] = {
-+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
-+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
-+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
-+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
-+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
-+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
-+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
-+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
-+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
-+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
-+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
-+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
-+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
-+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
-+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
-+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
-+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
-+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
-+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
-+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
-+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
-+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
-+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
-+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
-+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
-+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
-+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
-+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
-+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
-+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
-+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
-+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
-+};
-+
-+static inline __u16 crc16_byte(__u16 crc, const __u8 data)
-+{
-+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
-+}
-+
-+__u16 crc16(__u16 crc, __u8 const *buffer, size_t len)
-+{
-+	while (len--)
-+		crc = crc16_byte(crc, *buffer++);
-+	return crc;
-+}
-+#endif
-+
-+__le16 ext3_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
-+			    struct ext3_group_desc *gdp)
-+{
-+	__u16 crc = 0;
-+
-+	if (sbi->s_es->s_feature_ro_compat &
-+	    cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-+		int offset = offsetof(struct ext3_group_desc, bg_checksum);
-+		__le32 le_group = cpu_to_le32(block_group);
-+
-+		crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
-+		crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
-+		crc = crc16(crc, (__u8 *)gdp, offset);
-+		offset += sizeof(gdp->bg_checksum); /* skip checksum */
-+		BUG_ON(offset != sizeof(*gdp)); /* XXX handle s_desc_size */
-+		/* for checksum of struct ext4_group_desc do the rest...
-+		if (offset < sbi->s_es->s_desc_size) {
-+			crc = crc16(crc, (__u8 *)gdp + offset,
-+				    sbi->s_es->s_desc_size - offset);
-+		 */
-+	}
-+
-+	return cpu_to_le16(crc);
-+}
-+
-+int ext3_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
-+				struct ext3_group_desc *gdp)
-+{
-+	if (gdp->bg_checksum != ext3_group_desc_csum(sbi, block_group, gdp))
-+		return 0;
-+
-+	return 1;
-+}
-+
- /* Called at mount-time, super-block is locked */
- static int ext3_check_descriptors (struct super_block * sb)
- {
-@@ -1270,6 +1355,13 @@ static int ext3_check_descriptors (struc
- 					le32_to_cpu(gdp->bg_inode_table));
- 			return 0;
- 		}
-+		if (!ext3_group_desc_csum_verify(sbi, i, gdp)) {
-+			ext3_error(sb, __FUNCTION__,
-+				   "Checksum for group %d failed (%u!=%u)\n", i,
-+				   le16_to_cpu(ext3_group_desc_csum(sbi,i,gdp)),
-+				   le16_to_cpu(gdp->bg_checksum));
-+			return 0;
-+		}
- 		block += EXT3_BLOCKS_PER_GROUP(sb);
- 		gdp++;
- 	}
-Index: linux-2.6.16.27-0.9-full/fs/ext3/group.h
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/group.h	2007-02-13 18:39:59.640066087 +0300
-+++ linux-2.6.16.27-0.9-full/fs/ext3/group.h	2007-03-28 18:30:06.000000000 +0400
-@@ -0,0 +1,29 @@
-+/*
-+ *  linux/fs/ext3/group.h
-+ *
-+ * Copyright (C) 2007 Cluster File Systems, Inc
-+ *
-+ * Author: Andreas Dilger <adilger@clusterfs.com>
-+ */
-+
-+#ifndef _LINUX_EXT3_GROUP_H
-+#define _LINUX_EXT3_GROUP_H
-+#if defined(CONFIG_CRC16) || defined(CONFIG_CRC16_MODULE)
-+#include <linux/crc16.h>
-+#endif
-+
-+extern __le16 ext3_group_desc_csum(struct ext3_sb_info *sbi, __u32 group,
-+				   struct ext3_group_desc *gdp);
-+extern int ext3_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 group,
-+				       struct ext3_group_desc *gdp);
-+struct buffer_head *read_block_bitmap(struct super_block *sb,
-+				      unsigned int block_group);
-+extern unsigned ext3_init_block_bitmap(struct super_block *sb,
-+				       struct buffer_head *bh, int group,
-+				       struct ext3_group_desc *desc);
-+#define ext3_free_blocks_after_init(sb, group, desc)			\
-+		ext3_init_block_bitmap(sb, NULL, group, desc)
-+extern unsigned ext3_init_inode_bitmap(struct super_block *sb,
-+				       struct buffer_head *bh, int group,
-+				       struct ext3_group_desc *desc);
-+#endif /* _LINUX_EXT3_GROUP_H */
-Index: linux-2.6.16.27-0.9-full/fs/ext3/ialloc.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/ialloc.c	2007-03-28 18:20:17.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/ialloc.c	2007-03-28 18:30:06.000000000 +0400
-@@ -28,6 +28,7 @@
- 
- #include "xattr.h"
- #include "acl.h"
-+#include "group.h"
- 
- /*
-  * ialloc.c contains the inodes allocation and deallocation routines
-@@ -43,6 +44,52 @@
-  * the free blocks count in the block.
-  */
- 
-+/*
-+ * To avoid calling the atomic setbit hundreds or thousands of times, we only
-+ * need to use it within a single byte (to ensure we get endianness right).
-+ * We can use memset for the rest of the bitmap as there are no other users.
-+ */
-+static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
-+{
-+	int i;
-+
-+	if (start_bit >= end_bit)
-+		return;
-+
-+	ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit);
-+	for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
-+		ext3_set_bit(i, bitmap);
-+	if (i < end_bit)
-+		memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
-+}
-+
-+/* Initializes an uninitialized inode bitmap */
-+unsigned ext3_init_inode_bitmap(struct super_block *sb,
-+				struct buffer_head *bh, int block_group,
-+				struct ext3_group_desc *gdp)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+
-+	J_ASSERT_BH(bh, buffer_locked(bh));
-+
-+	/* If checksum is bad mark all blocks and inodes use to prevent
-+	 * allocation, essentially implementing a per-group read-only flag. */
-+	if (!ext3_group_desc_csum_verify(sbi, block_group, gdp)) {
-+		ext3_error(sb, __FUNCTION__, "Checksum bad for group %u\n",
-+			   block_group);
-+		gdp->bg_free_blocks_count = 0;
-+		gdp->bg_free_inodes_count = 0;
-+		gdp->bg_itable_unused = 0;
-+		memset(bh->b_data, 0xff, sb->s_blocksize);
-+		return 0;
-+	}
-+
-+	memset(bh->b_data, 0, (EXT3_INODES_PER_GROUP(sb) + 7) / 8);
-+	mark_bitmap_end(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb),
-+			bh->b_data);
-+
-+	return EXT3_INODES_PER_GROUP(sb);
-+}
- 
- /*
-  * Read the inode allocation bitmap for a given block_group, reading
-@@ -59,8 +106,19 @@ read_inode_bitmap(struct super_block * s
- 	desc = ext3_get_group_desc(sb, block_group, NULL);
- 	if (!desc)
- 		goto error_out;
--
--	bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+	if (desc->bg_flags & cpu_to_le16(EXT3_BG_INODE_UNINIT)) {
-+		bh = sb_getblk(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+		if (!buffer_uptodate(bh)) {
-+			lock_buffer(bh);
-+			if (!buffer_uptodate(bh)) {
-+				ext3_init_inode_bitmap(sb, bh,block_group,desc);
-+				set_buffer_uptodate(bh);
-+			}
-+			unlock_buffer(bh);
-+		}
-+	} else {
-+		bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+	}
- 	if (!bh)
- 		ext3_error(sb, "read_inode_bitmap",
- 			    "Cannot read inode bitmap - "
-@@ -169,6 +227,8 @@ void ext3_free_inode (handle_t *handle, 
- 			if (is_directory)
- 				gdp->bg_used_dirs_count = cpu_to_le16(
- 				  le16_to_cpu(gdp->bg_used_dirs_count) - 1);
-+			gdp->bg_checksum = ext3_group_desc_csum(sbi,block_group,
-+								gdp);
- 			spin_unlock(sb_bgl_lock(sbi, block_group));
- 			percpu_counter_inc(&sbi->s_freeinodes_counter);
- 			if (is_directory)
-@@ -453,7 +513,7 @@ struct inode *ext3_new_inode(handle_t *h
- 	struct ext3_sb_info *sbi;
- 	int err = 0;
- 	struct inode *ret;
--	int i;
-+	int i, free = 0;
- 
- 	/* Cannot create files in a deleted directory */
- 	if (!dir || !dir->i_nlink)
-@@ -570,11 +630,13 @@ repeat_in_this_group:
- 	goto out;
- 
- got:
--	ino += group * EXT3_INODES_PER_GROUP(sb) + 1;
--	if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
--		ext3_error (sb, "ext3_new_inode",
--			    "reserved inode or inode > inodes count - "
--			    "block_group = %d, inode=%lu", group, ino);
-+	ino++;
-+	if ((group == 0 && ino < EXT3_FIRST_INO(sb)) ||
-+	    ino > EXT3_INODES_PER_GROUP(sb)) {
-+		ext3_error(sb, __FUNCTION__,
-+			   "reserved inode or inode > inodes count - "
-+			   "block_group = %d, inode=%lu", group,
-+			   ino + group * EXT3_INODES_PER_GROUP(sb));
- 		err = -EIO;
- 		goto fail;
- 	}
-@@ -582,13 +644,65 @@ got:
- 	BUFFER_TRACE(bh2, "get_write_access");
- 	err = ext3_journal_get_write_access(handle, bh2);
- 	if (err) goto fail;
-+
-+	/* We may have to initialize the block bitmap if it isn't already */
-+	if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
-+	    gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		struct buffer_head *block_bh = read_block_bitmap(sb, group);
-+
-+		BUFFER_TRACE(block_bh, "get block bitmap access");
-+		err = ext3_journal_get_write_access(handle, block_bh);
-+		if (err) {
-+			brelse(block_bh);
-+			goto fail;
-+		}
-+
-+		free = 0;
-+		spin_lock(sb_bgl_lock(sbi, group));
-+		/* recheck and clear flag under lock if we still need to */
-+		if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+			gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
-+			free = ext3_free_blocks_after_init(sb, group, gdp);
-+			gdp->bg_free_blocks_count = cpu_to_le16(free);
-+		}
-+		spin_unlock(sb_bgl_lock(sbi, group));
-+
-+		/* Don't need to dirty bitmap block if we didn't change it */
-+		if (free) {
-+			BUFFER_TRACE(block_bh, "dirty block bitmap");
-+			err = ext3_journal_dirty_metadata(handle, block_bh);
-+		}
-+
-+		brelse(block_bh);
-+		if (err)
-+			goto fail;
-+	}
-+
- 	spin_lock(sb_bgl_lock(sbi, group));
-+	/* If we didn't allocate from within the initialized part of the inode
-+	 * table then we need to initialize up to this inode. */
-+	if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-+		if (gdp->bg_flags & cpu_to_le16(EXT3_BG_INODE_UNINIT)) {
-+			gdp->bg_flags &= cpu_to_le16(~EXT3_BG_INODE_UNINIT);
-+			free = EXT3_INODES_PER_GROUP(sb);
-+		} else {
-+			free = EXT3_INODES_PER_GROUP(sb) -
-+				le16_to_cpu(gdp->bg_itable_unused);
-+		}
-+
-+		if (ino > free) {
-+			gdp->bg_itable_unused =
-+				cpu_to_le16(EXT3_INODES_PER_GROUP(sb) - ino);
-+		}
-+	}
-+
- 	gdp->bg_free_inodes_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
- 	if (S_ISDIR(mode)) {
- 		gdp->bg_used_dirs_count =
- 			cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
- 	}
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, group));
- 	BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
- 	err = ext3_journal_dirty_metadata(handle, bh2);
-@@ -610,7 +724,7 @@ got:
- 		inode->i_gid = current->fsgid;
- 	inode->i_mode = mode;
- 
--	inode->i_ino = ino;
-+	inode->i_ino = ino + group * EXT3_INODES_PER_GROUP(sb);
- 	/* This is the optimal IO size (for stat), not the fs block size */
- 	inode->i_blksize = PAGE_SIZE;
- 	inode->i_blocks = 0;
-Index: linux-2.6.16.27-0.9-full/fs/ext3/mballoc.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/mballoc.c	2007-03-28 16:03:19.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/mballoc.c	2007-03-28 18:30:36.000000000 +0400
-@@ -36,6 +36,8 @@
- #include <linux/seq_file.h>
- #include <linux/version.h>
- 
-+#include "group.h"
-+
- /*
-  * MUSTDO:
-  *   - test ext3_ext_search_left() and ext3_ext_search_right()
-@@ -323,6 +325,7 @@ struct ext3_group_info {
- 	unsigned long	bb_state;
- 	unsigned long 	bb_tid;
- 	struct ext3_free_metadata *bb_md_cur;
-+	struct ext3_group_desc *bb_gdp;
- 	unsigned short	bb_first_free;
- 	unsigned short	bb_free;
- 	unsigned short	bb_fragments;
-@@ -928,10 +931,7 @@ static int ext3_mb_init_cache(struct pag
- 		if (first_group + i >= EXT3_SB(sb)->s_groups_count)
- 			break;
- 
--		err = -EIO;
--		desc = ext3_get_group_desc(sb, first_group + i, NULL);
--		if (desc == NULL)
--			goto out;
-+		desc = EXT3_GROUP_INFO(sb, first_group + i)->bb_gdp;
- 
- 		err = -ENOMEM;
- 		bh[i] = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap));
-@@ -946,7 +946,12 @@ static int ext3_mb_init_cache(struct pag
- 			unlock_buffer(bh[i]);
- 			continue;
- 		}
--
-+		if (desc->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+			ext3_init_block_bitmap(sb, bh[i], first_group + i,desc);
-+			set_buffer_uptodate(bh[i]);
-+			unlock_buffer(bh[i]);
-+			continue;
-+		}
- 		get_bh(bh[i]);
- 		bh[i]->b_end_io = end_buffer_read_sync;
- 		submit_bh(READ, bh[i]);
-@@ -1703,6 +1708,10 @@ static int ext3_mb_good_group(struct ext
- 	switch (cr) {
- 		case 0:
- 			BUG_ON(ac->ac_2order == 0);
-+			/* If this group is uninitialized, skip it initially */
-+			if (grp->bb_gdp->bg_flags &
-+			    cpu_to_le16(EXT3_BG_BLOCK_UNINIT))
-+				return 0;
- 			bits = ac->ac_sb->s_blocksize_bits + 1;
- 			for (i = ac->ac_2order; i <= bits; i++)
- 				if (grp->bb_counters[i] > 0)
-@@ -1796,7 +1805,9 @@ repeat:
- 			}
- 
- 			ac->ac_groups_scanned++;
--			if (cr == 0)
-+			if (cr == 0 || (e3b.bd_info->bb_gdp->bg_flags &
-+					cpu_to_le16(EXT3_BG_BLOCK_UNINIT) &&
-+					ac->ac_2order != 0))
- 				ext3_mb_simple_scan_group(ac, &e3b);
- 			else if (cr == 1 && ac->ac_g_ex.fe_len == sbi->s_stripe)
- 				ext3_mb_scan_aligned(ac, &e3b);
-@@ -2267,12 +2278,13 @@ int ext3_mb_init_backend(struct super_bl
- 			i--;
- 			goto err_freebuddy;
- 		}
-+		memset(meta_group_info[j], 0, len);
- 		desc = ext3_get_group_desc(sb, i, NULL);
-+		meta_group_info[j]->bb_gdp = desc;
- 		if (desc == NULL) {
- 			printk(KERN_ERR"EXT3-fs: can't read descriptor %u\n",i);
- 			goto err_freebuddy;
- 		}
--		memset(meta_group_info[j], 0, len);
- 		set_bit(EXT3_GROUP_INFO_NEED_INIT_BIT,
- 			&meta_group_info[j]->bb_state);
- 
-@@ -2936,9 +2948,17 @@ int ext3_mb_mark_diskspace_used(struct e
- 	mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len);
- 
- 	spin_lock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
-+	if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
-+		gdp->bg_free_blocks_count =
-+			cpu_to_le16(ext3_free_blocks_after_init(sb,
-+							    ac->ac_b_ex.fe_group,
-+							    gdp));
-+	}
- 	gdp->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)
- 				- ac->ac_b_ex.fe_len);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, - ac->ac_b_ex.fe_len);
- 
-@@ -4303,6 +4323,7 @@ do_more:
- 	spin_lock(sb_bgl_lock(sbi, block_group));
- 	gdp->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, block_group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, block_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
- 
-Index: linux-2.6.16.27-0.9-full/fs/ext3/balloc.c
-===================================================================
---- linux-2.6.16.27-0.9-full.orig/fs/ext3/balloc.c	2007-03-28 16:03:20.000000000 +0400
-+++ linux-2.6.16.27-0.9-full/fs/ext3/balloc.c	2007-03-28 18:30:06.000000000 +0400
-@@ -21,6 +21,7 @@
- #include <linux/quotaops.h>
- #include <linux/buffer_head.h>
- 
-+#include "group.h"
- /*
-  * balloc.c contains the blocks allocation and deallocation routines
-  */
-@@ -74,6 +75,75 @@ struct ext3_group_desc * ext3_get_group_
- 	return desc + offset;
- }
- 
-+/* Initializes an uninitialized block bitmap if given, and returns the
-+ * number of blocks free in the group. */
-+unsigned ext3_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
-+				int block_group, struct ext3_group_desc *gdp)
-+{
-+	unsigned long start;
-+	int bit, bit_max;
-+	unsigned free_blocks;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+
-+	if (bh) {
-+		J_ASSERT_BH(bh, buffer_locked(bh));
-+
-+		/* If checksum is bad mark all blocks use to prevent allocation,
-+		 * essentially implementing a per-group read-only flag. */
-+		if (!ext3_group_desc_csum_verify(sbi, block_group, gdp)) {
-+			ext3_error(sb, __FUNCTION__,
-+				   "Checksum bad for group %u\n", block_group);
-+			gdp->bg_free_blocks_count = 0;
-+			gdp->bg_free_inodes_count = 0;
-+			gdp->bg_itable_unused = 0;
-+			memset(bh->b_data, 0xff, sb->s_blocksize);
-+			return 0;
-+		}
-+		memset(bh->b_data, 0, sb->s_blocksize);
-+	}
-+
-+	/* Check for superblock and gdt backups in this group */
-+	bit_max = ext3_bg_has_super(sb, block_group);
-+
-+	if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
-+	    block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
-+			  sbi->s_desc_per_block) {
-+		if (bit_max) {
-+			bit_max += ext3_bg_num_gdb(sb, block_group);
-+			bit_max +=le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
-+		}
-+	} else { /* For META_BG_BLOCK_GROUPS */
-+		int group_rel = (block_group -
-+				 le32_to_cpu(sbi->s_es->s_first_meta_bg)) %
-+				EXT3_DESC_PER_BLOCK(sb);
-+		if (group_rel == 0 || group_rel == 1 ||
-+		    (group_rel == EXT3_DESC_PER_BLOCK(sb) - 1))
-+			bit_max += 1;
-+	}
-+
-+	/* Last and first groups are always initialized */
-+	free_blocks = EXT3_BLOCKS_PER_GROUP(sb) - bit_max;
-+
-+	if (bh) {
-+		for (bit = 0; bit < bit_max; bit++)
-+			ext3_set_bit(bit, bh->b_data);
-+
-+		start = block_group * EXT3_BLOCKS_PER_GROUP(sb) +
-+			le32_to_cpu(sbi->s_es->s_first_data_block);
-+
-+		/* Set bits for block and inode bitmaps, and inode table */
-+		ext3_set_bit(le32_to_cpu(gdp->bg_block_bitmap) - start,
-+			     bh->b_data);
-+		ext3_set_bit(le32_to_cpu(gdp->bg_inode_bitmap) - start,
-+			     bh->b_data);
-+		for (bit = le32_to_cpu(gdp->bg_inode_table) - start,
-+		     bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++)
-+			ext3_set_bit(bit, bh->b_data);
-+	}
-+
-+	return free_blocks - sbi->s_itb_per_group - 2;
-+}
-+
- /*
-  * Read the bitmap for a given block_group, reading into the specified 
-  * slot in the superblock's bitmap cache.
-@@ -89,7 +159,19 @@ read_block_bitmap(struct super_block *sb
- 	desc = ext3_get_group_desc (sb, block_group, NULL);
- 	if (!desc)
- 		goto error_out;
--	bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-+	if (desc->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		bh = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap));
-+		if (!buffer_uptodate(bh)) {
-+			lock_buffer(bh);
-+			if (!buffer_uptodate(bh)) {
-+				ext3_init_block_bitmap(sb, bh,block_group,desc);
-+				set_buffer_uptodate(bh);
-+			}
-+			unlock_buffer(bh);
-+		}
-+	} else {
-+		bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-+	}
- 	if (!bh)
- 		ext3_error (sb, "read_block_bitmap",
- 			    "Cannot read block bitmap - "
-@@ -468,6 +550,7 @@ do_more:
- 	desc->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) +
- 			group_freed);
-+	desc->bg_checksum = ext3_group_desc_csum(sbi, block_group, desc);
- 	spin_unlock(sb_bgl_lock(sbi, block_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
- 
-@@ -1378,8 +1461,11 @@ allocated:
- 			ret_block, goal_hits, goal_attempts);
- 
- 	spin_lock(sb_bgl_lock(sbi, group_no));
-+	if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT))
-+		gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
- 	gdp->bg_free_blocks_count =
- 			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, group_no, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, group_no));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, -1);
- 
-
-%diffstat
- fs/ext3/balloc.c        |   88 +++++++++++++++++++++++++++++
- fs/ext3/group.h         |   38 ++++++++++++
- fs/ext3/ialloc.c        |  144 +++++++++++++++++++++++++++++++++++++++++++-----
- fs/ext3/mballoc.c       |   35 +++++++++--
- fs/ext3/resize.c        |    2 
- fs/ext3/super.c         |   92 ++++++++++++++++++++++++++++++
- include/linux/ext3_fs.h |   16 ++++-
- 7 files changed, 388 insertions(+), 27 deletions(-)
diff --git a/lustre/kernel_patches/patches/ext3-uninit-2.6-suse.patch b/lustre/kernel_patches/patches/ext3-uninit-2.6-suse.patch
deleted file mode 100644
index 8a34ea5afa..0000000000
--- a/lustre/kernel_patches/patches/ext3-uninit-2.6-suse.patch
+++ /dev/null
@@ -1,653 +0,0 @@
-Add support for the uninit_groups feature to the kernel.
-
-Keep a high water mark of used inodes for each group to improve e2fsck time.
-Block and inode bitmaps can be uninitialized on disk via a flag in the
-group descriptor to avoid reading or scanning them at e2fsck time.
-A checksum of each group descriptor is used to ensure that corruption in
-the group descriptor's bit flags does not cause incorrect operation.
-
-Index: linux-2.6.5-7.283-full/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.5-7.283-full.orig/include/linux/ext3_fs.h	2007-03-28 17:33:05.000000000 +0400
-+++ linux-2.6.5-7.283-full/include/linux/ext3_fs.h	2007-03-28 18:33:35.000000000 +0400
-@@ -153,16 +153,22 @@ struct ext3_allocation_request {
-  */
- struct ext3_group_desc
- {
--	__u32	bg_block_bitmap;		/* Blocks bitmap block */
--	__u32	bg_inode_bitmap;		/* Inodes bitmap block */
-+	__u32	bg_block_bitmap;	/* Blocks bitmap block */
-+	__u32	bg_inode_bitmap;	/* Inodes bitmap block */
- 	__u32	bg_inode_table;		/* Inodes table block */
- 	__u16	bg_free_blocks_count;	/* Free blocks count */
- 	__u16	bg_free_inodes_count;	/* Free inodes count */
- 	__u16	bg_used_dirs_count;	/* Directories count */
--	__u16	bg_pad;
--	__u32	bg_reserved[3];
-+	__u16	bg_flags;		/* EXT3_BG_flags (UNINIT, etc) */
-+	__u32	bg_reserved[2];		/* Likely block/inode bitmap checksum */
-+	__u16	bg_itable_unused;	/* Unused inodes count */
-+	__u16	bg_checksum;		/* crc16(sb_uuid+group+desc) */
- };
- 
-+#define EXT3_BG_INODE_UNINIT	0x0001	/* Inode table/bitmap not in use */
-+#define EXT3_BG_BLOCK_UNINIT	0x0002	/* Block bitmap not in use */
-+#define EXT3_BG_INODE_ZEROED	0x0004	/* On-disk itable initialized to zero */
-+
- /*
-  * Macro-instructions used to manage group descriptors
-  */
-@@ -458,7 +464,7 @@ struct ext3_super_block {
- 	 */
- 	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
- 	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
--	__u16	s_padding1;
-+	__u16	s_reserved_gdt_blocks;	/* Per group desc for online growth */
- 	/*
- 	 * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
- 	 */
-@@ -546,6 +552,7 @@ static inline struct ext3_inode_info *EX
- #define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
- #define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
- #define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
-+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010
- #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK	0x0020
- 
- #define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
-@@ -562,6 +569,7 @@ static inline struct ext3_inode_info *EX
- 					 EXT3_FEATURE_INCOMPAT_EXTENTS)
- #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
- 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
-+					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
- 					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
- 					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
- 
-Index: linux-2.6.5-7.283-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/super.c	2007-03-28 17:33:05.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/super.c	2007-03-28 18:33:35.000000000 +0400
-@@ -36,6 +36,7 @@
- #include <linux/quotaops.h>
- #include "xattr.h"
- #include "acl.h"
-+#include "group.h"
- 
- static int ext3_load_journal(struct super_block *, struct ext3_super_block *);
- static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
-@@ -996,6 +997,90 @@ static int ext3_setup_super(struct super
- 	return res;
- }
- 
-+#if !defined(CONFIG_CRC16) && !defined(CONFIG_CRC16_MODULE)
-+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
-+__u16 const crc16_table[256] = {
-+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
-+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
-+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
-+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
-+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
-+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
-+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
-+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
-+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
-+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
-+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
-+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
-+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
-+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
-+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
-+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
-+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
-+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
-+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
-+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
-+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
-+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
-+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
-+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
-+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
-+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
-+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
-+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
-+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
-+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
-+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
-+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
-+};
-+
-+static inline __u16 crc16_byte(__u16 crc, const __u8 data)
-+{
-+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
-+}
-+
-+__u16 crc16(__u16 crc, __u8 const *buffer, size_t len)
-+{
-+	while (len--)
-+		crc = crc16_byte(crc, *buffer++);
-+	return crc;
-+}
-+#endif
-+
-+__le16 ext3_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
-+			    struct ext3_group_desc *gdp)
-+{
-+	__u16 crc = 0;
-+
-+	if (sbi->s_es->s_feature_ro_compat &
-+	    cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-+		int offset = offsetof(struct ext3_group_desc, bg_checksum);
-+		__le32 le_group = cpu_to_le32(block_group);
-+
-+		crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
-+		crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
-+		crc = crc16(crc, (__u8 *)gdp, offset);
-+		offset += sizeof(gdp->bg_checksum); /* skip checksum */
-+		BUG_ON(offset != sizeof(*gdp)); /* XXX handle s_desc_size */
-+		/* for checksum of struct ext4_group_desc do the rest...
-+		if (offset < sbi->s_es->s_desc_size) {
-+			crc = crc16(crc, (__u8 *)gdp + offset,
-+				    sbi->s_es->s_desc_size - offset);
-+		 */
-+	}
-+
-+	return cpu_to_le16(crc);
-+}
-+
-+int ext3_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
-+				struct ext3_group_desc *gdp)
-+{
-+	if (gdp->bg_checksum != ext3_group_desc_csum(sbi, block_group, gdp))
-+		return 0;
-+
-+	return 1;
-+}
-+
- static int ext3_check_descriptors (struct super_block * sb)
- {
- 	struct ext3_sb_info *sbi = EXT3_SB(sb);
-@@ -1044,6 +1129,13 @@ static int ext3_check_descriptors (struc
- 					le32_to_cpu(gdp->bg_inode_table));
- 			return 0;
- 		}
-+		if (!ext3_group_desc_csum_verify(sbi, i, gdp)) {
-+			ext3_error(sb, __FUNCTION__,
-+				   "Checksum for group %d failed (%u!=%u)\n", i,
-+				   le16_to_cpu(ext3_group_desc_csum(sbi,i,gdp)),
-+				   le16_to_cpu(gdp->bg_checksum));
-+			return 0;
-+		}
- 		block += EXT3_BLOCKS_PER_GROUP(sb);
- 		gdp++;
- 	}
-Index: linux-2.6.5-7.283-full/fs/ext3/group.h
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/group.h	2007-02-13 18:39:59.640066087 +0300
-+++ linux-2.6.5-7.283-full/fs/ext3/group.h	2007-03-28 18:33:35.000000000 +0400
-@@ -0,0 +1,29 @@
-+/*
-+ *  linux/fs/ext3/group.h
-+ *
-+ * Copyright (C) 2007 Cluster File Systems, Inc
-+ *
-+ * Author: Andreas Dilger <adilger@clusterfs.com>
-+ */
-+
-+#ifndef _LINUX_EXT3_GROUP_H
-+#define _LINUX_EXT3_GROUP_H
-+#if defined(CONFIG_CRC16) || defined(CONFIG_CRC16_MODULE)
-+#include <linux/crc16.h>
-+#endif
-+
-+extern __le16 ext3_group_desc_csum(struct ext3_sb_info *sbi, __u32 group,
-+				   struct ext3_group_desc *gdp);
-+extern int ext3_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 group,
-+				       struct ext3_group_desc *gdp);
-+struct buffer_head *read_block_bitmap(struct super_block *sb,
-+				      unsigned int block_group);
-+extern unsigned ext3_init_block_bitmap(struct super_block *sb,
-+				       struct buffer_head *bh, int group,
-+				       struct ext3_group_desc *desc);
-+#define ext3_free_blocks_after_init(sb, group, desc)			\
-+		ext3_init_block_bitmap(sb, NULL, group, desc)
-+extern unsigned ext3_init_inode_bitmap(struct super_block *sb,
-+				       struct buffer_head *bh, int group,
-+				       struct ext3_group_desc *desc);
-+#endif /* _LINUX_EXT3_GROUP_H */
-Index: linux-2.6.5-7.283-full/fs/ext3/ialloc.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/ialloc.c	2007-03-28 17:33:03.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/ialloc.c	2007-03-28 18:33:35.000000000 +0400
-@@ -28,6 +28,7 @@
- 
- #include "xattr.h"
- #include "acl.h"
-+#include "group.h"
- 
- /*
-  * ialloc.c contains the inodes allocation and deallocation routines
-@@ -43,6 +44,52 @@
-  * the free blocks count in the block.
-  */
- 
-+/*
-+ * To avoid calling the atomic setbit hundreds or thousands of times, we only
-+ * need to use it within a single byte (to ensure we get endianness right).
-+ * We can use memset for the rest of the bitmap as there are no other users.
-+ */
-+static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
-+{
-+	int i;
-+
-+	if (start_bit >= end_bit)
-+		return;
-+
-+	ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit);
-+	for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
-+		ext3_set_bit(i, bitmap);
-+	if (i < end_bit)
-+		memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
-+}
-+
-+/* Initializes an uninitialized inode bitmap */
-+unsigned ext3_init_inode_bitmap(struct super_block *sb,
-+				struct buffer_head *bh, int block_group,
-+				struct ext3_group_desc *gdp)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+
-+	J_ASSERT_BH(bh, buffer_locked(bh));
-+
-+	/* If checksum is bad mark all blocks and inodes use to prevent
-+	 * allocation, essentially implementing a per-group read-only flag. */
-+	if (!ext3_group_desc_csum_verify(sbi, block_group, gdp)) {
-+		ext3_error(sb, __FUNCTION__, "Checksum bad for group %u\n",
-+			   block_group);
-+		gdp->bg_free_blocks_count = 0;
-+		gdp->bg_free_inodes_count = 0;
-+		gdp->bg_itable_unused = 0;
-+		memset(bh->b_data, 0xff, sb->s_blocksize);
-+		return 0;
-+	}
-+
-+	memset(bh->b_data, 0, (EXT3_INODES_PER_GROUP(sb) + 7) / 8);
-+	mark_bitmap_end(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb),
-+			bh->b_data);
-+
-+	return EXT3_INODES_PER_GROUP(sb);
-+}
- 
- /*
-  * Read the inode allocation bitmap for a given block_group, reading
-@@ -59,8 +106,19 @@ read_inode_bitmap(struct super_block * s
- 	desc = ext3_get_group_desc(sb, block_group, NULL);
- 	if (!desc)
- 		goto error_out;
--
--	bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+	if (desc->bg_flags & cpu_to_le16(EXT3_BG_INODE_UNINIT)) {
-+		bh = sb_getblk(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+		if (!buffer_uptodate(bh)) {
-+			lock_buffer(bh);
-+			if (!buffer_uptodate(bh)) {
-+				ext3_init_inode_bitmap(sb, bh,block_group,desc);
-+				set_buffer_uptodate(bh);
-+			}
-+			unlock_buffer(bh);
-+		}
-+	} else {
-+		bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+	}
- 	if (!bh)
- 		ext3_error(sb, "read_inode_bitmap",
- 			    "Cannot read inode bitmap - "
-@@ -168,6 +226,8 @@ void ext3_free_inode (handle_t *handle, 
- 			if (is_directory)
- 				gdp->bg_used_dirs_count = cpu_to_le16(
- 				  le16_to_cpu(gdp->bg_used_dirs_count) - 1);
-+			gdp->bg_checksum = ext3_group_desc_csum(sbi,block_group,
-+								gdp);
- 			spin_unlock(sb_bgl_lock(sbi, block_group));
- 			percpu_counter_inc(&sbi->s_freeinodes_counter);
- 			if (is_directory)
-@@ -454,7 +514,7 @@ struct inode *ext3_new_inode(handle_t *h
- 	struct ext3_sb_info *sbi;
- 	int err = 0;
- 	struct inode *ret;
--	int i;
-+	int i, free = 0;
- 
- 	/* Cannot create files in a deleted directory */
- 	if (!dir || !dir->i_nlink)
-@@ -570,11 +630,13 @@ repeat_in_this_group:
- 	goto out;
- 
- got:
--	ino += group * EXT3_INODES_PER_GROUP(sb) + 1;
--	if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
--		ext3_error (sb, "ext3_new_inode",
--			    "reserved inode or inode > inodes count - "
--			    "block_group = %d, inode=%lu", group, ino);
-+	ino++;
-+	if ((group == 0 && ino < EXT3_FIRST_INO(sb)) ||
-+	    ino > EXT3_INODES_PER_GROUP(sb)) {
-+		ext3_error(sb, __FUNCTION__,
-+			   "reserved inode or inode > inodes count - "
-+			   "block_group = %d, inode=%lu", group,
-+			   ino + group * EXT3_INODES_PER_GROUP(sb));
- 		err = -EIO;
- 		goto fail;
- 	}
-@@ -582,13 +644,65 @@ got:
- 	BUFFER_TRACE(bh2, "get_write_access");
- 	err = ext3_journal_get_write_access(handle, bh2);
- 	if (err) goto fail;
-+
-+	/* We may have to initialize the block bitmap if it isn't already */
-+	if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
-+	    gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		struct buffer_head *block_bh = read_block_bitmap(sb, group);
-+
-+		BUFFER_TRACE(block_bh, "get block bitmap access");
-+		err = ext3_journal_get_write_access(handle, block_bh);
-+		if (err) {
-+			brelse(block_bh);
-+			goto fail;
-+		}
-+
-+		free = 0;
-+		spin_lock(sb_bgl_lock(sbi, group));
-+		/* recheck and clear flag under lock if we still need to */
-+		if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+			gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
-+			free = ext3_free_blocks_after_init(sb, group, gdp);
-+			gdp->bg_free_blocks_count = cpu_to_le16(free);
-+		}
-+		spin_unlock(sb_bgl_lock(sbi, group));
-+
-+		/* Don't need to dirty bitmap block if we didn't change it */
-+		if (free) {
-+			BUFFER_TRACE(block_bh, "dirty block bitmap");
-+			err = ext3_journal_dirty_metadata(handle, block_bh);
-+		}
-+
-+		brelse(block_bh);
-+		if (err)
-+			goto fail;
-+	}
-+
- 	spin_lock(sb_bgl_lock(sbi, group));
-+	/* If we didn't allocate from within the initialized part of the inode
-+	 * table then we need to initialize up to this inode. */
-+	if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-+		if (gdp->bg_flags & cpu_to_le16(EXT3_BG_INODE_UNINIT)) {
-+			gdp->bg_flags &= cpu_to_le16(~EXT3_BG_INODE_UNINIT);
-+			free = EXT3_INODES_PER_GROUP(sb);
-+		} else {
-+			free = EXT3_INODES_PER_GROUP(sb) -
-+				le16_to_cpu(gdp->bg_itable_unused);
-+		}
-+
-+		if (ino > free) {
-+			gdp->bg_itable_unused =
-+				cpu_to_le16(EXT3_INODES_PER_GROUP(sb) - ino);
-+		}
-+	}
-+
- 	gdp->bg_free_inodes_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
- 	if (S_ISDIR(mode)) {
- 		gdp->bg_used_dirs_count =
- 			cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
- 	}
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, group));
- 	BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
- 	err = ext3_journal_dirty_metadata(handle, bh2);
-@@ -610,7 +724,7 @@ got:
- 		inode->i_gid = current->fsgid;
- 	inode->i_mode = mode;
- 
--	inode->i_ino = ino;
-+	inode->i_ino = ino + group * EXT3_INODES_PER_GROUP(sb);
- 	/* This is the optimal IO size (for stat), not the fs block size */
- 	inode->i_blksize = PAGE_SIZE;
- 	inode->i_blocks = 0;
-Index: linux-2.6.5-7.283-full/fs/ext3/mballoc.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/mballoc.c	2007-03-28 15:46:00.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/mballoc.c	2007-03-28 18:33:35.000000000 +0400
-@@ -36,6 +36,8 @@
- #include <linux/seq_file.h>
- #include <linux/version.h>
- 
-+#include "group.h"
-+
- /*
-  * MUSTDO:
-  *   - test ext3_ext_search_left() and ext3_ext_search_right()
-@@ -323,6 +325,7 @@ struct ext3_group_info {
- 	unsigned long	bb_state;
- 	unsigned long 	bb_tid;
- 	struct ext3_free_metadata *bb_md_cur;
-+	struct ext3_group_desc *bb_gdp;
- 	unsigned short	bb_first_free;
- 	unsigned short	bb_free;
- 	unsigned short	bb_fragments;
-@@ -928,10 +931,7 @@ static int ext3_mb_init_cache(struct pag
- 		if (first_group + i >= EXT3_SB(sb)->s_groups_count)
- 			break;
- 
--		err = -EIO;
--		desc = ext3_get_group_desc(sb, first_group + i, NULL);
--		if (desc == NULL)
--			goto out;
-+		desc = EXT3_GROUP_INFO(sb, first_group + i)->bb_gdp;
- 
- 		err = -ENOMEM;
- 		bh[i] = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap));
-@@ -946,7 +946,12 @@ static int ext3_mb_init_cache(struct pag
- 			unlock_buffer(bh[i]);
- 			continue;
- 		}
--
-+		if (desc->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+			ext3_init_block_bitmap(sb, bh[i], first_group + i,desc);
-+			set_buffer_uptodate(bh[i]);
-+			unlock_buffer(bh[i]);
-+			continue;
-+		}
- 		get_bh(bh[i]);
- 		bh[i]->b_end_io = end_buffer_read_sync;
- 		submit_bh(READ, bh[i]);
-@@ -1703,6 +1708,10 @@ static int ext3_mb_good_group(struct ext
- 	switch (cr) {
- 		case 0:
- 			BUG_ON(ac->ac_2order == 0);
-+			/* If this group is uninitialized, skip it initially */
-+			if (grp->bb_gdp->bg_flags &
-+			    cpu_to_le16(EXT3_BG_BLOCK_UNINIT))
-+				return 0;
- 			bits = ac->ac_sb->s_blocksize_bits + 1;
- 			for (i = ac->ac_2order; i <= bits; i++)
- 				if (grp->bb_counters[i] > 0)
-@@ -1796,7 +1805,9 @@ repeat:
- 			}
- 
- 			ac->ac_groups_scanned++;
--			if (cr == 0)
-+			if (cr == 0 || (e3b.bd_info->bb_gdp->bg_flags &
-+					cpu_to_le16(EXT3_BG_BLOCK_UNINIT) &&
-+					ac->ac_2order != 0))
- 				ext3_mb_simple_scan_group(ac, &e3b);
- 			else if (cr == 1 && ac->ac_g_ex.fe_len == sbi->s_stripe)
- 				ext3_mb_scan_aligned(ac, &e3b);
-@@ -2267,12 +2278,13 @@ int ext3_mb_init_backend(struct super_bl
- 			i--;
- 			goto err_freebuddy;
- 		}
-+		memset(meta_group_info[j], 0, len);
- 		desc = ext3_get_group_desc(sb, i, NULL);
-+		meta_group_info[j]->bb_gdp = desc;
- 		if (desc == NULL) {
- 			printk(KERN_ERR"EXT3-fs: can't read descriptor %u\n",i);
- 			goto err_freebuddy;
- 		}
--		memset(meta_group_info[j], 0, len);
- 		set_bit(EXT3_GROUP_INFO_NEED_INIT_BIT,
- 			&meta_group_info[j]->bb_state);
- 
-@@ -2936,9 +2948,17 @@ int ext3_mb_mark_diskspace_used(struct e
- 	mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len);
- 
- 	spin_lock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
-+	if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
-+		gdp->bg_free_blocks_count =
-+			cpu_to_le16(ext3_free_blocks_after_init(sb,
-+							    ac->ac_b_ex.fe_group,
-+							    gdp));
-+	}
- 	gdp->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)
- 				- ac->ac_b_ex.fe_len);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, - ac->ac_b_ex.fe_len);
- 
-@@ -4303,6 +4323,7 @@ do_more:
- 	spin_lock(sb_bgl_lock(sbi, block_group));
- 	gdp->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, block_group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, block_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
- 
-Index: linux-2.6.5-7.283-full/fs/ext3/balloc.c
-===================================================================
---- linux-2.6.5-7.283-full.orig/fs/ext3/balloc.c	2007-03-28 17:33:02.000000000 +0400
-+++ linux-2.6.5-7.283-full/fs/ext3/balloc.c	2007-03-28 18:33:35.000000000 +0400
-@@ -20,6 +20,7 @@
- #include <linux/quotaops.h>
- #include <linux/buffer_head.h>
- 
-+#include "group.h"
- /*
-  * balloc.c contains the blocks allocation and deallocation routines
-  */
-@@ -72,6 +73,75 @@ struct ext3_group_desc * ext3_get_group_
- 	return gdp + desc;
- }
- 
-+/* Initializes an uninitialized block bitmap if given, and returns the
-+ * number of blocks free in the group. */
-+unsigned ext3_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
-+				int block_group, struct ext3_group_desc *gdp)
-+{
-+	unsigned long start;
-+	int bit, bit_max;
-+	unsigned free_blocks;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+
-+	if (bh) {
-+		J_ASSERT_BH(bh, buffer_locked(bh));
-+
-+		/* If checksum is bad mark all blocks use to prevent allocation,
-+		 * essentially implementing a per-group read-only flag. */
-+		if (!ext3_group_desc_csum_verify(sbi, block_group, gdp)) {
-+			ext3_error(sb, __FUNCTION__,
-+				   "Checksum bad for group %u\n", block_group);
-+			gdp->bg_free_blocks_count = 0;
-+			gdp->bg_free_inodes_count = 0;
-+			gdp->bg_itable_unused = 0;
-+			memset(bh->b_data, 0xff, sb->s_blocksize);
-+			return 0;
-+		}
-+		memset(bh->b_data, 0, sb->s_blocksize);
-+	}
-+
-+	/* Check for superblock and gdt backups in this group */
-+	bit_max = ext3_bg_has_super(sb, block_group);
-+
-+	if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
-+	    block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
-+			  sbi->s_desc_per_block) {
-+		if (bit_max) {
-+			bit_max += ext3_bg_num_gdb(sb, block_group);
-+			bit_max +=le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
-+		}
-+	} else { /* For META_BG_BLOCK_GROUPS */
-+		int group_rel = (block_group -
-+				 le32_to_cpu(sbi->s_es->s_first_meta_bg)) %
-+				EXT3_DESC_PER_BLOCK(sb);
-+		if (group_rel == 0 || group_rel == 1 ||
-+		    (group_rel == EXT3_DESC_PER_BLOCK(sb) - 1))
-+			bit_max += 1;
-+	}
-+
-+	/* Last and first groups are always initialized */
-+	free_blocks = EXT3_BLOCKS_PER_GROUP(sb) - bit_max;
-+
-+	if (bh) {
-+		for (bit = 0; bit < bit_max; bit++)
-+			ext3_set_bit(bit, bh->b_data);
-+
-+		start = block_group * EXT3_BLOCKS_PER_GROUP(sb) +
-+			le32_to_cpu(sbi->s_es->s_first_data_block);
-+
-+		/* Set bits for block and inode bitmaps, and inode table */
-+		ext3_set_bit(le32_to_cpu(gdp->bg_block_bitmap) - start,
-+			     bh->b_data);
-+		ext3_set_bit(le32_to_cpu(gdp->bg_inode_bitmap) - start,
-+			     bh->b_data);
-+		for (bit = le32_to_cpu(gdp->bg_inode_table) - start,
-+		     bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++)
-+			ext3_set_bit(bit, bh->b_data);
-+	}
-+
-+	return free_blocks - sbi->s_itb_per_group - 2;
-+}
-+
- /*
-  * Read the bitmap for a given block_group, reading into the specified 
-  * slot in the superblock's bitmap cache.
-@@ -87,7 +157,19 @@ read_block_bitmap(struct super_block *sb
- 	desc = ext3_get_group_desc (sb, block_group, NULL);
- 	if (!desc)
- 		goto error_out;
--	bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-+	if (desc->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		bh = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap));
-+		if (!buffer_uptodate(bh)) {
-+			lock_buffer(bh);
-+			if (!buffer_uptodate(bh)) {
-+				ext3_init_block_bitmap(sb, bh,block_group,desc);
-+				set_buffer_uptodate(bh);
-+			}
-+			unlock_buffer(bh);
-+		}
-+	} else {
-+		bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-+	}
- 	if (!bh)
- 		ext3_error (sb, "read_block_bitmap",
- 			    "Cannot read block bitmap - "
-@@ -432,6 +514,7 @@ do_more:
- 	gdp->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) +
- 			dquot_freed_blocks);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, block_group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, block_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
- 
-@@ -1372,8 +1455,11 @@ allocated:
- 			ret_block, goal_hits, goal_attempts);
- 
- 	spin_lock(sb_bgl_lock(sbi, group_no));
-+	if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT))
-+		gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
- 	gdp->bg_free_blocks_count =
- 			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, group_no, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, group_no));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, -1);
- 
diff --git a/lustre/kernel_patches/patches/ext3-uninit-2.6.9.patch b/lustre/kernel_patches/patches/ext3-uninit-2.6.9.patch
deleted file mode 100644
index 2dbeb80a2b..0000000000
--- a/lustre/kernel_patches/patches/ext3-uninit-2.6.9.patch
+++ /dev/null
@@ -1,664 +0,0 @@
-Add support for the uninit_groups feature to the kernel.
-
-Keep a high water mark of used inodes for each group to improve e2fsck time.
-Block and inode bitmaps can be uninitialized on disk via a flag in the
-group descriptor to avoid reading or scanning them at e2fsck time.
-A checksum of each group descriptor is used to ensure that corruption in
-the group descriptor's bit flags does not cause incorrect operation.
-
-Index: linux-2.6.9-full/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.9-full.orig/include/linux/ext3_fs.h	2007-03-28 18:35:41.000000000 +0400
-+++ linux-2.6.9-full/include/linux/ext3_fs.h	2007-03-28 18:36:16.000000000 +0400
-@@ -153,16 +153,22 @@ struct ext3_allocation_request {
-  */
- struct ext3_group_desc
- {
--	__le32	bg_block_bitmap;		/* Blocks bitmap block */
--	__le32	bg_inode_bitmap;		/* Inodes bitmap block */
-+	__le32	bg_block_bitmap;	/* Blocks bitmap block */
-+	__le32	bg_inode_bitmap;	/* Inodes bitmap block */
- 	__le32	bg_inode_table;		/* Inodes table block */
- 	__le16	bg_free_blocks_count;	/* Free blocks count */
- 	__le16	bg_free_inodes_count;	/* Free inodes count */
- 	__le16	bg_used_dirs_count;	/* Directories count */
--	__u16	bg_pad;
--	__le32	bg_reserved[3];
-+	__le16  bg_flags;		/* EXT3_BG_flags (UNINIT, etc) */
-+	__le32	bg_reserved[2];		/* Likely block/inode bitmap checksum */
-+	__le16	bg_itable_unused;	/* Unused inodes count */
-+	__le16	bg_checksum;		/* crc16(sb_uuid+group+desc) */
- };
- 
-+#define EXT3_BG_INODE_UNINIT	0x0001 /* Inode table/bitmap not in use */
-+#define EXT3_BG_BLOCK_UNINIT	0x0002 /* Block bitmap not in use */
-+#define EXT3_BG_INODE_ZEROED	0x0004 /* On-disk itable initialized to zero */
-+
- /*
-  * Macro-instructions used to manage group descriptors
-  */
-@@ -572,6 +578,7 @@ static inline struct ext3_inode_info *EX
- #define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
- #define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
- #define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
-+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM		0x0010
- #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK	0x0020
- 
- #define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
-@@ -588,6 +595,7 @@ static inline struct ext3_inode_info *EX
- 					 EXT3_FEATURE_INCOMPAT_EXTENTS)
- #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
- 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
-+					 EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
- 					 EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
- 					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
- 
-Index: linux-2.6.9-full/fs/ext3/resize.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/resize.c	2006-03-10 18:20:03.000000000 +0300
-+++ linux-2.6.9-full/fs/ext3/resize.c	2007-03-28 18:36:16.000000000 +0400
-@@ -19,6 +19,7 @@
- #include <linux/errno.h>
- #include <linux/slab.h>
- 
-+#include "group.h"
- 
- #define outside(b, first, last)	((b) < (first) || (b) >= (last))
- #define inside(b, first, last)	((b) >= (first) && (b) < (last))
-@@ -807,6 +808,7 @@ int ext3_group_add(struct super_block *s
- 	gdp->bg_inode_table = cpu_to_le32(input->inode_table);
- 	gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);
- 	gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb));
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, input->group, gdp);
- 
- 	/*
- 	 * Make the new blocks and inodes valid next.  We do this before
-Index: linux-2.6.9-full/fs/ext3/super.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/super.c	2007-03-28 18:35:42.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/super.c	2007-03-28 18:36:16.000000000 +0400
-@@ -38,6 +38,7 @@
- #include <asm/uaccess.h>
- #include "xattr.h"
- #include "acl.h"
-+#include "group.h"
- 
- static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
- 			     unsigned long journal_devnum);
-@@ -1090,6 +1091,90 @@ static int ext3_setup_super(struct super
- 	return res;
- }
- 
-+#if !defined(CONFIG_CRC16) && !defined(CONFIG_CRC16_MODULE)
-+/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */
-+__u16 const crc16_table[256] = {
-+	0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
-+	0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
-+	0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
-+	0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
-+	0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
-+	0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
-+	0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
-+	0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
-+	0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
-+	0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
-+	0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
-+	0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
-+	0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
-+	0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
-+	0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
-+	0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
-+	0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
-+	0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
-+	0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
-+	0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
-+	0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
-+	0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
-+	0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
-+	0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
-+	0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
-+	0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
-+	0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
-+	0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
-+	0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
-+	0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
-+	0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
-+	0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
-+};
-+
-+static inline __u16 crc16_byte(__u16 crc, const __u8 data)
-+{
-+	return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
-+}
-+
-+__u16 crc16(__u16 crc, __u8 const *buffer, size_t len)
-+{
-+	while (len--)
-+		crc = crc16_byte(crc, *buffer++);
-+	return crc;
-+}
-+#endif
-+
-+__le16 ext3_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
-+			    struct ext3_group_desc *gdp)
-+{
-+	__u16 crc = 0;
-+
-+	if (sbi->s_es->s_feature_ro_compat &
-+	    cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-+		int offset = offsetof(struct ext3_group_desc, bg_checksum);
-+		__le32 le_group = cpu_to_le32(block_group);
-+
-+		crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
-+		crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
-+		crc = crc16(crc, (__u8 *)gdp, offset);
-+		offset += sizeof(gdp->bg_checksum); /* skip checksum */
-+		BUG_ON(offset != sizeof(*gdp)); /* XXX handle s_desc_size */
-+		/* for checksum of struct ext4_group_desc do the rest...
-+		if (offset < sbi->s_es->s_desc_size) {
-+			crc = crc16(crc, (__u8 *)gdp + offset,
-+				    sbi->s_es->s_desc_size - offset);
-+		 */
-+	}
-+
-+	return cpu_to_le16(crc);
-+}
-+
-+int ext3_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
-+				struct ext3_group_desc *gdp)
-+{
-+	if (gdp->bg_checksum != ext3_group_desc_csum(sbi, block_group, gdp))
-+		return 0;
-+
-+	return 1;
-+}
-+
- /* Called at mount-time, super-block is locked */
- static int ext3_check_descriptors (struct super_block * sb)
- {
-@@ -1139,6 +1224,13 @@ static int ext3_check_descriptors (struc
- 					le32_to_cpu(gdp->bg_inode_table));
- 			return 0;
- 		}
-+		if (!ext3_group_desc_csum_verify(sbi, i, gdp)) {
-+			ext3_error(sb, __FUNCTION__,
-+				   "Checksum for group %d failed (%u!=%u)\n", i,
-+				   le16_to_cpu(ext3_group_desc_csum(sbi,i,gdp)),
-+				   le16_to_cpu(gdp->bg_checksum));
-+			return 0;
-+		}
- 		block += EXT3_BLOCKS_PER_GROUP(sb);
- 		gdp++;
- 	}
-Index: linux-2.6.9-full/fs/ext3/group.h
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/group.h	2007-02-13 18:39:59.640066087 +0300
-+++ linux-2.6.9-full/fs/ext3/group.h	2007-03-28 18:36:16.000000000 +0400
-@@ -0,0 +1,29 @@
-+/*
-+ *  linux/fs/ext3/group.h
-+ *
-+ * Copyright (C) 2007 Cluster File Systems, Inc
-+ *
-+ * Author: Andreas Dilger <adilger@clusterfs.com>
-+ */
-+
-+#ifndef _LINUX_EXT3_GROUP_H
-+#define _LINUX_EXT3_GROUP_H
-+#if defined(CONFIG_CRC16) || defined(CONFIG_CRC16_MODULE)
-+#include <linux/crc16.h>
-+#endif
-+
-+extern __le16 ext3_group_desc_csum(struct ext3_sb_info *sbi, __u32 group,
-+				   struct ext3_group_desc *gdp);
-+extern int ext3_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 group,
-+				       struct ext3_group_desc *gdp);
-+struct buffer_head *read_block_bitmap(struct super_block *sb,
-+				      unsigned int block_group);
-+extern unsigned ext3_init_block_bitmap(struct super_block *sb,
-+				       struct buffer_head *bh, int group,
-+				       struct ext3_group_desc *desc);
-+#define ext3_free_blocks_after_init(sb, group, desc)			\
-+		ext3_init_block_bitmap(sb, NULL, group, desc)
-+extern unsigned ext3_init_inode_bitmap(struct super_block *sb,
-+				       struct buffer_head *bh, int group,
-+				       struct ext3_group_desc *desc);
-+#endif /* _LINUX_EXT3_GROUP_H */
-Index: linux-2.6.9-full/fs/ext3/ialloc.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/ialloc.c	2007-03-28 18:35:38.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/ialloc.c	2007-03-28 18:36:16.000000000 +0400
-@@ -28,6 +28,7 @@
- 
- #include "xattr.h"
- #include "acl.h"
-+#include "group.h"
- 
- /*
-  * ialloc.c contains the inodes allocation and deallocation routines
-@@ -43,6 +44,52 @@
-  * the free blocks count in the block.
-  */
- 
-+/*
-+ * To avoid calling the atomic setbit hundreds or thousands of times, we only
-+ * need to use it within a single byte (to ensure we get endianness right).
-+ * We can use memset for the rest of the bitmap as there are no other users.
-+ */
-+static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
-+{
-+	int i;
-+
-+	if (start_bit >= end_bit)
-+		return;
-+
-+	ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit);
-+	for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
-+		ext3_set_bit(i, bitmap);
-+	if (i < end_bit)
-+		memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
-+}
-+
-+/* Initializes an uninitialized inode bitmap */
-+unsigned ext3_init_inode_bitmap(struct super_block *sb,
-+				struct buffer_head *bh, int block_group,
-+				struct ext3_group_desc *gdp)
-+{
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+
-+	J_ASSERT_BH(bh, buffer_locked(bh));
-+
-+	/* If checksum is bad mark all blocks and inodes use to prevent
-+	 * allocation, essentially implementing a per-group read-only flag. */
-+	if (!ext3_group_desc_csum_verify(sbi, block_group, gdp)) {
-+		ext3_error(sb, __FUNCTION__, "Checksum bad for group %u\n",
-+			   block_group);
-+		gdp->bg_free_blocks_count = 0;
-+		gdp->bg_free_inodes_count = 0;
-+		gdp->bg_itable_unused = 0;
-+		memset(bh->b_data, 0xff, sb->s_blocksize);
-+		return 0;
-+	}
-+
-+	memset(bh->b_data, 0, (EXT3_INODES_PER_GROUP(sb) + 7) / 8);
-+	mark_bitmap_end(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb),
-+			bh->b_data);
-+
-+	return EXT3_INODES_PER_GROUP(sb);
-+}
- 
- /*
-  * Read the inode allocation bitmap for a given block_group, reading
-@@ -59,8 +106,19 @@ read_inode_bitmap(struct super_block * s
- 	desc = ext3_get_group_desc(sb, block_group, NULL);
- 	if (!desc)
- 		goto error_out;
--
--	bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+	if (desc->bg_flags & cpu_to_le16(EXT3_BG_INODE_UNINIT)) {
-+		bh = sb_getblk(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+		if (!buffer_uptodate(bh)) {
-+			lock_buffer(bh);
-+			if (!buffer_uptodate(bh)) {
-+				ext3_init_inode_bitmap(sb, bh,block_group,desc);
-+				set_buffer_uptodate(bh);
-+			}
-+			unlock_buffer(bh);
-+		}
-+	} else {
-+		bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
-+	}
- 	if (!bh)
- 		ext3_error(sb, "read_inode_bitmap",
- 			    "Cannot read inode bitmap - "
-@@ -169,6 +227,8 @@ void ext3_free_inode (handle_t *handle, 
- 			if (is_directory)
- 				gdp->bg_used_dirs_count = cpu_to_le16(
- 				  le16_to_cpu(gdp->bg_used_dirs_count) - 1);
-+			gdp->bg_checksum = ext3_group_desc_csum(sbi,block_group,
-+								gdp);
- 			spin_unlock(sb_bgl_lock(sbi, block_group));
- 			percpu_counter_inc(&sbi->s_freeinodes_counter);
- 			if (is_directory)
-@@ -453,7 +513,7 @@ struct inode *ext3_new_inode(handle_t *h
- 	struct ext3_sb_info *sbi;
- 	int err = 0;
- 	struct inode *ret;
--	int i;
-+	int i, free = 0;
- 
- 	/* Cannot create files in a deleted directory */
- 	if (!dir || !dir->i_nlink)
-@@ -566,11 +626,13 @@ repeat_in_this_group:
- 	goto out;
- 
- got:
--	ino += group * EXT3_INODES_PER_GROUP(sb) + 1;
--	if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
--		ext3_error (sb, "ext3_new_inode",
--			    "reserved inode or inode > inodes count - "
--			    "block_group = %d, inode=%lu", group, ino);
-+	ino++;
-+	if ((group == 0 && ino < EXT3_FIRST_INO(sb)) ||
-+	    ino > EXT3_INODES_PER_GROUP(sb)) {
-+		ext3_error(sb, __FUNCTION__,
-+			   "reserved inode or inode > inodes count - "
-+			   "block_group = %d, inode=%lu", group,
-+			   ino + group * EXT3_INODES_PER_GROUP(sb));
- 		err = -EIO;
- 		goto fail;
- 	}
-@@ -578,13 +640,65 @@ got:
- 	BUFFER_TRACE(bh2, "get_write_access");
- 	err = ext3_journal_get_write_access(handle, bh2);
- 	if (err) goto fail;
-+
-+	/* We may have to initialize the block bitmap if it isn't already */
-+	if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
-+	    gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		struct buffer_head *block_bh = read_block_bitmap(sb, group);
-+
-+		BUFFER_TRACE(block_bh, "get block bitmap access");
-+		err = ext3_journal_get_write_access(handle, block_bh);
-+		if (err) {
-+			brelse(block_bh);
-+			goto fail;
-+		}
-+
-+		free = 0;
-+		spin_lock(sb_bgl_lock(sbi, group));
-+		/* recheck and clear flag under lock if we still need to */
-+		if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+			gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
-+			free = ext3_free_blocks_after_init(sb, group, gdp);
-+			gdp->bg_free_blocks_count = cpu_to_le16(free);
-+		}
-+		spin_unlock(sb_bgl_lock(sbi, group));
-+
-+		/* Don't need to dirty bitmap block if we didn't change it */
-+		if (free) {
-+			BUFFER_TRACE(block_bh, "dirty block bitmap");
-+			err = ext3_journal_dirty_metadata(handle, block_bh);
-+		}
-+
-+		brelse(block_bh);
-+		if (err)
-+			goto fail;
-+	}
-+
- 	spin_lock(sb_bgl_lock(sbi, group));
-+	/* If we didn't allocate from within the initialized part of the inode
-+	 * table then we need to initialize up to this inode. */
-+	if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-+		if (gdp->bg_flags & cpu_to_le16(EXT3_BG_INODE_UNINIT)) {
-+			gdp->bg_flags &= cpu_to_le16(~EXT3_BG_INODE_UNINIT);
-+			free = EXT3_INODES_PER_GROUP(sb);
-+		} else {
-+			free = EXT3_INODES_PER_GROUP(sb) -
-+				le16_to_cpu(gdp->bg_itable_unused);
-+		}
-+
-+		if (ino > free) {
-+			gdp->bg_itable_unused =
-+				cpu_to_le16(EXT3_INODES_PER_GROUP(sb) - ino);
-+		}
-+	}
-+
- 	gdp->bg_free_inodes_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
- 	if (S_ISDIR(mode)) {
- 		gdp->bg_used_dirs_count =
- 			cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
- 	}
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, group));
- 	BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
- 	err = ext3_journal_dirty_metadata(handle, bh2);
-@@ -606,7 +720,7 @@ got:
- 		inode->i_gid = current->fsgid;
- 	inode->i_mode = mode;
- 
--	inode->i_ino = ino;
-+	inode->i_ino = ino + group * EXT3_INODES_PER_GROUP(sb);
- 	/* This is the optimal IO size (for stat), not the fs block size */
- 	inode->i_blksize = PAGE_SIZE;
- 	inode->i_blocks = 0;
-Index: linux-2.6.9-full/fs/ext3/mballoc.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/mballoc.c	2007-03-28 15:42:45.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/mballoc.c	2007-03-28 18:36:16.000000000 +0400
-@@ -36,6 +36,8 @@
- #include <linux/seq_file.h>
- #include <linux/version.h>
- 
-+#include "group.h"
-+
- /*
-  * MUSTDO:
-  *   - test ext3_ext_search_left() and ext3_ext_search_right()
-@@ -323,6 +325,7 @@ struct ext3_group_info {
- 	unsigned long	bb_state;
- 	unsigned long 	bb_tid;
- 	struct ext3_free_metadata *bb_md_cur;
-+	struct ext3_group_desc *bb_gdp;
- 	unsigned short	bb_first_free;
- 	unsigned short	bb_free;
- 	unsigned short	bb_fragments;
-@@ -928,10 +931,7 @@ static int ext3_mb_init_cache(struct pag
- 		if (first_group + i >= EXT3_SB(sb)->s_groups_count)
- 			break;
- 
--		err = -EIO;
--		desc = ext3_get_group_desc(sb, first_group + i, NULL);
--		if (desc == NULL)
--			goto out;
-+		desc = EXT3_GROUP_INFO(sb, first_group + i)->bb_gdp;
- 
- 		err = -ENOMEM;
- 		bh[i] = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap));
-@@ -946,7 +946,12 @@ static int ext3_mb_init_cache(struct pag
- 			unlock_buffer(bh[i]);
- 			continue;
- 		}
--
-+		if (desc->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+			ext3_init_block_bitmap(sb, bh[i], first_group + i,desc);
-+			set_buffer_uptodate(bh[i]);
-+			unlock_buffer(bh[i]);
-+			continue;
-+		}
- 		get_bh(bh[i]);
- 		bh[i]->b_end_io = end_buffer_read_sync;
- 		submit_bh(READ, bh[i]);
-@@ -1703,6 +1708,10 @@ static int ext3_mb_good_group(struct ext
- 	switch (cr) {
- 		case 0:
- 			BUG_ON(ac->ac_2order == 0);
-+			/* If this group is uninitialized, skip it initially */
-+			if (grp->bb_gdp->bg_flags &
-+			    cpu_to_le16(EXT3_BG_BLOCK_UNINIT))
-+				return 0;
- 			bits = ac->ac_sb->s_blocksize_bits + 1;
- 			for (i = ac->ac_2order; i <= bits; i++)
- 				if (grp->bb_counters[i] > 0)
-@@ -1796,7 +1805,9 @@ repeat:
- 			}
- 
- 			ac->ac_groups_scanned++;
--			if (cr == 0)
-+			if (cr == 0 || (e3b.bd_info->bb_gdp->bg_flags &
-+					cpu_to_le16(EXT3_BG_BLOCK_UNINIT) &&
-+					ac->ac_2order != 0))
- 				ext3_mb_simple_scan_group(ac, &e3b);
- 			else if (cr == 1 && ac->ac_g_ex.fe_len == sbi->s_stripe)
- 				ext3_mb_scan_aligned(ac, &e3b);
-@@ -2267,12 +2278,13 @@ int ext3_mb_init_backend(struct super_bl
- 			i--;
- 			goto err_freebuddy;
- 		}
-+		memset(meta_group_info[j], 0, len);
- 		desc = ext3_get_group_desc(sb, i, NULL);
-+		meta_group_info[j]->bb_gdp = desc;
- 		if (desc == NULL) {
- 			printk(KERN_ERR"EXT3-fs: can't read descriptor %u\n",i);
- 			goto err_freebuddy;
- 		}
--		memset(meta_group_info[j], 0, len);
- 		set_bit(EXT3_GROUP_INFO_NEED_INIT_BIT,
- 			&meta_group_info[j]->bb_state);
- 
-@@ -2936,9 +2948,17 @@ int ext3_mb_mark_diskspace_used(struct e
- 	mb_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len);
- 
- 	spin_lock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
-+	if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
-+		gdp->bg_free_blocks_count =
-+			cpu_to_le16(ext3_free_blocks_after_init(sb,
-+							    ac->ac_b_ex.fe_group,
-+							    gdp));
-+	}
- 	gdp->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)
- 				- ac->ac_b_ex.fe_len);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, - ac->ac_b_ex.fe_len);
- 
-@@ -4303,6 +4323,7 @@ do_more:
- 	spin_lock(sb_bgl_lock(sbi, block_group));
- 	gdp->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, block_group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, block_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
- 
-Index: linux-2.6.9-full/fs/ext3/balloc.c
-===================================================================
---- linux-2.6.9-full.orig/fs/ext3/balloc.c	2007-03-28 15:45:41.000000000 +0400
-+++ linux-2.6.9-full/fs/ext3/balloc.c	2007-03-28 18:36:16.000000000 +0400
-@@ -20,6 +20,7 @@
- #include <linux/quotaops.h>
- #include <linux/buffer_head.h>
- 
-+#include "group.h"
- /*
-  * balloc.c contains the blocks allocation and deallocation routines
-  */
-@@ -73,6 +74,75 @@ struct ext3_group_desc * ext3_get_group_
- 	return gdp + desc;
- }
- 
-+/* Initializes an uninitialized block bitmap if given, and returns the
-+ * number of blocks free in the group. */
-+unsigned ext3_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
-+				int block_group, struct ext3_group_desc *gdp)
-+{
-+	unsigned long start;
-+	int bit, bit_max;
-+	unsigned free_blocks;
-+	struct ext3_sb_info *sbi = EXT3_SB(sb);
-+
-+	if (bh) {
-+		J_ASSERT_BH(bh, buffer_locked(bh));
-+
-+		/* If checksum is bad mark all blocks use to prevent allocation,
-+		 * essentially implementing a per-group read-only flag. */
-+		if (!ext3_group_desc_csum_verify(sbi, block_group, gdp)) {
-+			ext3_error(sb, __FUNCTION__,
-+				   "Checksum bad for group %u\n", block_group);
-+			gdp->bg_free_blocks_count = 0;
-+			gdp->bg_free_inodes_count = 0;
-+			gdp->bg_itable_unused = 0;
-+			memset(bh->b_data, 0xff, sb->s_blocksize);
-+			return 0;
-+		}
-+		memset(bh->b_data, 0, sb->s_blocksize);
-+	}
-+
-+	/* Check for superblock and gdt backups in this group */
-+	bit_max = ext3_bg_has_super(sb, block_group);
-+
-+	if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
-+	    block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
-+			  sbi->s_desc_per_block) {
-+		if (bit_max) {
-+			bit_max += ext3_bg_num_gdb(sb, block_group);
-+			bit_max +=le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
-+		}
-+	} else { /* For META_BG_BLOCK_GROUPS */
-+		int group_rel = (block_group -
-+				 le32_to_cpu(sbi->s_es->s_first_meta_bg)) %
-+				EXT3_DESC_PER_BLOCK(sb);
-+		if (group_rel == 0 || group_rel == 1 ||
-+		    (group_rel == EXT3_DESC_PER_BLOCK(sb) - 1))
-+			bit_max += 1;
-+	}
-+
-+	/* Last and first groups are always initialized */
-+	free_blocks = EXT3_BLOCKS_PER_GROUP(sb) - bit_max;
-+
-+	if (bh) {
-+		for (bit = 0; bit < bit_max; bit++)
-+			ext3_set_bit(bit, bh->b_data);
-+
-+		start = block_group * EXT3_BLOCKS_PER_GROUP(sb) +
-+			le32_to_cpu(sbi->s_es->s_first_data_block);
-+
-+		/* Set bits for block and inode bitmaps, and inode table */
-+		ext3_set_bit(le32_to_cpu(gdp->bg_block_bitmap) - start,
-+			     bh->b_data);
-+		ext3_set_bit(le32_to_cpu(gdp->bg_inode_bitmap) - start,
-+			     bh->b_data);
-+		for (bit = le32_to_cpu(gdp->bg_inode_table) - start,
-+		     bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++)
-+			ext3_set_bit(bit, bh->b_data);
-+	}
-+
-+	return free_blocks - sbi->s_itb_per_group - 2;
-+}
-+
- /*
-  * Read the bitmap for a given block_group, reading into the specified 
-  * slot in the superblock's bitmap cache.
-@@ -88,7 +158,19 @@ read_block_bitmap(struct super_block *sb
- 	desc = ext3_get_group_desc (sb, block_group, NULL);
- 	if (!desc)
- 		goto error_out;
--	bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-+	if (desc->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT)) {
-+		bh = sb_getblk(sb, le32_to_cpu(desc->bg_block_bitmap));
-+		if (!buffer_uptodate(bh)) {
-+			lock_buffer(bh);
-+			if (!buffer_uptodate(bh)) {
-+				ext3_init_block_bitmap(sb, bh,block_group,desc);
-+				set_buffer_uptodate(bh);
-+			}
-+			unlock_buffer(bh);
-+		}
-+	} else {
-+		bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap));
-+	}
- 	if (!bh)
- 		ext3_error (sb, "read_block_bitmap",
- 			    "Cannot read block bitmap - "
-@@ -429,6 +511,7 @@ do_more:
- 	gdp->bg_free_blocks_count =
- 		cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) +
- 			*pdquot_freed_blocks);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, block_group, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, block_group));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, count);
- 
-@@ -1330,8 +1413,11 @@ allocated:
- 			ret_block, goal_hits, goal_attempts);
- 
- 	spin_lock(sb_bgl_lock(sbi, group_no));
-+	if (gdp->bg_flags & cpu_to_le16(EXT3_BG_BLOCK_UNINIT))
-+		gdp->bg_flags &= cpu_to_le16(~EXT3_BG_BLOCK_UNINIT);
- 	gdp->bg_free_blocks_count =
- 			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
-+	gdp->bg_checksum = ext3_group_desc_csum(sbi, group_no, gdp);
- 	spin_unlock(sb_bgl_lock(sbi, group_no));
- 	percpu_counter_mod(&sbi->s_freeblocks_counter, -1);
- 
diff --git a/lustre/kernel_patches/patches/ext3-wantedi-2.6.15.patch b/lustre/kernel_patches/patches/ext3-wantedi-2.6.15.patch
deleted file mode 100644
index 9ed150ea6a..0000000000
--- a/lustre/kernel_patches/patches/ext3-wantedi-2.6.15.patch
+++ /dev/null
@@ -1,174 +0,0 @@
- fs/ext3/ialloc.c        |   35 ++++++++++++++++++++++++++++++++++-
- fs/ext3/ioctl.c         |   25 +++++++++++++++++++++++++
- fs/ext3/namei.c         |   21 +++++++++++++++++----
- include/linux/dcache.h  |    5 +++++
- include/linux/ext3_fs.h |    5 ++++-
- 5 files changed, 85 insertions(+), 6 deletions(-)
-
-Index: linux-2.6.15/fs/ext3/ialloc.c
-===================================================================
---- linux-2.6.15.orig/fs/ext3/ialloc.c	2006-02-19 15:23:12.000000000 +0300
-+++ linux-2.6.15/fs/ext3/ialloc.c	2006-02-21 00:26:52.000000000 +0300
-@@ -420,7 +420,8 @@ static int find_group_other(struct super
-  * For other inodes, search forward from the parent directory's block
-  * group to find a free inode.
-  */
--struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode)
-+struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode,
-+				unsigned long goal)
- {
- 	struct super_block *sb;
- 	struct buffer_head *bitmap_bh = NULL;
-@@ -448,6 +449,38 @@ struct inode *ext3_new_inode(handle_t *h
- 
- 	sbi = EXT3_SB(sb);
- 	es = sbi->s_es;
-+	if (goal) {
-+		group = (goal - 1) / EXT3_INODES_PER_GROUP(sb);
-+		ino = (goal - 1) % EXT3_INODES_PER_GROUP(sb);
-+		gdp = ext3_get_group_desc(sb, group, &bh2);
-+
-+		err = -EIO;
-+		bitmap_bh = read_inode_bitmap (sb, group);
-+		if (!bitmap_bh)
-+			goto fail;
-+
-+		BUFFER_TRACE(bh, "get_write_access");
-+		err = ext3_journal_get_write_access(handle, bitmap_bh);
-+		if (err) goto fail;
-+
-+		if (ext3_set_bit_atomic(sb_bgl_lock(sbi, group),
-+					ino, bitmap_bh->b_data)) {
-+			printk(KERN_ERR "goal inode %lu unavailable\n", goal);
-+			/* Oh well, we tried. */
-+			goto continue_allocation;
-+		}
-+
-+		BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
-+		err = ext3_journal_dirty_metadata(handle, bitmap_bh);
-+		if (err) goto fail;
-+
-+		/* We've shortcircuited the allocation system successfully,
-+		 * now finish filling in the inode.
-+		 */
-+		goto got;
-+	}
-+
-+continue_allocation:
- 	if (S_ISDIR(mode)) {
- 		if (test_opt (sb, OLDALLOC))
- 			group = find_group_dir(sb, dir);
-Index: linux-2.6.15/fs/ext3/ioctl.c
-===================================================================
---- linux-2.6.15.orig/fs/ext3/ioctl.c	2005-11-11 08:33:12.000000000 +0300
-+++ linux-2.6.15/fs/ext3/ioctl.c	2006-02-21 00:26:52.000000000 +0300
-@@ -25,6 +25,31 @@ int ext3_ioctl (struct inode * inode, st
- 	ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
- 
- 	switch (cmd) {
-+	case EXT3_IOC_CREATE_INUM: {
-+		char name[32];
-+		struct dentry *dchild, *dparent;
-+		int rc = 0;
-+
-+		dparent = list_entry(inode->i_dentry.next, struct dentry,
-+				     d_alias);
-+		snprintf(name, sizeof name, "%lu", arg);
-+		dchild = lookup_one_len(name, dparent, strlen(name));
-+		if (dchild->d_inode) {
-+			printk(KERN_ERR "%*s/%lu already exists (ino %lu)\n",
-+			       dparent->d_name.len, dparent->d_name.name, arg,
-+			       dchild->d_inode->i_ino);
-+			rc = -EEXIST;
-+		} else {
-+			dchild->d_fsdata = (void *)arg;
-+			rc = vfs_create(inode, dchild, 0644, NULL);
-+			if (rc)
-+				printk(KERN_ERR "vfs_create: %d\n", rc);
-+			else if (dchild->d_inode->i_ino != arg)
-+				rc = -EEXIST;
-+		}
-+		dput(dchild);
-+		return rc;
-+	}
- 	case EXT3_IOC_GETFLAGS:
- 		flags = ei->i_flags & EXT3_FL_USER_VISIBLE;
- 		return put_user(flags, (int __user *) arg);
-Index: linux-2.6.15/fs/ext3/namei.c
-===================================================================
---- linux-2.6.15.orig/fs/ext3/namei.c	2006-02-19 15:23:12.000000000 +0300
-+++ linux-2.6.15/fs/ext3/namei.c	2006-02-21 00:28:17.000000000 +0300
-@@ -1631,6 +1631,16 @@ static int ext3_add_nondir(handle_t *han
- 	return err;
- }
- 
-+static struct inode * ext3_new_inode_wantedi(handle_t *handle, struct inode *dir,
-+						int mode, struct dentry *dentry)
-+{
-+	unsigned long inum = 0;
-+
-+	if (dentry->d_fsdata != NULL)
-+		inum = (unsigned long) dentry->d_fsdata;
-+	return ext3_new_inode(handle, dir, mode, inum);
-+}
-+
- /*
-  * By the time this is called, we already have created
-  * the directory cache entry for the new file, but it
-@@ -1656,7 +1666,7 @@ retry:
- 	if (IS_DIRSYNC(dir))
- 		handle->h_sync = 1;
- 
--	inode = ext3_new_inode (handle, dir, mode);
-+	inode = ext3_new_inode_wantedi (handle, dir, mode, dentry);
- 	err = PTR_ERR(inode);
- 	if (!IS_ERR(inode)) {
- 		inode->i_op = &ext3_file_inode_operations;
-@@ -1690,7 +1700,7 @@ retry:
- 	if (IS_DIRSYNC(dir))
- 		handle->h_sync = 1;
- 
--	inode = ext3_new_inode (handle, dir, mode);
-+	inode = ext3_new_inode_wantedi (handle, dir, mode, dentry);
- 	err = PTR_ERR(inode);
- 	if (!IS_ERR(inode)) {
- 		init_special_inode(inode, inode->i_mode, rdev);
-@@ -1726,7 +1736,7 @@ retry:
- 	if (IS_DIRSYNC(dir))
- 		handle->h_sync = 1;
- 
--	inode = ext3_new_inode (handle, dir, S_IFDIR | mode);
-+	inode = ext3_new_inode_wantedi (handle, dir, S_IFDIR | mode, dentry);
- 	err = PTR_ERR(inode);
- 	if (IS_ERR(inode))
- 		goto out_stop;
-@@ -2131,7 +2141,7 @@ retry:
- 	if (IS_DIRSYNC(dir))
- 		handle->h_sync = 1;
- 
--	inode = ext3_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
-+	inode = ext3_new_inode_wantedi (handle, dir, S_IFLNK|S_IRWXUGO, dentry);
- 	err = PTR_ERR(inode);
- 	if (IS_ERR(inode))
- 		goto out_stop;
-Index: linux-2.6.15/include/linux/ext3_fs.h
-===================================================================
---- linux-2.6.15.orig/include/linux/ext3_fs.h	2005-11-11 08:33:12.000000000 +0300
-+++ linux-2.6.15/include/linux/ext3_fs.h	2006-02-21 00:26:52.000000000 +0300
-@@ -762,7 +762,8 @@ extern int ext3fs_dirhash(const char *na
- 			  dx_hash_info *hinfo);
- 
- /* ialloc.c */
--extern struct inode * ext3_new_inode (handle_t *, struct inode *, int);
-+extern struct inode * ext3_new_inode (handle_t *, struct inode *, int,
-+				      unsigned long);
- extern void ext3_free_inode (handle_t *, struct inode *);
- extern struct inode * ext3_orphan_get (struct super_block *, unsigned long);
- extern unsigned long ext3_count_free_inodes (struct super_block *);
-@@ -844,4 +845,6 @@ extern struct inode_operations ext3_fast
- 
- #endif	/* __KERNEL__ */
- 
-+/* EXT3_IOC_CREATE_INUM at bottom of file (visible to kernel and user). */
-+#define EXT3_IOC_CREATE_INUM			_IOW('f', 5, long)
- #endif	/* _LINUX_EXT3_FS_H */
diff --git a/lustre/kernel_patches/patches/grab_cache_page_nowait_gfp-2.6-suse.patch b/lustre/kernel_patches/patches/grab_cache_page_nowait_gfp-2.6-suse.patch
deleted file mode 100644
index 6f781b46e7..0000000000
--- a/lustre/kernel_patches/patches/grab_cache_page_nowait_gfp-2.6-suse.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/mm/filemap.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/mm/filemap.c	2004-11-11 10:28:45.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/mm/filemap.c	2005-02-01 01:36:08.000000000 -0500
-@@ -773,8 +773,19 @@
- struct page *
- grab_cache_page_nowait(struct address_space *mapping, unsigned long index)
- {
-+	return grab_cache_page_nowait_gfp(mapping, index,
-+					  mapping_gfp_mask(mapping) & 
-+					  ~__GFP_FS);
-+}
-+
-+EXPORT_SYMBOL(grab_cache_page_nowait);
-+
-+struct page *
-+grab_cache_page_nowait_gfp(struct address_space *mapping,
-+			   unsigned long index,
-+			   unsigned int gfp_mask)
-+{
- 	struct page *page = find_get_page(mapping, index);
--	int gfp_mask;
- 
- 	if (page) {
- 		if (!TestSetPageLocked(page))
-@@ -782,7 +793,7 @@
- 		page_cache_release(page);
- 		return NULL;
- 	}
--	gfp_mask = mapping_gfp_mask(mapping) & ~__GFP_FS;
-+
- 	page = alloc_pages(gfp_mask, 0);
- 	if (page && add_to_page_cache_lru(page, mapping, index, gfp_mask)) {
- 		page_cache_release(page);
-@@ -791,7 +802,7 @@
- 	return page;
- }
- 
--EXPORT_SYMBOL(grab_cache_page_nowait);
-+EXPORT_SYMBOL(grab_cache_page_nowait_gfp);
- 
- /*
-  * This is a generic file read routine, and uses the
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/pagemap.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/linux/pagemap.h	2004-11-11 10:28:43.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/pagemap.h	2005-02-01 01:29:06.000000000 -0500
-@@ -92,6 +92,9 @@
- 
- extern struct page * grab_cache_page_nowait(struct address_space *mapping,
- 				unsigned long index);
-+extern struct page * grab_cache_page_nowait_gfp(struct address_space *mapping,
-+						unsigned long index,
-+						unsigned int gfp_mask);
- extern struct page * read_cache_page(struct address_space *mapping,
- 				unsigned long index, filler_t *filler,
- 				void *data);
diff --git a/lustre/kernel_patches/patches/jbd-stats-2.6.13.4.patch b/lustre/kernel_patches/patches/jbd-stats-2.6.13.4.patch
deleted file mode 100644
index 4db8dd3879..0000000000
--- a/lustre/kernel_patches/patches/jbd-stats-2.6.13.4.patch
+++ /dev/null
@@ -1,735 +0,0 @@
-Index: linux-2.6.13.4/include/linux/jbd.h
-===================================================================
---- linux-2.6.13.4.orig/include/linux/jbd.h	2005-10-10 22:54:29.000000000 +0400
-+++ linux-2.6.13.4/include/linux/jbd.h	2005-11-20 01:35:08.000000000 +0300
-@@ -394,6 +394,16 @@
- };
- 
- 
-+/*
-+ * Some stats for checkpoint phase
-+ */
-+struct transaction_chp_stats_s {
-+	unsigned long		cs_chp_time;
-+	unsigned long		cs_forced_to_close;
-+	unsigned long		cs_written;
-+	unsigned long		cs_dropped;
-+};
-+
- /* The transaction_t type is the guts of the journaling mechanism.  It
-  * tracks a compound transaction through its various states:
-  *
-@@ -523,6 +533,21 @@
- 	spinlock_t		t_handle_lock;
- 
- 	/*
-+	 * Longest time some handle had to wait for running transaction
-+	 */
-+	unsigned long		t_max_wait;
-+
-+	/*
-+	 * When transaction started
-+	 */
-+	unsigned long		t_start;
-+
-+	/*
-+	 * Checkpointing stats [j_checkpoint_sem]
-+	 */
-+	struct transaction_chp_stats_s t_chp_stats;
-+
-+	/*
- 	 * Number of outstanding updates running on this transaction
- 	 * [t_handle_lock]
- 	 */
-@@ -553,6 +578,57 @@
- 
- };
- 
-+struct transaction_run_stats_s {
-+	unsigned long		rs_wait;
-+	unsigned long		rs_running;
-+	unsigned long		rs_locked;
-+	unsigned long		rs_flushing;
-+	unsigned long		rs_logging;
-+
-+	unsigned long		rs_handle_count;
-+	unsigned long		rs_blocks;
-+	unsigned long		rs_blocks_logged;
-+};
-+
-+struct transaction_stats_s
-+{
-+	int 			ts_type;
-+	unsigned long		ts_tid;
-+	union {
-+		struct transaction_run_stats_s run;
-+		struct transaction_chp_stats_s chp;
-+	} u;
-+};
-+
-+#define JBD_STATS_RUN		1
-+#define JBD_STATS_CHECKPOINT	2
-+
-+#define ts_wait			u.run.rs_wait
-+#define ts_running		u.run.rs_running
-+#define ts_locked		u.run.rs_locked
-+#define ts_flushing		u.run.rs_flushing
-+#define ts_logging		u.run.rs_logging
-+#define ts_handle_count		u.run.rs_handle_count
-+#define ts_blocks		u.run.rs_blocks
-+#define ts_blocks_logged	u.run.rs_blocks_logged
-+
-+#define ts_chp_time		u.chp.cs_chp_time
-+#define ts_forced_to_close	u.chp.cs_forced_to_close
-+#define ts_written		u.chp.cs_written
-+#define ts_dropped		u.chp.cs_dropped
-+
-+#define CURRENT_MSECS		(jiffies_to_msecs(jiffies))
-+
-+static inline unsigned int
-+jbd_time_diff(unsigned int start, unsigned int end)
-+{
-+	if (unlikely(start > end))
-+		end = end + (~0UL - start);
-+	else
-+		end -= start;
-+	return end;
-+}
-+
- /**
-  * struct journal_s - The journal_s type is the concrete type associated with
-  *     journal_t.
-@@ -800,6 +876,16 @@
- 	int			j_wbufsize;
- 
- 	/*
-+	 *
-+	 */
-+	struct transaction_stats_s *j_history;
-+	int			j_history_max;
-+	int			j_history_cur;
-+	spinlock_t		j_history_lock;
-+	struct proc_dir_entry	*j_proc_entry;
-+	struct transaction_stats_s j_stats;
-+	
-+	/*
- 	 * An opaque pointer to fs-private information.  ext3 puts its
- 	 * superblock pointer here
- 	 */
-Index: linux-2.6.13.4/fs/jbd/transaction.c
-===================================================================
---- linux-2.6.13.4.orig/fs/jbd/transaction.c	2005-10-10 22:54:29.000000000 +0400
-+++ linux-2.6.13.4/fs/jbd/transaction.c	2005-11-20 01:31:23.000000000 +0300
-@@ -58,6 +58,8 @@
- 
- 	J_ASSERT(journal->j_running_transaction == NULL);
- 	journal->j_running_transaction = transaction;
-+	transaction->t_max_wait = 0;
-+	transaction->t_start = CURRENT_MSECS;
- 
- 	return transaction;
- }
-@@ -84,6 +86,7 @@
- 	int nblocks = handle->h_buffer_credits;
- 	transaction_t *new_transaction = NULL;
- 	int ret = 0;
-+	unsigned long ts = CURRENT_MSECS;
- 
- 	if (nblocks > journal->j_max_transaction_buffers) {
- 		printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
-@@ -217,6 +220,12 @@
- 	/* OK, account for the buffers that this operation expects to
- 	 * use and add the handle to the running transaction. */
- 
-+	if (time_after(transaction->t_start, ts)) {
-+		ts = jbd_time_diff(ts, transaction->t_start);
-+		if (ts > transaction->t_max_wait)
-+			transaction->t_max_wait= ts;
-+	}
-+
- 	handle->h_transaction = transaction;
- 	transaction->t_outstanding_credits += nblocks;
- 	transaction->t_updates++;
-Index: linux-2.6.13.4/fs/jbd/journal.c
-===================================================================
---- linux-2.6.13.4.orig/fs/jbd/journal.c	2005-10-10 22:54:29.000000000 +0400
-+++ linux-2.6.13.4/fs/jbd/journal.c	2005-11-20 02:07:44.000000000 +0300
-@@ -36,6 +36,7 @@
- #include <asm/uaccess.h>
- #include <asm/page.h>
- #include <linux/proc_fs.h>
-+#include <linux/seq_file.h>
- 
- EXPORT_SYMBOL(journal_start);
- EXPORT_SYMBOL(journal_restart);
-@@ -646,6 +647,300 @@
- 	return journal_add_journal_head(bh);
- }
- 
-+struct jbd_stats_proc_session {
-+	journal_t *journal;
-+	struct transaction_stats_s *stats;
-+	int start;
-+	int max;
-+};
-+
-+static void *jbd_history_skip_empty(struct jbd_stats_proc_session *s,
-+					struct transaction_stats_s *ts,
-+					int first)
-+{
-+	if (ts == s->stats + s->max)
-+		ts = s->stats;
-+	if (!first && ts == s->stats + s->start)
-+		return NULL;
-+	while (ts->ts_type == 0) {
-+		ts++;
-+		if (ts == s->stats + s->max)
-+			ts = s->stats;
-+		if (ts == s->stats + s->start)
-+			return NULL;
-+	}
-+	return ts;
-+
-+}
-+
-+static void *jbd_seq_history_start(struct seq_file *seq, loff_t *pos)
-+{
-+	struct jbd_stats_proc_session *s = seq->private;
-+	struct transaction_stats_s *ts;
-+	int l = *pos;
-+
-+	if (l == 0)
-+		return SEQ_START_TOKEN;
-+	ts = jbd_history_skip_empty(s, s->stats + s->start, 1);
-+	if (!ts)
-+		return NULL;
-+	while (--l && (ts = jbd_history_skip_empty(s, ++ts, 0)) != NULL);
-+	return ts;
-+}
-+
-+static void *jbd_seq_history_next(struct seq_file *seq, void *v, loff_t *pos)
-+{
-+	struct jbd_stats_proc_session *s = seq->private;
-+	struct transaction_stats_s *ts = v;
-+
-+	++*pos;
-+	if (v == SEQ_START_TOKEN)
-+		return jbd_history_skip_empty(s, s->stats + s->start, 1);
-+	else
-+		return jbd_history_skip_empty(s, ++ts, 0);
-+}
-+
-+static int jbd_seq_history_show(struct seq_file *seq, void *v)
-+{
-+	struct transaction_stats_s *ts = v;
-+	if (v == SEQ_START_TOKEN) {
-+		seq_printf(seq, "%-4s %-5s %-5s %-5s %-5s %-5s %-5s %-6s %-5s "
-+				"%-5s %-5s %-5s %-5s %-5s\n", "R/C", "tid",
-+				"wait", "run", "lock", "flush", "log", "hndls",
-+				"block", "inlog", "ctime", "write", "drop",
-+				"close");
-+		return 0;
-+	}
-+	if (ts->ts_type == JBD_STATS_RUN)
-+		seq_printf(seq, "%-4s %-5lu %-5lu %-5lu %-5lu %-5lu %-5lu "
-+				"%-6lu %-5lu %-5lu\n", "R", ts->ts_tid,
-+				ts->ts_wait, ts->ts_running, ts->ts_locked,
-+				ts->ts_flushing, ts->ts_logging,
-+				ts->ts_handle_count, ts->ts_blocks,
-+				ts->ts_blocks_logged);
-+	else if (ts->ts_type == JBD_STATS_CHECKPOINT)
-+		seq_printf(seq, "%-4s %-5lu %48s %-5lu %-5lu %-5lu %-5lu\n",
-+				"C", ts->ts_tid, " ", ts->ts_chp_time,
-+				ts->ts_written, ts->ts_dropped,
-+				ts->ts_forced_to_close);
-+	else
-+		J_ASSERT(0);
-+	return 0;
-+}
-+
-+static void jbd_seq_history_stop(struct seq_file *seq, void *v)
-+{
-+}
-+
-+static struct seq_operations jbd_seq_history_ops = {
-+	.start  = jbd_seq_history_start,
-+	.next   = jbd_seq_history_next,
-+	.stop   = jbd_seq_history_stop,
-+	.show   = jbd_seq_history_show,
-+};
-+
-+static int jbd_seq_history_open(struct inode *inode, struct file *file)
-+{
-+	journal_t *journal = PDE(inode)->data;
-+	struct jbd_stats_proc_session *s;
-+	int rc, size;
-+
-+	s = kmalloc(sizeof(*s), GFP_KERNEL);
-+	if (s == NULL)
-+		return -EIO;
-+	size = sizeof(struct transaction_stats_s) * journal->j_history_max;
-+	s->stats = kmalloc(size, GFP_KERNEL);
-+	if (s == NULL) {
-+		kfree(s);
-+		return -EIO;
-+	}
-+	spin_lock(&journal->j_history_lock);
-+	memcpy(s->stats, journal->j_history, size);
-+	s->max = journal->j_history_max;
-+	s->start = journal->j_history_cur % s->max;
-+	spin_unlock(&journal->j_history_lock);
-+	
-+	rc = seq_open(file, &jbd_seq_history_ops);
-+	if (rc == 0) {
-+		struct seq_file *m = (struct seq_file *)file->private_data;
-+		m->private = s;
-+	} else {
-+		kfree(s->stats);
-+		kfree(s);
-+	}
-+	return rc;
-+
-+}
-+
-+static int jbd_seq_history_release(struct inode *inode, struct file *file)
-+{
-+	struct seq_file *seq = (struct seq_file *)file->private_data;
-+	struct jbd_stats_proc_session *s = seq->private;
-+	kfree(s->stats);
-+	kfree(s);
-+	return seq_release(inode, file);
-+}
-+
-+static struct file_operations jbd_seq_history_fops = {
-+	.owner		= THIS_MODULE,
-+	.open           = jbd_seq_history_open,
-+	.read           = seq_read,
-+	.llseek         = seq_lseek,
-+	.release        = jbd_seq_history_release,
-+};
-+
-+static void *jbd_seq_info_start(struct seq_file *seq, loff_t *pos)
-+{
-+	return *pos ? NULL : SEQ_START_TOKEN;
-+}
-+
-+static void *jbd_seq_info_next(struct seq_file *seq, void *v, loff_t *pos)
-+{
-+	return NULL;
-+}
-+
-+static int jbd_seq_info_show(struct seq_file *seq, void *v)
-+{
-+	struct jbd_stats_proc_session *s = seq->private;
-+	if (v != SEQ_START_TOKEN)
-+		return 0;
-+	seq_printf(seq, "%lu transaction, each upto %u blocks\n",
-+			s->stats->ts_tid,
-+			s->journal->j_max_transaction_buffers);
-+	if (s->stats->ts_tid == 0)
-+		return 0;
-+	seq_printf(seq, "average: \n  %lums waiting for transaction\n",
-+			s->stats->ts_wait / s->stats->ts_tid);
-+	seq_printf(seq, "  %lums running transaction\n",
-+			s->stats->ts_running / s->stats->ts_tid);
-+	seq_printf(seq, "  %lums transaction was being locked\n",
-+			s->stats->ts_locked / s->stats->ts_tid);
-+	seq_printf(seq, "  %lums flushing data (in ordered mode)\n",
-+			s->stats->ts_flushing / s->stats->ts_tid);
-+	seq_printf(seq, "  %lums logging transaction\n",
-+			s->stats->ts_logging / s->stats->ts_tid);
-+	seq_printf(seq, "  %lu handles per transaction\n",
-+			s->stats->ts_handle_count / s->stats->ts_tid);
-+	seq_printf(seq, "  %lu blocks per transaction\n",
-+			s->stats->ts_blocks / s->stats->ts_tid);
-+	seq_printf(seq, "  %lu logged blocks per transaction\n",
-+			s->stats->ts_blocks_logged / s->stats->ts_tid);
-+	return 0;
-+}
-+
-+static void jbd_seq_info_stop(struct seq_file *seq, void *v)
-+{
-+}
-+
-+static struct seq_operations jbd_seq_info_ops = {
-+	.start  = jbd_seq_info_start,
-+	.next   = jbd_seq_info_next,
-+	.stop   = jbd_seq_info_stop,
-+	.show   = jbd_seq_info_show,
-+};
-+
-+static int jbd_seq_info_open(struct inode *inode, struct file *file)
-+{
-+	journal_t *journal = PDE(inode)->data;
-+	struct jbd_stats_proc_session *s;
-+	int rc, size;
-+
-+	s = kmalloc(sizeof(*s), GFP_KERNEL);
-+	if (s == NULL)
-+		return -EIO;
-+	size = sizeof(struct transaction_stats_s);
-+	s->stats = kmalloc(size, GFP_KERNEL);
-+	if (s == NULL) {
-+		kfree(s);
-+		return -EIO;
-+	}
-+	spin_lock(&journal->j_history_lock);
-+	memcpy(s->stats, &journal->j_stats, size);
-+	s->journal = journal;
-+	spin_unlock(&journal->j_history_lock);
-+	
-+	rc = seq_open(file, &jbd_seq_info_ops);
-+	if (rc == 0) {
-+		struct seq_file *m = (struct seq_file *)file->private_data;
-+		m->private = s;
-+	} else {
-+		kfree(s->stats);
-+		kfree(s);
-+	}
-+	return rc;
-+
-+}
-+
-+static int jbd_seq_info_release(struct inode *inode, struct file *file)
-+{
-+	struct seq_file *seq = (struct seq_file *)file->private_data;
-+	struct jbd_stats_proc_session *s = seq->private;
-+	kfree(s->stats);
-+	kfree(s);
-+	return seq_release(inode, file);
-+}
-+
-+static struct file_operations jbd_seq_info_fops = {
-+	.owner		= THIS_MODULE,
-+	.open           = jbd_seq_info_open,
-+	.read           = seq_read,
-+	.llseek         = seq_lseek,
-+	.release        = jbd_seq_info_release,
-+};
-+
-+static struct proc_dir_entry *proc_jbd_stats = NULL;
-+
-+static void jbd_stats_proc_init(journal_t *journal)
-+{
-+	char name[64];
-+
-+	snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
-+	journal->j_proc_entry = proc_mkdir(name, proc_jbd_stats);
-+	if (journal->j_proc_entry) {
-+		struct proc_dir_entry *p;
-+		p = create_proc_entry("history", S_IRUGO,
-+				journal->j_proc_entry);
-+		if (p) {
-+			p->proc_fops = &jbd_seq_history_fops;
-+			p->data = journal;
-+			p = create_proc_entry("info", S_IRUGO,
-+						journal->j_proc_entry);
-+			if (p) {
-+				p->proc_fops = &jbd_seq_info_fops;
-+				p->data = journal;
-+			}
-+		}
-+	}
-+}
-+
-+static void jbd_stats_proc_exit(journal_t *journal)
-+{
-+	char name[64];
-+
-+	snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
-+	remove_proc_entry("info", journal->j_proc_entry);
-+	remove_proc_entry("history", journal->j_proc_entry);
-+	remove_proc_entry(name, proc_jbd_stats);
-+}
-+
-+static void journal_init_stats(journal_t *journal)
-+{
-+	int size;
-+
-+	if (proc_jbd_stats == NULL)
-+		return;
-+
-+	journal->j_history_max = 100;
-+	size = sizeof(struct transaction_stats_s) * journal->j_history_max;
-+	journal->j_history = kmalloc(size, GFP_KERNEL);
-+	if (journal->j_history == NULL) {
-+		journal->j_history_max = 0;
-+		return;
-+	}
-+	memset(journal->j_history, 0, size);
-+	spin_lock_init(&journal->j_history_lock);
-+}
-+
- /*
-  * Management for journal control blocks: functions to create and
-  * destroy journal_t structures, and to initialise and read existing
-@@ -688,6 +983,9 @@
- 		kfree(journal);
- 		goto fail;
- 	}
-+	
-+	journal_init_stats(journal);
-+
- 	return journal;
- fail:
- 	return NULL;
-@@ -731,6 +1029,7 @@
- 	journal->j_blk_offset = start;
- 	journal->j_maxlen = len;
- 	journal->j_blocksize = blocksize;
-+	jbd_stats_proc_init(journal);
- 
- 	bh = __getblk(journal->j_dev, start, journal->j_blocksize);
- 	J_ASSERT(bh != NULL);
-@@ -780,6 +1079,7 @@
- 
- 	journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
- 	journal->j_blocksize = inode->i_sb->s_blocksize;
-+	jbd_stats_proc_init(journal);
- 
- 	/* journal descriptor can store up to n blocks -bzzz */
- 	n = journal->j_blocksize / sizeof(journal_block_tag_t);
-@@ -1161,6 +1461,8 @@
- 		brelse(journal->j_sb_buffer);
- 	}
- 
-+	if (journal->j_proc_entry)
-+		jbd_stats_proc_exit(journal);
- 	if (journal->j_inode)
- 		iput(journal->j_inode);
- 	if (journal->j_revoke)
-@@ -1929,6 +2231,28 @@
- 
- #endif
- 
-+#if defined(CONFIG_PROC_FS)
-+
-+#define JBD_STATS_PROC_NAME "fs/jbd"
-+
-+static void __init create_jbd_stats_proc_entry(void)
-+{
-+	proc_jbd_stats = proc_mkdir(JBD_STATS_PROC_NAME, NULL);
-+}
-+
-+static void __exit remove_jbd_stats_proc_entry(void)
-+{
-+	if (proc_jbd_stats)
-+		remove_proc_entry(JBD_STATS_PROC_NAME, NULL);
-+}
-+
-+#else
-+
-+#define create_jbd_stats_proc_entry() do {} while (0)
-+#define remove_jbd_stats_proc_entry() do {} while (0)
-+
-+#endif
-+
- kmem_cache_t *jbd_handle_cache;
- 
- static int __init journal_init_handle_cache(void)
-@@ -1983,6 +2307,7 @@
- 	if (ret != 0)
- 		journal_destroy_caches();
- 	create_jbd_proc_entry();
-+	create_jbd_stats_proc_entry();
- 	return ret;
- }
- 
-@@ -1994,6 +2319,7 @@
- 		printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
- #endif
- 	remove_jbd_proc_entry();
-+	remove_jbd_stats_proc_entry();
- 	journal_destroy_caches();
- }
- 
-Index: linux-2.6.13.4/fs/jbd/checkpoint.c
-===================================================================
---- linux-2.6.13.4.orig/fs/jbd/checkpoint.c	2005-11-19 22:46:03.000000000 +0300
-+++ linux-2.6.13.4/fs/jbd/checkpoint.c	2005-11-20 02:24:09.000000000 +0300
-@@ -166,6 +166,7 @@
- 			transaction_t *t = jh->b_transaction;
- 			tid_t tid = t->t_tid;
- 
-+			transaction->t_chp_stats.cs_forced_to_close++;
- 			spin_unlock(&journal->j_list_lock);
- 			jbd_unlock_bh_state(bh);
- 			log_start_commit(journal, tid);
-@@ -226,7 +227,7 @@
-  */
- static int __flush_buffer(journal_t *journal, struct journal_head *jh,
- 			struct buffer_head **bhs, int *batch_count,
--			int *drop_count)
-+			int *drop_count, transaction_t *transaction)
- {
- 	struct buffer_head *bh = jh2bh(jh);
- 	int ret = 0;
-@@ -247,6 +248,7 @@
- 		set_buffer_jwrite(bh);
- 		bhs[*batch_count] = bh;
- 		jbd_unlock_bh_state(bh);
-+		transaction->t_chp_stats.cs_written++;
- 		(*batch_count)++;
- 		if (*batch_count == NR_BATCH) {
- 			__flush_batch(journal, bhs, batch_count);
-@@ -315,6 +317,8 @@
- 		tid_t this_tid;
- 
- 		transaction = journal->j_checkpoint_transactions;
-+		if (transaction->t_chp_stats.cs_chp_time == 0)
-+			transaction->t_chp_stats.cs_chp_time = CURRENT_MSECS;
- 		this_tid = transaction->t_tid;
- 		jh = transaction->t_checkpoint_list;
- 		last_jh = jh->b_cpprev;
-@@ -331,7 +335,8 @@
- 				retry = 1;
- 				break;
- 			}
--			retry = __flush_buffer(journal, jh, bhs, &batch_count, &drop_count);
-+			retry = __flush_buffer(journal, jh, bhs, &batch_count,
-+						&drop_count, transaction);
- 			if (cond_resched_lock(&journal->j_list_lock)) {
- 				retry = 1;
- 				break;
-@@ -609,6 +614,8 @@
- 
- void __journal_drop_transaction(journal_t *journal, transaction_t *transaction)
- {
-+	struct transaction_stats_s stats;
-+
- 	assert_spin_locked(&journal->j_list_lock);
- 	if (transaction->t_cpnext) {
- 		transaction->t_cpnext->t_cpprev = transaction->t_cpprev;
-@@ -633,5 +640,25 @@
- 	J_ASSERT(journal->j_running_transaction != transaction);
- 
- 	jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
-+
-+	/*
-+	 * File the transaction for history
-+	 */
-+	if (transaction->t_chp_stats.cs_written != 0 ||
-+			transaction->t_chp_stats.cs_chp_time != 0) {
-+		stats.ts_type = JBD_STATS_CHECKPOINT;
-+		stats.ts_tid = transaction->t_tid;
-+		stats.u.chp = transaction->t_chp_stats;
-+		if (stats.ts_chp_time)
-+			stats.ts_chp_time = 
-+				jbd_time_diff(stats.ts_chp_time, CURRENT_MSECS);
-+		spin_lock(&journal->j_history_lock);
-+		memcpy(journal->j_history + journal->j_history_cur, &stats,
-+				sizeof(stats));
-+		if (++journal->j_history_cur == journal->j_history_max)
-+			journal->j_history_cur = 0;
-+		spin_unlock(&journal->j_history_lock);
-+	}
-+
- 	kfree(transaction);
- }
-Index: linux-2.6.13.4/fs/jbd/commit.c
-===================================================================
---- linux-2.6.13.4.orig/fs/jbd/commit.c	2005-10-10 22:54:29.000000000 +0400
-+++ linux-2.6.13.4/fs/jbd/commit.c	2005-11-20 00:54:10.000000000 +0300
-@@ -21,6 +21,7 @@
- #include <linux/mm.h>
- #include <linux/pagemap.h>
- #include <linux/smp_lock.h>
-+#include <linux/jiffies.h>
- 
- /*
-  * Default IO end handler for temporary BJ_IO buffer_heads.
-@@ -168,6 +169,7 @@
-  */
- void journal_commit_transaction(journal_t *journal)
- {
-+	struct transaction_stats_s stats;
- 	transaction_t *commit_transaction;
- 	struct journal_head *jh, *new_jh, *descriptor;
- 	struct buffer_head **wbuf = journal->j_wbuf;
-@@ -214,6 +216,11 @@
- 	spin_lock(&journal->j_state_lock);
- 	commit_transaction->t_state = T_LOCKED;
- 
-+	stats.ts_wait = commit_transaction->t_max_wait;
-+	stats.ts_locked = CURRENT_MSECS;
-+	stats.ts_running = jbd_time_diff(commit_transaction->t_start,
-+						stats.ts_locked);
-+	
- 	spin_lock(&commit_transaction->t_handle_lock);
- 	while (commit_transaction->t_updates) {
- 		DEFINE_WAIT(wait);
-@@ -286,6 +293,9 @@
- 	 */
- 	journal_switch_revoke_table(journal);
- 
-+	stats.ts_flushing = CURRENT_MSECS;
-+	stats.ts_locked = jbd_time_diff(stats.ts_locked, stats.ts_flushing);
-+
- 	commit_transaction->t_state = T_FLUSH;
- 	journal->j_committing_transaction = commit_transaction;
- 	journal->j_running_transaction = NULL;
-@@ -444,6 +454,11 @@
- 	 */
- 	commit_transaction->t_state = T_COMMIT;
- 
-+	stats.ts_logging = CURRENT_MSECS;
-+	stats.ts_flushing = jbd_time_diff(stats.ts_flushing, stats.ts_logging);
-+	stats.ts_blocks = commit_transaction->t_outstanding_credits;
-+	stats.ts_blocks_logged = 0;
-+
- 	descriptor = NULL;
- 	bufs = 0;
- 	while (commit_transaction->t_buffers) {
-@@ -592,6 +607,7 @@
- 				submit_bh(WRITE, bh);
- 			}
- 			cond_resched();
-+			stats.ts_blocks_logged += bufs;
- 
- 			/* Force a new descriptor to be generated next
-                            time round the loop. */
-@@ -756,6 +772,7 @@
- 		cp_transaction = jh->b_cp_transaction;
- 		if (cp_transaction) {
- 			JBUFFER_TRACE(jh, "remove from old cp transaction");
-+			cp_transaction->t_chp_stats.cs_dropped++;
- 			__journal_remove_checkpoint(jh);
- 		}
- 
-@@ -803,6 +820,36 @@
- 
- 	J_ASSERT(commit_transaction->t_state == T_COMMIT);
- 
-+	commit_transaction->t_start = CURRENT_MSECS;
-+	stats.ts_logging = jbd_time_diff(stats.ts_logging,
-+						commit_transaction->t_start);
-+
-+	/*
-+	 * File the transaction for history
-+	 */
-+	stats.ts_type = JBD_STATS_RUN;
-+	stats.ts_tid = commit_transaction->t_tid;
-+	stats.ts_handle_count = commit_transaction->t_handle_count;
-+	spin_lock(&journal->j_history_lock);
-+	memcpy(journal->j_history + journal->j_history_cur, &stats,
-+			sizeof(stats));
-+	if (++journal->j_history_cur == journal->j_history_max)
-+		journal->j_history_cur = 0;
-+
-+	/*
-+	 * Calculate overall stats
-+	 */
-+	journal->j_stats.ts_tid++;
-+	journal->j_stats.ts_wait += stats.ts_wait;
-+	journal->j_stats.ts_running += stats.ts_running;
-+	journal->j_stats.ts_locked += stats.ts_locked;
-+	journal->j_stats.ts_flushing += stats.ts_flushing;
-+	journal->j_stats.ts_logging += stats.ts_logging;
-+	journal->j_stats.ts_handle_count += stats.ts_handle_count;
-+	journal->j_stats.ts_blocks += stats.ts_blocks;
-+	journal->j_stats.ts_blocks_logged += stats.ts_blocks_logged;
-+	spin_unlock(&journal->j_history_lock);
-+
- 	/*
- 	 * This is a bit sleazy.  We borrow j_list_lock to protect
- 	 * journal->j_committing_transaction in __journal_remove_checkpoint.
diff --git a/lustre/kernel_patches/patches/kexec-2.6-suse-lnxi.patch b/lustre/kernel_patches/patches/kexec-2.6-suse-lnxi.patch
deleted file mode 100644
index a84f43dbd5..0000000000
--- a/lustre/kernel_patches/patches/kexec-2.6-suse-lnxi.patch
+++ /dev/null
@@ -1,1603 +0,0 @@
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/MAINTAINERS
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/MAINTAINERS	2004-11-18 20:59:11.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/MAINTAINERS	2004-11-18 23:25:15.000000000 -0500
-@@ -1199,6 +1199,17 @@
- W:	http://www.cse.unsw.edu.au/~neilb/patches/linux-devel/
- S:	Maintained
- 
-+KEXEC
-+P:	Eric Biederman
-+P:	Randy Dunlap
-+M:	ebiederm@xmission.com
-+M:	rddunlap@osdl.org
-+W:	http://www.xmission.com/~ebiederm/files/kexec/
-+W:	http://developer.osdl.org/rddunlap/kexec/
-+L:	linux-kernel@vger.kernel.org
-+L:	fastboot@osdl.org
-+S:	Maintained
-+
- LANMEDIA WAN CARD DRIVER
- P:	Andrew Stanley-Jones
- M:	asj@lanmedia.com
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/Kconfig
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/Kconfig	2004-11-18 20:59:11.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/Kconfig	2004-11-18 23:25:15.000000000 -0500
-@@ -411,6 +411,23 @@
- 	depends on IA32_EMULATION
- 	default y
- 
-+config KEXEC
-+	bool "kexec system call (EXPERIMENTAL)"
-+	depends on EXPERIMENTAL
-+	help
-+	  kexec is a system call that implements the ability to shutdown your
-+	  current kernel, and to start another kernel.  It is like a reboot
-+	  but it is indepedent of the system firmware.   And like a reboot
-+	  you can start any kernel with it, not just Linux.
-+
-+	  The name comes from the similiarity to the exec system call.
-+
-+	  It is an ongoing process to be certain the hardware in a machine
-+	  is properly shutdown, so do not be surprised if this code does not
-+	  initially work for you.  It may help to enable device hotplugging
-+	  support.  As of this writing the exact hardware interface is
-+	  strongly in flux, so no good recommendation can be made.
-+
- endmenu
- 
- source drivers/Kconfig
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/Makefile
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/Makefile	2004-11-11 10:28:46.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/Makefile	2004-11-18 23:26:29.000000000 -0500
-@@ -19,6 +19,7 @@
- obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o  nmi.o
- obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o mpparse.o \
- 		genapic.o genapic_cluster.o genapic_flat.o
-+obj-$(CONFIG_KEXEC)		+= machine_kexec.o relocate_kernel.o
- obj-$(CONFIG_PM)		+= suspend.o
- obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend_asm.o
- obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/apic.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/apic.c	2004-11-11 10:28:46.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/apic.c	2004-11-18 23:25:15.000000000 -0500
-@@ -143,6 +143,36 @@
- 		outb(0x70, 0x22);
- 		outb(0x00, 0x23);
- 	}
-+	else {
-+		/* Go back to Virtual Wire compatibility mode */
-+		unsigned long value;
-+
-+		/* For the spurious interrupt use vector F, and enable it */
-+		value = apic_read(APIC_SPIV);
-+		value &= ~APIC_VECTOR_MASK;
-+		value |= APIC_SPIV_APIC_ENABLED;
-+		value |= 0xf;
-+		apic_write_around(APIC_SPIV, value);
-+
-+		/* For LVT0 make it edge triggered, active high, external and enabled */
-+		value = apic_read(APIC_LVT0);
-+		value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
-+			APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
-+			APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
-+		value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
-+		value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXINT);
-+		apic_write_around(APIC_LVT0, value);
-+
-+		/* For LVT1 make it edge triggered, active high, nmi and enabled */
-+		value = apic_read(APIC_LVT1);
-+		value &= ~(
-+			APIC_MODE_MASK | APIC_SEND_PENDING |
-+			APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
-+			APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
-+		value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
-+		value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
-+		apic_write_around(APIC_LVT1, value);
-+	}
- }
- 
- void disable_local_APIC(void)
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/e820.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/e820.c	2004-04-03 22:36:53.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/e820.c	2004-11-18 23:25:15.000000000 -0500
-@@ -185,8 +185,6 @@
- 	int i;
- 	for (i = 0; i < e820.nr_map; i++) {
- 		struct resource *res;
--		if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
--			continue;
- 		res = alloc_bootmem_low(sizeof(struct resource));
- 		switch (e820.map[i].type) {
- 		case E820_RAM:	res->name = "System RAM"; break;
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/i8259.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/i8259.c	2004-11-18 20:59:11.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/i8259.c	2004-11-18 23:25:15.000000000 -0500
-@@ -318,6 +318,44 @@
- 	}
- }
- 
-+static int i8259A_resume(struct sys_device *dev)
-+{
-+	init_8259A(0);
-+	return 0;
-+}
-+
-+static int i8259A_shutdown(struct sys_device *dev)
-+{
-+	/* Put the i8259A into a quiescent state that
-+	 * the kernel initialization code can get it
-+	 * out of.
-+	 */
-+	outb(0xff, 0x21);	/* mask all of 8259A-1 */
-+	outb(0xff, 0xA1);	/* mask all of 8259A-1 */
-+	return 0;
-+}
-+
-+static struct sysdev_class i8259_sysdev_class = {
-+	set_kset_name("i8259"),
-+	.resume = i8259A_resume,
-+	.shutdown = i8259A_shutdown,
-+};
-+
-+static struct sys_device device_i8259A = {
-+	.id	= 0,
-+	.cls	= &i8259_sysdev_class,
-+};
-+
-+static int __init i8259A_init_sysfs(void)
-+{
-+	int error = sysdev_class_register(&i8259_sysdev_class);
-+	if (!error)
-+		error = sysdev_register(&device_i8259A);
-+	return error;
-+}
-+
-+device_initcall(i8259A_init_sysfs);
-+
- void __init init_8259A(int auto_eoi)
- {
- 	unsigned long flags;
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/io_apic.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/io_apic.c	2004-11-11 10:28:46.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/io_apic.c	2004-11-18 23:25:15.000000000 -0500
-@@ -328,7 +328,7 @@
- /*
-  * Find the pin to which IRQ[irq] (ISA) is connected
-  */
--static int __init find_isa_irq_pin(int irq, int type)
-+static int find_isa_irq_pin(int irq, int type)
- {
- 	int i;
- 
-@@ -1112,11 +1112,43 @@
-  */
- void disable_IO_APIC(void)
- {
-+	int pin;
- 	/*
- 	 * Clear the IO-APIC before rebooting:
- 	 */
- 	clear_IO_APIC();
- 
-+	/*
-+	 * If the i82559 is routed through an IOAPIC
-+	 * Put that IOAPIC in virtual wire mode
-+	 * so legacy interrups can be delivered.
-+	 */
-+	pin = find_isa_irq_pin(0, mp_ExtINT);
-+	if (pin != -1) {
-+		struct IO_APIC_route_entry entry;
-+		unsigned long flags;
-+
-+		memset(&entry, 0, sizeof(entry));
-+		entry.mask            = 0; /* Enabled */
-+		entry.trigger         = 0; /* Edge */
-+		entry.irr             = 0;
-+		entry.polarity        = 0; /* High */
-+		entry.delivery_status = 0;
-+		entry.dest_mode       = 0; /* Physical */
-+		entry.delivery_mode   = 7; /* ExtInt */
-+		entry.vector          = 0;
-+		entry.dest.physical.physical_dest = 0;
-+
-+
-+		/*
-+		 * Add it to the IO-APIC irq-routing table:
-+		 */
-+		spin_lock_irqsave(&ioapic_lock, flags);
-+		io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
-+		io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
-+		spin_unlock_irqrestore(&ioapic_lock, flags);
-+	}
-+
- 	disconnect_bsp_APIC();
- }
- 
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/machine_kexec.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/machine_kexec.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/machine_kexec.c	2004-11-18 23:25:15.000000000 -0500
-@@ -0,0 +1,246 @@
-+/*
-+ * machine_kexec.c - handle transition of Linux booting another kernel
-+ * Copyright (C) 2002-2004 Eric Biederman  <ebiederm@xmission.com>
-+ *
-+ * This source code is licensed under the GNU General Public License,
-+ * Version 2.  See the file COPYING for more details.
-+ */
-+
-+#include <linux/mm.h>
-+#include <linux/kexec.h>
-+#include <linux/delay.h>
-+#include <linux/string.h>
-+#include <linux/reboot.h>
-+#include <asm/pda.h>
-+#include <asm/pgtable.h>
-+#include <asm/pgalloc.h>
-+#include <asm/tlbflush.h>
-+#include <asm/mmu_context.h>
-+#include <asm/io.h>
-+#include <asm/apic.h>
-+#include <asm/cpufeature.h>
-+#include <asm/hw_irq.h>
-+
-+#define LEVEL0_SIZE (1UL << 12UL)
-+#define LEVEL1_SIZE (1UL << 21UL)
-+#define LEVEL2_SIZE (1UL << 30UL)
-+#define LEVEL3_SIZE (1UL << 39UL)
-+#define LEVEL4_SIZE (1UL << 48UL)
-+
-+#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-+#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE)
-+#define L2_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-+#define L3_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-+
-+static void init_level2_page(
-+	uint64_t *level2p, unsigned long addr)
-+{
-+	unsigned long end_addr;
-+	addr &= PAGE_MASK;
-+	end_addr = addr + LEVEL2_SIZE;
-+	while(addr < end_addr) {
-+		*(level2p++) = addr | L1_ATTR;
-+		addr += LEVEL1_SIZE;
-+	}
-+}
-+
-+static int init_level3_page(struct kimage *image,
-+	uint64_t *level3p, unsigned long addr, unsigned long last_addr)
-+{
-+	unsigned long end_addr;
-+	int result;
-+	result = 0;
-+	addr &= PAGE_MASK;
-+	end_addr = addr + LEVEL3_SIZE;
-+	while((addr < last_addr) && (addr < end_addr)) {
-+		struct page *page;
-+		uint64_t *level2p;
-+		page = kimage_alloc_control_pages(image, 0);
-+		if (!page) {
-+			result = -ENOMEM;
-+			goto out;
-+		}
-+		level2p = (uint64_t *)page_address(page);
-+		init_level2_page(level2p, addr);
-+		*(level3p++) = __pa(level2p) | L2_ATTR;
-+		addr += LEVEL2_SIZE;
-+	}
-+	/* clear the unused entries */
-+	while(addr < end_addr) {
-+		*(level3p++) = 0;
-+		addr += LEVEL2_SIZE;
-+	}
-+out:
-+	return result;
-+}
-+
-+
-+static int init_level4_page(struct kimage *image, 
-+	uint64_t *level4p, unsigned long addr, unsigned long last_addr)
-+{
-+	unsigned long end_addr;
-+	int result;
-+	result = 0;
-+	addr &= PAGE_MASK;
-+	end_addr = addr + LEVEL4_SIZE;
-+	while((addr < last_addr) && (addr < end_addr)) {
-+		struct page *page;
-+		uint64_t *level3p;
-+		page = kimage_alloc_control_pages(image, 0);
-+		if (!page) {
-+			result = -ENOMEM;
-+			goto out;
-+		}
-+		level3p = (uint64_t *)page_address(page);
-+		result = init_level3_page(image, level3p, addr, last_addr);
-+		if (result) {
-+			goto out;
-+		}
-+		*(level4p++) = __pa(level3p) | L3_ATTR;
-+		addr += LEVEL3_SIZE;
-+	}
-+	/* clear the unused entries */
-+	while(addr < end_addr) {
-+		*(level4p++) = 0;
-+		addr += LEVEL3_SIZE;
-+	}
-+ out:
-+	return result;
-+}
-+
-+
-+static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
-+{
-+	uint64_t *level4p;
-+	level4p = (uint64_t *)__va(start_pgtable);
-+	return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT);
-+}
-+
-+static void set_idt(void *newidt, __u16 limit)
-+{
-+	unsigned char curidt[10];
-+
-+	/* x86-64 supports unaliged loads & stores */
-+	(*(__u16 *)(curidt)) = limit;
-+	(*(__u64 *)(curidt +2)) = (unsigned long)(newidt);
-+
-+	__asm__ __volatile__ (
-+		"lidt %0\n"
-+		: "=m" (curidt)
-+		);
-+};
-+
-+
-+static void set_gdt(void *newgdt, __u16 limit)
-+{
-+	unsigned char curgdt[10];
-+
-+	/* x86-64 supports unaligned loads & stores */
-+	(*(__u16 *)(curgdt)) = limit;
-+	(*(__u64 *)(curgdt +2)) = (unsigned long)(newgdt);
-+
-+	__asm__ __volatile__ (
-+		"lgdt %0\n"
-+		: "=m" (curgdt)
-+		);
-+};
-+
-+static void load_segments(void)
-+{
-+	__asm__ __volatile__ (
-+		"\tmovl $"STR(__KERNEL_DS)",%eax\n"
-+		"\tmovl %eax,%ds\n"
-+		"\tmovl %eax,%es\n"
-+		"\tmovl %eax,%ss\n"
-+		"\tmovl %eax,%fs\n"
-+		"\tmovl %eax,%gs\n"
-+		);
-+#undef STR
-+#undef __STR
-+}
-+
-+typedef void (*relocate_new_kernel_t)(
-+	unsigned long indirection_page, unsigned long control_code_buffer,
-+	unsigned long start_address, unsigned long pgtable);
-+
-+const extern unsigned char relocate_new_kernel[];
-+extern void relocate_new_kernel_end(void);
-+const extern unsigned long relocate_new_kernel_size;
-+
-+int machine_kexec_prepare(struct kimage *image)
-+{
-+	unsigned long start_pgtable, control_code_buffer;
-+	int result;
-+
-+	/* Calculate the offsets */
-+	start_pgtable       = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
-+	control_code_buffer = start_pgtable + 4096UL;
-+
-+	/* Setup the identity mapped 64bit page table */
-+	result = init_pgtable(image, start_pgtable);
-+	if (result) {
-+		return result;
-+	}
-+
-+	/* Place the code in the reboot code buffer */
-+	memcpy(__va(control_code_buffer), relocate_new_kernel, relocate_new_kernel_size);
-+
-+	return 0;
-+}
-+
-+void machine_kexec_cleanup(struct kimage *image)
-+{
-+	return;
-+}
-+
-+/*
-+ * Do not allocate memory (or fail in any way) in machine_kexec().
-+ * We are past the point of no return, committed to rebooting now.
-+ */
-+void machine_kexec(struct kimage *image)
-+{
-+	unsigned long indirection_page;
-+	unsigned long control_code_buffer;
-+	unsigned long start_pgtable;
-+	relocate_new_kernel_t rnk;
-+
-+	/* Interrupts aren't acceptable while we reboot */
-+	local_irq_disable();
-+
-+	/* Calculate the offsets */
-+	indirection_page    = image->head & PAGE_MASK;
-+	start_pgtable       = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
-+	control_code_buffer = start_pgtable + 4096UL;
-+
-+	/* Set the low half of the page table to my identity mapped
-+	 * page table for kexec.  Leave the high half pointing at the
-+	 * kernel pages.   Don't bother to flush the global pages
-+	 * as that will happen when I fully switch to my identity mapped
-+	 * page table anyway.
-+	 */
-+	memcpy((void *)read_pda(level4_pgt), __va(start_pgtable), PAGE_SIZE/2);
-+	__flush_tlb();
-+
-+
-+	/* The segment registers are funny things, they are
-+	 * automatically loaded from a table, in memory wherever you
-+	 * set them to a specific selector, but this table is never
-+	 * accessed again unless you set the segment to a different selector.
-+	 *
-+	 * The more common model are caches where the behide
-+	 * the scenes work is done, but is also dropped at arbitrary
-+	 * times.
-+	 *
-+	 * I take advantage of this here by force loading the
-+	 * segments, before I zap the gdt with an invalid value.
-+	 */
-+	load_segments();
-+	/* The gdt & idt are now invalid.
-+	 * If you want to load them you must set up your own idt & gdt.
-+	 */
-+	set_gdt(phys_to_virt(0),0);
-+	set_idt(phys_to_virt(0),0);
-+	/* now call it */
-+	rnk = (relocate_new_kernel_t) control_code_buffer;
-+	(*rnk)(indirection_page, control_code_buffer, image->start, start_pgtable);
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/reboot.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/reboot.c	2004-04-03 22:37:59.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/reboot.c	2004-11-18 23:25:15.000000000 -0500
-@@ -91,31 +91,6 @@
- 		      [target] "b" (WARMBOOT_TRAMP));
- }
- 
--#ifdef CONFIG_SMP
--static void smp_halt(void)
--{
--	int cpuid = safe_smp_processor_id(); 
--		static int first_entry = 1;
--
--		if (first_entry) { 
--			first_entry = 0;
--			smp_call_function((void *)machine_restart, NULL, 1, 0);
--		} 
--			
--	smp_stop_cpu(); 
--
--	/* AP calling this. Just halt */
--	if (cpuid != boot_cpu_id) { 
--		for (;;) 
--			asm("hlt");
--	}
--
--	/* Wait for all other CPUs to have run smp_stop_cpu */
--	while (!cpus_empty(cpu_online_map))
--		rep_nop(); 
--}
--#endif
--
- static inline void kb_wait(void)
- {
- 	int i;
-@@ -125,23 +100,45 @@
- 			break;
- }
- 
--void machine_restart(char * __unused)
-+void machine_shutdown(void)
- {
--	int i;
--
-+	/* Stop the cpus and apics */
- #ifdef CONFIG_SMP
--	smp_halt(); 
--#endif
-+	int reboot_cpu_id;
-+
-+	/* The boot cpu is always logical cpu 0 */
-+	reboot_cpu_id = 0;
-+
-+	/* Make certain the cpu I'm about to reboot on is online */
-+	if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
-+		reboot_cpu_id = smp_processor_id();
-+	}
-+
-+	/* Make certain I only run on the appropriate processor */
-+	set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
- 
-+	/* O.K Now that I'm on the appropriate processor, 
-+	 * stop all of the others.
-+	 */
-+	smp_send_stop();
-+#endif
-+	
- 	local_irq_disable();
--       
-+
- #ifndef CONFIG_SMP
- 	disable_local_APIC();
- #endif
- 
- 	disable_IO_APIC();
--	
-+
- 	local_irq_enable();
-+}
-+
-+void machine_restart(char * __unused)
-+{
-+	int i;
-+
-+	machine_shutdown();
- 	
- 	/* Tell the BIOS if we want cold or warm reboot */
- 	*((unsigned short *)__va(0x472)) = reboot_mode;
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/relocate_kernel.S
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/relocate_kernel.S	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/relocate_kernel.S	2004-11-18 23:25:15.000000000 -0500
-@@ -0,0 +1,141 @@
-+/*
-+ * relocate_kernel.S - put the kernel image in place to boot
-+ * Copyright (C) 2002-2004 Eric Biederman  <ebiederm@xmission.com>
-+ *
-+ * This source code is licensed under the GNU General Public License,
-+ * Version 2.  See the file COPYING for more details.
-+ */
-+
-+#include <linux/linkage.h>
-+
-+	/*
-+	 * Must be relocatable PIC code callable as a C function, that once
-+	 * it starts can not use the previous processes stack.
-+	 */
-+	.globl relocate_new_kernel
-+	.code64
-+relocate_new_kernel:
-+	/* %rdi indirection_page
-+	 * %rsi reboot_code_buffer
-+	 * %rdx start address
-+	 * %rcx page_table
-+	 * %r8  arg5
-+	 * %r9  arg6
-+	 */		
-+
-+	/* zero out flags, and disable interrupts */
-+	pushq $0
-+	popfq
-+
-+	/* set a new stack at the bottom of our page... */
-+	lea   4096(%rsi), %rsp
-+
-+	/* store the parameters back on the stack */
-+	pushq	%rdx /* store the start address */	
-+
-+	/* Set cr0 to a known state:
-+	 * 31 1 == Paging enabled
-+	 * 18 0 == Alignment check disabled
-+	 * 16 0 == Write protect disabled
-+	 * 3  0 == No task switch
-+	 * 2  0 == Don't do FP software emulation.
-+	 * 0  1 == Proctected mode enabled
-+	 */
-+	movq	%cr0, %rax
-+	andq	$~((1<<18)|(1<<16)|(1<<3)|(1<<2)), %rax
-+	orl	$((1<<31)|(1<<0)), %eax
-+	movq	%rax, %cr0
-+
-+	/* Set cr4 to a known state:
-+	 * 10 0 == xmm exceptions disabled
-+	 * 9  0 == xmm registers instructions disabled
-+	 * 8  0 == performance monitoring counter disabled
-+	 * 7  0 == page global disabled
-+	 * 6  0 == machine check exceptions disabled	
-+	 * 5  1 == physical address extension enabled	
-+	 * 4  0 == page size extensions	disabled
-+	 * 3  0 == Debug extensions disabled 	
-+	 * 2  0 == Time stamp disable (disabled) 	
-+	 * 1  0 == Protected mode virtual interrupts disabled
-+	 * 0  0 == VME disabled
-+	 */
-+
-+	movq	$((1<<5)), %rax
-+	movq	%rax, %cr4
-+
-+	jmp 1f
-+1:
-+
-+	/* Switch to the identity mapped page tables,
-+	 * and flush the TLB.	
-+	*/
-+	movq	%rcx, %cr3
-+
-+	/* Do the copies */
-+	movq	%rdi, %rbx	/* Put the indirection page in %rbx */
-+	xorq	%rdi, %rdi
-+	xorq	%rsi, %rsi
-+	
-+0:	/* top, read another word for the indirection page */
-+	
-+	movq	(%rbx), %rcx
-+	addq	$8,	%rbx
-+	testq	$0x1,	%rcx  /* is it a destination page? */
-+	jz	1f
-+	movq	%rcx,	%rdi
-+	andq	$0xfffffffffffff000, %rdi
-+	jmp	0b
-+1:
-+	testq	$0x2,	%rcx  /* is it an indirection page? */
-+	jz	1f
-+	movq	%rcx,   %rbx
-+	andq	$0xfffffffffffff000, %rbx
-+	jmp	0b
-+1:
-+	testq	$0x4,	%rcx  /* is it the done indicator? */
-+	jz	1f
-+	jmp	2f
-+1:
-+	testq	$0x8,	%rcx  /* is it the source indicator? */
-+	jz	0b	      /* Ignore it otherwise */
-+	movq	%rcx,   %rsi  /* For ever source page do a copy */
-+	andq	$0xfffffffffffff000, %rsi
-+
-+	movq	$512,   %rcx
-+	rep ; movsq
-+	jmp	0b
-+2:
-+
-+	/* To be certain of avoiding problems with self-modifying code
-+	 * I need to execute a serializing instruction here.
-+	 * So I flush the TLB by reloading %cr3 here, it's handy, 
-+	 * and not processor dependent.
-+	 */
-+	movq	%cr3, %rax
-+	movq	%rax, %cr3
-+
-+	/* set all of the registers to known values */
-+	/* leave %rsp alone */
-+
-+	xorq	%rax, %rax
-+	xorq	%rbx, %rbx
-+	xorq    %rcx, %rcx
-+	xorq    %rdx, %rdx
-+	xorq    %rsi, %rsi
-+	xorq    %rdi, %rdi
-+	xorq    %rbp, %rbp
-+	xorq	%r8,  %r8
-+	xorq	%r9,  %r9
-+	xorq	%r10, %r9
-+	xorq	%r11, %r11
-+	xorq	%r12, %r12
-+	xorq	%r13, %r13
-+	xorq	%r14, %r14
-+	xorq	%r15, %r15
-+
-+	ret
-+relocate_new_kernel_end:
-+
-+	.globl relocate_new_kernel_size
-+relocate_new_kernel_size:
-+	.quad relocate_new_kernel_end - relocate_new_kernel
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/apicdef.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-x86_64/apicdef.h	2004-11-11 10:28:46.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/apicdef.h	2004-11-18 23:26:05.000000000 -0500
-@@ -32,8 +32,8 @@
- #define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
- #define			APIC_ALL_CPUS		0xFFu
- #define		APIC_DFR	0xE0
--#define			APIC_DFR_CLUSTER	0x0FFFFFFFu
--#define			APIC_DFR_FLAT		0xFFFFFFFFu
-+#define			APIC_DFR_CLUSTER	0x0FFFFFFFul
-+#define			APIC_DFR_FLAT		0xFFFFFFFFul
- #define		APIC_SPIV	0xF0
- #define			APIC_SPIV_FOCUS_DISABLED	(1<<9)
- #define			APIC_SPIV_APIC_ENABLED		(1<<8)
-@@ -89,6 +89,7 @@
- #define			APIC_LVT_REMOTE_IRR		(1<<14)
- #define			APIC_INPUT_POLARITY		(1<<13)
- #define			APIC_SEND_PENDING		(1<<12)
-+#define			APIC_MODE_MASK			0x700
- #define			GET_APIC_DELIVERY_MODE(x)	(((x)>>8)&0x7)
- #define			SET_APIC_DELIVERY_MODE(x,y)	(((x)&~0x700)|((y)<<8))
- #define				APIC_MODE_FIXED		0x0
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/kexec.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-x86_64/kexec.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/kexec.h	2004-11-18 23:25:15.000000000 -0500
-@@ -0,0 +1,25 @@
-+#ifndef _X86_64_KEXEC_H
-+#define _X86_64_KEXEC_H
-+
-+#include <asm/page.h>
-+#include <asm/proto.h>
-+
-+/*
-+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
-+ * I.e. Maximum page that is mapped directly into kernel memory,
-+ * and kmap is not required.
-+ *
-+ * So far x86_64 is limited to 40 physical address bits.
-+ */
-+
-+/* Maximum physical address we can use pages from */
-+#define KEXEC_SOURCE_MEMORY_LIMIT      (0xFFFFFFFFFFUL)
-+/* Maximum address we can reach in physical address mode */
-+#define KEXEC_DESTINATION_MEMORY_LIMIT (0xFFFFFFFFFFUL)
-+/* Maximum address we can use for the control pages */
-+#define KEXEC_CONTROL_MEMORY_LIMIT     (0xFFFFFFFFFFUL)
-+
-+/* Allocate one page for the pdp and the second for the code */
-+#define KEXEC_CONTROL_CODE_SIZE  (4096UL + 4096UL)
-+
-+#endif /* _X86_64_KEXEC_H */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/unistd.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-x86_64/unistd.h	2004-11-11 10:28:49.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/unistd.h	2004-11-18 23:27:18.000000000 -0500
-@@ -551,7 +551,22 @@
- #define __NR_mq_getsetattr 	245
- __SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
- 
--#define __NR_syscall_max __NR_mq_getsetattr
-+#define __NR_mq_open 240
-+__SYSCALL(__NR_mq_open, sys_ni_syscall)
-+#define __NR_mq_unlink 241
-+__SYSCALL(__NR_mq_unlink, sys_ni_syscall)
-+#define __NR_mq_timedsend 242
-+__SYSCALL(__NR_mq_timedsend, sys_ni_syscall)
-+#define __NR_mq_timedreceive 243
-+__SYSCALL(__NR_mq_timedreceive, sys_ni_syscall)
-+#define __NR_mq_notify 244
-+__SYSCALL(__NR_mq_notify, sys_ni_syscall)
-+#define __NR_mq_getsetattr 245
-+__SYSCALL(__NR_mq_getsetattr, sys_ni_syscall)
-+#define __NR_kexec_load 246
-+__SYSCALL(__NR_kexec_load, sys_kexec_load)
-+
-+#define __NR_syscall_max __NR_kexec_load
- #ifndef __NO_STUBS
- 
- /* user-visible error numbers are in the range -1 - -4095 */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/kexec.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/linux/kexec.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/kexec.h	2004-11-18 23:25:15.000000000 -0500
-@@ -0,0 +1,56 @@
-+#ifndef LINUX_KEXEC_H
-+#define LINUX_KEXEC_H
-+
-+#if CONFIG_KEXEC
-+#include <linux/types.h>
-+#include <linux/list.h>
-+#include <asm/kexec.h>
-+
-+/*
-+ * This structure is used to hold the arguments that are used when loading
-+ * kernel binaries.
-+ */
-+
-+typedef unsigned long kimage_entry_t;
-+#define IND_DESTINATION  0x1
-+#define IND_INDIRECTION  0x2
-+#define IND_DONE         0x4
-+#define IND_SOURCE       0x8
-+
-+#define KEXEC_SEGMENT_MAX 8
-+struct kexec_segment {
-+	void *buf;
-+	size_t bufsz;
-+	void *mem;
-+	size_t memsz;
-+};
-+
-+struct kimage {
-+	kimage_entry_t head;
-+	kimage_entry_t *entry;
-+	kimage_entry_t *last_entry;
-+
-+	unsigned long destination;
-+
-+	unsigned long start;
-+	struct page *control_code_page;
-+
-+	unsigned long nr_segments;
-+	struct kexec_segment segment[KEXEC_SEGMENT_MAX];
-+
-+	struct list_head control_pages;
-+	struct list_head dest_pages;
-+	struct list_head unuseable_pages;
-+};
-+
-+
-+/* kexec interface functions */
-+extern void machine_kexec(struct kimage *image);
-+extern int machine_kexec_prepare(struct kimage *image);
-+extern void machine_kexec_cleanup(struct kimage *image);
-+extern asmlinkage long sys_kexec(unsigned long entry, long nr_segments,
-+	struct kexec_segment *segments);
-+extern struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order);
-+extern struct kimage *kexec_image;
-+#endif
-+#endif /* LINUX_KEXEC_H */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/reboot.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/linux/reboot.h	2004-04-03 22:38:27.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/reboot.h	2004-11-18 23:25:15.000000000 -0500
-@@ -22,6 +22,7 @@
-  * POWER_OFF   Stop OS and remove all power from system, if possible.
-  * RESTART2    Restart system using given command string.
-  * SW_SUSPEND  Suspend system using software suspend if compiled in.
-+ * KEXEC       Restart system using a previously loaded Linux kernel
-  */
- 
- #define	LINUX_REBOOT_CMD_RESTART	0x01234567
-@@ -31,6 +32,7 @@
- #define	LINUX_REBOOT_CMD_POWER_OFF	0x4321FEDC
- #define	LINUX_REBOOT_CMD_RESTART2	0xA1B2C3D4
- #define	LINUX_REBOOT_CMD_SW_SUSPEND	0xD000FCE2
-+#define LINUX_REBOOT_CMD_KEXEC          0x45584543
- 
- 
- #ifdef __KERNEL__
-@@ -49,6 +51,8 @@
- extern void machine_halt(void);
- extern void machine_power_off(void);
- 
-+extern void machine_shutdown(void);
-+
- #endif
- 
- #endif /* _LINUX_REBOOT_H */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/syscalls.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/linux/syscalls.h	2004-11-11 10:28:49.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/syscalls.h	2004-11-18 23:25:15.000000000 -0500
-@@ -19,6 +19,7 @@
- struct iovec;
- struct itimerspec;
- struct itimerval;
-+struct kexec_segment;
- struct linux_dirent;
- struct linux_dirent64;
- struct list_head;
-@@ -154,6 +155,8 @@
- asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,
- 				void __user *arg);
- asmlinkage long sys_restart_syscall(void);
-+asmlinkage long sys_kexec_load(void *entry, unsigned long nr_segments,
-+			      struct kexec_segment *segments, unsigned long flags);
- 
- asmlinkage long sys_exit(int error_code);
- asmlinkage void sys_exit_group(int error_code);
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/Makefile
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/kernel/Makefile	2004-11-11 10:28:43.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/Makefile	2004-11-18 23:25:15.000000000 -0500
-@@ -17,6 +17,7 @@
- obj-$(CONFIG_KALLSYMS) += kallsyms.o
- obj-$(CONFIG_PM) += power/
- obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
-+obj-$(CONFIG_KEXEC) += kexec.o
- obj-$(CONFIG_COMPAT) += compat.o
- obj-$(CONFIG_PAGG) += pagg.o
- obj-$(CONFIG_IKCONFIG) += configs.o
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/kexec.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/kernel/kexec.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/kexec.c	2004-11-18 23:25:15.000000000 -0500
-@@ -0,0 +1,640 @@
-+/*
-+ * kexec.c - kexec system call
-+ * Copyright (C) 2002-2004 Eric Biederman  <ebiederm@xmission.com>
-+ *
-+ * This source code is licensed under the GNU General Public License,
-+ * Version 2.  See the file COPYING for more details.
-+ */
-+
-+#include <linux/mm.h>
-+#include <linux/file.h>
-+#include <linux/slab.h>
-+#include <linux/fs.h>
-+#include <linux/kexec.h>
-+#include <linux/spinlock.h>
-+#include <linux/list.h>
-+#include <linux/highmem.h>
-+#include <net/checksum.h>
-+#include <asm/page.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-+
-+/*
-+ * When kexec transitions to the new kernel there is a one-to-one
-+ * mapping between physical and virtual addresses.  On processors
-+ * where you can disable the MMU this is trivial, and easy.  For
-+ * others it is still a simple predictable page table to setup.
-+ *
-+ * In that environment kexec copies the new kernel to its final
-+ * resting place.  This means I can only support memory whose
-+ * physical address can fit in an unsigned long.  In particular
-+ * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled.
-+ * If the assembly stub has more restrictive requirements
-+ * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be
-+ * defined more restrictively in <asm/kexec.h>.
-+ *
-+ * The code for the transition from the current kernel to the
-+ * the new kernel is placed in the control_code_buffer, whose size
-+ * is given by KEXEC_CONTROL_CODE_SIZE.  In the best case only a single
-+ * page of memory is necessary, but some architectures require more.
-+ * Because this memory must be identity mapped in the transition from
-+ * virtual to physical addresses it must live in the range
-+ * 0 - TASK_SIZE, as only the user space mappings are arbitrarily
-+ * modifiable.
-+ *
-+ * The assembly stub in the control code buffer is passed a linked list
-+ * of descriptor pages detailing the source pages of the new kernel,
-+ * and the destination addresses of those source pages.  As this data
-+ * structure is not used in the context of the current OS, it must
-+ * be self-contained.
-+ *
-+ * The code has been made to work with highmem pages and will use a
-+ * destination page in its final resting place (if it happens
-+ * to allocate it).  The end product of this is that most of the
-+ * physical address space, and most of RAM can be used.
-+ *
-+ * Future directions include:
-+ *  - allocating a page table with the control code buffer identity
-+ *    mapped, to simplify machine_kexec and make kexec_on_panic more
-+ *    reliable.
-+ */
-+
-+/*
-+ * KIMAGE_NO_DEST is an impossible destination address..., for
-+ * allocating pages whose destination address we do not care about.
-+ */
-+#define KIMAGE_NO_DEST (-1UL)
-+
-+static int kimage_is_destination_range(
-+	struct kimage *image, unsigned long start, unsigned long end);
-+static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long dest);
-+
-+
-+static int kimage_alloc(struct kimage **rimage,
-+	unsigned long nr_segments, struct kexec_segment *segments)
-+{
-+	int result;
-+	struct kimage *image;
-+	size_t segment_bytes;
-+	unsigned long i;
-+
-+	/* Allocate a controlling structure */
-+	result = -ENOMEM;
-+	image = kmalloc(sizeof(*image), GFP_KERNEL);
-+	if (!image) {
-+		goto out;
-+	}
-+	memset(image, 0, sizeof(*image));
-+	image->head = 0;
-+	image->entry = &image->head;
-+	image->last_entry = &image->head;
-+
-+	/* Initialize the list of control pages */
-+	INIT_LIST_HEAD(&image->control_pages);
-+
-+	/* Initialize the list of destination pages */
-+	INIT_LIST_HEAD(&image->dest_pages);
-+
-+	/* Initialize the list of unuseable pages */
-+	INIT_LIST_HEAD(&image->unuseable_pages);
-+
-+	/* Read in the segments */
-+	image->nr_segments = nr_segments;
-+	segment_bytes = nr_segments * sizeof*segments;
-+	result = copy_from_user(image->segment, segments, segment_bytes);
-+	if (result)
-+		goto out;
-+
-+	/*
-+	 * Verify we have good destination addresses.  The caller is
-+	 * responsible for making certain we don't attempt to load
-+	 * the new image into invalid or reserved areas of RAM.  This
-+	 * just verifies it is an address we can use.
-+	 */
-+	result = -EADDRNOTAVAIL;
-+	for (i = 0; i < nr_segments; i++) {
-+		unsigned long mend;
-+		mend = ((unsigned long)(image->segment[i].mem)) +
-+			image->segment[i].memsz;
-+		if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT)
-+			goto out;
-+	}
-+
-+	/*
-+	 * Find a location for the control code buffer, and add it
-+	 * the vector of segments so that it's pages will also be
-+	 * counted as destination pages.
-+	 */
-+	result = -ENOMEM;
-+	image->control_code_page = kimage_alloc_control_pages(image,
-+		get_order(KEXEC_CONTROL_CODE_SIZE));
-+	if (!image->control_code_page) {
-+		printk(KERN_ERR "Could not allocate control_code_buffer\n");
-+		goto out;
-+	}
-+
-+	result = 0;
-+ out:
-+	if (result == 0) {
-+		*rimage = image;
-+	} else {
-+		kfree(image);
-+	}
-+	return result;
-+}
-+
-+static int kimage_is_destination_range(
-+	struct kimage *image, unsigned long start, unsigned long end)
-+{
-+	unsigned long i;
-+
-+	for (i = 0; i < image->nr_segments; i++) {
-+		unsigned long mstart, mend;
-+		mstart = (unsigned long)image->segment[i].mem;
-+		mend   = mstart + image->segment[i].memsz;
-+		if ((end > mstart) && (start < mend)) {
-+			return 1;
-+		}
-+	}
-+	return 0;
-+}
-+
-+static struct page *kimage_alloc_pages(unsigned int gfp_mask, unsigned int order)
-+{
-+	struct page *pages;
-+	pages = alloc_pages(gfp_mask, order);
-+	if (pages) {
-+		unsigned int count, i;
-+		pages->mapping = NULL;
-+		pages->private = order;
-+		count = 1 << order;
-+		for(i = 0; i < count; i++) {
-+			SetPageReserved(pages + i);
-+		}
-+	}
-+	return pages;
-+}
-+
-+static void kimage_free_pages(struct page *page)
-+{
-+	unsigned int order, count, i;
-+	order = page->private;
-+	count = 1 << order;
-+	for(i = 0; i < count; i++) {
-+		ClearPageReserved(page + i);
-+	}
-+	__free_pages(page, order);
-+}
-+
-+static void kimage_free_page_list(struct list_head *list)
-+{
-+	struct list_head *pos, *next;
-+	list_for_each_safe(pos, next, list) {
-+		struct page *page;
-+
-+		page = list_entry(pos, struct page, lru);
-+		list_del(&page->lru);
-+
-+		kimage_free_pages(page);
-+	}
-+}
-+		
-+struct page *kimage_alloc_control_pages(struct kimage *image, unsigned int order)
-+{
-+	/* Control pages are special, they are the intermediaries
-+	 * that are needed while we copy the rest of the pages
-+	 * to their final resting place.  As such they must
-+	 * not conflict with either the destination addresses
-+	 * or memory the kernel is already using.
-+	 *
-+	 * The only case where we really need more than one of
-+	 * these are for architectures where we cannot disable
-+	 * the MMU and must instead generate an identity mapped
-+	 * page table for all of the memory.
-+	 *
-+	 * At worst this runs in O(N) of the image size.
-+	 */
-+	struct list_head extra_pages;
-+	struct page *pages;
-+	unsigned int count;
-+
-+	count = 1 << order;
-+	INIT_LIST_HEAD(&extra_pages);
-+
-+	/* Loop while I can allocate a page and the page allocated
-+	 * is a destination page.
-+	 */
-+	do {
-+		unsigned long pfn, epfn, addr, eaddr;
-+		pages = kimage_alloc_pages(GFP_KERNEL, order);
-+		if (!pages)
-+			break;
-+		pfn   = page_to_pfn(pages);
-+		epfn  = pfn + count;
-+		addr  = pfn << PAGE_SHIFT;
-+		eaddr = epfn << PAGE_SHIFT;
-+		if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) ||
-+			kimage_is_destination_range(image, addr, eaddr))
-+		{
-+			list_add(&pages->lru, &extra_pages);
-+			pages = NULL;
-+		}
-+	} while(!pages);
-+	if (pages) {
-+		/* Remember the allocated page... */
-+		list_add(&pages->lru, &image->control_pages);
-+
-+		/* Because the page is already in it's destination
-+		 * location we will never allocate another page at
-+		 * that address.  Therefore kimage_alloc_pages
-+		 * will not return it (again) and we don't need
-+		 * to give it an entry in image->segment[].
-+		 */
-+	}
-+	/* Deal with the destination pages I have inadvertently allocated.
-+	 *
-+	 * Ideally I would convert multi-page allocations into single
-+	 * page allocations, and add everyting to image->dest_pages.
-+	 * 
-+	 * For now it is simpler to just free the pages.
-+	 */
-+	kimage_free_page_list(&extra_pages);
-+	return pages;
-+	
-+}
-+
-+static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
-+{
-+	if (*image->entry != 0) {
-+		image->entry++;
-+	}
-+	if (image->entry == image->last_entry) {
-+		kimage_entry_t *ind_page;
-+		struct page *page;
-+		page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST);
-+		if (!page) {
-+			return -ENOMEM;
-+		}
-+		ind_page = page_address(page);
-+		*image->entry = virt_to_phys(ind_page) | IND_INDIRECTION;
-+		image->entry = ind_page;
-+		image->last_entry =
-+			ind_page + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1);
-+	}
-+	*image->entry = entry;
-+	image->entry++;
-+	*image->entry = 0;
-+	return 0;
-+}
-+
-+static int kimage_set_destination(
-+	struct kimage *image, unsigned long destination)
-+{
-+	int result;
-+
-+	destination &= PAGE_MASK;
-+	result = kimage_add_entry(image, destination | IND_DESTINATION);
-+	if (result == 0) {
-+		image->destination = destination;
-+	}
-+	return result;
-+}
-+
-+
-+static int kimage_add_page(struct kimage *image, unsigned long page)
-+{
-+	int result;
-+
-+	page &= PAGE_MASK;
-+	result = kimage_add_entry(image, page | IND_SOURCE);
-+	if (result == 0) {
-+		image->destination += PAGE_SIZE;
-+	}
-+	return result;
-+}
-+
-+
-+static void kimage_free_extra_pages(struct kimage *image)
-+{
-+	/* Walk through and free any extra destination pages I may have */
-+	kimage_free_page_list(&image->dest_pages);
-+
-+	/* Walk through and free any unuseable pages I have cached */
-+	kimage_free_page_list(&image->unuseable_pages);
-+
-+}
-+static int kimage_terminate(struct kimage *image)
-+{
-+	int result;
-+
-+	result = kimage_add_entry(image, IND_DONE);
-+	if (result == 0) {
-+		/* Point at the terminating element */
-+		image->entry--;
-+		kimage_free_extra_pages(image);
-+	}
-+	return result;
-+}
-+
-+#define for_each_kimage_entry(image, ptr, entry) \
-+	for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \
-+		ptr = (entry & IND_INDIRECTION)? \
-+			phys_to_virt((entry & PAGE_MASK)): ptr +1)
-+
-+static void kimage_free_entry(kimage_entry_t entry)
-+{
-+	struct page *page;
-+
-+	page = pfn_to_page(entry >> PAGE_SHIFT);
-+	kimage_free_pages(page);
-+}
-+
-+static void kimage_free(struct kimage *image)
-+{
-+	kimage_entry_t *ptr, entry;
-+	kimage_entry_t ind = 0;
-+
-+	if (!image)
-+		return;
-+	kimage_free_extra_pages(image);
-+	for_each_kimage_entry(image, ptr, entry) {
-+		if (entry & IND_INDIRECTION) {
-+			/* Free the previous indirection page */
-+			if (ind & IND_INDIRECTION) {
-+				kimage_free_entry(ind);
-+			}
-+			/* Save this indirection page until we are
-+			 * done with it.
-+			 */
-+			ind = entry;
-+		}
-+		else if (entry & IND_SOURCE) {
-+			kimage_free_entry(entry);
-+		}
-+	}
-+	/* Free the final indirection page */
-+	if (ind & IND_INDIRECTION) {
-+		kimage_free_entry(ind);
-+	}
-+
-+	/* Handle any machine specific cleanup */
-+	machine_kexec_cleanup(image);
-+
-+	/* Free the kexec control pages... */
-+	kimage_free_page_list(&image->control_pages);
-+	kfree(image);
-+}
-+
-+static kimage_entry_t *kimage_dst_used(struct kimage *image, unsigned long page)
-+{
-+	kimage_entry_t *ptr, entry;
-+	unsigned long destination = 0;
-+
-+	for_each_kimage_entry(image, ptr, entry) {
-+		if (entry & IND_DESTINATION) {
-+			destination = entry & PAGE_MASK;
-+		}
-+		else if (entry & IND_SOURCE) {
-+			if (page == destination) {
-+				return ptr;
-+			}
-+			destination += PAGE_SIZE;
-+		}
-+	}
-+	return 0;
-+}
-+
-+static struct page *kimage_alloc_page(struct kimage *image, unsigned int gfp_mask, unsigned long destination)
-+{
-+	/*
-+	 * Here we implement safeguards to ensure that a source page
-+	 * is not copied to its destination page before the data on
-+	 * the destination page is no longer useful.
-+	 *
-+	 * To do this we maintain the invariant that a source page is
-+	 * either its own destination page, or it is not a
-+	 * destination page at all.
-+	 *
-+	 * That is slightly stronger than required, but the proof
-+	 * that no problems will not occur is trivial, and the
-+	 * implementation is simply to verify.
-+	 *
-+	 * When allocating all pages normally this algorithm will run
-+	 * in O(N) time, but in the worst case it will run in O(N^2)
-+	 * time.   If the runtime is a problem the data structures can
-+	 * be fixed.
-+	 */
-+	struct page *page;
-+	unsigned long addr;
-+
-+	/*
-+	 * Walk through the list of destination pages, and see if I
-+	 * have a match.
-+	 */
-+	list_for_each_entry(page, &image->dest_pages, lru) {
-+		addr = page_to_pfn(page) << PAGE_SHIFT;
-+		if (addr == destination) {
-+			list_del(&page->lru);
-+			return page;
-+		}
-+	}
-+	page = NULL;
-+	while (1) {
-+		kimage_entry_t *old;
-+
-+		/* Allocate a page, if we run out of memory give up */
-+		page = kimage_alloc_pages(gfp_mask, 0);
-+		if (!page) {
-+			return 0;
-+		}
-+		/* If the page cannot be used file it away */
-+		if (page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
-+			list_add(&page->lru, &image->unuseable_pages);
-+			continue;
-+		}
-+		addr = page_to_pfn(page) << PAGE_SHIFT;
-+
-+		/* If it is the destination page we want use it */
-+		if (addr == destination)
-+			break;
-+
-+		/* If the page is not a destination page use it */
-+		if (!kimage_is_destination_range(image, addr, addr + PAGE_SIZE))
-+			break;
-+
-+		/*
-+		 * I know that the page is someones destination page.
-+		 * See if there is already a source page for this
-+		 * destination page.  And if so swap the source pages.
-+		 */
-+		old = kimage_dst_used(image, addr);
-+		if (old) {
-+			/* If so move it */
-+			unsigned long old_addr;
-+			struct page *old_page;
-+
-+			old_addr = *old & PAGE_MASK;
-+			old_page = pfn_to_page(old_addr >> PAGE_SHIFT);
-+			copy_highpage(page, old_page);
-+			*old = addr | (*old & ~PAGE_MASK);
-+
-+			/* The old page I have found cannot be a
-+			 * destination page, so return it.
-+			 */
-+			addr = old_addr;
-+			page = old_page;
-+			break;
-+		}
-+		else {
-+			/* Place the page on the destination list I
-+			 * will use it later.
-+			 */
-+			list_add(&page->lru, &image->dest_pages);
-+		}
-+	}
-+	return page;
-+}
-+
-+static int kimage_load_segment(struct kimage *image,
-+	struct kexec_segment *segment)
-+{
-+	unsigned long mstart;
-+	int result;
-+	unsigned long offset;
-+	unsigned long offset_end;
-+	unsigned char *buf;
-+
-+	result = 0;
-+	buf = segment->buf;
-+	mstart = (unsigned long)segment->mem;
-+
-+	offset_end = segment->memsz;
-+
-+	result = kimage_set_destination(image, mstart);
-+	if (result < 0) {
-+		goto out;
-+	}
-+	for (offset = 0;  offset < segment->memsz; offset += PAGE_SIZE) {
-+		struct page *page;
-+		char *ptr;
-+		size_t size, leader;
-+		page = kimage_alloc_page(image, GFP_HIGHUSER, mstart + offset);
-+		if (page == 0) {
-+			result  = -ENOMEM;
-+			goto out;
-+		}
-+		result = kimage_add_page(image, page_to_pfn(page) << PAGE_SHIFT);
-+		if (result < 0) {
-+			goto out;
-+		}
-+		ptr = kmap(page);
-+		if (segment->bufsz < offset) {
-+			/* We are past the end zero the whole page */
-+			memset(ptr, 0, PAGE_SIZE);
-+			kunmap(page);
-+			continue;
-+		}
-+		size = PAGE_SIZE;
-+		leader = 0;
-+		if ((offset == 0)) {
-+			leader = mstart & ~PAGE_MASK;
-+		}
-+		if (leader) {
-+			/* We are on the first page zero the unused portion */
-+			memset(ptr, 0, leader);
-+			size -= leader;
-+			ptr += leader;
-+		}
-+		if (size > (segment->bufsz - offset)) {
-+			size = segment->bufsz - offset;
-+		}
-+		if (size < (PAGE_SIZE - leader)) {
-+			/* zero the trailing part of the page */
-+			memset(ptr + size, 0, (PAGE_SIZE - leader) - size);
-+		}
-+		result = copy_from_user(ptr, buf + offset, size);
-+		kunmap(page);
-+		if (result) {
-+			result = (result < 0) ? result : -EIO;
-+			goto out;
-+		}
-+	}
-+ out:
-+	return result;
-+}
-+
-+/*
-+ * Exec Kernel system call: for obvious reasons only root may call it.
-+ *
-+ * This call breaks up into three pieces.
-+ * - A generic part which loads the new kernel from the current
-+ *   address space, and very carefully places the data in the
-+ *   allocated pages.
-+ *
-+ * - A generic part that interacts with the kernel and tells all of
-+ *   the devices to shut down.  Preventing on-going dmas, and placing
-+ *   the devices in a consistent state so a later kernel can
-+ *   reinitialize them.
-+ *
-+ * - A machine specific part that includes the syscall number
-+ *   and the copies the image to it's final destination.  And
-+ *   jumps into the image at entry.
-+ *
-+ * kexec does not sync, or unmount filesystems so if you need
-+ * that to happen you need to do that yourself.
-+ */
-+struct kimage *kexec_image = NULL;
-+
-+asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
-+	struct kexec_segment *segments, unsigned long flags)
-+{
-+	struct kimage *image;
-+	int result;
-+
-+	/* We only trust the superuser with rebooting the system. */
-+	if (!capable(CAP_SYS_BOOT))
-+		return -EPERM;
-+
-+	/*
-+	 * In case we need just a little bit of special behavior for
-+	 * reboot on panic.
-+	 */
-+	if (flags != 0)
-+		return -EINVAL;
-+
-+	if (nr_segments > KEXEC_SEGMENT_MAX)
-+		return -EINVAL;
-+
-+	image = NULL;
-+	result = 0;
-+
-+	if (nr_segments > 0) {
-+		unsigned long i;
-+		result = kimage_alloc(&image, nr_segments, segments);
-+		if (result) {
-+			goto out;
-+		}
-+		result = machine_kexec_prepare(image);
-+		if (result) {
-+			goto out;
-+		}
-+		image->start = entry;
-+		for (i = 0; i < nr_segments; i++) {
-+			result = kimage_load_segment(image, &image->segment[i]);
-+			if (result) {
-+				goto out;
-+			}
-+		}
-+		result = kimage_terminate(image);
-+		if (result) {
-+			goto out;
-+		}
-+	}
-+
-+	image = xchg(&kexec_image, image);
-+
-+ out:
-+	kimage_free(image);
-+	return result;
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/sys.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/kernel/sys.c	2004-11-11 10:28:49.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/sys.c	2004-11-18 23:25:15.000000000 -0500
-@@ -17,6 +17,8 @@
- #include <linux/init.h>
- #include <linux/highuid.h>
- #include <linux/fs.h>
-+#include <linux/kernel.h>
-+#include <linux/kexec.h>
- #include <linux/workqueue.h>
- #include <linux/device.h>
- #include <linux/times.h>
-@@ -226,6 +228,7 @@
- cond_syscall(sys_lookup_dcookie)
- cond_syscall(sys_swapon)
- cond_syscall(sys_swapoff)
-+cond_syscall(sys_kexec_load)
- cond_syscall(sys_init_module)
- cond_syscall(sys_delete_module)
- cond_syscall(sys_socketpair)
-@@ -505,6 +508,24 @@
- 		machine_restart(buffer);
- 		break;
- 
-+#ifdef CONFIG_KEXEC
-+	case LINUX_REBOOT_CMD_KEXEC:
-+	{
-+		struct kimage *image;
-+		image = xchg(&kexec_image, 0);
-+		if (!image) {
-+			unlock_kernel();
-+			return -EINVAL;
-+		}
-+		notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
-+		system_state = SYSTEM_BOOTING;
-+		device_shutdown();
-+		printk(KERN_EMERG "Starting new kernel\n");
-+		machine_shutdown();
-+		machine_kexec(image);
-+		break;
-+	}
-+#endif
- #ifdef CONFIG_SOFTWARE_SUSPEND
- 	case LINUX_REBOOT_CMD_SW_SUSPEND:
- 		{
diff --git a/lustre/kernel_patches/patches/kjournald_affinity.patch b/lustre/kernel_patches/patches/kjournald_affinity.patch
deleted file mode 100644
index 977676b8a0..0000000000
--- a/lustre/kernel_patches/patches/kjournald_affinity.patch
+++ /dev/null
@@ -1,52 +0,0 @@
---- linux-2.6.10.orig/fs/ext3/super.c	2004-12-24 22:35:28.000000000 +0100
-+++ linux-2.6.10/fs/ext3/super.c	2005-01-18 12:27:51.896529310 +0100
-@@ -1787,6 +1787,33 @@
- 	return NULL;
- }
- 
-+#ifdef CONFIG_NUMA
-+#include <linux/nodemask.h>
-+#include <asm/topology.h>
-+
-+static int journal_node_affinity = 0;
-+spinlock_t journal_node_affinity_lock = SPIN_LOCK_UNLOCKED;
-+
-+static void ext3_bind_journal_thread(journal_t *journal) {
-+	int i, node;
-+
-+	spin_lock(&journal_node_affinity_lock);
-+	for (i = 0; i < MAX_NUMNODES; i++) {
-+		node = (journal_node_affinity + i) % MAX_NUMNODES;
-+
-+		if (!nr_cpus_node(node) || !node_online(node))
-+			continue;
-+
-+		set_cpus_allowed(journal->j_task, node_to_cpumask(node));
-+		journal_node_affinity = (node + 1) % MAX_NUMNODES;
-+		break;
-+	}
-+	spin_unlock(&journal_node_affinity_lock);
-+}
-+#else
-+#define ext3_bind_journal_thread(journal) do {} while (0)
-+#endif
-+
- static int ext3_load_journal(struct super_block * sb,
- 			     struct ext3_super_block * es)
- {
-@@ -1852,6 +1875,7 @@
- 		return err;
- 	}
- 
-+	ext3_bind_journal_thread(journal);
- 	EXT3_SB(sb)->s_journal = journal;
- 	ext3_clear_journal_err(sb, es);
- 	return 0;
-@@ -1881,6 +1908,7 @@
- 		return -EIO;
- 	}
- 
-+	ext3_bind_journal_thread(journal);
- 	EXT3_SB(sb)->s_journal = journal;
- 
- 	ext3_update_dynamic_rev(sb);
diff --git a/lustre/kernel_patches/patches/link_notlast-susefix.patch b/lustre/kernel_patches/patches/link_notlast-susefix.patch
deleted file mode 100644
index e3efbb465b..0000000000
--- a/lustre/kernel_patches/patches/link_notlast-susefix.patch
+++ /dev/null
@@ -1,16 +0,0 @@
---- linux-2.6.5-7.141/fs/namei.c.orig	2005-04-01 18:03:37.788262784 +0300
-+++ linux-2.6.5-7.141/fs/namei.c	2005-04-01 18:05:43.058218856 +0300
-@@ -719,10 +719,12 @@
- 			goto out_dput;
- 
- 		if (inode->i_op->follow_link) {
-+			int save_flags = nd->flags;
- 			mntget(next.mnt);
- 			nd->flags |= LOOKUP_LINK_NOTLAST;
- 			err = do_follow_link(next.dentry, nd);
--			nd->flags &= ~LOOKUP_LINK_NOTLAST;
-+			if (!(save_flags & LOOKUP_LINK_NOTLAST))
-+				nd->flags &= ~LOOKUP_LINK_NOTLAST;
- 			dput(next.dentry);
- 			mntput(next.mnt);
- 			if (err)
diff --git a/lustre/kernel_patches/patches/lustre_build.patch b/lustre/kernel_patches/patches/lustre_build.patch
deleted file mode 100644
index 70f6a37d4b..0000000000
--- a/lustre/kernel_patches/patches/lustre_build.patch
+++ /dev/null
@@ -1,33 +0,0 @@
- fs/Kconfig  |    8 ++++++++
- fs/Makefile |    1 +
- 2 files changed, 9 insertions(+)
-
---- linux-2.5.72/fs/Makefile~lustre_build	2003-06-16 22:20:05.000000000 -0600
-+++ linux-2.5.72-braam/fs/Makefile	2003-06-22 10:11:57.000000000 -0600
-@@ -57,6 +57,7 @@ obj-$(CONFIG_RAMFS)		+= ramfs/
- obj-$(CONFIG_HUGETLBFS)		+= hugetlbfs/
- obj-$(CONFIG_CODA_FS)		+= coda/
- obj-$(CONFIG_INTERMEZZO_FS)	+= intermezzo/
-+obj-$(CONFIG_LUSTRE_FS)		+= lustre/
- obj-$(CONFIG_MINIX_FS)		+= minix/
- obj-$(CONFIG_FAT_FS)		+= fat/
- obj-$(CONFIG_UMSDOS_FS)		+= umsdos/
---- linux-2.5.72/fs/Kconfig~lustre_build	2003-06-16 22:20:05.000000000 -0600
-+++ linux-2.5.72-braam/fs/Kconfig	2003-06-22 10:47:15.000000000 -0600
-@@ -1561,6 +1561,14 @@ config CODA_FS
- 	  whenever you want), say M here and read
- 	  <file:Documentation/modules.txt>.  The module will be called coda.
- 
-+config LUSTRE_FS
-+	bool "Lustre: next generation clustering file system (EXPERIMENTAL)"
-+	depends on INET && EXPERIMENTAL
-+	help
-+	  Lustre is a next generation storage architecture which includes a
-+	  POSIX compliant cluster file system. For details see
-+	  <http://www.lustre.org/>.
-+
- config INTERMEZZO_FS
- 	tristate "InterMezzo file system support (replicating fs) (EXPERIMENTAL)"
- 	depends on INET && EXPERIMENTAL
-
-_
diff --git a/lustre/kernel_patches/patches/mtd-2.6-suse-lnxi.patch b/lustre/kernel_patches/patches/mtd-2.6-suse-lnxi.patch
deleted file mode 100644
index 85b2ca2553..0000000000
--- a/lustre/kernel_patches/patches/mtd-2.6-suse-lnxi.patch
+++ /dev/null
@@ -1,35414 +0,0 @@
-Index: linux-2.6.5/drivers/mtd/Kconfig
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/Kconfig	2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/Kconfig	2005-02-01 17:11:17.000000000 -0500
-@@ -1,4 +1,4 @@
--# $Id: Kconfig,v 1.3 2003/05/28 11:02:23 dwmw2 Exp $
-+# $Id: Kconfig,v 1.6 2004/08/09 13:19:42 dwmw2 Exp $
- 
- menu "Memory Technology Devices (MTD)"
- 
-@@ -28,7 +28,7 @@
- 	  Determines the verbosity level of the MTD debugging messages.
- 
- config MTD_PARTITIONS
--	tristate "MTD partitioning support"
-+	bool "MTD partitioning support"
- 	depends on MTD
- 	help
- 	  If you have a device which needs to divide its flash chip(s) up
-@@ -68,9 +68,23 @@
- 	  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: linux-2.6.5/drivers/mtd/Makefile
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/Makefile	2004-04-03 22:36:57.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/Makefile	2005-02-01 17:11:17.000000000 -0500
-@@ -1,28 +1,14 @@
- #
- # 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.5 2004/08/10 20:51:49 dwmw2 Exp $
- 
- # Core functionality.
--obj-$(CONFIG_MTD)		+= mtdcore.o
-+mtd-y				:= mtdcore.o
-+mtd-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
-+obj-$(CONFIG_MTD)		+= $(mtd-y)
-+
- obj-$(CONFIG_MTD_CONCAT)	+= mtdconcat.o
--obj-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
- obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
- obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
- obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
-Index: linux-2.6.5/drivers/mtd/afs.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/afs.c	2004-04-03 22:38:15.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/afs.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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: linux-2.6.5/drivers/mtd/chips/Kconfig
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/Kconfig	2004-04-03 22:36:54.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/Kconfig	2005-02-01 17:11:17.000000000 -0500
-@@ -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.9 2004/07/16 15:32:14 dwmw2 Exp $
- 
- menu "RAM/ROM/Flash chip drivers"
- 	depends on MTD!=n
-@@ -85,59 +85,72 @@
- 	  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 @@
- 	  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 @@
- 	  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
-@@ -194,6 +233,7 @@
- 	  with this driver will return -ENODEV upon access.
- 
- config MTD_OBSOLETE_CHIPS
-+	depends on MTD && BROKEN
- 	bool "Older (theoretically obsoleted now) drivers for non-CFI chips"
- 	help
- 	  This option does not enable any code directly, but will allow you to
-Index: linux-2.6.5/drivers/mtd/chips/Makefile
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/Makefile	2004-04-03 22:36:53.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/Makefile	2005-02-01 17:11:17.000000000 -0500
-@@ -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: linux-2.6.5/drivers/mtd/chips/amd_flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/amd_flash.c	2004-04-03 22:36:53.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/amd_flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.25 2004/08/09 13:19:43 dwmw2 Exp $
-  *
-  * Copyright (c) 2001 Axis Communications AB
-  *
-@@ -718,7 +718,7 @@
- 		       "memory for MTD erase region info\n", map->name);
- 		kfree(mtd);
- 		map->fldrv_priv = NULL;
--		return 0;
-+		return NULL;
- 	}
- 
- 	reg_idx = 0;
-@@ -780,8 +780,8 @@
- 	map->fldrv_priv = private;
- 
- 	map->fldrv = &amd_flash_chipdrv;
--	MOD_INC_USE_COUNT;
- 
-+	__module_get(THIS_MODULE);
- 	return mtd;
- }
- 
-@@ -1307,9 +1307,7 @@
- 	}
- 		
- 	instr->state = MTD_ERASE_DONE;
--	if (instr->callback) {
--		instr->callback(instr);
--	}
-+	mtd_erase_callback(instr);
- 	
- 	return 0;
- }
-Index: linux-2.6.5/drivers/mtd/chips/cfi_cmdset_0001.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/cfi_cmdset_0001.c	2004-04-03 22:36:54.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/cfi_cmdset_0001.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.156 2004/09/17 11:45:05 eric Exp $
-  *
-  * 
-  * 10/10/2000	Nicolas Pitre <nico@cam.org>
-@@ -34,12 +34,20 @@
- #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
- 
-+#define MANUFACTURER_INTEL	0x0089
-+#define I82802AB	0x00ad
-+#define I82802AC	0x00ac
-+#define MANUFACTURER_ST         0x0020
-+#define M50LPW080       0x002F
-+
- static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
--static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
--static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-+//static int cfi_intelext_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 *);
-@@ -53,13 +61,19 @@
- 
- struct mtd_info *cfi_cmdset_0001(struct map_info *, int);
- 
--static struct mtd_info *cfi_intelext_setup (struct map_info *);
-+static struct mtd_info *cfi_intelext_setup (struct mtd_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);
- static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
- 			size_t len);
- 
-+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
-+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
-+#include "fwh_lock.h"
-+
-+
- 
- /*
-  *  *********** SETUP AND PROBE BITS  ***********
-@@ -79,17 +93,18 @@
- 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,13 +125,93 @@
- 	}
- 	
- 	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 mtd_info *mtd, void* param)
-+{
-+	struct map_info *map = mtd->priv;
-+	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 mtd_info *mtd, void* param)
-+{
-+	struct map_info *map = mtd->priv;
-+	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 mtd_info *mtd, void* param)
-+{
-+	struct map_info *map = mtd->priv;
-+	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 void fixup_use_point(struct mtd_info *mtd, void *param)
-+{
-+	struct map_info *map = mtd->priv;
-+	if (!mtd->point && map_is_linear(map)) {
-+		mtd->point   = cfi_intelext_point;
-+		mtd->unpoint = cfi_intelext_unpoint;
-+	}
-+}
-+
-+static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
-+{
-+	struct map_info *map = mtd->priv;
-+	struct cfi_private *cfi = map->fldrv_priv;
-+	if (cfi->cfiq->BufWriteTimeoutTyp) {
-+		printk(KERN_INFO "Using buffer write method\n" );
-+		mtd->write = cfi_intelext_write_buffers;
-+	}
-+}
-+
-+static struct cfi_fixup cfi_fixup_table[] = {
-+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE
-+	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_intel_strataflash, NULL }, 
-+#endif
-+#if !FORCE_WORD_WRITE
-+	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL },
-+#endif
-+	{ CFI_MFR_ST, 0x00ba, /* M28W320CT */ fixup_st_m28w320ct, NULL },
-+	{ CFI_MFR_ST, 0x00bb, /* M28W320CB */ fixup_st_m28w320cb, NULL },
-+	{ 0, 0, NULL, NULL }
-+};
-+
-+static struct cfi_fixup jedec_fixup_table[] = {
-+	{ MANUFACTURER_INTEL, I82802AB,   fixup_use_fwh_lock, NULL, },
-+	{ MANUFACTURER_INTEL, I82802AC,   fixup_use_fwh_lock, NULL, },
-+	{ MANUFACTURER_ST,    M50LPW080,  fixup_use_fwh_lock, NULL, },
-+	{ 0, 0, NULL, NULL }
-+};
-+static struct cfi_fixup fixup_table[] = {
-+	/* The CFI vendor ids and the JEDEC vendor IDs appear
-+	 * to be common.  It is like the devices id's are as
-+	 * well.  This table is to pick all cases where
-+	 * we know that is the case.
-+	 */
-+	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_point, NULL },
-+	{ 0, 0, NULL, NULL }
-+};
-+
- /* This routine is made available to other mtd code via
-  * inter_module_register.  It must only be accessed through
-  * inter_module_get which will bump the use count of this module.  The
-@@ -127,9 +222,30 @@
- struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
- {
- 	struct cfi_private *cfi = map->fldrv_priv;
-+	struct mtd_info *mtd;
- 	int i;
--	__u32 base = cfi->chips[0].start;
- 
-+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-+	if (!mtd) {
-+		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
-+		return NULL;
-+	}
-+	memset(mtd, 0, sizeof(*mtd));
-+	mtd->priv = map;
-+	mtd->type = MTD_NORFLASH;
-+
-+	/* Fill in the default mtd operations */
-+	mtd->erase   = cfi_intelext_erase_varsize;
-+	mtd->read    = cfi_intelext_read;
-+	mtd->write   = cfi_intelext_write_words;
-+	mtd->sync    = cfi_intelext_sync;
-+	mtd->lock    = cfi_intelext_lock;
-+	mtd->unlock  = cfi_intelext_unlock;
-+	mtd->suspend = cfi_intelext_suspend;
-+	mtd->resume  = cfi_intelext_resume;
-+	mtd->flags   = MTD_CAP_NORFLASH;
-+	mtd->name    = map->name;
-+	
- 	if (cfi->cfi_mode == CFI_MODE_CFI) {
- 		/* 
- 		 * It's a real CFI chip, not one for which the probe
-@@ -138,33 +254,10 @@
- 		 */
- 		__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)
--			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);
-+		extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp");
- 		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);
-+			kfree(mtd);
- 			return NULL;
- 		}
- 		
-@@ -172,6 +265,11 @@
- 		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(mtd, cfi_fixup_table);
- 			
- #ifdef DEBUG_CFI_FEATURES
- 		/* Tell the user about it in lots of lovely detail */
-@@ -179,19 +277,15 @@
- #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;	
- 	}
-+	else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
-+		/* Apply jedec specific fixups */
-+		cfi_fixup(mtd, jedec_fixup_table);
-+	}
-+	/* Apply generic fixups */
-+	cfi_fixup(mtd, fixup_table);
- 
- 	for (i=0; i< cfi->numchips; i++) {
- 		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
-@@ -202,30 +296,19 @@
- 
- 	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);
-+	return cfi_intelext_setup(mtd);
- }
- 
--static struct mtd_info *cfi_intelext_setup(struct map_info *map)
-+static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
- {
-+	struct map_info *map = mtd->priv;
- 	struct cfi_private *cfi = map->fldrv_priv;
--	struct mtd_info *mtd;
- 	unsigned long offset = 0;
- 	int i,j;
- 	unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
- 
--	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
- 	//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
- 
--	if (!mtd) {
--		printk(KERN_ERR "Failed to allocate memory for MTD device\n");
--		goto setup_err;
--	}
--
--	memset(mtd, 0, sizeof(*mtd));
--	mtd->priv = map;
--	mtd->type = MTD_NORFLASH;
- 	mtd->size = devsize * cfi->numchips;
- 
- 	mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
-@@ -265,32 +348,16 @@
- 		       mtd->eraseregions[i].numblocks);
- 	}
- 
--	/* Also select the correct geometry setup too */ 
--	mtd->erase = cfi_intelext_erase_varsize;
--	mtd->read = cfi_intelext_read;
--
--	if (map_is_linear(map)) {
--		mtd->point = cfi_intelext_point;
--		mtd->unpoint = cfi_intelext_unpoint;
--	}
--
--	if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) {
--		printk(KERN_INFO "Using buffer write method\n" );
--		mtd->write = cfi_intelext_write_buffers;
--	} else {
--		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;
--	mtd->sync = cfi_intelext_sync;
--	mtd->lock = cfi_intelext_lock;
--	mtd->unlock = cfi_intelext_unlock;
--	mtd->suspend = cfi_intelext_suspend;
--	mtd->resume = cfi_intelext_resume;
--	mtd->flags = MTD_CAP_NORFLASH;
--	map->fldrv = &cfi_intelext_chipdrv;
--	mtd->name = map->name;
-+#endif
-+
-+	/* 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 +368,87 @@
- 		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 +457,87 @@
- {
- 	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);
-@@ -347,38 +553,39 @@
- 		return 0;
- 
- 	case FL_ERASING:
--		if (!(cfip->FeatureSupport & 2) ||
-+		if (!cfip ||
-+		    !(cfip->FeatureSupport & 2) ||
- 		    !(mode == FL_READY || mode == FL_POINT ||
- 		     (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
- 			goto sleep;
- 
- 
- 		/* 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%x\n", status);
-+				       "suspended: status = 0x%lx\n", status.x[0]);
- 				return -EIO;
- 			}
- 
-@@ -412,6 +619,32 @@
- {
- 	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,13 +657,15 @@
- 		   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;
-@@ -449,7 +684,7 @@
- 	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);
- 
-@@ -457,7 +692,7 @@
- 
- 	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++;
-@@ -475,12 +710,10 @@
- 	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 */
-@@ -565,7 +798,7 @@
- 	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);
-@@ -575,7 +808,7 @@
- 	}
- 
- 	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;
- 	}
-@@ -626,7 +859,7 @@
- 	}
- 	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;
-@@ -657,7 +890,7 @@
- 		}
- 
- 		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;
- 		}
- 
-@@ -688,7 +921,7 @@
- 	int base_offst,reg_sz;
- 	
- 	/* Check that we actually have some protection registers */
--	if(!(extp->FeatureSupport&64)){
-+	if(!extp || !(extp->FeatureSupport&64)){
- 		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
- 		return 0;
- 	}
-@@ -707,7 +940,7 @@
- 	int base_offst,reg_sz;
- 	
- 	/* Check that we actually have some protection registers */
--	if(!(extp->FeatureSupport&64)){
-+	if(!extp || !(extp->FeatureSupport&64)){
- 		printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
- 		return 0;
- 	}
-@@ -717,12 +950,12 @@
- 
- 	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;
- 
-@@ -739,11 +972,12 @@
- 	}
- 
- 	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);
- 
-@@ -764,8 +998,8 @@
- 			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 */
-@@ -793,11 +1027,11 @@
- 	/* 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:
-@@ -824,35 +1058,22 @@
- 	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;
-@@ -865,30 +1086,18 @@
- 		}
- 	}
- 	
--	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 ++; 
-@@ -898,32 +1107,18 @@
- 		}
- 	}
- 
--	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;
-@@ -934,11 +1129,11 @@
- 				  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);
- 	
-@@ -952,29 +1147,28 @@
- 		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 %x). 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);
-@@ -983,84 +1177,47 @@
- 
- 		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;
-+		map_word datum;
- 
--		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;
--		}
-+		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);
- 
-@@ -1080,8 +1237,8 @@
- 			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 */
-@@ -1110,11 +1267,11 @@
-  	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;
- 	}
- 
-@@ -1129,7 +1286,7 @@
- {
- 	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;
-@@ -1142,8 +1299,8 @@
- 	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,
-@@ -1162,7 +1319,6 @@
- 		}
- 	}
- 
--	/* 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));
-@@ -1189,102 +1345,11 @@
- 	return 0;
- }
- 
--typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
--			      unsigned long adr, void *thunk);
--
--static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_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;
--	int chipnum, ret = 0;
--	int i, first;
--	struct mtd_erase_region_info *regions = mtd->eraseregions;
--
--	if (ofs > mtd->size)
--		return -EINVAL;
--
--	if ((len + ofs) > mtd->size)
--		return -EINVAL;
--
--	/* Check that both start and end of the requested erase are
--	 * aligned with the erasesize at the appropriate addresses.
--	 */
--
--	i = 0;
--
--	/* Skip all erase regions which are ended before the start of 
--	   the requested erase. Actually, to save on the calculations,
--	   we skip to the first erase region which starts after the
--	   start of the requested erase, and then go back one.
--	*/
--	
--	while (i < mtd->numeraseregions && ofs >= regions[i].offset)
--	       i++;
--	i--;
--
--	/* OK, now i is pointing at the erase region in which this 
--	   erase request starts. Check the start of the requested
--	   erase range is aligned with the erase size which is in
--	   effect here.
--	*/
--
--	if (ofs & (regions[i].erasesize-1))
--		return -EINVAL;
--
--	/* Remember the erase region we start on */
--	first = i;
--
--	/* Next, check that the end of the requested erase is aligned
--	 * with the erase region at that address.
--	 */
--
--	while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
--		i++;
--
--	/* As before, drop back one to point at the region in which
--	   the address actually falls
--	*/
--	i--;
--	
--	if ((ofs + len) & (regions[i].erasesize-1))
--		return -EINVAL;
--
--	chipnum = ofs >> cfi->chipshift;
--	adr = ofs - (chipnum << cfi->chipshift);
--
--	i=first;
--
--	while(len) {
--		ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk);
--		
--		if (ret)
--			return ret;
--
--		adr += regions[i].erasesize;
--		len -= regions[i].erasesize;
--
--		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
--			i++;
--
--		if (adr >> cfi->chipshift) {
--			adr = 0;
--			chipnum++;
--			
--			if (chipnum >= cfi->numchips)
--			break;
--		}
--	}
--
--	return 0;
--}
--
--
--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);
-@@ -1305,17 +1370,17 @@
- 
- 	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);
--	set_current_state(TASK_UNINTERRUPTIBLE);
--	schedule_timeout((chip->erase_time*HZ)/(2*1000));
-+	INVALIDATE_CACHED_RANGE(map, adr, len);
-+	msleep(chip->erase_time / 2);
- 	spin_lock(chip->mutex);
- 
- 	/* FIXME. Use a timer to check this, and return immediately. */
-@@ -1340,19 +1405,19 @@
- 			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;
-@@ -1369,43 +1434,46 @@
- 	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;
- 		}
- 	}
-@@ -1423,13 +1491,12 @@
- 	ofs = instr->addr;
- 	len = instr->len;
- 
--	ret = cfi_intelext_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0);
-+	ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
- 	if (ret)
- 		return ret;
- 
- 	instr->state = MTD_ERASE_DONE;
--	if (instr->callback)
--		instr->callback(instr);
-+	mtd_erase_callback(instr);
- 	
- 	return 0;
- }
-@@ -1475,7 +1542,8 @@
- }
- 
- #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;
-@@ -1483,8 +1551,7 @@
- 	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
-@@ -1492,10 +1559,11 @@
- #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;
- 
-@@ -1512,13 +1580,13 @@
- 	}
- 
- 	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();
-@@ -1533,15 +1601,16 @@
- 	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;
-@@ -1567,18 +1636,18 @@
- #ifdef DEBUG_LOCK_BITS
- 	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
- 	       __FUNCTION__, ofs, len);
--	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
--				  ofs, len, 0);
-+	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-+		ofs, len, 0);
- #endif
- 
--	ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, 
--					ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
-+	ret = cfi_varsize_frob(mtd, do_xxlock_oneblock, 
-+		ofs, len, DO_XXLOCK_ONEBLOCK_LOCK);
- 	
- #ifdef DEBUG_LOCK_BITS
--	printk(KERN_DEBUG __FUNCTION__
--	       "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
--	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
--				  ofs, len, 0);
-+	printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
-+	       __FUNCTION__, ret);
-+	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-+		ofs, len, 0);
- #endif
- 
- 	return ret;
-@@ -1591,17 +1660,18 @@
- #ifdef DEBUG_LOCK_BITS
- 	printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n",
- 	       __FUNCTION__, ofs, len);
--	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock,
--				  ofs, len, 0);
-+	cfi_varsize_frob(mtd, do_printlockstatus_oneblock,
-+		ofs, len, 0);
- #endif
- 
--	ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock,
-+	ret = cfi_varsize_frob(mtd, do_xxlock_oneblock,
- 					ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK);
- 	
- #ifdef DEBUG_LOCK_BITS
--	printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret);
--	cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, 
--				  ofs, len, 0);
-+	printk(KERN_DEBUG "%s: lock status after, ret=%d\n",
-+	       __FUNCTION__, ret);
-+	cfi_varsize_frob(mtd, do_printlockstatus_oneblock, 
-+		ofs, len, 0);
- #endif
- 	
- 	return ret;
-@@ -1679,7 +1749,7 @@
- 		
- 		/* 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);
- 		}
-@@ -1694,6 +1764,7 @@
- 	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: linux-2.6.5/drivers/mtd/chips/cfi_cmdset_0002.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/cfi_cmdset_0002.c	2004-04-03 22:36:57.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/cfi_cmdset_0002.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.109 2004/09/15 23:48:09 thayne Exp $
-  *
-  */
- 
-+#include <linux/config.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/kernel.h>
-@@ -24,17 +30,24 @@
- #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
-+
-+#define MANUFACTURER_AMD	0x0001
-+#define MANUFACTURER_SST	0x00BF
-+#define SST49LF004B	        0x0060
- 
- 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 void cfi_amdstd_sync (struct mtd_info *);
- static int cfi_amdstd_suspend (struct mtd_info *);
-@@ -44,8 +57,11 @@
- static void cfi_amdstd_destroy(struct mtd_info *);
- 
- struct mtd_info *cfi_cmdset_0002(struct map_info *, int);
--static struct mtd_info *cfi_amdstd_setup (struct map_info *);
-+static struct mtd_info *cfi_amdstd_setup (struct mtd_info *);
- 
-+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
-+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
-+#include "fwh_lock.h"
- 
- static struct mtd_chip_driver cfi_amdstd_chipdrv = {
- 	.probe		= NULL, /* Not usable directly */
-@@ -55,50 +71,199 @@
- };
- 
- 
-+/* #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 mtd_info *mtd, void* param)
-+{
-+	struct map_info *map = mtd->priv;
-+	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 void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
-+{
-+	struct map_info *map = mtd->priv;
-+	struct cfi_private *cfi = map->fldrv_priv;
-+	if (cfi->cfiq->BufWriteTimeoutTyp) {
-+		DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" );
-+		mtd->write = cfi_amdstd_write_buffers;
-+	}
-+}
-+
-+static void fixup_use_secsi(struct mtd_info *mtd, void *param)
-+{
-+	/* Setup for chips with a secsi area */
-+	mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
-+	mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
-+}
-+
-+static void fixup_use_erase_chip(struct mtd_info *mtd, void *param)
-+{
-+	struct map_info *map = mtd->priv;
-+	struct cfi_private *cfi = map->fldrv_priv;
-+	if ((cfi->cfiq->NumEraseRegions == 1) &&
-+		((cfi->cfiq->EraseRegionInfo[0] & 0xffff) == 0)) {
-+		mtd->erase = cfi_amdstd_erase_chip;
-+	}
-+	
-+}
-+
-+static struct cfi_fixup cfi_fixup_table[] = {
-+#ifdef AMD_BOOTLOC_BUG
-+	{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
-+#endif
-+	{ CFI_MFR_AMD, 0x0050, fixup_use_secsi, NULL, },
-+	{ CFI_MFR_AMD, 0x0053, fixup_use_secsi, NULL, },
-+	{ CFI_MFR_AMD, 0x0055, fixup_use_secsi, NULL, },
-+	{ CFI_MFR_AMD, 0x0056, fixup_use_secsi, NULL, },
-+	{ CFI_MFR_AMD, 0x005C, fixup_use_secsi, NULL, },
-+	{ CFI_MFR_AMD, 0x005F, fixup_use_secsi, NULL, },
-+#if !FORCE_WORD_WRITE
-+	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
-+#endif
-+	{ 0, 0, NULL, NULL }
-+};
-+static struct cfi_fixup jedec_fixup_table[] = {
-+	{ MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
-+	{ 0, 0, NULL, NULL }
-+};
-+
-+static struct cfi_fixup fixup_table[] = {
-+	/* The CFI vendor ids and the JEDEC vendor IDs appear
-+	 * to be common.  It is like the devices id's are as
-+	 * well.  This table is to pick all cases where
-+	 * we know that is the case.
-+	 */
-+	{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL },
-+	{ 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;
-+	struct mtd_info *mtd;
- 	int i;
--	__u8 major, minor;
--	__u32 base = cfi->chips[0].start;
-+
-+	mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
-+	if (!mtd) {
-+		printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
-+		return NULL;
-+	}
-+	memset(mtd, 0, sizeof(*mtd));
-+	mtd->priv = map;
-+	mtd->type = MTD_NORFLASH;
-+
-+	/* Fill in the default mtd operations */
-+	mtd->erase   = cfi_amdstd_erase_varsize;
-+	mtd->write   = cfi_amdstd_write_words;
-+	mtd->read    = cfi_amdstd_read;
-+	mtd->sync    = cfi_amdstd_sync;
-+	mtd->suspend = cfi_amdstd_suspend;
-+	mtd->resume  = cfi_amdstd_resume;
-+	mtd->flags   = MTD_CAP_NORFLASH;
-+	mtd->name    = map->name;
- 
- 	if (cfi->cfi_mode==CFI_MODE_CFI){
-+		unsigned char bootloc;
-+		/* 
-+		 * 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;
- 
--		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);    
-+		extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu");
-+		if (!extp) {
-+			kfree(mtd);
-+			return NULL;
-+		}
-+
-+		/* Install our own private info structure */
-+		cfi->cmdset_priv = extp;	
-+
-+		/* Apply cfi device specific fixups */
-+		cfi_fixup(mtd, cfi_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;
-+		}
- 
--		/* 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,32 +277,50 @@
- 			}
- 		}
- 		/*
--		 * 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);
-+				kfree(mtd);
-+				kfree(extp);
-+				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 */
-+	else if (cfi->cfi_mode == CFI_MODE_JEDEC) {
-+		/* Apply jedec specific fixups */
-+		cfi_fixup(mtd, jedec_fixup_table);
-+	}
-+	/* Apply generic fixups */
-+	cfi_fixup(mtd, fixup_table);
- 
- 	for (i=0; i< cfi->numchips; i++) {
- 		cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
-@@ -146,135 +329,66 @@
- 	}		
- 	
- 	map->fldrv = &cfi_amdstd_chipdrv;
--
--	cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL);
--	return cfi_amdstd_setup(map);
-+	
-+	return cfi_amdstd_setup(mtd);
- }
- 
--static struct mtd_info *cfi_amdstd_setup(struct map_info *map)
-+
-+static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
- {
-+	struct map_info *map = mtd->priv;
- 	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);
-+	/* Select the correct geometry setup */ 
-+	mtd->size = devsize * cfi->numchips;
- 
--	if (!mtd) {
--	  printk(KERN_WARNING "Failed to allocate memory for MTD device\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;
- 	}
--
--	memset(mtd, 0, sizeof(*mtd));
--	mtd->priv = 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;
--		}
- 			
--		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 (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 (mtd->erasesize < ersize) {
-+			mtd->erasesize = ersize;
- 		}
--#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
--	}
--
--	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");
-+		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;
--		break;
- 	}
--	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 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
- 
-+	/* 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){
--		case 0x50:
--		case 0x53:
--		case 0x55:
--		case 0x56:
--		case 0x5C:
--		case 0x5F:
--			/* Yes */
--			mtd->read_user_prot_reg = cfi_amdstd_secsi_read;
--			mtd->read_fact_prot_reg = cfi_amdstd_secsi_read;
--		default:		       
--			;
--		}
--	}
--	
--		
--	mtd->sync = cfi_amdstd_sync;
--	mtd->suspend = cfi_amdstd_suspend;
--	mtd->resume = cfi_amdstd_resume;
--	mtd->flags = MTD_CAP_NORFLASH;
--	map->fldrv = &cfi_amdstd_chipdrv;
--	mtd->name = map->name;
- 	__module_get(THIS_MODULE);
- 	return mtd;
- 
-@@ -289,46 +403,182 @@
- 	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
-+		      || !cfip
-+		      || (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 +620,7 @@
- 	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 +632,11 @@
- 
- 	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 +653,15 @@
- 	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 +716,388 @@
- 	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;
- 
-+	adr += chip->start;
-+
-+	cfi_spin_lock(chip->mutex);
-+	ret = get_chip(map, chip, adr, FL_WRITING);
-+	if (ret) {
-+		cfi_spin_unlock(chip->mutex);
-+		return ret;
-+	}
-+
-+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
-+	       __func__, adr, datum.x[0] );
-+
-+	/*
-+	 * 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);
-  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);
- 
--	if (chip->state != FL_READY) {
-+	/* See comment above for timeout value. */
-+	timeo = jiffies + uWriteTimeout; 
-+	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);
-+			schedule();
-+			remove_wait_queue(&chip->wq, &wait);
-+			timeo = jiffies + (HZ / 2); /* FIXME */
-+			cfi_spin_lock(chip->mutex);
-+			continue;
-+		}
-+
-+		/* 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 (time_after(jiffies, timeo)) {
-+			printk(KERN_WARNING "MTD %s(): software timeout\n",
-+				__func__ );
-+			break;
-+		}
-+
-+		/* Latency issues. Drop the lock, wait a while and retry */
-+		cfi_spin_unlock(chip->mutex);
-+		cfi_udelay(1);
-+		cfi_spin_lock(chip->mutex);
-+	}
-+
-+	/* reset on all failures. */
-+	map_write( map, CMD(0xF0), chip->start );
-+	/* FIXME - should have reset delay before continuing */
-+	if (++retry_cnt <= MAX_WORD_RETRIES) 
-+		goto retry;
-+
-+	ret = -EIO;
-+ op_done:
-+	chip->state = FL_READY;
-+	put_chip(map, chip, adr);
-+	cfi_spin_unlock(chip->mutex);
-+
-+	return ret;
-+}
-+
-+
-+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)
-+		return 0;
-+
-+	chipnum = to >> cfi->chipshift;
-+	ofs = to  - (chipnum << cfi->chipshift);
-+	chipstart = cfi->chips[chipnum].start;
-+
-+	/* If it's not bus-aligned, do the first byte write */
-+	if (ofs & (map_bankwidth(map)-1)) {
-+		unsigned long bus_ofs = ofs & ~(map_bankwidth(map)-1);
-+		int i = ofs - bus_ofs;
-+		int n = 0;
-+		map_word tmp_buf;
-+
-+ retry:
-+		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", chip->state);
-+			printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state);
- #endif
--		set_current_state(TASK_UNINTERRUPTIBLE);
--		add_wait_queue(&chip->wq, &wait);
--                
--		cfi_spin_unlock(chip->mutex);
-+			set_current_state(TASK_UNINTERRUPTIBLE);
-+			add_wait_queue(&cfi->chips[chipnum].wq, &wait);
- 
--		schedule();
--		remove_wait_queue(&chip->wq, &wait);
-+			cfi_spin_unlock(cfi->chips[chipnum].mutex);
-+
-+			schedule();
-+			remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
- #if 0
--		printk(KERN_DEBUG "Wake up to write:\n");
--		if(signal_pending(current))
--			return -EINTR;
-+			if(signal_pending(current))
-+				return -EINTR;
- #endif
--		timeo = jiffies + HZ;
-+			goto retry;
-+		}
- 
--		goto retry;
--	}	
-+		/* Load 'tmp_buf' with old contents of flash */
-+		tmp_buf = map_read(map, bus_ofs+chipstart);
- 
--	chip->state = FL_WRITING;
-+		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, tmp_buf);
-+		if (ret) 
-+			return ret;
-+		
-+		ofs += n;
-+		buf += n;
-+		(*retlen) += n;
-+		len -= n;
-+
-+		if (ofs >> cfi->chipshift) {
-+			chipnum ++; 
-+			ofs = 0;
-+			if (chipnum == cfi->numchips)
-+				return 0;
-+		}
-+	}
-+	
-+	/* We are now aligned, write as much as possible */
-+	while(len >= map_bankwidth(map)) {
-+		map_word datum;
-+
-+		datum = map_word_load(map, buf);
-+
-+		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;
-+		}
-+	}
-+
-+	/* Write the trailing bytes if any */
-+	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, tmp_buf);
-+		if (ret) 
-+			return ret;
-+		
-+		(*retlen) += len;
-+	}
-+
-+	return 0;
-+}
-+
-+
-+/*
-+ * 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)
-+{
-+	struct cfi_private *cfi = map->fldrv_priv;
-+	unsigned long timeo = jiffies + HZ;
-+	/* see comments in do_write_oneword() regarding uWriteTimeo. */
-+	unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
-+	int ret = -EIO;
-+	unsigned long cmd_adr;
-+	int z, words;
-+	map_word datum;
- 
- 	adr += chip->start;
--	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n",
--	       __func__, adr, datum );
-+	cmd_adr = adr;
- 
--	ENABLE_VPP(map);
--	if (fast) { /* Unlock bypass */
--		cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL);
-+	cfi_spin_lock(chip->mutex);
-+	ret = get_chip(map, chip, adr, FL_WRITING);
-+	if (ret) {
-+		cfi_spin_unlock(chip->mutex);
-+		return ret;
- 	}
--	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);
-+
-+	datum = map_word_load(map, buf);
-+
-+	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
-+	       __func__, adr, datum.x[0] );
-+
-+	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(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+
-+	/* Write Buffer Load */
-+	map_write(map, CMD(0x25), cmd_adr);
-+
-+	chip->state = FL_WRITING_TO_BUFFER;
-+
-+	/* 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);
-+
-+		z += map_bankwidth(map);
-+		buf += map_bankwidth(map);
- 	}
--	cfi_write(map, datum, adr);
-+	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->word_write_time);
-+	cfi_udelay(chip->buffer_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);
-+			continue;
-+		}
- 
--		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_ready(map, adr))
-+			goto op_done;
-+		    
-+		if( time_after(jiffies, timeo))
-+			break;
- 
--	/*
--	 * 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;
--	}
--
--	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 write_failed;
-+		/* Latency issues. Drop the lock, wait a while and retry */
-+		cfi_spin_unlock(chip->mutex);
-+		cfi_udelay(1);
-+		cfi_spin_lock(chip->mutex);
- 	}
- 
--	/*
--	 * 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",
-+	printk(KERN_WARNING "MTD %s(): software timeout\n",
- 	       __func__ );
- 
--	printk(KERN_WARNING
--	       "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
--	       __func__, adr, datum,
--	       prev_oldstatus, prev_status,
--	       oldstatus, status);
--
-- 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 */
- 
-- 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_buffers(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 wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
- 	int ret = 0;
- 	int chipnum;
--	unsigned long ofs, chipstart;
-+	unsigned long ofs;
- 
- 	*retlen = 0;
- 	if (!len)
-@@ -679,176 +1105,94 @@
- 
- 	chipnum = to >> cfi->chipshift;
- 	ofs = to  - (chipnum << cfi->chipshift);
--	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);
--		int i = ofs - bus_ofs;
--		int n = 0;
--		u_char tmp_buf[8];
--		cfi_word datum;
--
--		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--;
--
--		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 */
--		}
- 
--		ret = do_write_oneword(map, &cfi->chips[chipnum], 
--				       bus_ofs, datum, 0);
--		if (ret) 
-+	/* 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, ofs + (chipnum<<cfi->chipshift),
-+					     local_len, retlen, buf);
-+		if (ret)
- 			return ret;
--		
--		ofs += n;
--		buf += n;
--		(*retlen) += n;
-+		ofs += local_len;
-+		buf += local_len;
-+		len -= local_len;
- 
- 		if (ofs >> cfi->chipshift) {
--			chipnum ++; 
-+			chipnum ++;
- 			ofs = 0;
- 			if (chipnum == cfi->numchips)
- 				return 0;
- 		}
- 	}
--	
--	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;
-+	/* 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);
- 
--		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);
--			}
-+		ret = do_write_buffer(map, &cfi->chips[chipnum], 
-+				      ofs, buf, size);
-+		if (ret)
- 			return ret;
--		}
- 
--		ofs += CFIDEV_BUSWIDTH;
--		buf += CFIDEV_BUSWIDTH;
--		(*retlen) += CFIDEV_BUSWIDTH;
--		len -= CFIDEV_BUSWIDTH;
-+		ofs += size;
-+		buf += size;
-+		(*retlen) += size;
-+		len -= size;
- 
- 		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);
--			}
--
- 			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);
--	}
-+	if (len) {
-+		size_t retlen_dregs = 0;
- 
--	/* 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 */
--		}
-+		ret = cfi_amdstd_write_words(mtd, ofs + (chipnum<<cfi->chipshift),
-+					     len, &retlen_dregs, buf);
- 
--		ret = do_write_oneword(map, &cfi->chips[chipnum], 
--				ofs, datum, 0);
--		if (ret) 
--			return ret;
--		
--		(*retlen) += n;
-+		*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)
- {
--	unsigned int oldstatus, status, prev_oldstatus, prev_status;
--	unsigned int dq6;
-+	struct cfi_private *cfi = map->fldrv_priv;
- 	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;
- 
-- retry:
--	cfi_spin_lock(chip->mutex);
-+	adr = cfi->addr_unlock1;
- 
--	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;
--
--		goto retry;
--	}	
--
--	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);
-@@ -856,175 +1200,82 @@
- 	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;
- 
--	/* 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 );
--
--	while( ( ( status ^ oldstatus ) & dq6 )
--	       && ! ( ta = time_after(jiffies, timeo) ) ) {
--		int wait_reps;
-+	cfi_spin_unlock(chip->mutex);
-+	set_current_state(TASK_UNINTERRUPTIBLE);
-+	schedule_timeout((chip->erase_time*HZ)/(2*1000));
-+	cfi_spin_lock(chip->mutex);
- 
--		/* an initial short sleep */
--		cfi_spin_unlock(chip->mutex);
--		schedule_timeout(HZ/100);
--		cfi_spin_lock(chip->mutex);
--		
-+	timeo = jiffies + (HZ*20);
-+
-+	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("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;
- 		}
-+		if (chip->erase_suspended) {
-+			/* This erase was suspended and resumed.
-+			   Adjust the timeout */
-+			timeo = jiffies + (HZ*20); /* FIXME */
-+			chip->erase_suspended = 0;
-+		}
- 
--		/* 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);
-+		if (chip_ready(map, adr))
-+			goto op_done;
- 
--			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 (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%.8x): 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 inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
- {
--	unsigned int oldstatus, status, prev_oldstatus, prev_status;
--	unsigned int dq6;
--	unsigned long timeo = jiffies + HZ;
- 	struct cfi_private *cfi = map->fldrv_priv;
-+	unsigned long timeo = jiffies + HZ;
- 	DECLARE_WAITQUEUE(wait, current);
- 	int ret = 0;
--	int ta = 0;
--	cfi_word ones = 0;
- 
-- retry:
--	cfi_spin_lock(chip->mutex);
-+	adr += chip->start;
- 
--	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_ERASING);
-+	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;
--
--		goto retry;
--	}	
--
--	chip->state = FL_ERASING;
--
--	adr += chip->start;
- 	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
- 	       __func__, adr );
- 
-@@ -1034,279 +1285,85 @@
- 	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);
- 
--	cfi_write(map, CMD(0x30), adr);
-+	chip->state = FL_ERASING;
-+	chip->erase_suspended = 0;
-+	chip->in_progress_block_addr = 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);
-+	cfi_spin_unlock(chip->mutex);
-+	set_current_state(TASK_UNINTERRUPTIBLE);
-+	schedule_timeout((chip->erase_time*HZ)/(2*1000));
-+	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 );
--
--	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 );
--		}
--		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 ( 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__ );
-+		if (chip->erase_suspended) {
-+			/* This erase was suspended and resumed.
-+			   Adjust the timeout */
-+			timeo = jiffies + (HZ*20); /* FIXME */
-+			chip->erase_suspended = 0;
- 		}
--		goto erase_failed;
--	}
- 
--	printk(KERN_WARNING
--	       "MTD %s(): Wacky!  Unable to decode failure status\n",
--	       __func__ );
-+		if (chip_ready(map, adr))
-+			goto op_done;
- 
--	printk(KERN_WARNING
--	       "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n",
--	       __func__, adr, ones,
--	       prev_oldstatus, prev_status,
--	       oldstatus, status);
-+		if (time_after(jiffies, timeo))
-+			break;
- 
-- erase_failed:
--	ret = -EIO;
-+		/* 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. */
--	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)
--{
--	struct map_info *map = mtd->priv;
--	struct cfi_private *cfi = map->fldrv_priv;
--	unsigned long adr, len;
--	int chipnum, ret = 0;
--	int i, first;
--	struct mtd_erase_region_info *regions = mtd->eraseregions;
--
--	if (instr->addr > mtd->size)
--		return -EINVAL;
--
--	if ((instr->len + instr->addr) > mtd->size)
--		return -EINVAL;
--
--	/* Check that both start and end of the requested erase are
--	 * aligned with the erasesize at the appropriate addresses.
--	 */
--
--	i = 0;
--
--	/* Skip all erase regions which are ended before the start of 
--	   the requested erase. Actually, to save on the calculations,
--	   we skip to the first erase region which starts after the
--	   start of the requested erase, and then go back one.
--	*/
--	
--	while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
--	       i++;
--	i--;
--
--	/* OK, now i is pointing at the erase region in which this 
--	   erase request starts. Check the start of the requested
--	   erase range is aligned with the erase size which is in
--	   effect here.
--	*/
--
--	if (instr->addr & (regions[i].erasesize-1))
--		return -EINVAL;
--
--	/* Remember the erase region we start on */
--	first = i;
--
--	/* Next, check that the end of the requested erase is aligned
--	 * with the erase region at that address.
--	 */
--
--	while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
--		i++;
--
--	/* As before, drop back one to point at the region in which
--	   the address actually falls
--	*/
--	i--;
--	
--	if ((instr->addr + instr->len) & (regions[i].erasesize-1))
--		return -EINVAL;
--	
--	chipnum = instr->addr >> cfi->chipshift;
--	adr = instr->addr - (chipnum << cfi->chipshift);
--	len = instr->len;
--
--	i=first;
--
--	while(len) {
--		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
--
--		if (ret)
--			return ret;
--
--		adr += regions[i].erasesize;
--		len -= regions[i].erasesize;
--
--		if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
--			i++;
--
--		if (adr >> cfi->chipshift) {
--			adr = 0;
--			chipnum++;
--			
--			if (chipnum >= cfi->numchips)
--			break;
--		}
--	}
--
--	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)
-+int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
- {
--	struct map_info *map = mtd->priv;
--	struct cfi_private *cfi = map->fldrv_priv;
--	unsigned long adr, len;
--	int chipnum, ret = 0;
--
--	if (instr->addr & (mtd->erasesize - 1))
--		return -EINVAL;
--
--	if (instr->len & (mtd->erasesize -1))
--		return -EINVAL;
--
--	if ((instr->len + instr->addr) > mtd->size)
--		return -EINVAL;
-+	unsigned long ofs, len;
-+	int ret;
- 
--	chipnum = instr->addr >> cfi->chipshift;
--	adr = instr->addr - (chipnum << cfi->chipshift);
-+	ofs = instr->addr;
- 	len = instr->len;
- 
--	while(len) {
--		ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
--
--		if (ret)
--			return ret;
--
--		adr += mtd->erasesize;
--		len -= mtd->erasesize;
-+	ret = cfi_varsize_frob(mtd, do_erase_oneblock, ofs, len, NULL);
-+	if (ret)
-+		return ret;
- 
--		if (adr >> cfi->chipshift) {
--			adr = 0;
--			chipnum++;
--			
--			if (chipnum >= cfi->numchips)
--			break;
--		}
--	}
--		
- 	instr->state = MTD_ERASE_DONE;
--	if (instr->callback)
--		instr->callback(instr);
-+	mtd_erase_callback(instr);
- 	
- 	return 0;
- }
- 
-+
- static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
- {
- 	struct map_info *map = mtd->priv;
-@@ -1324,12 +1381,12 @@
- 		return ret;
- 
- 	instr->state = MTD_ERASE_DONE;
--	if (instr->callback)
--		instr->callback(instr);
-+	mtd_erase_callback(instr);
- 	
- 	return 0;
- }
- 
-+
- static void cfi_amdstd_sync (struct mtd_info *mtd)
- {
- 	struct map_info *map = mtd->priv;
-@@ -1368,7 +1425,7 @@
- 
- 			schedule();
- 
--		        remove_wait_queue(&chip->wq, &wait);
-+			remove_wait_queue(&chip->wq, &wait);
- 			
- 			goto retry;
- 		}
-@@ -1427,7 +1484,7 @@
- 	/* 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 +1500,7 @@
- 	return ret;
- }
- 
-+
- static void cfi_amdstd_resume(struct mtd_info *mtd)
- {
- 	struct map_info *map = mtd->priv;
-@@ -1458,7 +1516,7 @@
- 		
- 		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
-@@ -1480,21 +1538,23 @@
- 
- 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: linux-2.6.5/drivers/mtd/chips/cfi_cmdset_0020.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/cfi_cmdset_0020.c	2004-04-03 22:36:55.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/cfi_cmdset_0020.c	2005-02-01 17:11:17.000000000 -0500
-@@ -4,6 +4,7 @@
-  *
-  * (C) 2000 Red Hat. GPL'd
-  *
-+ * $Id: cfi_cmdset_0020.c,v 1.15 2004/08/09 13:19:43 dwmw2 Exp $
-  * 
-  * 10/10/2000	Nicolas Pitre <nico@cam.org>
-  * 	- completely revamped method functions so they are aware and
-@@ -38,7 +39,7 @@
- 
- static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
- static int cfi_staa_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
--static int cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+static int cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,
- 		unsigned long count, loff_t to, size_t *retlen);
- static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *);
- static void cfi_staa_sync (struct mtd_info *);
-@@ -116,7 +117,6 @@
- {
- 	struct cfi_private *cfi = map->fldrv_priv;
- 	int i;
--	__u32 base = cfi->chips[0].start;
- 
- 	if (cfi->cfi_mode) {
- 		/* 
-@@ -126,36 +126,11 @@
- 		 */
- 		__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 @@
- 		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 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 @@
- 	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 @@
- 	 */
- 	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 @@
- 		}
- 		
- 		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 @@
- 
- 	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 @@
- 		/* 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 @@
- 		   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 @@
- 				  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 @@
- 		
- 	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 = %x\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 @@
- 	}
- 
- 	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 @@
- 		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 @@
- 			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 @@
- 	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 @@
- {
- 	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 @@
- 	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
-@@ -700,7 +657,7 @@
- #define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1))
- #define ECCBUF_MOD(x) ((x) &  (ECCBUF_SIZE - 1))
- static int
--cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs,
- 		unsigned long count, loff_t to, size_t *retlen)
- {
- 	unsigned long i;
-@@ -769,7 +726,7 @@
- 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 @@
- 	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 @@
- 
- 	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 @@
- 			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 = %x.\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 @@
- 	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;
- 		}
- 	}
-@@ -1006,8 +966,7 @@
- 	}
- 		
- 	instr->state = MTD_ERASE_DONE;
--	if (instr->callback)
--		instr->callback(instr);
-+	mtd_erase_callback(instr);
- 	
- 	return 0;
- }
-@@ -1072,7 +1031,7 @@
- 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 +1049,12 @@
- 	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 +1082,8 @@
- 	}
- 
- 	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 +1096,15 @@
- 	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 = %x.\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 +1180,7 @@
- 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 +1198,12 @@
- 	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 +1231,8 @@
- 	}
- 
- 	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 +1245,15 @@
- 	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 = %x.\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 +1382,7 @@
- 		
- 		/* 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);
- 		}
-@@ -1440,11 +1399,6 @@
- 	kfree(cfi);
- }
- 
--#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
--#define cfi_staa_init init_module
--#define cfi_staa_exit cleanup_module
--#endif
--
- static char im_name[]="cfi_cmdset_0020";
- 
- int __init cfi_staa_init(void)
-Index: linux-2.6.5/drivers/mtd/chips/cfi_probe.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/cfi_probe.c	2004-04-03 22:37:40.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/cfi_probe.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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 @@
- #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 @@
-    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 @@
- 		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 @@
- 	}
- 
- 	/* 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 @@
- 			 * 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 @@
- 	
- 	/* 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 @@
- 	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 @@
- 		       (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 @@
- 		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: linux-2.6.5/drivers/mtd/chips/cfi_util.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/cfi_util.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/cfi_util.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,188 @@
-+/*
-+ * Common Flash Interface support:
-+ *   Generic utility functions not dependant on command set
-+ *
-+ * Copyright (C) 2002 Red Hat
-+ * Copyright (C) 2003 STMicroelectronics Limited
-+ *
-+ * This code is covered by the GPL.
-+ *
-+ * $Id: cfi_util.c,v 1.5 2004/08/12 06:40:23 eric Exp $
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <asm/io.h>
-+#include <asm/byteorder.h>
-+
-+#include <linux/errno.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/interrupt.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/cfi.h>
-+#include <linux/mtd/compatmac.h>
-+
-+struct cfi_extquery *
-+cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
-+{
-+	struct cfi_private *cfi = map->fldrv_priv;
-+	__u32 base = 0; // cfi->chips[0].start;
-+	int ofs_factor = cfi->interleave * cfi->device_type;
-+	int i;
-+	struct cfi_extquery *extp = NULL;
-+
-+	printk(" %s Extended Query Table at 0x%4.4X\n", name, adr);
-+	if (!adr)
-+		goto out;
-+
-+	/* Switch it into Query Mode */
-+	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
-+
-+	extp = kmalloc(size, GFP_KERNEL);
-+	if (!extp) {
-+		printk(KERN_ERR "Failed to allocate memory\n");
-+		goto out;
-+	}
-+		
-+	/* Read in the Extended Query Table */
-+	for (i=0; i<size; i++) {
-+		((unsigned char *)extp)[i] = 
-+			cfi_read_query(map, base+((adr+i)*ofs_factor));
-+	}
-+
-+	if (extp->MajorVersion != '1' || 
-+	    (extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
-+		printk(KERN_WARNING "  Unknown %s Extended Query "
-+		       "version %c.%c.\n",  name, extp->MajorVersion,
-+		       extp->MinorVersion);
-+		kfree(extp);
-+		extp = NULL;
-+		goto out;
-+	}
-+
-+out:
-+	/* Make sure it's in read mode */
-+	cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
-+	cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
-+
-+	return extp;
-+}
-+
-+EXPORT_SYMBOL(cfi_read_pri);
-+
-+void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup *fixups)
-+{
-+	struct map_info *map = mtd->priv;
-+	struct cfi_private *cfi = map->fldrv_priv;
-+	struct cfi_fixup *f;
-+
-+	for (f=fixups; f->fixup; f++) {
-+		if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
-+		    ((f->id  == CFI_ID_ANY)  || (f->id  == cfi->id))) {
-+			f->fixup(mtd, f->param);
-+		}
-+	}
-+}
-+
-+EXPORT_SYMBOL(cfi_fixup);
-+
-+int cfi_varsize_frob(struct mtd_info *mtd, varsize_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;
-+	int chipnum, ret = 0;
-+	int i, first;
-+	struct mtd_erase_region_info *regions = mtd->eraseregions;
-+
-+	if (ofs > mtd->size)
-+		return -EINVAL;
-+
-+	if ((len + ofs) > mtd->size)
-+		return -EINVAL;
-+
-+	/* Check that both start and end of the requested erase are
-+	 * aligned with the erasesize at the appropriate addresses.
-+	 */
-+
-+	i = 0;
-+
-+	/* Skip all erase regions which are ended before the start of 
-+	   the requested erase. Actually, to save on the calculations,
-+	   we skip to the first erase region which starts after the
-+	   start of the requested erase, and then go back one.
-+	*/
-+	
-+	while (i < mtd->numeraseregions && ofs >= regions[i].offset)
-+	       i++;
-+	i--;
-+
-+	/* OK, now i is pointing at the erase region in which this 
-+	   erase request starts. Check the start of the requested
-+	   erase range is aligned with the erase size which is in
-+	   effect here.
-+	*/
-+
-+	if (ofs & (regions[i].erasesize-1))
-+		return -EINVAL;
-+
-+	/* Remember the erase region we start on */
-+	first = i;
-+
-+	/* Next, check that the end of the requested erase is aligned
-+	 * with the erase region at that address.
-+	 */
-+
-+	while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset)
-+		i++;
-+
-+	/* As before, drop back one to point at the region in which
-+	   the address actually falls
-+	*/
-+	i--;
-+	
-+	if ((ofs + len) & (regions[i].erasesize-1))
-+		return -EINVAL;
-+
-+	chipnum = ofs >> cfi->chipshift;
-+	adr = ofs - (chipnum << cfi->chipshift);
-+
-+	i=first;
-+
-+	while(len) {
-+		unsigned long chipmask;
-+		int size = regions[i].erasesize;
-+
-+		ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
-+		
-+		if (ret)
-+			return ret;
-+
-+		adr += size;
-+		len -= size;
-+
-+		chipmask = (1 << cfi->chipshift) - 1;
-+		if ((adr & chipmask) == ((regions[i].offset + size * regions[i].numblocks) & chipmask))
-+			i++;
-+
-+		if (adr >> cfi->chipshift) {
-+			adr = 0;
-+			chipnum++;
-+			
-+			if (chipnum >= cfi->numchips)
-+			break;
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+EXPORT_SYMBOL(cfi_varsize_frob);
-+
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.5/drivers/mtd/chips/chipreg.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/chipreg.c	2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/chipreg.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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: linux-2.6.5/drivers/mtd/chips/fwh_lock.h
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/fwh_lock.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/fwh_lock.h	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,107 @@
-+#ifndef FWH_LOCK_H
-+#define FWH_LOCK_H
-+
-+
-+enum fwh_lock_state {
-+        FWH_UNLOCKED   = 0,
-+	FWH_DENY_WRITE = 1,
-+	FWH_IMMUTABLE  = 2,
-+	FWH_DENY_READ  = 4,
-+};
-+
-+struct fwh_xxlock_thunk {
-+	enum fwh_lock_state val;
-+	flstate_t state;
-+};
-+
-+
-+#define FWH_XXLOCK_ONEBLOCK_LOCK   ((struct fwh_xxlock_thunk){ FWH_DENY_WRITE, FL_LOCKING})
-+#define FWH_XXLOCK_ONEBLOCK_UNLOCK ((struct fwh_xxlock_thunk){ FWH_UNLOCKED,   FL_UNLOCKING})
-+
-+/*
-+ * This locking/unlock is specific to firmware hub parts.  Only one
-+ * is known that supports the Intel command set.    Firmware
-+ * hub parts cannot be interleaved as they are on the LPC bus
-+ * so this code has not been tested with interleaved chips,
-+ * and will likely fail in that context.
-+ */
-+static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, 
-+	unsigned long adr, int len, void *thunk)
-+{
-+	struct cfi_private *cfi = map->fldrv_priv;
-+	struct fwh_xxlock_thunk *xxlt = (struct fwh_xxlock_thunk *)thunk;
-+	int ret;
-+
-+	/* Refuse the operation if the we cannot look behind the chip */
-+	if (chip->start < 0x400000) {
-+		DEBUG( MTD_DEBUG_LEVEL3,
-+			"MTD %s(): chip->start: %lx wanted >= 0x400000\n",
-+			__func__, chip->start );
-+		return -EIO;
-+	}
-+	/*
-+	 * lock block registers:
-+	 * - on 64k boundariesand
-+	 * - bit 1 set high
-+	 * - block lock registers are 4MiB lower - overflow subtract (danger)
-+	 * 
-+	 * The address manipulation is first done on the logical address
-+	 * which is 0 at the start of the chip, and then the offset of
-+	 * the individual chip is addted to it.  Any other order a weird
-+	 * map offset could cause problems.
-+	 */
-+	adr = (adr & ~0xffffUL) | 0x2;
-+	adr += chip->start - 0x400000;
-+
-+	/*
-+	 * 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.
-+	 */
-+	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 fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
-+{
-+	int ret;
-+
-+	ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
-+		(void *)&FWH_XXLOCK_ONEBLOCK_LOCK);
-+
-+	return ret;
-+}
-+
-+
-+static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len)
-+{
-+	int ret;
-+
-+	ret = cfi_varsize_frob(mtd, fwh_xxlock_oneblock, ofs, len,
-+		(void *)&FWH_XXLOCK_ONEBLOCK_UNLOCK);
-+	
-+	return ret;
-+}
-+
-+static void fixup_use_fwh_lock(struct mtd_info *mtd, void *param)
-+{
-+	printk(KERN_NOTICE "using fwh lock/unlock method\n");
-+	/* Setup for the chips with the fwh lock method */
-+	mtd->lock   = fwh_lock_varsize;
-+	mtd->unlock = fwh_unlock_varsize;
-+}
-+#endif /* FWH_LOCK_H */
-Index: linux-2.6.5/drivers/mtd/chips/gen_probe.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/gen_probe.c	2005-02-01 16:55:45.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/gen_probe.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.21 2004/08/14 15:14:05 dwmw2 Exp $
-  */
- 
- #include <linux/kernel.h>
-@@ -50,24 +50,22 @@
- 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. */
- 	if (!genprobe_new_chip(map, cp, &cfi)) {
- 		/* The probe didn't like it */
--		DEBUG(MTD_DEBUG_LEVEL3,
--		      "MTD %s(): %s: Found no %s device at location zero\n",
--		      __func__, cp->name, map->name);
-+		printk(KERN_DEBUG "%s: Found no %s device at location zero\n",
-+		       cp->name, map->name);
- 		return NULL;
- 	}		
- 
-@@ -81,46 +79,47 @@
- 		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 
-@@ -132,19 +131,26 @@
- 	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);
-+	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++];
- 
--	/* 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;
-+			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;
- }
- 
-@@ -152,131 +158,31 @@
- 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;
-+
-+		/* Minimum device size. Don't look for one 8-bit device
-+		   in a 16-bit bus, etc. */
-+		type = map_bankwidth(map) / nr_chips;
-+
-+		for (; type <= CFI_DEVICETYPE_X32; type<<=1) {
-+			cfi->device_type = 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: linux-2.6.5/drivers/mtd/chips/jedec.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/jedec.c	2004-04-03 22:37:23.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/jedec.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.21 2004/08/09 13:19:43 dwmw2 Exp $
-  */
- 
- #include <linux/init.h>
-@@ -128,7 +128,7 @@
-    {
-       printk("mtd: Increase MAX_JEDEC_CHIPS, too many banks.\n");
-       kfree(MTD);
--      return 0;
-+      return NULL;
-    }
-    
-    for (Base = 0; Base < map->size; Base += my_bank_size)
-@@ -141,7 +141,7 @@
- 	 if (jedec_probe8(map,Base,priv) == 0) {
- 		 printk("did recognize jedec chip\n");
- 		 kfree(MTD);
--	         return 0;
-+	         return NULL;
- 	 }
-       }
-       if (map->buswidth == 2)
-@@ -167,7 +167,7 @@
-       {
- 	 printk("mtd: Failed. Device has incompatible mixed sector sizes\n");
- 	 kfree(MTD);
--	 return 0;
-+	 return NULL;
-       }      
-    }
-    
-@@ -193,7 +193,7 @@
-       {
- 	 printk("mtd: Internal Error, JEDEC not set\n");
- 	 kfree(MTD);
--	 return 0;
-+	 return NULL;
-       }
-       
-       if (Uniq != 0)
-@@ -221,7 +221,7 @@
-    if (!priv->size) {
- 	   printk("priv->size is zero\n");
- 	   kfree(MTD);
--	   return 0;
-+	   return NULL;
-    }
-    if (priv->size/my_bank_size) {
- 	   if (priv->size/my_bank_size == 1) {
-@@ -240,7 +240,7 @@
- 		      {
- 			 printk("mtd: Failed. Cannot handle unsymmetric banking\n");
- 			 kfree(MTD);
--			 return 0;
-+			 return NULL;
- 		      }      
- 		   }
- 	   }
-@@ -385,7 +385,7 @@
-    for (I = 0; JEDEC_table[I].jedec != 0; I++)
-       if (JEDEC_table[I].jedec == Id)
- 	 return JEDEC_table + I;
--   return 0;
-+   return NULL;
- }
- 
- // Look for flash using an 8 bit bus interface
-@@ -780,8 +780,7 @@
-        	    
-    //printk("done\n");
-    instr->state = MTD_ERASE_DONE;
--   if (instr->callback)
--	instr->callback(instr);
-+   mtd_erase_callback(instr);
-    return 0;
-    
-    #undef flread
-Index: linux-2.6.5/drivers/mtd/chips/jedec_probe.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/jedec_probe.c	2005-02-01 16:55:45.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/jedec_probe.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.57 2004/09/17 11:45:05 eric 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>
-@@ -27,6 +29,7 @@
- #define MANUFACTURER_AMD	0x0001
- #define MANUFACTURER_ATMEL	0x001f
- #define MANUFACTURER_FUJITSU	0x0004
-+#define MANUFACTURER_HYUNDAI	0x00AD
- #define MANUFACTURER_INTEL	0x0089
- #define MANUFACTURER_MACRONIX	0x00C2
- #define MANUFACTURER_PMC	0x009D
-@@ -37,8 +40,13 @@
- 
- 
- /* 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
-@@ -49,6 +57,7 @@
- #define AM29F040	0x00A4
- #define AM29LV040B	0x004F
- #define AM29F032B	0x0041
-+#define AM29F002T	0x00B0
- 
- /* Atmel */
- #define AT49BV512	0x0003
-@@ -59,6 +68,7 @@
- #define AT49BV32XT	0x00C9
- 
- /* Fujitsu */
-+#define MBM29F040C	0x00A4
- #define MBM29LV650UE	0x22D7
- #define MBM29LV320TE	0x22F6
- #define MBM29LV320BE	0x22F9
-@@ -66,6 +76,11 @@
- #define MBM29LV160BE	0x2249
- #define MBM29LV800BA	0x225B
- #define MBM29LV800TA	0x22DA
-+#define MBM29LV400TC	0x22B9
-+#define MBM29LV400BC	0x22BA
-+
-+/* Hyundai */
-+#define HY29F002T	0x00B0
- 
- /* Intel */
- #define I28F004B3T	0x00d4
-@@ -92,9 +107,11 @@
- #define I82802AC	0x00ac
- 
- /* Macronix */
-+#define MX29LV040C	0x004F
- #define MX29LV160T	0x22C4
- #define MX29LV160B	0x2249
- #define MX29F016	0x00AD
-+#define MX29F002T	0x00B0
- #define MX29F004T	0x0045
- #define MX29F004B	0x0046
- 
-@@ -109,8 +126,14 @@
- #define M29W160DT	0x22C4
- #define M29W160DB	0x2249
- #define M29W040B	0x00E3
-+#define M50FW040	0x002C
-+#define M50FW080	0x002D
-+#define M50FW016	0x002E
-+#define M50LPW080       0x002F
- 
- /* SST */
-+#define SST29EE020	0x0010
-+#define SST29LE020	0x0012
- #define SST29EE512	0x005d
- #define SST29LE512	0x003d
- #define SST39LF800	0x2781
-@@ -121,6 +144,8 @@
- #define SST39LF040	0x00D7
- #define SST39SF010A	0x00B5
- #define SST39SF020A	0x00B6
-+#define SST49LF004B	0x0060
-+#define SST49LF008A	0x005a
- #define SST49LF030A	0x001C
- #define SST49LF040A	0x0051
- #define SST49LF080A	0x005B
-@@ -158,8 +183,8 @@
- 
- 
- struct unlock_addr {
--	int addr1;
--	int addr2;
-+	u32 addr1;
-+	u32 addr2;
- };
- 
- 
-@@ -211,11 +236,10 @@
- 	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 +309,40 @@
- 		}
- 	}, {
- 		.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,
- 		.name		= "AMD AM29LV800BB",
- 		.uaddr		= {
-@@ -301,6 +359,45 @@
- 			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",
-@@ -417,6 +514,17 @@
- 			ERASEINFO(0x10000,8),
- 		}
- 	}, {
-+		mfr_id: MANUFACTURER_AMD,
-+		dev_id: AM29F002T,
-+		name: "AMD AM29F002T",
-+		DevSize: SIZE_256KiB,
-+		NumEraseRegions: 4,
-+		regions: {ERASEINFO(0x10000,3),
-+			  ERASEINFO(0x08000,1),
-+			  ERASEINFO(0x02000,2),
-+			  ERASEINFO(0x04000,1)
-+		}
-+	}, {
- 		.mfr_id		= MANUFACTURER_ATMEL,
- 		.dev_id		= AT49BV512,
- 		.name		= "Atmel AT49BV512",
-@@ -505,6 +613,19 @@
- 		}
- 	}, {
- 		.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,
- 		.name		= "Fujitsu MBM29LV650UE",
- 		.uaddr		= {
-@@ -615,6 +736,51 @@
- 			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_HYUNDAI,
-+		dev_id: HY29F002T,
-+		name: "Hyundai HY29F002T",
-+		DevSize: SIZE_256KiB,
-+		NumEraseRegions: 4,
-+		regions: {ERASEINFO(0x10000,3),
-+			  ERASEINFO(0x08000,1),
-+			  ERASEINFO(0x02000,2),
-+			  ERASEINFO(0x04000,1)
-+		}
-+	}, {
- 		.mfr_id		= MANUFACTURER_INTEL,
- 		.dev_id		= I28F004B3B,
- 		.name		= "Intel 28F004B3B",
-@@ -920,6 +1086,19 @@
- 		}
- 	}, {
- 		.mfr_id		= MANUFACTURER_MACRONIX,
-+		.dev_id		= MX29LV040C,
-+		.name		= "Macronix MX29LV040C",
-+		.uaddr		= {
-+			[0] = MTD_UADDR_0x0555_0x02AA,  /* x8 */
-+		},
-+		.DevSize	= SIZE_512KiB,
-+		.CmdSet		= P_ID_AMD_STD,
-+		.NumEraseRegions= 1,
-+		.regions	= {
-+			ERASEINFO(0x10000,8),
-+		}
-+	}, {
-+		.mfr_id		= MANUFACTURER_MACRONIX,
- 		.dev_id		= MX29LV160T,
- 		.name		= "MXIC MX29LV160T",
- 		.uaddr		= {
-@@ -998,6 +1177,17 @@
- 			ERASEINFO(0x10000,7),
- 		}
- 	}, {
-+		mfr_id: MANUFACTURER_MACRONIX,
-+		dev_id: MX29F002T,
-+		name: "Macronix MX29F002T",
-+		DevSize: SIZE_256KiB,
-+		NumEraseRegions: 4,
-+		regions: {ERASEINFO(0x10000,3),
-+			  ERASEINFO(0x08000,1),
-+			  ERASEINFO(0x02000,2),
-+			  ERASEINFO(0x04000,1)
-+		}
-+	}, {
- 		.mfr_id		= MANUFACTURER_PMC,
- 		.dev_id		= PM49FL002,
- 		.name		= "PMC Pm49FL002",
-@@ -1064,6 +1254,30 @@
- 		}
-         }, {
- 		.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",
-  		.uaddr		= {
-@@ -1116,6 +1330,32 @@
- 		}
- 	}, {
- 		.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,
- 		.name		= "SST 49LF030A",
-  		.uaddr		= {
-@@ -1154,6 +1394,22 @@
- 			ERASEINFO(0x01000,256),
- 		}
- 	}, {
-+               .mfr_id         = MANUFACTURER_SST,     /* should be CFI */
-+               .dev_id         = SST39LF160,
-+               .name           = "SST 39LF160",
-+               .uaddr          = {
-+                       [0] = MTD_UADDR_0x5555_0x2AAA,  /* x8 */
-+                       [1] = MTD_UADDR_0x5555_0x2AAA   /* x16 */
-+               },
-+               .DevSize        = SIZE_2MiB,
-+               .CmdSet         = P_ID_AMD_STD,
-+               .NumEraseRegions= 2,
-+               .regions        = {
-+                       ERASEINFO(0x1000,256),
-+                       ERASEINFO(0x1000,256)
-+               }
-+
-+       }, {
- 		.mfr_id		= MANUFACTURER_ST,	/* FIXME - CFI device? */
- 		.dev_id		= M29W800DT,
- 		.name		= "ST M29W800DT",
-@@ -1234,6 +1490,58 @@
- 		.regions	= {
- 			ERASEINFO(0x10000,8),
- 		}
-+        }, {
-+		.mfr_id		= MANUFACTURER_ST,
-+		.dev_id		= M50FW040,
-+		.name		= "ST M50FW040",
-+		.uaddr		= {
-+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-+		},
-+		.DevSize	= SIZE_512KiB,
-+		.CmdSet		= P_ID_INTEL_EXT,
-+		.NumEraseRegions= 1,
-+		.regions	= {
-+			ERASEINFO(0x10000,8),
-+		}
-+        }, {
-+		.mfr_id		= MANUFACTURER_ST,
-+		.dev_id		= M50FW080,
-+		.name		= "ST M50FW080",
-+		.uaddr		= {
-+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-+		},
-+		.DevSize	= SIZE_1MiB,
-+		.CmdSet		= P_ID_INTEL_EXT,
-+		.NumEraseRegions= 1,
-+		.regions	= {
-+			ERASEINFO(0x10000,16),
-+		}
-+        }, {
-+		.mfr_id		= MANUFACTURER_ST,
-+		.dev_id		= M50FW016,
-+		.name		= "ST M50FW016",
-+		.uaddr		= {
-+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-+		},
-+		.DevSize	= SIZE_2MiB,
-+		.CmdSet		= P_ID_INTEL_EXT,
-+		.NumEraseRegions= 1,
-+		.regions	= {
-+			ERASEINFO(0x10000,32),
-+		}
-+	}, {
-+		.mfr_id		= MANUFACTURER_ST,
-+		.dev_id		= M50LPW080,
-+		.name		= "ST M50LPW080",
-+		.uaddr		= {
-+			[0] = MTD_UADDR_UNNECESSARY,    /* x8 */
-+		},
-+		.DevSize	= SIZE_1MiB,
-+		.CmdSet		= P_ID_INTEL_EXT,
-+		.NumEraseRegions= 1,
-+		.regions	= {
-+			ERASEINFO(0x10000,16),
-+		}
- 	}, {
- 		.mfr_id		= MANUFACTURER_TOSHIBA,
- 		.dev_id		= TC58FVT160,
-@@ -1344,44 +1652,59 @@
- 			ERASEINFO(0x02000, 2),
- 			ERASEINFO(0x04000, 1),
- 		}
--	} 
-+	}
- };
- 
- 
- 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;
-+	u32 ofs = cfi_build_cmd_addr(0, cfi_interleave(cfi), cfi->device_type);
- 	mask = (1 << (cfi->device_type * 8)) -1;
--	result = cfi_read(map, base);
--	result &= mask;
--	return result;
-+	result = map_read(map, base + ofs);
-+	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;
--	osf = cfi->interleave *cfi->device_type;
-+	map_word result;
-+	unsigned long mask;
-+	u32 ofs = cfi_build_cmd_addr(1, cfi_interleave(cfi), 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 + ofs);
-+	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) {
-+		DEBUG( MTD_DEBUG_LEVEL3,
-+		       "reset unlock called %x %x \n",
-+		       cfi->addr_unlock1,cfi->addr_unlock2);
-+		cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, 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
-@@ -1409,6 +1732,12 @@
- 
- 	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;
- }
-@@ -1439,17 +1768,19 @@
- 	for (i=0; i<num_erase_regions; i++){
- 		p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
- 	}
--	p_cfi->cmdset_priv = 0;
-+	p_cfi->cmdset_priv = NULL;
- 
- 	/* This may be redundant for some cases, but it doesn't hurt */
- 	p_cfi->mfr = jedec_table[index].mfr_id;
- 	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;
- 	}
-+
-+	/* Mask out address bits which are smaller than the device type */
- 	p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
- 	p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
- 
-@@ -1473,8 +1804,35 @@
- 	u32 mfr, id;
- 	__u8 uaddr;
- 
--	/* 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;
- 	}
- 
-@@ -1482,7 +1840,7 @@
- 	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(cfi) * ( 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,
-@@ -1491,20 +1849,20 @@
- 	}
- 
- 	uaddr = finfo_uaddr(finfo, cfi->device_type);
--	if ( MTD_UADDR_NOT_SUPPORTED ) {
-+	if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) {
- 		goto match_done;
- 	}
- 
- 	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 != cfi->addr_unlock1 ||
-+		  unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) {
- 		DEBUG( MTD_DEBUG_LEVEL3,
--		       "MTD %s(): 0x%.4x 0x%.4x did not match\n",
--		       __func__,
--		       unlock_addrs[uaddr].addr1,
--		       unlock_addrs[uaddr].addr2 );
-+			"MTD %s(): 0x%.4x 0x%.4x did not match\n",
-+			__func__,
-+			unlock_addrs[uaddr].addr1,
-+			unlock_addrs[uaddr].addr2);
- 		goto match_done;
- 	}
- 
-@@ -1540,10 +1898,10 @@
- 	 */
- 	DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ );
- 	if(cfi->addr_unlock1) {
--		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(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
- 	}
--	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
- 	/* FIXME - should have a delay before continuing */
- 
-  match_done:	
-@@ -1552,41 +1910,24 @@
- 
- 
- 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;
-+	u32 probe_offset1, probe_offset2;
- 
--	/*
--	 * 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;
--		}
-+		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;
-+		cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
- 	}
- 
-- retry:
- 	/* Make certain we aren't probing past the end of map */
- 	if (base >= map->size) {
- 		printk(KERN_NOTICE
-@@ -1595,30 +1936,30 @@
- 		return 0;
- 		
- 	}
--	if ((base + cfi->addr_unlock1) >= map->size) {
--		printk(KERN_NOTICE
--			"Probe at addr_unlock1(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
--			base, cfi->addr_unlock1, map->size -1);
--
--		return 0;
-+	/* Ensure the unlock addresses we try stay inside the map */
-+	probe_offset1 = cfi_build_cmd_addr(
-+		cfi->addr_unlock1, 
-+		cfi_interleave(cfi), 
-+		cfi->device_type);
-+	probe_offset2 = cfi_build_cmd_addr(
-+		cfi->addr_unlock1, 
-+		cfi_interleave(cfi), 
-+		cfi->device_type);
-+	if (	((base + probe_offset1 + map_bankwidth(map)) >= map->size) ||
-+		((base + probe_offset2 + map_bankwidth(map)) >= map->size))
-+	{
-+		goto retry;
- 	}
--	if ((base + cfi->addr_unlock2) >= map->size) {
--		printk(KERN_NOTICE
--			"Probe at addr_unlock2(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n",
--			base, cfi->addr_unlock2, map->size -1);
--		return 0;
- 		
--	}
--
- 	/* Reset */
- 	jedec_reset(base, map, cfi);
- 
- 	/* Autoselect Mode */
- 	if(cfi->addr_unlock1) {
--		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(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
-+		cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL);
- 	}
--	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL);
-+	cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL);
- 	/* FIXME - should have a delay before continuing */
- 
- 	if (!cfi->numchips) {
-@@ -1628,9 +1969,8 @@
- 		cfi->mfr = jedec_read_mfr(map, base, cfi);
- 		cfi->id = jedec_read_id(map, base, cfi);
- 		DEBUG(MTD_DEBUG_LEVEL3,
--		      "MTD %s(): Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
--		      __func__, cfi->mfr, cfi->id, cfi->interleave,
--		      cfi->device_type);
-+		      "Search for id:(%02x %02x) interleave(%d) type(%d)\n", 
-+			cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type);
- 		for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) {
- 			if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) {
- 				DEBUG( MTD_DEBUG_LEVEL3,
-@@ -1642,16 +1982,7 @@
- 				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;
-@@ -1668,21 +1999,24 @@
- 		}
- 	}
- 	
--	/* 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;
- 			}
- 			
-@@ -1694,7 +2028,7 @@
- 			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;
- 			}
- 		}
-@@ -1702,22 +2036,16 @@
- 		
- 	/* 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",
--	       map->name, cfi->interleave, cfi->device_type*8, base, 
--	       map->buswidth*8);
-+	printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
-+	       map->name, cfi_interleave(cfi), cfi->device_type*8, base, 
-+	       map->bankwidth*8);
- 	
- 	return 1;
- }
-Index: linux-2.6.5/drivers/mtd/chips/map_ram.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/map_ram.c	2004-04-03 22:36:55.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/map_ram.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.20 2004/08/09 13:19:43 dwmw2 Exp $
-  */
- 
- #include <linux/module.h>
-@@ -104,13 +104,17 @@
- 	/* 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);
- 
--	if (instr->callback)
--		instr->callback(instr);
-+	for (i=0; i<instr->len; i += map_bankwidth(map))
-+		map_write(map, allff, instr->addr + i);
-+
-+	instr->state = MTD_ERASE_DONE;
-+
-+	mtd_erase_callback(instr);
- 
- 	return 0;
- }
-Index: linux-2.6.5/drivers/mtd/chips/map_rom.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/map_rom.c	2004-04-03 22:37:25.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/map_rom.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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: linux-2.6.5/drivers/mtd/chips/sharp.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/chips/sharp.c	2004-04-03 22:37:23.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/chips/sharp.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.14 2004/08/09 13:19:43 dwmw2 Exp $
-  *
-  * Devices supported:
-  *   LH28F016SCT Symmetrical block flash memory, 2Mx8
-@@ -30,6 +30,7 @@
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/cfi.h>
- #include <linux/delay.h>
-+#include <linux/init.h>
- 
- #define CMD_RESET		0xffffffff
- #define CMD_READ_ID		0x90909090
-@@ -154,7 +155,7 @@
- 	map->fldrv = &sharp_chipdrv;
- 	map->fldrv_priv = sharp;
- 
--	MOD_INC_USE_COUNT;
-+	__module_get(THIS_MODULE);
- 	return mtd;
- }
- 
-@@ -424,8 +425,7 @@
- 	}
- 
- 	instr->state = MTD_ERASE_DONE;
--	if(instr->callback)
--		instr->callback(instr);
-+	mtd_erase_callback(instr);
- 
- 	return 0;
- }
-Index: linux-2.6.5/drivers/mtd/cmdlinepart.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/cmdlinepart.c	2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/cmdlinepart.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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 ')'
-  * 
-@@ -94,7 +94,7 @@
- 		if (size < PAGE_SIZE)
- 		{
- 			printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
--			return 0;
-+			return NULL;
- 		}
- 	}
- 
-@@ -121,7 +121,7 @@
- 		if ((p = strchr(name, delim)) == 0)
- 		{
- 			printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
--			return 0;
-+			return NULL;
- 		}
- 		name_len = p - name;
- 		s = p + 1;
-@@ -148,12 +148,12 @@
- 		if (size == SIZE_REMAINING)
- 		{
- 			printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
--			return 0;
-+			return NULL;
- 		}
- 		/* more partitions follow, parse them */
- 		if ((parts = newpart(s + 1, &s, num_parts, 
- 		                     this_part + 1, &extra_mem, extra_mem_size)) == 0)
--		  return 0;
-+		  return NULL;
- 	}
- 	else
- 	{	/* this is the last partition: allocate space for all */
-@@ -166,7 +166,7 @@
- 		if (!parts)
- 		{
- 			printk(KERN_ERR ERRP "out of memory\n");
--			return 0;
-+			return NULL;
- 		}
- 		memset(parts, 0, alloc_size);
- 		extra_mem = (unsigned char *)(parts + *num_parts);
-@@ -358,14 +358,7 @@
- 	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: linux-2.6.5/drivers/mtd/devices/Kconfig
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/Kconfig	2004-04-03 22:38:28.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/Kconfig	2005-02-01 17:11:17.000000000 -0500
-@@ -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.12 2004/08/10 13:12:18 dwmw2 Exp $
- 
- menu "Self-contained MTD device drivers"
- 	depends on MTD!=n
-@@ -40,9 +40,12 @@
- 
- config MTD_MS02NV
- 	tristate "DEC MS02-NV NVRAM module support"
--	depends on CONFIG_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 @@
- 	  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
-@@ -115,7 +128,7 @@
- comment "Disk-On-Chip Device Drivers"
- 
- config MTD_DOC2000
--	tristate "M-Systems Disk-On-Chip 2000 and Millennium"
-+	tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)"
- 	depends on MTD
- 	---help---
- 	  This provides an MTD device driver for the M-Systems DiskOnChip
-@@ -131,8 +144,12 @@
- 	  emulate a block device by using a kind of file system on the flash
- 	  chips.
- 
-+	  NOTE: This driver is deprecated and will probably be removed soon.
-+	  Please try the new DiskOnChip driver under "NAND Flash Device
-+	  Drivers".
-+
- config MTD_DOC2001
--	tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (see help)"
-+	tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)"
- 	depends on MTD
- 	---help---
- 	  This provides an alternative MTD device driver for the M-Systems 
-@@ -147,6 +164,10 @@
- 	  emulate a block device by using a kind of file system on the flash
- 	  chips.
- 
-+	  NOTE: This driver is deprecated and will probably be removed soon.
-+	  Please try the new DiskOnChip driver under "NAND Flash Device
-+	  Drivers".
-+
- config MTD_DOC2001PLUS
- 	tristate "M-Systems Disk-On-Chip Millennium Plus"
- 	depends on MTD
-@@ -159,12 +180,23 @@
- 	  to emulate a block device by using a kind of file system on the 
- 	  flash chips.
- 
-+	  NOTE: This driver will soon be replaced by the new DiskOnChip driver
-+	  under "NAND Flash Device Drivers" (currently that driver does not
-+	  support all Millennium Plus devices).
-+
- 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.
-+	  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"
-Index: linux-2.6.5/drivers/mtd/devices/Makefile
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/Makefile	2004-04-03 22:36:13.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/Makefile	2005-02-01 17:11:17.000000000 -0500
-@@ -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 ***
- #
-@@ -13,8 +13,10 @@
- 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: linux-2.6.5/drivers/mtd/devices/blkmtd-24.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/blkmtd-24.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/blkmtd-24.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,1056 @@
-+/*
-+ * $Id: blkmtd-24.c,v 1.23 2004/08/09 18:49:42 dmarlin Exp $
-+ *
-+ * blkmtd.c - use a block device as a fake MTD
-+ *
-+ * Author: Simon Evans <spse@secret.org.uk>
-+ *
-+ * Copyright (C) 2001,2002 Simon Evans
-+ *
-+ * Licence: GPL
-+ *
-+ * How it works:
-+ *	The driver uses raw/io to read/write the device and the page
-+ *	cache to cache access. Writes update the page cache with the
-+ *	new data and mark it dirty and add the page into a kiobuf.
-+ *	When the kiobuf becomes full or the next extry is to an earlier
-+ *	block in the kiobuf then it is flushed to disk. This allows
-+ *	writes to remained ordered and gives a small and simple outgoing
-+ *	write cache.
-+ *
-+ *	It can be loaded Read-Only to prevent erases and writes to the
-+ *	medium.
-+ *
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/blkdev.h>
-+#include <linux/iobuf.h>
-+#include <linux/slab.h>
-+#include <linux/pagemap.h>
-+#include <linux/list.h>
-+#include <linux/mtd/mtd.h>
-+
-+#ifdef CONFIG_MTD_DEBUG
-+#ifdef CONFIG_PROC_FS
-+#  include <linux/proc_fs.h>
-+#  define BLKMTD_PROC_DEBUG
-+   static struct proc_dir_entry *blkmtd_proc;
-+#endif
-+#endif
-+
-+
-+#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg)
-+#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg)
-+#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg)
-+#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg)
-+
-+
-+/* Default erase size in KiB, always make it a multiple of PAGE_SIZE */
-+#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)	/* 128KiB */
-+#define VERSION "1.10"
-+
-+/* Info for the block device */
-+struct blkmtd_dev {
-+	struct list_head list;
-+	struct block_device *binding;
-+	struct mtd_info mtd_info;
-+	struct kiobuf *rd_buf, *wr_buf;
-+	long iobuf_locks;
-+	struct semaphore wrbuf_mutex;
-+};
-+
-+
-+/* Static info about the MTD, used in cleanup_module */
-+static LIST_HEAD(blkmtd_device_list);
-+
-+
-+static void blkmtd_sync(struct mtd_info *mtd);
-+
-+#define MAX_DEVICES 4
-+
-+/* Module parameters passed by insmod/modprobe */
-+char *device[MAX_DEVICES];    /* the block device to use */
-+int erasesz[MAX_DEVICES];     /* optional default erase size */
-+int ro[MAX_DEVICES];          /* optional read only flag */
-+int sync;
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-+MODULE_DESCRIPTION("Emulate an MTD using a block device");
-+MODULE_PARM(device, "1-4s");
-+MODULE_PARM_DESC(device, "block device to use");
-+MODULE_PARM(erasesz, "1-4i");
-+MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB.");
-+MODULE_PARM(ro, "1-4i");
-+MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors");
-+MODULE_PARM(sync, "i");
-+MODULE_PARM_DESC(sync, "1=Synchronous writes");
-+
-+
-+/**
-+ * read_pages - read in pages via the page cache
-+ * @dev: device to read from
-+ * @pagenrs: list of page numbers wanted
-+ * @pagelst: storage for struce page * pointers
-+ * @pages: count of pages wanted
-+ *
-+ * Read pages, getting them from the page cache if available
-+ * else reading them in from disk if not. pagelst must be preallocated
-+ * to hold the page count.
-+ */
-+static int read_pages(struct blkmtd_dev *dev, int pagenrs[], struct page **pagelst, int pages)
-+{
-+	kdev_t kdev;
-+	struct page *page;
-+	int cnt = 0;
-+	struct kiobuf *iobuf;
-+	int err = 0;
-+
-+	if(!dev) {
-+		err("read_pages: PANIC dev == NULL");
-+		return -EIO;
-+	}
-+	kdev = to_kdev_t(dev->binding->bd_dev);
-+
-+	DEBUG(2, "read_pages: reading %d pages\n", pages);
-+	if(test_and_set_bit(0, &dev->iobuf_locks)) {
-+		err = alloc_kiovec(1, &iobuf);
-+		if (err) {
-+			crit("cant allocate kiobuf");
-+			return -ENOMEM;
-+		}
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+		iobuf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-+		if(iobuf->blocks == NULL) {
-+			crit("cant allocate iobuf blocks");
-+			free_kiovec(1, &iobuf);
-+			return -ENOMEM;
-+		}
-+#endif
-+	} else {
-+		iobuf = dev->rd_buf;
-+	}
-+
-+	iobuf->nr_pages = 0;
-+	iobuf->length = 0;
-+	iobuf->offset = 0;
-+	iobuf->locked = 1;
-+	
-+	for(cnt = 0; cnt < pages; cnt++) {
-+		page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenrs[cnt]);
-+		pagelst[cnt] = page;
-+		if(!Page_Uptodate(page)) {
-+				iobuf->blocks[iobuf->nr_pages] = pagenrs[cnt];
-+				iobuf->maplist[iobuf->nr_pages++] = page;
-+		}
-+	}
-+
-+	if(iobuf->nr_pages) {
-+		iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
-+		err = brw_kiovec(READ, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
-+		DEBUG(3, "blkmtd: read_pages: finished, err = %d\n", err);
-+		if(err < 0) {
-+			while(pages--) {
-+				ClearPageUptodate(pagelst[pages]);
-+				unlock_page(pagelst[pages]);
-+				page_cache_release(pagelst[pages]);
-+			}
-+		} else {
-+			while(iobuf->nr_pages--) {
-+				SetPageUptodate(iobuf->maplist[iobuf->nr_pages]);
-+			}
-+			err = 0;
-+		}
-+	}
-+
-+
-+	if(iobuf != dev->rd_buf) {
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+		kfree(iobuf->blocks);
-+#endif
-+		free_kiovec(1, &iobuf);
-+	} else {
-+		clear_bit(0, &dev->iobuf_locks);
-+	}
-+	DEBUG(2, "read_pages: done, err = %d\n", err);
-+	return err;
-+}
-+
-+
-+/**
-+ * commit_pages - commit pages in the writeout kiobuf to disk
-+ * @dev: device to write to
-+ *
-+ * If the current dev has pages in the dev->wr_buf kiobuf,
-+ * they are written to disk using brw_kiovec()
-+ */
-+static int commit_pages(struct blkmtd_dev *dev)
-+{
-+	struct kiobuf *iobuf = dev->wr_buf;
-+	kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
-+	int err = 0;
-+
-+	iobuf->length = iobuf->nr_pages << PAGE_SHIFT;
-+	iobuf->locked = 1;
-+	if(iobuf->length) {
-+		int i;
-+		DEBUG(2, "blkmtd: commit_pages: nrpages = %d\n", iobuf->nr_pages);
-+		/* Check all the pages are dirty and lock them */
-+		for(i = 0; i < iobuf->nr_pages; i++) {
-+			struct page *page = iobuf->maplist[i];
-+			BUG_ON(!PageDirty(page));
-+			lock_page(page);
-+		}
-+		err = brw_kiovec(WRITE, 1, &iobuf, kdev, iobuf->blocks, PAGE_SIZE);
-+		DEBUG(3, "commit_write: committed %d pages err = %d\n", iobuf->nr_pages, err);
-+		while(iobuf->nr_pages) {
-+			struct page *page = iobuf->maplist[--iobuf->nr_pages];
-+			ClearPageDirty(page);
-+			SetPageUptodate(page);
-+			unlock_page(page);
-+			page_cache_release(page);
-+		}
-+	}
-+
-+	DEBUG(2, "blkmtd: sync: end, err = %d\n", err);
-+	iobuf->offset = 0;
-+	iobuf->nr_pages = 0;
-+	iobuf->length = 0;
-+	return err;
-+}
-+
-+
-+/**
-+ * write_pages - write block of data to device via the page cache
-+ * @dev: device to write to
-+ * @buf: data source or NULL if erase (output is set to 0xff)
-+ * @to: offset into output device
-+ * @len: amount to data to write
-+ * @retlen: amount of data written
-+ *
-+ * Grab pages from the page cache and fill them with the source data.
-+ * Non page aligned start and end result in a readin of the page and
-+ * part of the page being modified. Pages are added to the wr_buf kiobuf
-+ * until this becomes full or the next page written to has a lower pagenr
-+ * then the current max pagenr in the kiobuf.
-+ */
-+static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to,
-+		    size_t len, int *retlen)
-+{
-+	int pagenr, offset;
-+	size_t start_len = 0, end_len;
-+	int pagecnt = 0;
-+	struct kiobuf *iobuf = dev->wr_buf;
-+	int err = 0;
-+	struct page *pagelst[2];
-+	int pagenrs[2];
-+	int readpages = 0;
-+	int ignorepage = -1;
-+
-+	pagenr = to >> PAGE_SHIFT;
-+	offset = to & ~PAGE_MASK;
-+
-+	DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %zd pagenr = %d offset = %d\n",
-+	      buf, (long)to, len, pagenr, offset);
-+
-+	*retlen = 0;
-+	/* see if we have to do a partial write at the start */
-+	if(offset) {
-+		start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len;
-+		len -= start_len;
-+	}
-+
-+	/* calculate the length of the other two regions */
-+	end_len = len & ~PAGE_MASK;
-+	len -= end_len;
-+
-+	if(start_len) {
-+		pagenrs[0] = pagenr;
-+		readpages++;
-+		pagecnt++;
-+	}
-+	if(len)
-+		pagecnt += len >> PAGE_SHIFT;
-+	if(end_len) {
-+		pagenrs[readpages] = pagenr + pagecnt;
-+		readpages++;
-+		pagecnt++;
-+	}
-+
-+	DEBUG(3, "blkmtd: write: start_len = %zd len = %zd end_len = %zd pagecnt = %d\n",
-+	      start_len, len, end_len, pagecnt);
-+
-+	down(&dev->wrbuf_mutex);
-+
-+	if(iobuf->nr_pages && ((pagenr <= iobuf->blocks[iobuf->nr_pages-1])
-+			       || (iobuf->nr_pages + pagecnt) >= KIO_STATIC_PAGES)) {
-+
-+		if((pagenr == iobuf->blocks[iobuf->nr_pages-1])
-+		   && ((iobuf->nr_pages + pagecnt) < KIO_STATIC_PAGES)) {
-+			iobuf->nr_pages--;
-+			ignorepage = pagenr;
-+		} else {
-+			DEBUG(3, "blkmtd: doing writeout pagenr = %d max_pagenr = %ld pagecnt = %d idx = %d\n",
-+			      pagenr, iobuf->blocks[iobuf->nr_pages-1],
-+			      pagecnt, iobuf->nr_pages);
-+			commit_pages(dev);
-+		}
-+	}
-+	
-+	if(readpages) {
-+		err = read_pages(dev, pagenrs, pagelst, readpages);
-+		if(err < 0)
-+			goto readin_err;
-+	}
-+
-+	if(start_len) {
-+		/* do partial start region */
-+		struct page *page;
-+
-+		DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %zd offset = %d\n",
-+		      pagenr, start_len, offset);
-+		page = pagelst[0];
-+		BUG_ON(!buf);
-+		if(PageDirty(page) && pagenr != ignorepage) {
-+			err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d ignorepage = %d\n",
-+			    to, start_len, len, end_len, pagenr, ignorepage);
-+			BUG();
-+		}
-+		memcpy(page_address(page)+offset, buf, start_len);
-+		SetPageDirty(page);
-+		SetPageUptodate(page);
-+		unlock_page(page);
-+		buf += start_len;
-+		*retlen = start_len;
-+		err = 0;
-+		iobuf->blocks[iobuf->nr_pages] = pagenr++;
-+		iobuf->maplist[iobuf->nr_pages] = page;
-+		iobuf->nr_pages++;
-+	}
-+
-+	/* Now do the main loop to a page aligned, n page sized output */
-+	if(len) {
-+		int pagesc = len >> PAGE_SHIFT;
-+		DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n",
-+		      pagenr, pagesc);
-+		while(pagesc) {
-+			struct page *page;
-+
-+			/* see if page is in the page cache */
-+			DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr);
-+			page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenr);
-+			if(PageDirty(page) && pagenr != ignorepage) {
-+				BUG();
-+			}
-+			if(!page) {
-+				warn("write: cant grab cache page %d", pagenr);
-+				err = -ENOMEM;
-+				goto write_err;
-+			}
-+			if(!buf) {
-+				memset(page_address(page), 0xff, PAGE_SIZE);
-+			} else {
-+				memcpy(page_address(page), buf, PAGE_SIZE);
-+				buf += PAGE_SIZE;
-+			}
-+			iobuf->blocks[iobuf->nr_pages] = pagenr++;
-+			iobuf->maplist[iobuf->nr_pages] = page;
-+			iobuf->nr_pages++;
-+			SetPageDirty(page);
-+			SetPageUptodate(page);
-+			unlock_page(page);
-+			pagesc--;
-+			*retlen += PAGE_SIZE;
-+		}
-+	}
-+
-+	if(end_len) {
-+		/* do the third region */
-+		struct page *page;
-+		DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %zd\n",
-+		      pagenr, end_len);
-+		page = pagelst[readpages-1];
-+		BUG_ON(!buf);
-+		if(PageDirty(page) && pagenr != ignorepage) {
-+			err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d ignorepage = %d\n",
-+			    to, start_len, len, end_len, pagenr, ignorepage);
-+			BUG();
-+		}
-+		memcpy(page_address(page), buf, end_len);
-+		SetPageDirty(page);
-+		SetPageUptodate(page);
-+		unlock_page(page);
-+		DEBUG(3, "blkmtd: write: writing out partial end\n");
-+		*retlen += end_len;
-+		err = 0;
-+		iobuf->blocks[iobuf->nr_pages] = pagenr;
-+		iobuf->maplist[iobuf->nr_pages] = page;
-+		iobuf->nr_pages++;
-+	}
-+
-+	DEBUG(2, "blkmtd: write: end, retlen = %zd, err = %d\n", *retlen, err);
-+
-+	if(sync) {
-+write_err:
-+		commit_pages(dev);
-+	}
-+
-+readin_err:
-+	up(&dev->wrbuf_mutex);
-+	return err;
-+}
-+
-+
-+/* erase a specified part of the device */
-+static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+	struct blkmtd_dev *dev = mtd->priv;
-+	struct mtd_erase_region_info *einfo = mtd->eraseregions;
-+	int numregions = mtd->numeraseregions;
-+	size_t from;
-+	u_long len;
-+	int err = -EIO;
-+	size_t retlen;
-+
-+	/* check readonly */
-+	if(!dev->wr_buf) {
-+		err("error: mtd%d trying to erase readonly device %s",
-+		    mtd->index, mtd->name);
-+		instr->state = MTD_ERASE_FAILED;
-+		goto erase_callback;
-+	}
-+
-+	instr->state = MTD_ERASING;
-+	from = instr->addr;
-+	len = instr->len;
-+
-+	/* check erase region has valid start and length */
-+	DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n",
-+	      bdevname(dev->binding->bd_dev), from, len);
-+	while(numregions) {
-+		DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
-+		      einfo->offset, einfo->erasesize, einfo->numblocks);
-+		if(from >= einfo->offset
-+		   && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) {
-+			if(len == einfo->erasesize
-+			   && ( (from - einfo->offset) % einfo->erasesize == 0))
-+				break;
-+		}
-+		numregions--;
-+		einfo++;
-+	}
-+
-+	if(!numregions) {
-+		/* Not a valid erase block */
-+		err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
-+		instr->state = MTD_ERASE_FAILED;
-+		err = -EIO;
-+	}
-+
-+	if(instr->state != MTD_ERASE_FAILED) {
-+		/* do the erase */
-+		DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
-+		err = write_pages(dev, NULL, from, len, &retlen);
-+		if(err < 0) {
-+			err("erase failed err = %d", err);
-+			instr->state = MTD_ERASE_FAILED;
-+		} else {
-+			instr->state = MTD_ERASE_DONE;
-+			err = 0;
-+		}
-+	}
-+
-+	DEBUG(3, "blkmtd: erase: checking callback\n");
-+ erase_callback:
-+	mtd_erase_callback(instr);
-+	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
-+	return err;
-+}
-+
-+
-+/* read a range of the data via the page cache */
-+static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len,
-+		       size_t *retlen, u_char *buf)
-+{
-+	struct blkmtd_dev *dev = mtd->priv;
-+	int err = 0;
-+	int offset;
-+	int pagenr, pages;
-+	struct page **pagelst;
-+	int *pagenrs;
-+	int i;
-+
-+	*retlen = 0;
-+
-+	DEBUG(2, "blkmtd: read: dev = `%s' from = %lld len = %zd buf = %p\n",
-+	      bdevname(dev->binding->bd_dev), from, len, buf);
-+
-+	pagenr = from >> PAGE_SHIFT;
-+	offset = from - (pagenr << PAGE_SHIFT);
-+
-+	pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT;
-+	DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n",
-+	      pagenr, offset, pages);
-+
-+	pagelst = kmalloc(sizeof(struct page *) * pages, GFP_KERNEL);
-+	if(!pagelst)
-+		return -ENOMEM;
-+	pagenrs = kmalloc(sizeof(int) * pages, GFP_KERNEL);
-+	if(!pagenrs) {
-+		kfree(pagelst);
-+		return -ENOMEM;
-+	}
-+	for(i = 0; i < pages; i++)
-+		pagenrs[i] = pagenr+i;
-+
-+	err = read_pages(dev, pagenrs, pagelst, pages);
-+	if(err)
-+		goto readerr;
-+
-+	pagenr = 0;
-+	while(pages) {
-+		struct page *page;
-+		int cpylen;
-+
-+		DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr);
-+		page = pagelst[pagenr];
-+
-+		cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE;
-+		if(offset+cpylen > PAGE_SIZE)
-+			cpylen = PAGE_SIZE-offset;
-+
-+		memcpy(buf + *retlen, page_address(page) + offset, cpylen);
-+		offset = 0;
-+		len -= cpylen;
-+		*retlen += cpylen;
-+		pagenr++;
-+		pages--;
-+		unlock_page(page);
-+		if(!PageDirty(page))
-+			page_cache_release(page);
-+	}
-+
-+ readerr:
-+	kfree(pagelst);
-+	kfree(pagenrs);
-+	DEBUG(2, "blkmtd: end read: retlen = %zd, err = %d\n", *retlen, err);
-+	return err;
-+}
-+
-+
-+/* write data to the underlying device */
-+static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-+			size_t *retlen, const u_char *buf)
-+{
-+	struct blkmtd_dev *dev = mtd->priv;
-+	int err;
-+
-+	*retlen = 0;
-+	if(!len)
-+		return 0;
-+
-+	DEBUG(2, "blkmtd: write: dev = `%s' to = %lld len = %zd buf = %p\n",
-+	      bdevname(dev->binding->bd_dev), to, len, buf);
-+
-+	/* handle readonly and out of range numbers */
-+
-+	if(!dev->wr_buf) {
-+		err("error: trying to write to a readonly device %s", mtd->name);
-+		return -EROFS;
-+	}
-+
-+	if(to >= mtd->size) {
-+		return -ENOSPC;
-+	}
-+
-+	if(to + len > mtd->size) {
-+		len = (mtd->size - to);
-+	}
-+
-+	err = write_pages(dev, buf, to, len, retlen);
-+	if(err < 0)
-+		*retlen = 0;
-+	else
-+		err = 0;
-+	DEBUG(2, "blkmtd: write: end, err = %d\n", err);
-+	return err;
-+}
-+
-+
-+/* sync the device - wait until the write queue is empty */
-+static void blkmtd_sync(struct mtd_info *mtd)
-+{
-+	struct blkmtd_dev *dev = mtd->priv;
-+	struct kiobuf *iobuf = dev->wr_buf;
-+
-+	DEBUG(2, "blkmtd: sync: called\n");
-+	if(iobuf == NULL)
-+		return;
-+
-+	DEBUG(3, "blkmtd: kiovec: length = %d nr_pages = %d\n",
-+	      iobuf->length, iobuf->nr_pages);
-+	down(&dev->wrbuf_mutex);
-+	if(iobuf->nr_pages)
-+		commit_pages(dev);
-+	up(&dev->wrbuf_mutex);
-+}
-+
-+
-+#ifdef BLKMTD_PROC_DEBUG
-+/* procfs stuff */
-+static int blkmtd_proc_read(char *page, char **start, off_t off,
-+			    int count, int *eof, void *data)
-+{
-+	int len;
-+	struct list_head *temp1, *temp2;
-+
-+	MOD_INC_USE_COUNT;
-+
-+	/* Count the size of the page lists */
-+
-+	len = sprintf(page, "dev\twr_idx\tmax_idx\tnrpages\tclean\tdirty\tlocked\tlru\n");
-+	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
-+		struct blkmtd_dev *dev = list_entry(temp1,  struct blkmtd_dev,
-+						    list);
-+		struct list_head *temp;
-+		struct page *pagei;
-+
-+		int clean = 0, dirty = 0, locked = 0, lru = 0;
-+		/* Count the size of the page lists */
-+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->clean_pages) {
-+			pagei = list_entry(temp, struct page, list);
-+			clean++;
-+			if(PageLocked(pagei))
-+				locked++;
-+			if(PageDirty(pagei))
-+				dirty++;
-+			if(PageLRU(pagei))
-+				lru++;
-+		}
-+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->dirty_pages) {
-+			pagei = list_entry(temp, struct page, list);
-+			if(PageLocked(pagei))
-+				locked++;
-+			if(PageDirty(pagei))
-+				dirty++;
-+			if(PageLRU(pagei))
-+				lru++;
-+		}
-+		list_for_each(temp, &dev->binding->bd_inode->i_mapping->locked_pages) {
-+			pagei = list_entry(temp, struct page, list);
-+			if(PageLocked(pagei))
-+				locked++;
-+			if(PageDirty(pagei))
-+				dirty++;
-+			if(PageLRU(pagei))
-+				lru++;
-+		}
-+
-+		len += sprintf(page+len, "mtd%d:\t%ld\t%d\t%ld\t%d\t%d\t%d\t%d\n",
-+			       dev->mtd_info.index,
-+			       (dev->wr_buf && dev->wr_buf->nr_pages) ?
-+			       dev->wr_buf->blocks[dev->wr_buf->nr_pages-1] : 0,
-+			       (dev->wr_buf) ? dev->wr_buf->nr_pages : 0,
-+			       dev->binding->bd_inode->i_mapping->nrpages,
-+			       clean, dirty, locked, lru);
-+	}
-+
-+	if(len <= count)
-+		*eof = 1;
-+
-+	MOD_DEC_USE_COUNT;
-+	return len;
-+}
-+#endif
-+
-+
-+static void free_device(struct blkmtd_dev *dev)
-+{
-+	DEBUG(2, "blkmtd: free_device() dev = %p\n", dev);
-+	if(dev) {
-+		del_mtd_device(&dev->mtd_info);
-+		info("mtd%d: [%s] removed", dev->mtd_info.index,
-+		     dev->mtd_info.name + strlen("blkmtd: "));
-+		if(dev->mtd_info.eraseregions)
-+			kfree(dev->mtd_info.eraseregions);
-+		if(dev->mtd_info.name)
-+			kfree(dev->mtd_info.name);
-+
-+		if(dev->rd_buf) {
-+			dev->rd_buf->locked = 0;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+			if(dev->rd_buf->blocks)
-+				kfree(dev->rd_buf->blocks);
-+#endif
-+			free_kiovec(1, &dev->rd_buf);
-+		}
-+		if(dev->wr_buf) {
-+			dev->wr_buf->locked = 0;
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)			
-+			if(dev->wr_buf->blocks)
-+				kfree(dev->rw_buf->blocks);
-+#endif
-+			free_kiovec(1, &dev->wr_buf);
-+		}
-+
-+		if(dev->binding) {
-+			kdev_t kdev = to_kdev_t(dev->binding->bd_dev);
-+			invalidate_inode_pages(dev->binding->bd_inode);
-+			set_blocksize(kdev, 1 << 10);
-+			blkdev_put(dev->binding, BDEV_RAW);
-+		}
-+		kfree(dev);
-+	}
-+}
-+
-+
-+/* For a given size and initial erase size, calculate the number
-+ * and size of each erase region. Goes round the loop twice,
-+ * once to find out how many regions, then allocates space,
-+ * then round the loop again to fill it in.
-+ */
-+static struct mtd_erase_region_info *calc_erase_regions(
-+	size_t erase_size, size_t total_size, int *regions)
-+{
-+	struct mtd_erase_region_info *info = NULL;
-+
-+	DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
-+	      erase_size, total_size, *regions);
-+	/* Make any user specified erasesize be a power of 2
-+	   and at least PAGE_SIZE */
-+	if(erase_size) {
-+		int es = erase_size;
-+		erase_size = 1;
-+		while(es != 1) {
-+			es >>= 1;
-+			erase_size <<= 1;
-+		}
-+		if(erase_size < PAGE_SIZE)
-+			erase_size = PAGE_SIZE;
-+	} else {
-+		erase_size = CONFIG_MTD_BLKDEV_ERASESIZE;
-+	}
-+
-+	*regions = 0;
-+
-+	do {
-+		int tot_size = total_size;
-+		int er_size = erase_size;
-+		int count = 0, offset = 0, regcnt = 0;
-+
-+		while(tot_size) {
-+			count = tot_size / er_size;
-+			if(count) {
-+				tot_size = tot_size % er_size;
-+				if(info) {
-+					DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n",
-+					      offset, er_size, count);
-+					(info+regcnt)->offset = offset;
-+					(info+regcnt)->erasesize = er_size;
-+					(info+regcnt)->numblocks = count;
-+					(*regions)++;
-+				}
-+				regcnt++;
-+				offset += (count * er_size);
-+			}
-+			while(er_size > tot_size)
-+				er_size >>= 1;
-+		}
-+		if(info == NULL) {
-+			info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
-+			if(!info)
-+				break;
-+		}
-+	} while(!(*regions));
-+	DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
-+	      erase_size, total_size, *regions);
-+	return info;
-+}
-+
-+
-+extern kdev_t name_to_kdev_t(char *line) __init;
-+
-+
-+static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size)
-+{
-+	int maj, min;
-+	kdev_t kdev;
-+	int mode;
-+	struct blkmtd_dev *dev;
-+
-+#ifdef MODULE
-+	struct file *file = NULL;
-+	struct inode *inode;
-+#endif
-+
-+	if(!devname)
-+		return NULL;
-+
-+	/* Get a handle on the device */
-+	mode = (readonly) ? O_RDONLY : O_RDWR;
-+
-+#ifdef MODULE
-+
-+	file = filp_open(devname, mode, 0);
-+	if(IS_ERR(file)) {
-+		err("error: cant open device %s", devname);
-+		DEBUG(2, "blkmtd: filp_open returned %ld\n", PTR_ERR(file));
-+		return NULL;
-+	}
-+
-+	/* determine is this is a block device and
-+	 * if so get its major and minor numbers
-+	 */
-+	inode = file->f_dentry->d_inode;
-+	if(!S_ISBLK(inode->i_mode)) {
-+		err("%s not a block device", devname);
-+		filp_close(file, NULL);
-+		return NULL;
-+	}
-+	kdev = inode->i_rdev;
-+	filp_close(file, NULL);
-+#else
-+	kdev = name_to_kdev_t(devname);
-+#endif	/* MODULE */
-+
-+	if(!kdev) {
-+		err("bad block device: `%s'", devname);
-+		return NULL;
-+	}
-+
-+	maj = MAJOR(kdev);
-+	min = MINOR(kdev);
-+	DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n",
-+	      maj, min);
-+
-+	if(maj == MTD_BLOCK_MAJOR) {
-+		err("attempting to use an MTD device as a block device");
-+		return NULL;
-+	}
-+
-+	DEBUG(1, "blkmtd: devname = %s\n", bdevname(kdev));
-+
-+	dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL);
-+	if(dev == NULL)
-+		return NULL;
-+
-+	memset(dev, 0, sizeof(struct blkmtd_dev));
-+	if(alloc_kiovec(1, &dev->rd_buf)) {
-+		err("cant allocate read iobuf");
-+		goto devinit_err;
-+	}
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+	dev->rd_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-+	if(dev->rd_buf->blocks == NULL) {
-+		crit("cant allocate rd_buf blocks");
-+		goto devinit_err;
-+	}
-+#endif
-+	
-+	if(!readonly) {
-+		if(alloc_kiovec(1, &dev->wr_buf)) {
-+			err("cant allocate kiobuf - readonly enabled");
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-+		} else {
-+			dev->wr_buf->blocks = kmalloc(KIO_MAX_SECTORS * sizeof(unsigned long), GFP_KERNEL);
-+			if(dev->wr_buf->blocks == NULL) {
-+				crit("cant allocate wr_buf blocks - readonly enabled");
-+				free_kiovec(1, &iobuf);
-+			}
-+#endif
-+		}
-+		if(dev->wr_buf)
-+			init_MUTEX(&dev->wrbuf_mutex);
-+	}
-+
-+	/* get the block device */
-+	dev->binding = bdget(kdev_t_to_nr(MKDEV(maj, min)));
-+	if(blkdev_get(dev->binding, mode, 0, BDEV_RAW))
-+		goto devinit_err;
-+
-+	if(set_blocksize(kdev, PAGE_SIZE)) {
-+		err("cant set block size to PAGE_SIZE on %s", bdevname(kdev));
-+		goto devinit_err;
-+	}
-+
-+	dev->mtd_info.size = dev->binding->bd_inode->i_size & PAGE_MASK;
-+
-+	/* Setup the MTD structure */
-+	/* make the name contain the block device in */
-+	dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL);
-+	if(dev->mtd_info.name == NULL)
-+		goto devinit_err;
-+
-+	sprintf(dev->mtd_info.name, "blkmtd: %s", devname);
-+	dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size,
-+							&dev->mtd_info.numeraseregions);
-+	if(dev->mtd_info.eraseregions == NULL)
-+		goto devinit_err;
-+
-+	dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize;
-+	DEBUG(1, "blkmtd: init: found %d erase regions\n",
-+	      dev->mtd_info.numeraseregions);
-+
-+	if(readonly) {
-+		dev->mtd_info.type = MTD_ROM;
-+		dev->mtd_info.flags = MTD_CAP_ROM;
-+	} else {
-+		dev->mtd_info.type = MTD_RAM;
-+		dev->mtd_info.flags = MTD_CAP_RAM;
-+	}
-+	dev->mtd_info.erase = blkmtd_erase;
-+	dev->mtd_info.read = blkmtd_read;
-+	dev->mtd_info.write = blkmtd_write;
-+	dev->mtd_info.sync = blkmtd_sync;
-+	dev->mtd_info.point = 0;
-+	dev->mtd_info.unpoint = 0;
-+	dev->mtd_info.priv = dev;
-+	dev->mtd_info.owner = THIS_MODULE;
-+
-+	list_add(&dev->list, &blkmtd_device_list);
-+	if (add_mtd_device(&dev->mtd_info)) {
-+		/* Device didnt get added, so free the entry */
-+		list_del(&dev->list);
-+		free_device(dev);
-+		return NULL;
-+	} else {
-+		info("mtd%d: [%s] erase_size = %dKiB %s",
-+		     dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "),
-+		     dev->mtd_info.erasesize >> 10,
-+		     (dev->wr_buf) ? "" : "(read-only)");
-+	}
-+	
-+	return dev;
-+
-+ devinit_err:
-+	free_device(dev);
-+	return NULL;
-+}
-+
-+
-+/* Cleanup and exit - sync the device and kill of the kernel thread */
-+static void __devexit cleanup_blkmtd(void)
-+{
-+	struct list_head *temp1, *temp2;
-+#ifdef BLKMTD_PROC_DEBUG
-+	if(blkmtd_proc) {
-+		remove_proc_entry("blkmtd_debug", NULL);
-+	}
-+#endif
-+
-+	/* Remove the MTD devices */
-+	list_for_each_safe(temp1, temp2, &blkmtd_device_list) {
-+		struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev,
-+						    list);
-+		blkmtd_sync(&dev->mtd_info);
-+		free_device(dev);
-+	}
-+}
-+
-+#ifndef MODULE
-+
-+/* Handle kernel boot params */
-+
-+
-+static int __init param_blkmtd_device(char *str)
-+{
-+	int i;
-+
-+	for(i = 0; i < MAX_DEVICES; i++) {
-+		device[i] = str;
-+		DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]);
-+		strsep(&str, ",");
-+	}
-+	return 1;
-+}
-+
-+
-+static int __init param_blkmtd_erasesz(char *str)
-+{
-+	int i;
-+	for(i = 0; i < MAX_DEVICES; i++) {
-+		char *val = strsep(&str, ",");
-+		if(val)
-+			erasesz[i] = simple_strtoul(val, NULL, 0);
-+		DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]);
-+	}
-+
-+	return 1;
-+}
-+
-+
-+static int __init param_blkmtd_ro(char *str)
-+{
-+	int i;
-+	for(i = 0; i < MAX_DEVICES; i++) {
-+		char *val = strsep(&str, ",");
-+		if(val)
-+			ro[i] = simple_strtoul(val, NULL, 0);
-+		DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]);
-+	}
-+
-+	return 1;
-+}
-+
-+
-+static int __init param_blkmtd_sync(char *str)
-+{
-+	if(str[0] == '1')
-+		sync = 1;
-+	return 1;
-+}
-+
-+__setup("blkmtd_device=", param_blkmtd_device);
-+__setup("blkmtd_erasesz=", param_blkmtd_erasesz);
-+__setup("blkmtd_ro=", param_blkmtd_ro);
-+__setup("blkmtd_sync=", param_blkmtd_sync);
-+
-+#endif
-+
-+
-+/* Startup */
-+static int __init init_blkmtd(void)
-+{
-+	int i;
-+
-+	/* Check args - device[0] is the bare minimum*/
-+	if(!device[0]) {
-+		err("error: missing `device' name\n");
-+		return -EINVAL;
-+	}
-+
-+	for(i = 0; i < MAX_DEVICES; i++)
-+		add_device(device[i], ro[i], erasesz[i] << 10);
-+
-+	if(list_empty(&blkmtd_device_list))
-+		goto init_err;
-+
-+	info("version " VERSION);
-+
-+#ifdef BLKMTD_PROC_DEBUG
-+	/* create proc entry */
-+	DEBUG(2, "Creating /proc/blkmtd_debug\n");
-+	blkmtd_proc = create_proc_read_entry("blkmtd_debug", 0444,
-+					     NULL, blkmtd_proc_read, NULL);
-+	if(blkmtd_proc == NULL) {
-+		err("Cant create /proc/blkmtd_debug");
-+	} else {
-+		blkmtd_proc->owner = THIS_MODULE;
-+	}
-+#endif
-+
-+	if(!list_empty(&blkmtd_device_list))
-+		/* Everything is ok if we got here */
-+		return 0;
-+
-+ init_err:
-+	return -EINVAL;
-+}
-+
-+module_init(init_blkmtd);
-+module_exit(cleanup_blkmtd);
-Index: linux-2.6.5/drivers/mtd/devices/blkmtd.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/blkmtd.c	2005-02-01 16:55:31.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/blkmtd.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: blkmtd-25.c,v 1.5 2003/07/16 06:48:27 spse Exp $
-+ * $Id: blkmtd.c,v 1.23 2004/08/09 14:03:19 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.23 $"
- 
- /* Info for the block device */
- struct blkmtd_dev {
-@@ -246,7 +246,7 @@
- 	pagenr = to >> PAGE_SHIFT;
- 	offset = to & ~PAGE_MASK;
- 
--	DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %d pagenr = %d offset = %d\n",
-+	DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %zd pagenr = %d offset = %d\n",
- 	      buf, (long)to, len, pagenr, offset);
- 
- 	/* see if we have to do a partial write at the start */
-@@ -270,21 +270,21 @@
- 
- 	down(&dev->wrbuf_mutex);
- 
--	DEBUG(3, "blkmtd: write: start_len = %d len = %d end_len = %d pagecnt = %d\n",
-+	DEBUG(3, "blkmtd: write: start_len = %zd len = %zd end_len = %zd pagecnt = %d\n",
- 	      start_len, len, end_len, pagecnt);
- 
- 	if(start_len) {
- 		/* do partial start region */
- 		struct page *page;
- 
--		DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n",
-+		DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %zd offset = %d\n",
- 		      pagenr, start_len, offset);
- 
- 		BUG_ON(!buf);
- 		page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
- 		lock_page(page);
- 		if(PageDirty(page)) {
--			err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d\n",
-+			err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d\n",
- 			    to, start_len, len, end_len, pagenr);
- 			BUG();
- 		}
-@@ -346,13 +346,13 @@
- 	if(end_len) {
- 		/* do the third region */
- 		struct page *page;
--		DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n",
-+		DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %zd\n",
- 		      pagenr, end_len);
- 		BUG_ON(!buf);
- 		page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev);
- 		lock_page(page);
- 		if(PageDirty(page)) {
--			err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d\n",
-+			err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d\n",
- 			    to, start_len, len, end_len, pagenr);
- 			BUG();
- 		}
-@@ -375,7 +375,7 @@
- 	if(bio)
- 		blkmtd_write_out(bio);
- 
--	DEBUG(2, "blkmtd: write: end, retlen = %d, err = %d\n", *retlen, err);
-+	DEBUG(2, "blkmtd: write: end, retlen = %zd, err = %d\n", *retlen, err);
- 	up(&dev->wrbuf_mutex);
- 
- 	if(retlen)
-@@ -393,14 +393,14 @@
- 	size_t from;
- 	u_long len;
- 	int err = -EIO;
--	int retlen;
-+	size_t retlen;
- 
- 	instr->state = MTD_ERASING;
- 	from = instr->addr;
- 	len = instr->len;
- 
- 	/* check erase region has valid start and length */
--	DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n",
-+	DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n",
- 	      mtd->name+9, from, len);
- 	while(numregions) {
- 		DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n",
-@@ -417,14 +417,14 @@
- 
- 	if(!numregions) {
- 		/* Not a valid erase block */
--		err("erase: invalid erase request 0x%lX @ 0x%08X", len, from);
-+		err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from);
- 		instr->state = MTD_ERASE_FAILED;
- 		err = -EIO;
- 	}
- 
- 	if(instr->state != MTD_ERASE_FAILED) {
- 		/* do the erase */
--		DEBUG(3, "Doing erase from = %d len = %ld\n", from, len);
-+		DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len);
- 		err = write_pages(dev, NULL, from, len, &retlen);
- 		if(err || retlen != len) {
- 			err("erase failed err = %d", err);
-@@ -435,9 +435,7 @@
- 	}
- 
- 	DEBUG(3, "blkmtd: erase: checking callback\n");
--	if (instr->callback) {
--		(*(instr->callback))(instr);
--	}
-+	mtd_erase_callback(instr);
- 	DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err);
- 	return err;
- }
-@@ -453,8 +451,8 @@
- 	int pagenr, pages;
- 	size_t thislen = 0;
- 
--	DEBUG(2, "blkmtd: read: dev = `%s' from = %ld len = %d buf = %p\n",
--	      mtd->name+9, (long int)from, len, buf);
-+	DEBUG(2, "blkmtd: read: dev = `%s' from = %lld len = %zd buf = %p\n",
-+	      mtd->name+9, from, len, buf);
- 
- 	if(from > mtd->size)
- 		return -EINVAL;
-@@ -496,7 +494,7 @@
-  readerr:
- 	if(retlen)
- 		*retlen = thislen;
--	DEBUG(2, "blkmtd: end read: retlen = %d, err = %d\n", thislen, err);
-+	DEBUG(2, "blkmtd: end read: retlen = %zd, err = %d\n", thislen, err);
- 	return err;
- }
- 
-@@ -511,8 +509,8 @@
- 	if(!len)
- 		return 0;
- 
--	DEBUG(2, "blkmtd: write: dev = `%s' to = %ld len = %d buf = %p\n",
--	      mtd->name+9, (long int)to, len, buf);
-+	DEBUG(2, "blkmtd: write: dev = `%s' to = %lld len = %zd buf = %p\n",
-+	      mtd->name+9, to, len, buf);
- 
- 	if(to >= mtd->size) {
- 		return -ENOSPC;
-@@ -565,7 +563,7 @@
- {
- 	struct mtd_erase_region_info *info = NULL;
- 
--	DEBUG(2, "calc_erase_regions, es = %d size = %d regions = %d\n",
-+	DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n",
- 	      erase_size, total_size, *regions);
- 	/* Make any user specified erasesize be a power of 2
- 	   and at least PAGE_SIZE */
-@@ -613,7 +611,7 @@
- 				break;
- 		}
- 	} while(!(*regions));
--	DEBUG(2, "calc_erase_regions done, es = %d size = %d regions = %d\n",
-+	DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n",
- 	      erase_size, total_size, *regions);
- 	return info;
- }
-Index: linux-2.6.5/drivers/mtd/devices/doc2000.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/doc2000.c	2004-04-03 22:36:12.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/doc2000.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.63 2004/09/16 23:51:56 gleixner Exp $
-  */
- 
- #include <linux/kernel.h>
-@@ -19,12 +19,14 @@
- #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,9 +55,12 @@
- 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, int oobsel);
-+			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, int oobsel);
-+			 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 kvec *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,
-@@ -84,7 +89,7 @@
- /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
- static int _DoC_WaitReady(struct DiskOnChip *doc)
- {
--	unsigned long docptr = doc->virtadr;
-+	void __iomem *docptr = doc->virtadr;
- 	unsigned long timeo = jiffies + (HZ * 10);
- 
- 	DEBUG(MTD_DEBUG_LEVEL3,
-@@ -92,6 +97,10 @@
- 
- 	/* 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;
-@@ -105,7 +114,8 @@
- 
- static inline int DoC_WaitReady(struct DiskOnChip *doc)
- {
--	unsigned long docptr = doc->virtadr;
-+	void __iomem *docptr = doc->virtadr;
-+
- 	/* This is inline, to optimise the common case, where it's ready instantly */
- 	int ret = 0;
- 
-@@ -131,7 +141,7 @@
- static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
- 			      unsigned char xtraflags)
- {
--	unsigned long docptr = doc->virtadr;
-+	void __iomem *docptr = doc->virtadr;
- 
- 	if (DoC_is_2000(doc))
- 		xtraflags |= CDSN_CTRL_FLASH_IO;
-@@ -145,6 +155,8 @@
- 
- 	/* 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);
-@@ -161,10 +173,8 @@
- static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
- 		       unsigned char xtraflags1, unsigned char xtraflags2)
- {
--	unsigned long docptr;
- 	int i;
--
--	docptr = doc->virtadr;
-+	void __iomem *docptr = doc->virtadr;
- 
- 	if (DoC_is_2000(doc))
- 		xtraflags1 |= CDSN_CTRL_FLASH_IO;
-@@ -206,6 +216,9 @@
- 		}
- 	}
- 
-+	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 
-@@ -226,11 +239,9 @@
- {
- 	volatile int dummy;
- 	int modulus = 0xffff;
--	unsigned long docptr;
-+	void __iomem *docptr = doc->virtadr;
- 	int i;
- 
--	docptr = doc->virtadr;
--
- 	if (len <= 0)
- 		return;
- 
-@@ -257,11 +268,9 @@
- /* Write a buffer to DoC, taking care of Millennium odditys */
- static void DoC_WriteBuf(struct DiskOnChip *doc, const u_char * buf, int len)
- {
--	unsigned long docptr;
-+	void __iomem *docptr = doc->virtadr;
- 	int i;
- 
--	docptr = doc->virtadr;
--
- 	if (len <= 0)
- 		return;
- 
-@@ -278,7 +287,7 @@
- 
- static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip)
- {
--	unsigned long docptr = doc->virtadr;
-+	void __iomem *docptr = doc->virtadr;
- 
- 	/* Software requirement 11.4.4 before writing DeviceSelect */
- 	/* Deassert the CE line to eliminate glitches on the FCE# outputs */
-@@ -302,7 +311,7 @@
- 
- static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor)
- {
--	unsigned long docptr = doc->virtadr;
-+	void __iomem *docptr = doc->virtadr;
- 
- 	/* Select the floor (bank) of chips required */
- 	WriteDOC(floor, docptr, FloorSelect);
-@@ -344,15 +353,25 @@
- 
- 	/* 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);
--
--	/* 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);
-+	if (DoC_is_Millennium(doc)) {
-+		DoC_Delay(doc, 2);
-+		dummy = ReadDOC(doc->virtadr, ReadPipeInit);
-+		mfr = ReadDOC(doc->virtadr, LastDataRead);
-+
-+		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)
-@@ -386,11 +405,10 @@
- 			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;
-@@ -410,20 +428,16 @@
- 
- /* 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;
-@@ -515,6 +529,7 @@
- {
- 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
- 	struct DiskOnChip *old = NULL;
-+	int maxchips;
- 
- 	/* We must avoid being called twice for the same device. */
- 
-@@ -538,14 +553,28 @@
- 
- 
- 	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,
-@@ -566,6 +595,7 @@
- 	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;
-@@ -578,7 +608,7 @@
- 	init_MUTEX(&this->lock);
- 
- 	/* Ident all the chips present. */
--	DoC_ScanChips(this);
-+	DoC_ScanChips(this, maxchips);
- 
- 	if (!this->totlen) {
- 		kfree(mtd);
-@@ -597,20 +627,19 @@
- 		    size_t * retlen, u_char * buf)
- {
- 	/* Just a special case of doc_read_ecc */
--	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
-+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
- }
- 
- static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
--			size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel)
-+			size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
- {
- 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
--	unsigned long docptr;
-+	void __iomem *docptr = this->virtadr;
- 	struct Nand *mychip;
- 	unsigned char syndrome[6];
- 	volatile char dummy;
- 	int i, len256 = 0, ret=0;
--
--	docptr = this->virtadr;
-+	size_t left = len;
- 
- 	/* Don't allow read past end of device */
- 	if (from >= this->totlen)
-@@ -618,122 +647,131 @@
- 
- 	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);
-+	*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;
- 
--	/* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
-+		/* 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); */
- 
--	/* Find the chip which is to be used and select it */
--	mychip = &this->chips[from >> (this->chipshift)];
- 
--	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[from >> (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);
-+		}
- 
--	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);
--	}
-+		this->curfloor = mychip->floor;
-+		this->curchip = mychip->chip;
- 
--	/* 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);
-+		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);
- 
--		DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
--		DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
--			    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);
-+		}
- 
--	DoC_ReadBuf(this, &buf[len256], len - len256);
-+		/* 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);
-+
-+			DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
-+			DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
-+				    CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
-+		}
- 
--	/* Let the caller know we completed it */
--	*retlen = len;
-+		DoC_ReadBuf(this, &buf[len256], len - len256);
- 
--	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);
-+		/* Let the caller know we completed it */
-+		*retlen += len;
- 
--		/* 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);
--		}
-+		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 */
-+			/* 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);
-@@ -745,21 +783,21 @@
- 		     size_t * retlen, const u_char * buf)
- {
- 	char eccbuf[6];
--	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
-+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
- }
- 
- 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, int oobsel)
-+			 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 */
--	unsigned long docptr;
-+	void __iomem *docptr = this->virtadr;
- 	volatile char dummy;
- 	int len256 = 0;
- 	struct Nand *mychip;
--
--	docptr = this->virtadr;
-+	size_t left = len;
-+	int status;
- 
- 	/* Don't allow write past end of device */
- 	if (to >= this->totlen)
-@@ -767,65 +805,133 @@
- 
- 	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;
--
--	/* 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);
-+	*retlen = 0;
-+	while (left) {
-+		len = left;
-+
-+		/* Don't allow a single write to cross a 512-byte block boundary */
-+		if (to + len > ((to | 0x1ff) + 1))
-+			len = ((to | 0x1ff) + 1) - to;
-+
-+		/* 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 */
- 
--	/* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
-+		/* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
- 
--	/* Find the chip which is to be used and select it */
--	mychip = &this->chips[to >> (this->chipshift)];
-+		/* Find the chip which is to be used and select it */
-+		mychip = &this->chips[to >> (this->chipshift)];
- 
--	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);
--	}
-+		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);
-+		}
- 
--	this->curfloor = mychip->floor;
--	this->curchip = mychip->chip;
-+		this->curfloor = mychip->floor;
-+		this->curchip = 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);
-+		/* 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);
- 
--	DoC_Command(this, NAND_CMD_SEQIN, 0);
--	DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
-+		DoC_Command(this, NAND_CMD_SEQIN, 0);
-+		DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
- 
--	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);
--	}
-+		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);
-+		/* 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;
-@@ -833,94 +939,106 @@
- 			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 kvec *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)
- {
- 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
- 	int len256 = 0, ret;
--	unsigned long docptr;
- 	struct Nand *mychip;
- 
- 	down(&this->lock);
- 
--	docptr = this->virtadr;
--
- 	mychip = &this->chips[ofs >> this->chipshift];
- 
- 	if (this->curfloor != mychip->floor) {
-@@ -975,9 +1093,10 @@
- {
- 	struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
- 	int len256 = 0;
--	unsigned long docptr = this->virtadr;
-+	void __iomem *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]);
-@@ -1026,10 +1145,16 @@
- 		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;
-@@ -1045,10 +1170,16 @@
- 	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;
-@@ -1079,8 +1210,9 @@
- 	__u32 ofs = instr->addr;
- 	__u32 len = instr->len;
- 	volatile int dummy;
--	unsigned long docptr;
-+	void __iomem *docptr = this->virtadr;
- 	struct Nand *mychip;
-+	int status;
- 
-  	down(&this->lock);
- 
-@@ -1091,8 +1223,6 @@
- 
- 	instr->state = MTD_ERASING;
- 		
--	docptr = this->virtadr;
--
- 	/* FIXME: Do this in the background. Use timers or schedule_task() */
- 	while(len) {
- 		mychip = &this->chips[ofs >> this->chipshift];
-@@ -1112,10 +1242,16 @@
- 
- 		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;
-@@ -1127,8 +1263,7 @@
- 	instr->state = MTD_ERASE_DONE;
- 
-  callback:
--	if (instr->callback)
--		instr->callback(instr);
-+	mtd_erase_callback(instr);
- 
- 	up(&this->lock);
- 	return 0;
-Index: linux-2.6.5/drivers/mtd/devices/doc2001.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/doc2001.c	2004-04-03 22:36:54.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/doc2001.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.45 2004/09/16 23:51:57 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,9 +38,11 @@
- 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, int oobsel);
-+			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, int oobsel);
-+			 size_t *retlen, const u_char *buf, 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,
-@@ -49,7 +52,7 @@
- static struct mtd_info *docmillist = NULL;
- 
- /* Perform the required delay cycles by reading from the NOP register */
--static void DoC_Delay(unsigned long docptr, unsigned short cycles)
-+static void DoC_Delay(void __iomem * docptr, unsigned short cycles)
- {
- 	volatile char dummy;
- 	int i;
-@@ -59,7 +62,7 @@
- }
- 
- /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
--static int _DoC_WaitReady(unsigned long docptr)
-+static int _DoC_WaitReady(void __iomem * docptr)
- {
- 	unsigned short c = 0xffff;
- 
-@@ -76,7 +79,7 @@
- 	return (c == 0);
- }
- 
--static inline int DoC_WaitReady(unsigned long docptr)
-+static inline int DoC_WaitReady(void __iomem * docptr)
- {
- 	/* This is inline, to optimise the common case, where it's ready instantly */
- 	int ret = 0;
-@@ -100,7 +103,7 @@
-    with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
-    required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
- 
--static inline void DoC_Command(unsigned long docptr, unsigned char command,
-+static inline void DoC_Command(void __iomem * docptr, unsigned char command,
- 			       unsigned char xtraflags)
- {
- 	/* Assert the CLE (Command Latch Enable) line to the flash chip */
-@@ -120,7 +123,7 @@
-    with the internal pipeline. Each of 4 delay cycles (read from the NOP register) is
-    required after writing to CDSN Control register, see Software Requirement 11.4 item 3. */
- 
--static inline void DoC_Address(unsigned long docptr, int numbytes, unsigned long ofs,
-+static inline void DoC_Address(void __iomem * docptr, int numbytes, unsigned long ofs,
- 			       unsigned char xtraflags1, unsigned char xtraflags2)
- {
- 	/* Assert the ALE (Address Latch Enable) line to the flash chip */
-@@ -158,7 +161,7 @@
- }
- 
- /* DoC_SelectChip: Select a given flash chip within the current floor */
--static int DoC_SelectChip(unsigned long docptr, int chip)
-+static int DoC_SelectChip(void __iomem * docptr, int chip)
- {
- 	/* Select the individual flash chip requested */
- 	WriteDOC(chip, docptr, CDSNDeviceSelect);
-@@ -169,7 +172,7 @@
- }
- 
- /* DoC_SelectFloor: Select a given floor (bank of flash chips) */
--static int DoC_SelectFloor(unsigned long docptr, int floor)
-+static int DoC_SelectFloor(void __iomem * docptr, int floor)
- {
- 	/* Select the floor (bank) of chips required */
- 	WriteDOC(floor, docptr, FloorSelect);
-@@ -226,7 +229,7 @@
- 			       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;
- 		}
- 	}
-@@ -403,17 +406,18 @@
- 		     size_t *retlen, u_char *buf)
- {
- 	/* Just a special case of doc_read_ecc */
--	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
-+	return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
- }
- 
- static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
--			 size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
-+			 size_t *retlen, u_char *buf, u_char *eccbuf,
-+			 struct nand_oobinfo *oobsel)
- {
- 	int i, ret;
- 	volatile char dummy;
- 	unsigned char syndrome[6];
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem *docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
- 
- 	/* Don't allow read past end of device */
-@@ -529,16 +533,17 @@
- 		      size_t *retlen, const u_char *buf)
- {
- 	char eccbuf[6];
--	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
-+	return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
- }
- 
- 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, int oobsel)
-+			  size_t *retlen, const u_char *buf, u_char *eccbuf,
-+			 struct nand_oobinfo *oobsel)
- {
- 	int i,ret = 0;
- 	volatile char dummy;
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem *docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[to >> (this->chipshift)];
- 
- 	/* Don't allow write past end of device */
-@@ -673,7 +678,7 @@
- #endif
- 	volatile char dummy;
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem *docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
- 
- 	/* Find the chip which is to be used and select it */
-@@ -725,7 +730,7 @@
- 	volatile char dummy;
- 	int ret = 0;
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem *docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
- 
- 	/* Find the chip which is to be used and select it */
-@@ -794,7 +799,7 @@
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
- 	__u32 ofs = instr->addr;
- 	__u32 len = instr->len;
--	unsigned long docptr = this->virtadr;
-+	void __iomem *docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
- 
- 	if (len != mtd->erasesize) 
-@@ -840,8 +845,7 @@
- 		instr->state = MTD_ERASE_DONE;
- 	dummy = ReadDOC(docptr, LastDataRead);
- 
--	if (instr->callback) 
--		instr->callback(instr);
-+	mtd_erase_callback(instr);
- 
- 	return 0;
- }
-Index: linux-2.6.5/drivers/mtd/devices/doc2001plus.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/doc2001plus.c	2004-04-03 22:36:12.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/doc2001plus.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.10 2004/09/16 23:51:57 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>
-@@ -54,7 +57,7 @@
- 
- 
- /* Perform the required delay cycles by writing to the NOP register */
--static void DoC_Delay(unsigned long docptr, int cycles)
-+static void DoC_Delay(void __iomem * docptr, int cycles)
- {
- 	int i;
- 
-@@ -65,7 +68,7 @@
- #define	CDSN_CTRL_FR_B_MASK	(CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
- 
- /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
--static int _DoC_WaitReady(unsigned long docptr)
-+static int _DoC_WaitReady(void __iomem * docptr)
- {
- 	unsigned int c = 0xffff;
- 
-@@ -82,7 +85,7 @@
- 	return (c == 0);
- }
- 
--static inline int DoC_WaitReady(unsigned long docptr)
-+static inline int DoC_WaitReady(void __iomem * docptr)
- {
- 	/* This is inline, to optimise the common case, where it's ready instantly */
- 	int ret = 0;
-@@ -103,7 +106,7 @@
-  * can detect. M-systems suggest always check this on any block level
-  * operation and setting to normal mode if in reset mode.
-  */
--static inline void DoC_CheckASIC(unsigned long docptr)
-+static inline void DoC_CheckASIC(void __iomem * docptr)
- {
- 	/* Make sure the DoC is in normal mode */
- 	if ((ReadDOC(docptr, Mplus_DOCControl) & DOC_MODE_NORMAL) == 0) {
-@@ -115,7 +118,7 @@
- /* DoC_Command: Send a flash command to the flash chip through the Flash
-  * command register. Need 2 Write Pipeline Terminates to complete send.
-  */
--static inline void DoC_Command(unsigned long docptr, unsigned char command,
-+static inline void DoC_Command(void __iomem * docptr, unsigned char command,
- 			       unsigned char xtraflags)
- {
- 	WriteDOC(command, docptr, Mplus_FlashCmd);
-@@ -130,7 +133,7 @@
- 			       unsigned long ofs, unsigned char xtraflags1,
- 			       unsigned char xtraflags2)
- {
--	unsigned long docptr = doc->virtadr;
-+	void __iomem * docptr = doc->virtadr;
- 
- 	/* Allow for possible Mill Plus internal flash interleaving */
- 	ofs >>= doc->interleave;
-@@ -160,14 +163,14 @@
- }
- 
- /* DoC_SelectChip: Select a given flash chip within the current floor */
--static int DoC_SelectChip(unsigned long docptr, int chip)
-+static int DoC_SelectChip(void __iomem * docptr, int chip)
- {
- 	/* No choice for flash chip on Millennium Plus */
- 	return 0;
- }
- 
- /* DoC_SelectFloor: Select a given floor (bank of flash chips) */
--static int DoC_SelectFloor(unsigned long docptr, int floor)
-+static int DoC_SelectFloor(void __iomem * docptr, int floor)
- {
- 	WriteDOC((floor & 0x3), docptr, Mplus_DeviceSelect);
- 	return 0;
-@@ -183,24 +186,35 @@
-  *  | 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)
-@@ -239,7 +253,7 @@
- 	return cmd;
- }
- 
--static inline void MemReadDOC(unsigned long docptr, unsigned char *buf, int len)
-+static inline void MemReadDOC(void __iomem * docptr, unsigned char *buf, int len)
- {
- #ifndef USE_MEMCPY
- 	int i;
-@@ -250,7 +264,7 @@
- #endif
- }
- 
--static inline void MemWriteDOC(unsigned long docptr, unsigned char *buf, int len)
-+static inline void MemWriteDOC(void __iomem * docptr, unsigned char *buf, int len)
- {
- #ifndef USE_MEMCPY
- 	int i;
-@@ -266,7 +280,7 @@
- {
- 	int mfr, id, i, j;
- 	volatile char dummy;
--	unsigned long docptr = doc->virtadr;
-+	void __iomem * docptr = doc->virtadr;
- 
- 	/* Page in the required floor/chip */
- 	DoC_SelectFloor(docptr, floor);
-@@ -294,10 +308,12 @@
- 	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 @@
- 			       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 @@
- 	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(conf, this->virtadr, 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;
-@@ -503,7 +531,7 @@
- 	int i;
- 	loff_t fofs;
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem * docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
- 	unsigned char *bp, buf[1056];
- 	char c[32];
-@@ -588,7 +616,7 @@
- 	loff_t fofs;
- 	unsigned char syndrome[6];
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem * docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[from >> (this->chipshift)];
- 
- 	/* Don't allow read past end of device */
-@@ -727,7 +755,7 @@
- 	loff_t fto;
- 	volatile char dummy;
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem * docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[to >> (this->chipshift)];
- 
- 	/* Don't allow write past end of device */
-@@ -739,7 +767,7 @@
- 		return -EINVAL;
- 
- 	/* Determine position of OOB flags, before or after data */
--	before = to & 0x200;
-+	before = (this->interleave && (to & 0x200));
- 
- 	DoC_CheckASIC(docptr);
- 
-@@ -853,7 +881,7 @@
- {
- 	loff_t fofs, base;
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem * docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
- 	size_t i, size, got, want;
- 
-@@ -886,7 +914,10 @@
- 		/* 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) {
-@@ -928,7 +959,7 @@
- 	volatile char dummy;
- 	loff_t fofs, base;
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
--	unsigned long docptr = this->virtadr;
-+	void __iomem * docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
- 	size_t i, size, got, want;
- 	int ret = 0;
-@@ -963,7 +994,10 @@
- 		/* 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) {
-@@ -1027,7 +1061,7 @@
- 	struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
- 	__u32 ofs = instr->addr;
- 	__u32 len = instr->len;
--	unsigned long docptr = this->virtadr;
-+	void __iomem * docptr = this->virtadr;
- 	struct Nand *mychip = &this->chips[ofs >> this->chipshift];
- 
- 	DoC_CheckASIC(docptr);
-@@ -1077,8 +1111,7 @@
- 	/* Disable flash internally */
- 	WriteDOC(0, docptr, Mplus_FlashSelect);
- 
--	if (instr->callback) 
--		instr->callback(instr);
-+	mtd_erase_callback(instr);
- 
- 	return 0;
- }
-Index: linux-2.6.5/drivers/mtd/devices/docprobe.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/docprobe.c	2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/docprobe.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.42 2004/09/16 23:51:57 gleixner Exp $	*/
- 
- 
- 
-@@ -135,6 +135,9 @@
- 		 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 @@
- 		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 @@
- 			tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
- 			if (tmp != tmpb && tmp == tmpc)
- 					return ChipID;
--			break;
- 		default:
- 			break;
- 		}
-@@ -199,8 +207,8 @@
- 
- 	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 @@
- 		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);
- 
-@@ -256,12 +270,18 @@
- 		memset((char *)this, 0, sizeof(struct DiskOnChip));
- 
- 		mtd->priv = this;
--		this->virtadr = docptr;
-+		this->virtadr = (void __iomem *)docptr;
- 		this->physadr = physadr;
- 		this->ChipID = ChipID;
- 		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: linux-2.6.5/drivers/mtd/devices/lart.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/lart.c	2004-04-03 22:36:57.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/lart.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.7 2004/08/09 13:19:44 dwmw2 Exp $
-  *
-  * Author: Abraham vd Merwe <abraham@2d3d.co.za>
-  *
-@@ -433,7 +433,7 @@
- 	 }
- 
-    instr->state = MTD_ERASE_DONE;
--   if (instr->callback) instr->callback (instr);
-+   mtd_erase_callback(instr);
- 
-    return (0);
- }
-Index: linux-2.6.5/drivers/mtd/devices/ms02-nv.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/ms02-nv.c	2004-04-03 22:36:15.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/ms02-nv.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.7 2004/07/29 14:16:45 macro Exp $
-  */
- 
- #include <linux/init.h>
-@@ -29,18 +29,18 @@
- 
- 
- 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_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
- MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
- 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 @@
- 
- 	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 @@
- 		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 @@
- 
- 	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: linux-2.6.5/drivers/mtd/devices/ms02-nv.h
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/ms02-nv.h	2004-04-03 22:37:07.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/ms02-nv.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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: linux-2.6.5/drivers/mtd/devices/mtdram.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/mtdram.c	2004-04-03 22:36:15.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/mtdram.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,6 +1,6 @@
- /*
-  * mtdram - a test mtd device
-- * $Id: mtdram.c,v 1.32 2003/05/21 15:15:07 dwmw2 Exp $
-+ * $Id: mtdram.c,v 1.33 2004/08/09 13:19:44 dwmw2 Exp $
-  * Author: Alexander Larsson <alex@cendio.se>
-  *
-  * Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
-@@ -57,9 +57,8 @@
-   memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
- 	
-   instr->state = MTD_ERASE_DONE;
-+  mtd_erase_callback(instr);
- 
--  if (instr->callback)
--    (*(instr->callback))(instr);
-   return 0;
- }
- 
-Index: linux-2.6.5/drivers/mtd/devices/phram.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/phram.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/phram.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,359 @@
-+/**
-+ *
-+ * $Id: phram.c,v 1.2 2004/08/09 13:19:44 dwmw2 Exp $
-+ *
-+ * Copyright (c) Jochen Schaeuble <psionic@psionic.de>
-+ * 07/2003	rewritten by Joern Engel <joern@wh.fh-wedel.de>
-+ *
-+ * DISCLAIMER:  This driver makes use of Rusty's excellent module code,
-+ * so it will not work for 2.4 without changes and it wont work for 2.4
-+ * as a module without major changes.  Oh well!
-+ *
-+ * Usage:
-+ *
-+ * one commend line parameter per device, each in the form:
-+ *   phram=<name>,<start>,<len>
-+ * <name> may be up to 63 characters.
-+ * <start> and <len> can be octal, decimal or hexadecimal.  If followed
-+ * by "k", "M" or "G", the numbers will be interpreted as kilo, mega or
-+ * gigabytes.
-+ *
-+ */
-+
-+#include <asm/io.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/mtd/mtd.h>
-+
-+#define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args)
-+
-+struct phram_mtd_list {
-+	struct list_head list;
-+	struct mtd_info *mtdinfo;
-+};
-+
-+static LIST_HEAD(phram_list);
-+
-+
-+
-+int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+	u_char *start = (u_char *)mtd->priv;
-+
-+	if (instr->addr + instr->len > mtd->size)
-+		return -EINVAL;
-+	
-+	memset(start + instr->addr, 0xff, instr->len);
-+
-+	/* This'll catch a few races. Free the thing before returning :) 
-+	 * I don't feel at all ashamed. This kind of thing is possible anyway
-+	 * with flash, but unlikely.
-+	 */
-+
-+	instr->state = MTD_ERASE_DONE;
-+
-+	mtd_erase_callback(instr);
-+
-+	return 0;
-+}
-+
-+int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
-+		size_t *retlen, u_char **mtdbuf)
-+{
-+	u_char *start = (u_char *)mtd->priv;
-+
-+	if (from + len > mtd->size)
-+		return -EINVAL;
-+	
-+	*mtdbuf = start + from;
-+	*retlen = len;
-+	return 0;
-+}
-+
-+void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
-+{
-+}
-+
-+int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
-+		size_t *retlen, u_char *buf)
-+{
-+	u_char *start = (u_char *)mtd->priv;
-+
-+	if (from + len > mtd->size)
-+		return -EINVAL;
-+	
-+	memcpy(buf, start + from, len);
-+
-+	*retlen = len;
-+	return 0;
-+}
-+
-+int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
-+		size_t *retlen, const u_char *buf)
-+{
-+	u_char *start = (u_char *)mtd->priv;
-+
-+	if (to + len > mtd->size)
-+		return -EINVAL;
-+	
-+	memcpy(start + to, buf, len);
-+
-+	*retlen = len;
-+	return 0;
-+}
-+
-+
-+
-+static void unregister_devices(void)
-+{
-+	struct phram_mtd_list *this;
-+
-+	list_for_each_entry(this, &phram_list, list) {
-+		del_mtd_device(this->mtdinfo);
-+		iounmap(this->mtdinfo->priv);
-+		kfree(this->mtdinfo);
-+		kfree(this);
-+	}
-+}
-+
-+static int register_device(char *name, unsigned long start, unsigned long len)
-+{
-+	struct phram_mtd_list *new;
-+	int ret = -ENOMEM;
-+
-+	new = kmalloc(sizeof(*new), GFP_KERNEL);
-+	if (!new)
-+		goto out0;
-+
-+	new->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-+	if (!new->mtdinfo)
-+		goto out1;
-+	
-+	memset(new->mtdinfo, 0, sizeof(struct mtd_info));
-+
-+	ret = -EIO;
-+	new->mtdinfo->priv = ioremap(start, len);
-+	if (!new->mtdinfo->priv) {
-+		ERROR("ioremap failed\n");
-+		goto out2;
-+	}
-+
-+
-+	new->mtdinfo->name = name;
-+	new->mtdinfo->size = len;
-+	new->mtdinfo->flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
-+        new->mtdinfo->erase = phram_erase;
-+	new->mtdinfo->point = phram_point;
-+	new->mtdinfo->unpoint = phram_unpoint;
-+	new->mtdinfo->read = phram_read;
-+	new->mtdinfo->write = phram_write;
-+	new->mtdinfo->owner = THIS_MODULE;
-+	new->mtdinfo->type = MTD_RAM;
-+	new->mtdinfo->erasesize = 0x0;
-+
-+	ret = -EAGAIN;
-+	if (add_mtd_device(new->mtdinfo)) {
-+		ERROR("Failed to register new device\n");
-+		goto out3;
-+	}
-+
-+	list_add_tail(&new->list, &phram_list);
-+	return 0;	
-+
-+out3:
-+	iounmap(new->mtdinfo->priv);
-+out2:
-+	kfree(new->mtdinfo);
-+out1:
-+	kfree(new);
-+out0:
-+	return ret;
-+}
-+
-+static int ustrtoul(const char *cp, char **endp, unsigned int base)
-+{
-+	unsigned long result = simple_strtoul(cp, endp, base);
-+
-+	switch (**endp) {
-+	case 'G':
-+		result *= 1024;
-+	case 'M':
-+		result *= 1024;
-+	case 'k':
-+		result *= 1024;
-+		endp++;
-+	}
-+	return result;
-+}
-+
-+static int parse_num32(uint32_t *num32, const char *token)
-+{
-+	char *endp;
-+	unsigned long n;
-+
-+	n = ustrtoul(token, &endp, 0);
-+	if (*endp)
-+		return -EINVAL;
-+
-+	*num32 = n;
-+	return 0;
-+}
-+
-+static int parse_name(char **pname, const char *token)
-+{
-+	size_t len;
-+	char *name;
-+
-+	len = strlen(token) + 1;
-+	if (len > 64)
-+		return -ENOSPC;
-+
-+	name = kmalloc(len, GFP_KERNEL);
-+	if (!name)
-+		return -ENOMEM;
-+
-+	strcpy(name, token);
-+
-+	*pname = name;
-+	return 0;
-+}
-+
-+#define parse_err(fmt, args...) do {	\
-+	ERROR(fmt , ## args);	\
-+	return 0;		\
-+} while (0)
-+
-+static int phram_setup(const char *val, struct kernel_param *kp)
-+{
-+	char buf[64+12+12], *str = buf;
-+	char *token[3];
-+	char *name;
-+	uint32_t start;
-+	uint32_t len;
-+	int i, ret;
-+
-+	if (strnlen(val, sizeof(str)) >= sizeof(str))
-+		parse_err("parameter too long\n");
-+
-+	strcpy(str, val);
-+
-+	for (i=0; i<3; i++)
-+		token[i] = strsep(&str, ",");
-+
-+	if (str)
-+		parse_err("too many arguments\n");
-+
-+	if (!token[2])
-+		parse_err("not enough arguments\n");
-+
-+	ret = parse_name(&name, token[0]);
-+	if (ret == -ENOMEM)
-+		parse_err("out of memory\n");
-+	if (ret == -ENOSPC)
-+		parse_err("name too long\n");
-+	if (ret)
-+		return 0;
-+
-+	ret = parse_num32(&start, token[1]);
-+	if (ret)
-+		parse_err("illegal start address\n");
-+
-+	ret = parse_num32(&len, token[2]);
-+	if (ret)
-+		parse_err("illegal device length\n");
-+
-+	register_device(name, start, len);
-+
-+	return 0;
-+}
-+
-+module_param_call(phram, phram_setup, NULL, NULL, 000);
-+MODULE_PARM_DESC(phram, "Memory region to map. \"map=<name>,<start><length>\"");
-+
-+/*
-+ * Just for compatibility with slram, this is horrible and should go someday.
-+ */
-+static int __init slram_setup(const char *val, struct kernel_param *kp)
-+{
-+	char buf[256], *str = buf;
-+
-+	if (!val || !val[0])
-+		parse_err("no arguments to \"slram=\"\n");
-+
-+	if (strnlen(val, sizeof(str)) >= sizeof(str))
-+		parse_err("parameter too long\n");
-+
-+	strcpy(str, val);
-+
-+	while (str) {
-+		char *token[3];
-+		char *name;
-+		uint32_t start;
-+		uint32_t len;
-+		int i, ret;
-+
-+		for (i=0; i<3; i++) {
-+			token[i] = strsep(&str, ",");
-+			if (token[i])
-+				continue;
-+			parse_err("wrong number of arguments to \"slram=\"\n");
-+		}
-+
-+		/* name */
-+		ret = parse_name(&name, token[0]);
-+		if (ret == -ENOMEM)
-+			parse_err("of memory\n");
-+		if (ret == -ENOSPC)
-+			parse_err("too long\n");
-+		if (ret)
-+			return 1;
-+
-+		/* start */
-+		ret = parse_num32(&start, token[1]);
-+		if (ret)
-+			parse_err("illegal start address\n");
-+
-+		/* len */
-+		if (token[2][0] == '+')
-+			ret = parse_num32(&len, token[2] + 1);
-+		else
-+			ret = parse_num32(&len, token[2]);
-+
-+		if (ret)
-+			parse_err("illegal device length\n");
-+
-+		if (token[2][0] != '+') {
-+			if (len < start)
-+				parse_err("end < start\n");
-+			len -= start;
-+		}
-+
-+		register_device(name, start, len);
-+	}
-+	return 1;
-+}
-+
-+module_param_call(slram, slram_setup, NULL, NULL, 000);
-+MODULE_PARM_DESC(slram, "List of memory regions to map. \"map=<name>,<start><length/end>\"");
-+
-+
-+int __init init_phram(void)
-+{
-+	printk(KERN_ERR "phram loaded\n");
-+	return 0;
-+}
-+
-+static void __exit cleanup_phram(void)
-+{
-+	unregister_devices();
-+}
-+
-+module_init(init_phram);
-+module_exit(cleanup_phram);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
-+MODULE_DESCRIPTION("MTD driver for physical RAM");
-Index: linux-2.6.5/drivers/mtd/devices/pmc551.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/pmc551.c	2004-04-03 22:37:41.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/pmc551.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: pmc551.c,v 1.24 2003/05/20 21:03:08 dwmw2 Exp $
-+ * $Id: pmc551.c,v 1.28 2004/08/09 13:19:44 dwmw2 Exp $
-  *
-  * PMC551 PCI Mezzanine Ram Device
-  *
-@@ -109,12 +109,6 @@
- #include <linux/mtd/pmc551.h>
- #include <linux/mtd/compatmac.h>
- 
--#if LINUX_VERSION_CODE > 0x20300
--#define PCI_BASE_ADDRESS(dev) (dev->resource[0].start)
--#else
--#define PCI_BASE_ADDRESS(dev) (dev->base_address[0])
--#endif
--
- static struct mtd_info *pmc551list;
- 
- static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
-@@ -175,9 +169,7 @@
- 	printk(KERN_DEBUG "pmc551_erase() done\n");
- #endif
- 
--        if (instr->callback) {
--                (*(instr->callback))(instr);
--	}
-+        mtd_erase_callback(instr);
-         return 0;
- }
- 
-@@ -564,7 +556,7 @@
- 	       (size<1024)?size:(size<1048576)?size>>10:size>>20,
-                (size<1024)?'B':(size<1048576)?'K':'M',
- 	       size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
--               PCI_BASE_ADDRESS(dev)&PCI_BASE_ADDRESS_MEM_MASK );
-+               (dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK );
- 
-         /*
-          * Check to see the state of the memory
-@@ -694,7 +686,7 @@
-                 }
- 
-                 printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%lX\n",
--				    PCI_BASE_ADDRESS(PCI_Device));
-+				    PCI_Device->resource[0].start);
- 
-                 /*
-                  * The PMC551 device acts VERY weird if you don't init it
-@@ -748,7 +740,7 @@
- 			printk(KERN_NOTICE "pmc551: Using specified aperture size %dM\n", asize>>20);
- 			priv->asize = asize;
- 		}
--                priv->start = ioremap((PCI_BASE_ADDRESS(PCI_Device)
-+                priv->start = ioremap(((PCI_Device->resource[0].start)
-                                        & PCI_BASE_ADDRESS_MEM_MASK),
-                                       priv->asize);
- 		
-Index: linux-2.6.5/drivers/mtd/devices/slram.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/devices/slram.c	2004-04-03 22:36:12.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/devices/slram.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,6 +1,6 @@
- /*======================================================================
- 
--  $Id: slram.c,v 1.30 2003/05/20 21:03:08 dwmw2 Exp $
-+  $Id: slram.c,v 1.31 2004/08/09 13:19:44 dwmw2 Exp $
- 
-   This driver provides a method to access memory not used by the kernel
-   itself (i.e. if the kernel commandline mem=xxx is used). To actually
-@@ -98,12 +98,7 @@
- 
- 	instr->state = MTD_ERASE_DONE;
- 
--	if (instr->callback) {
--		(*(instr->callback))(instr);
--	}
--	else {
--		kfree(instr);
--	}
-+	mtd_erase_callback(instr);
- 
- 	return(0);
- }
-Index: linux-2.6.5/drivers/mtd/ftl.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/ftl.c	2004-04-03 22:37:45.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/ftl.c	2005-02-01 17:11:29.000000000 -0500
-@@ -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.53 2004/08/09 13:55:43 dwmw2 Exp $
-  *
-  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
-  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
-@@ -167,7 +167,8 @@
- {
-     erase_unit_header_t header;
-     loff_t offset, max_offset;
--    int ret;
-+    size_t ret;
-+    int err;
-     part->header.FormattedSize = 0;
-     max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size;
-     /* Search first megabyte for a valid FTL header */
-@@ -175,11 +176,11 @@
- 	 (offset + sizeof(header)) < max_offset;
- 	 offset += part->mbd.mtd->erasesize ? : 0x2000) {
- 
--	ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, 
-+	err = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, 
- 			      (unsigned char *)&header);
- 	
--	if (ret) 
--	    return ret;
-+	if (err) 
-+	    return err;
- 
- 	if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
-     }
-@@ -958,7 +959,7 @@
- 	if (ret) {
- 	    printk(KERN_NOTICE "ftl_cs: block write failed!\n");
- 	    printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
--		   " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
-+		   " = 0x%x, Offset = 0x%zx\n", log_addr, virt_addr,
- 		   offset);
- 	    return -EIO;
- 	}
-@@ -1093,7 +1094,7 @@
- 
- 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.53 2004/08/09 13:55:43 dwmw2 Exp $\n");
- 
- 	return register_mtd_blktrans(&ftl_tr);
- }
-Index: linux-2.6.5/drivers/mtd/inftlcore.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/inftlcore.c	2004-04-03 22:36:18.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/inftlcore.c	2005-02-01 17:11:29.000000000 -0500
-@@ -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.17 2004/08/09 13:56:48 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 @@
- 	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 @@
- 	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");
-@@ -155,8 +167,8 @@
- 	u16 pot = inftl->LastFreeEUN;
- 	int silly = inftl->nb_blocks;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=0x%x,"
--		"desperate=%d)\n", (int)inftl, desperate);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p,"
-+		"desperate=%d)\n", inftl, desperate);
- 
- 	/*
- 	 * Normally, we force a fold to happen before we run out of free
-@@ -198,8 +210,8 @@
- 	struct inftl_oob oob;
-         size_t retlen;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=0x%x,thisVUC=%d,"
--		"pending=%d)\n", (int)inftl, thisVUC, pendingblock);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,"
-+		"pending=%d)\n", inftl, thisVUC, pendingblock);
- 
- 	memset(BlockMap, 0xff, sizeof(BlockMap));
- 	memset(BlockDeleted, 0, sizeof(BlockDeleted));
-@@ -284,21 +296,22 @@
-                 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 @@
-                 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 {
-@@ -354,8 +366,8 @@
- 	u16 ChainLength = 0, thislen;
- 	u16 chain, EUN;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=0x%x,"
--		"pending=%d)\n", (int)inftl, pendingblock);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p,"
-+		"pending=%d)\n", inftl, pendingblock);
- 
- 	for (chain = 0; chain < inftl->nb_blocks; chain++) {
- 		EUN = inftl->VUtable[chain];
-@@ -416,8 +428,8 @@
- 	size_t retlen;
- 	int silly, silly2 = 3;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=0x%x,"
--		"block=%d)\n", (int)inftl, block);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p,"
-+		"block=%d)\n", inftl, block);
- 
- 	do {
- 		/*
-@@ -578,8 +590,8 @@
- 	struct inftl_bci bci;
- 	size_t retlen;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=0x%x,"
--		"thisVUC=%d)\n", (int)inftl, thisVUC);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p,"
-+		"thisVUC=%d)\n", inftl, thisVUC);
- 
- 	memset(BlockUsed, 0, sizeof(BlockUsed));
- 	memset(BlockDeleted, 0, sizeof(BlockDeleted));
-@@ -668,7 +680,6 @@
-                 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 {
-@@ -698,8 +709,8 @@
- 	size_t retlen;
- 	struct inftl_bci bci;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=0x%x,"
--		"block=%d)\n", (int)inftl, block);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p,"
-+		"block=%d)\n", inftl, block);
- 
- 	while (thisEUN < inftl->nb_blocks) {
- 		if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
-@@ -754,11 +765,11 @@
- 	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,"
--		"buffer=0x%x)\n", (int)inftl, block, (int)buffer);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld,"
-+		"buffer=%p)\n", inftl, block, buffer);
- 
- 	/* Is block all zero? */
- 	pend = buffer + SECTORSIZE;
-@@ -778,11 +789,13 @@
- 			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 {
-@@ -803,8 +816,8 @@
-         struct inftl_bci bci;
- 	size_t retlen;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=0x%x,block=%ld,"
--		"buffer=0x%x)\n", (int)inftl, block, (int)buffer);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"
-+		"buffer=%p)\n", inftl, block, buffer);
- 
- 	while (thisEUN < inftl->nb_blocks) {
- 		if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
-@@ -846,9 +859,8 @@
- 	} 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 @@
- 
- int __init init_inftl(void)
- {
--	printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.14 $, "
-+	printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.17 $, "
- 		"inftlmount.c %s\n", inftlmountrev);
- 
- 	return register_mtd_blktrans(&inftl_tr);
-Index: linux-2.6.5/drivers/mtd/inftlmount.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/inftlmount.c	2004-04-03 22:36:16.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/inftlmount.c	2005-02-01 17:11:29.000000000 -0500
-@@ -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.14 2004/08/09 13:57:42 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
-@@ -41,7 +41,7 @@
- #include <linux/mtd/inftl.h>
- #include <linux/mtd/compatmac.h>
- 
--char inftlmountrev[]="$Revision: 1.11 $";
-+char inftlmountrev[]="$Revision: 1.14 $";
- 
- /*
-  * find_boot_record: Find the INFTL Media Header and its Spare copy which
-@@ -54,14 +54,13 @@
- {
- 	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;
--	int retlen;
-+	size_t retlen;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=0x%x)\n",
--		(int)inftl);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=%p)\n", inftl);
- 
-         /*
- 	 * Assume logical EraseSize == physical erasesize for starting the
-@@ -72,7 +71,6 @@
-         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 +80,11 @@
- 		 * 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 +115,28 @@
- 			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 +190,9 @@
- 				"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 */
-@@ -293,7 +287,7 @@
- 		inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL);
- 		if (!inftl->PUtable) {
- 			printk(KERN_WARNING "INFTL: allocation of PUtable "
--				"failed (%d bytes)\n",
-+				"failed (%zd bytes)\n",
- 				inftl->nb_blocks * sizeof(u16));
- 			return -ENOMEM;
- 		}
-@@ -302,7 +296,7 @@
- 		if (!inftl->VUtable) {
- 			kfree(inftl->PUtable);
- 			printk(KERN_WARNING "INFTL: allocation of VUtable "
--				"failed (%d bytes)\n",
-+				"failed (%zd bytes)\n",
- 				inftl->nb_blocks * sizeof(u16));
- 			return -ENOMEM;
- 		}
-@@ -317,34 +311,23 @@
- 		/* 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)
-@@ -364,28 +347,22 @@
- 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];
-+	size_t retlen;
-+	int i;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x,"
--		"address=0x%x,len=%d,check_oob=%d)\n", (int)inftl,
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=%p,"
-+		"address=0x%x,len=%d,check_oob=%d)\n", 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 @@
-  * 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;
-+	size_t 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);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p,"
-+		"block=%d)\n", 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 @@
- 		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 {
-@@ -565,10 +551,11 @@
- 	int chain_length, do_format_chain;
- 	struct inftl_unithead1 h0;
- 	struct inftl_unittail h1;
--	int i, retlen;
-+	size_t retlen;
-+	int i;
- 	u8 *ANACtable, ANAC;
- 
--	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=0x%x)\n", (int)s);
-+	DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=%p)\n", s);
- 
- 	/* Search for INFTL MediaHeader and Spare INFTL Media Header */
- 	if (find_boot_record(s) < 0) {
-Index: linux-2.6.5/drivers/mtd/maps/Kconfig
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/Kconfig	2004-04-03 22:38:21.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/Kconfig	2005-02-01 17:11:17.000000000 -0500
-@@ -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.34 2004/09/02 01:27:07 eric Exp $
- 
- menu "Mapping drivers for chip access"
- 	depends on MTD!=n
-@@ -19,7 +19,8 @@
- 	  command set driver code to communicate with flash chips which
- 	  are mapped physically into the CPU's memory. You will need to
- 	  configure the physical address and size of the flash chips on
--	  your particular board as well as the bus width.
-+	  your particular board as well as the bus width, either statically
-+	  with config options or at run-time.
- 
- config MTD_PHYSMAP_START
- 	hex "Physical start address of flash mapping"
-@@ -30,6 +31,8 @@
- 	  are mapped on your particular target board. Refer to the
- 	  memory map which should hopefully be in the documentation for
- 	  your board.
-+	  Ignore this option if you use run-time physmap configuration
-+	  (i.e., run-time calling physmap_configure()).
- 
- config MTD_PHYSMAP_LEN
- 	hex "Physical length of flash mapping"
-@@ -42,9 +45,11 @@
- 	  than the total amount of flash present. Refer to the memory
- 	  map which should hopefully be in the documentation for your
- 	  board.
-+	  Ignore this option if you use run-time physmap configuration
-+	  (i.e., run-time calling physmap_configure()).
- 
--config MTD_PHYSMAP_BUSWIDTH
--	int "Bus width in octets"
-+config MTD_PHYSMAP_BANKWIDTH
-+	int "Bank width in octets"
- 	depends on MTD_PHYSMAP
- 	default "2"
- 	help
-@@ -52,6 +57,8 @@
- 	  in octets. For example, if you have a data bus width of 32
- 	  bits, you would set the bus width octect value to 4. This is
- 	  used internally by the CFI drivers.
-+	  Ignore this option if you use run-time physmap configuration
-+	  (i.e., run-time calling physmap_configure()).
- 
- config MTD_SUN_UFLASH
- 	tristate "Sun Microsystems userflash support"
-@@ -94,7 +101,7 @@
- 	  By default the flash is split into 3 partitions which are accessed
- 	  as separate MTD devices. This board utilizes Intel StrataFlash.
- 	  More info at
--	  <http://www.arcomcontrols.com/products/icp/pc104/processors/>.
-+	  <http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>.
- 
- config MTD_ELAN_104NC
- 	tristate "CFI Flash device mapped on Arcom ELAN-104NC"
-@@ -104,7 +111,7 @@
- 	  System's ELAN-104NC development board. By default the flash
- 	  is split into 3 partitions which are accessed as separate MTD
- 	  devices. This board utilizes Intel StrataFlash. More info at
--	  <http://www.arcomcontrols.com/products/icp/pc104/processors/>.
-+	  <http://www.arcomcontrols.com/products/icp/pc104/processors/ELAN104NC.htm>.
- 
- config MTD_LUBBOCK
- 	tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
-@@ -120,7 +127,7 @@
- 	  This provides a 'mapping' driver which supports the way in which
- 	  the flash chips are connected in the Octagon-5066 Single Board
- 	  Computer. More information on the board is available at
--	  <http://www.octagonsystems.com/Products/5066/5066.html>.
-+	  <http://www.octagonsystems.com/CPUpages/5066.html>.
- 
- config MTD_VMAX
- 	tristate "JEDEC Flash device mapped on Tempustech VMAX SBC301"
-@@ -129,7 +136,7 @@
- 	  This provides a 'mapping' driver which supports the way in which
- 	  the flash chips are connected in the Tempustech VMAX SBC301 Single
- 	  Board Computer. More information on the board is available at
--	  <http://www.tempustech.com/tt301.htm>.
-+	  <http://www.tempustech.com/>.
- 
- config MTD_SCx200_DOCFLASH
- 	tristate "Flash device mapped with DOCCS on NatSemi SCx200"
-@@ -151,11 +158,11 @@
- 
- 	  BE VERY CAREFUL.
- 
--config MTD_ICH2ROM
--	tristate "BIOS flash chip on Intel Hub Controller 2"
--	depends on X86 && MTD_JEDECPROBE && MTD_COMPLEX_MAPPINGS
-+config MTD_ICHXROM
-+	tristate "BIOS flash chip on Intel Controller Hub 2/3/4/5"
-+	depends on X86 && MTD_JEDECPROBE
- 	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 +184,7 @@
- 
- 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,13 +217,59 @@
- 	  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
- 	help
- 	  MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP".
--	  For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm
-- 	  and http://www.ssv-embedded.de/ssv/pc104/p170.htm
-+	  For details, see <http://www.ssv-embedded.de/ssv/pc104/p169.htm>
-+ 	  and <http://www.ssv-embedded.de/ssv/pc104/p170.htm>
- 
- config MTD_DILNETPC_BOOTSIZE
- 	hex "Size of DIL/Net PC flash boot partition"
-@@ -235,6 +288,13 @@
- 
- 	  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
-@@ -253,7 +313,7 @@
- 	  a strange sparse mapping. This 'mapping' driver supports that
- 	  arrangement, allowing the CFI probe and command set driver code
- 	  to communicate with the chips on the RPXLite board. More at
--	  <http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>.
-+	  <http://www.embeddedplanet.com/>.
- 
- config MTD_MBX860
- 	tristate "System flash on MBX860 board"
-@@ -265,7 +325,7 @@
- 
- 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
-@@ -295,13 +355,21 @@
- 	  use the flash chips on it, say 'Y'.
- 
- config MTD_EBONY
--	tristate "CFI Flash device mapped on IBM 440GP Ebony"
--	depends on MTD_CFI && PPC32 && 440 && EBONY
-+	tristate "Flash devices mapped on IBM 440GP Ebony"
-+	depends on MTD_CFI && PPC32 && 44x && EBONY
- 	help
- 	  This enables access routines for the flash chips on the IBM 440GP
- 	  Ebony board. If you have one of these boards and would like to
- 	  use the flash chips on it, say 'Y'.
- 
-+config MTD_OCOTEA
-+	tristate "Flash devices mapped on IBM 440GX Ocotea"
-+	depends on MTD_CFI && PPC32 && 44x && OCOTEA
-+	help
-+	  This enables access routines for the flash chips on the IBM 440GX
-+	  Ocotea board. If you have one of these boards and would like to
-+	  use the flash chips on it, say 'Y'.
-+
- config MTD_REDWOOD
- 	tristate "CFI Flash devices mapped on IBM Redwood"
- 	depends on MTD_CFI && PPC32 && 4xx && 40x && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 )
-@@ -388,13 +456,19 @@
- 	  the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
- 	  If you have such a board, say 'Y'.
- 
-+config MTD_IPAQ
-+	tristate "CFI Flash device mapped on Compaq/HP iPAQ"
-+	depends on ARM && IPAQ_HANDHELD && MTD_CFI
-+	help
-+	  This provides a driver for the on-board flash of the iPAQ.
-+
- config MTD_DC21285
- 	tristate "CFI Flash device mapped on DC21285 Footbridge"
- 	depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS
- 	help
- 	  This provides a driver for the flash accessed using Intel's
- 	  21285 bridge used with Intel's StrongARM processors. More info at
--	  <http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm>.
-+	  <http://www.intel.com/design/bridge/docs/21285_documentation.htm>.
- 
- config MTD_IQ80310
- 	tristate "CFI Flash device mapped on the XScale IQ80310 board"
-@@ -404,6 +478,24 @@
- 	  IQ80310 evaluation board. If you have one of these boards and would 
- 	  like to use the flash chips on it, say 'Y'.
- 
-+config MTD_IXP4XX
-+	tristate "CFI Flash device mapped on Intel IXP4xx based systems"
-+	depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX
-+	help
-+	  This enables MTD access to flash devices on platforms based 
-+	  on Intel's IXP4xx family of network processors such as the
-+	  IXDP425 and Coyote. If you have an IXP4xx based board and
-+	  would like to use the flash chips on it, say 'Y'.
-+
-+config MTD_IXP2000
-+	tristate "CFI Flash device mapped on Intel IXP2000 based systems"
-+	depends on ARM && MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP2000
-+	help
-+	  This enables MTD access to flash devices on platforms based 
-+	  on Intel's IXP2000 family of network processors such as the
-+	  IXDP425 and Coyote. If you have an IXP2000 based board and
-+	  would like to use the flash chips on it, say 'Y'.
-+
- config MTD_EPXA10DB
- 	tristate "CFI Flash device mapped on Epxa10db"
- 	depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT
-@@ -448,6 +540,13 @@
- 	  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 )
-@@ -455,6 +554,13 @@
- 	  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"
-@@ -480,5 +586,28 @@
- 	help
- 	  Map driver to support image based filesystems for uClinux.
- 
-+config MTD_WRSBC8260
-+	tristate "Map driver for WindRiver PowerQUICC II MPC82xx board"
-+	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: linux-2.6.5/drivers/mtd/maps/Makefile
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/Makefile	2004-04-03 22:36:12.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/Makefile	2005-02-01 17:11:17.000000000 -0500
-@@ -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.17 2004/09/02 00:13:41 dsaxena Exp $
- 
- ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
- obj-$(CONFIG_MTD)		+= map_funcs.o
-@@ -19,7 +19,7 @@
- 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
-@@ -31,6 +31,7 @@
- obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
- obj-$(CONFIG_MTD_TQM8XXL)	+= tqm8xxl.o
- obj-$(CONFIG_MTD_SA1100)	+= sa1100-flash.o
-+obj-$(CONFIG_MTD_IPAQ)		+= ipaq-flash.o
- obj-$(CONFIG_MTD_SBC_GXX)	+= sbc_gxx.o
- obj-$(CONFIG_MTD_SC520CDP)	+= sc520cdp.o
- obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
-@@ -42,6 +43,9 @@
- 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
-@@ -52,6 +56,14 @@
- obj-$(CONFIG_MTD_NETtel)	+= nettel.o
- obj-$(CONFIG_MTD_SCB2_FLASH)	+= scb2_flash.o
- obj-$(CONFIG_MTD_EBONY)		+= ebony.o
-+obj-$(CONFIG_MTD_OCOTEA)	+= ocotea.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_IXP2000)	+= ixp2000.o
-+obj-$(CONFIG_MTD_WRSBC8260)	+= wr_sbc82xx_flash.o
-+obj-$(CONFIG_MTD_DMV182)	+= dmv182.o
-Index: linux-2.6.5/drivers/mtd/maps/amd76xrom.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/amd76xrom.c	2004-04-03 22:36:52.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/amd76xrom.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.16 2004/09/17 11:45:06 eric Exp $
-  */
- 
- #include <linux/module.h>
-@@ -12,152 +12,265 @@
- #include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
-+#include <linux/mtd/cfi.h>
-+#include <linux/mtd/flashchip.h>
- #include <linux/config.h>
- #include <linux/pci.h>
- #include <linux/pci_ids.h>
-+#include <linux/list.h>
- 
- 
-+#define xstr(s) str(s)
-+#define str(s) #s
-+#define MOD_NAME xstr(KBUILD_BASENAME)
-+
-+#define ADDRESS_NAME_LEN 18
-+
-+#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
-+
-+struct amd76xrom_window {
-+	void __iomem *virt;
-+	unsigned long phys;
-+	unsigned long size;
-+	struct list_head maps;
-+	struct resource rsrc;
-+	struct pci_dev *pdev;
-+};
-+
- struct amd76xrom_map_info {
-+	struct list_head list;
- 	struct map_info map;
- 	struct mtd_info *mtd;
--	unsigned long window_addr;
--	u32 window_start, window_size;
--	struct pci_dev *pdev;
-+	struct resource rsrc;
-+	char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
- };
- 
--
--static struct amd76xrom_map_info amd76xrom_map = {
--	.map = {
--		.name = "AMD76X rom",
--		.size = 0,
--		.buswidth = 1,
--	},
--	.mtd = 0,
--	.window_addr = 0,
-+static struct amd76xrom_window amd76xrom_window = {
-+	.maps = LIST_HEAD_INIT(amd76xrom_window.maps),
- };
- 
-+static void amd76xrom_cleanup(struct amd76xrom_window *window)
-+{
-+	struct amd76xrom_map_info *map, *scratch;
-+	u8 byte;
-+
-+	if (window->pdev) {
-+		/* Disable writes through the rom window */
-+		pci_read_config_byte(window->pdev, 0x40, &byte);
-+		pci_write_config_byte(window->pdev, 0x40, byte & ~1);
-+	}
-+
-+	/* Free all of the mtd devices */
-+	list_for_each_entry_safe(map, scratch, &window->maps, list) {
-+		if (map->rsrc.parent) {
-+			release_resource(&map->rsrc);
-+		}
-+		del_mtd_device(map->mtd);
-+		map_destroy(map->mtd);
-+		list_del(&map->list);
-+		kfree(map);
-+	}
-+	if (window->rsrc.parent) 
-+		release_resource(&window->rsrc);
-+
-+	if (window->virt) {
-+		iounmap(window->virt);
-+		window->virt = NULL;
-+		window->phys = 0;
-+		window->size = 0;
-+		window->pdev = NULL;
-+	}
-+}
-+
-+
- static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
- 	const struct pci_device_id *ent)
- {
--	struct rom_window {
--		u32 start;
--		u32 size;
--		u8 segen_bits;
--	};
--	static struct rom_window rom_window[] = {
--		{ 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), },
--		{ 0xffc00000, 4*1024*1024, (1<<7), },
--		{ 0xffff0000, 64*1024,     0 },
--		{ 0         , 0,           0 },
--	};
--	static const u32 rom_probe_sizes[] = { 
--		5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, 
--		256*1024, 128*1024, 64*1024, 0};
--	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 };
-+	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
- 	u8 byte;
--	struct amd76xrom_map_info *info = &amd76xrom_map;
--	struct rom_window *window;
--	int i;
--	u32 rom_size;
--
--	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;
--		}
--		window++;
-+	struct amd76xrom_window *window = &amd76xrom_window;
-+	struct amd76xrom_map_info *map = 0;
-+	unsigned long map_top;
-+
-+	/* Remember the pci dev I find the window in */
-+	window->pdev = pdev;
-+
-+	/* Assume the rom window is properly setup, and find it's size */
-+	pci_read_config_byte(pdev, 0x43, &byte);
-+	if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) {
-+		window->phys = 0xffb00000; /* 5MiB */
-+	}
-+	else if ((byte & (1<<7)) == (1<<7)) {
-+		window->phys = 0xffc00000; /* 4MiB */
-+	}
-+	else {
-+		window->phys = 0xffff0000; /* 64KiB */
- 	}
--	if (!window->size) {
--		printk(KERN_ERR "amd76xrom: cannot reserve rom window\n");
--		goto err_out_none;
-+	window->size = 0xffffffffUL - window->phys + 1UL;
-+	
-+	/*
-+	 * 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.
-+	 */
-+	window->rsrc.name = MOD_NAME;
-+	window->rsrc.start = window->phys;
-+	window->rsrc.end   = window->phys + window->size - 1;
-+	window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+	if (request_resource(&iomem_resource, &window->rsrc)) {
-+		window->rsrc.parent = NULL;
-+		printk(KERN_ERR MOD_NAME
-+			" %s(): Unable to register resource"
-+			" 0x%.08lx-0x%.08lx - kernel bug?\n",
-+			__func__,
-+			window->rsrc.start, window->rsrc.end);
- 	}
--#endif /* REQUEST_MEM_REGION */
-+
-+#if 0
- 
- 	/* Enable the selected rom window */
- 	pci_read_config_byte(pdev, 0x43, &byte);
--	pci_write_config_byte(pdev, 0x43, byte | window->segen_bits);
-+	pci_write_config_byte(pdev, 0x43, byte | rwindow->segen_bits);
-+#endif
- 
- 	/* 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 */
- 
--	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);
-+	window->virt = ioremap_nocache(window->phys, window->size);
-+	if (!window->virt) {
-+		printk(KERN_ERR MOD_NAME ": Failed to ioremap\n");
-+		goto out;
-+	}
-+
-+	/* Get the first address to look for an rom chip at */
-+	map_top = window->phys;
-+#if 1
-+	/* The probe sequence run over the firmware hub lock
-+	 * registers sets them to 0x7 (no access).
-+	 * Probe at most the last 4M of the address space.
-+	 */
-+	if (map_top < 0xffc00000) {
-+		map_top = 0xffc00000;
-+	}
-+#endif
-+	/* Loop  through and look for rom chips */
-+	while((map_top - 1) < 0xffffffffUL) {
-+		struct cfi_private *cfi;
-+		unsigned long offset;
-+		int i;
- 
--	if (!info->window_addr) {
--		printk(KERN_ERR "Failed to ioremap\n");
--		goto err_out_free_mmio_region;
--	}
--	info->mtd = 0;
--	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 (!map) {
-+			map = kmalloc(sizeof(*map), GFP_KERNEL);
- 		}
--		if (info->mtd) {
--			break;
-+		if (!map) {
-+			printk(KERN_ERR MOD_NAME ": kmalloc failed");
-+			goto out;
-+		}
-+		memset(map, 0, sizeof(*map));
-+		INIT_LIST_HEAD(&map->list);
-+		map->map.name = map->map_name;
-+		map->map.phys = map_top;
-+		offset = map_top - window->phys;
-+		map->map.virt = (void __iomem *)
-+			(((unsigned long)(window->virt)) + offset);
-+		map->map.size = 0xffffffffUL - map_top + 1UL;
-+		/* Set the name of the map to the address I am trying */
-+		sprintf(map->map_name, "%s @%08lx",
-+			MOD_NAME, map->map.phys);
-+
-+		/* There is no generic VPP support */
-+		for(map->map.bankwidth = 32; map->map.bankwidth; 
-+			map->map.bankwidth >>= 1)
-+		{
-+			char **probe_type;
-+			/* Skip bankwidths that are not supported */
-+			if (!map_bankwidth_supported(map->map.bankwidth))
-+				continue;
-+
-+			/* Setup the map methods */
-+			simple_map_init(&map->map);
-+
-+			/* Try all of the probe methods */
-+			probe_type = rom_probe_types;
-+			for(; *probe_type; probe_type++) {
-+				map->mtd = do_map_probe(*probe_type, &map->map);
-+				if (map->mtd)
-+					goto found;
-+			}
-+		}
-+		map_top += ROM_PROBE_STEP_SIZE;
-+		continue;
-+	found:
-+		/* Trim the size if we are larger than the map */
-+		if (map->mtd->size > map->map.size) {
-+			printk(KERN_WARNING MOD_NAME
-+				" rom(%u) larger than window(%lu). fixing...\n",
-+				map->mtd->size, map->map.size);
-+			map->mtd->size = map->map.size;
-+		}
-+		if (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.
-+			 */
-+			map->rsrc.name  = map->map_name;
-+			map->rsrc.start = map->map.phys;
-+			map->rsrc.end   = map->map.phys + map->mtd->size - 1;
-+			map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+			if (request_resource(&window->rsrc, &map->rsrc)) {
-+				printk(KERN_ERR MOD_NAME
-+					": cannot reserve MTD resource\n");
-+				map->rsrc.parent = NULL;
-+			}
-+		}
-+
-+		/* Make the whole region visible in the map */
-+		map->map.virt = window->virt;
-+		map->map.phys = window->phys;
-+		cfi = map->map.fldrv_priv;
-+		for(i = 0; i < cfi->numchips; i++) {
-+			cfi->chips[i].start += offset;
- 		}
-+		
-+		/* Now that the mtd devices is complete claim and export it */
-+		map->mtd->owner = THIS_MODULE;
-+		add_mtd_device(map->mtd);
-+
-+
-+		/* Calculate the new value of map_top */
-+		map_top += map->mtd->size;
-+
-+		/* File away the map structure */
-+		list_add(&map->list, &window->maps);
-+		map = 0;
- 	}
--	if (!info->mtd) {
--		goto err_out_iounmap;
-+
-+ out:
-+	/* Free any left over map structures */
-+	if (map) {
-+		kfree(map);
-+	}
-+	/* See if I have any map structures */
-+	if (list_empty(&window->maps)) {
-+		amd76xrom_cleanup(window);
-+		return -ENODEV;
- 	}
--	printk(KERN_NOTICE "amd76xrom chip at offset: 0x%x\n",
--		window->size - rom_size);
--		
--	info->mtd->owner = THIS_MODULE;
--	add_mtd_device(info->mtd);
--	info->window_start = window->start;
--	info->window_size = window->size;
- 	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 */
--	return -ENODEV;
- }
- 
- 
- 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 = 0;
--	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);
-+	struct amd76xrom_window *window = &amd76xrom_window;
- 
--#if REQUEST_MEM_REGION
--	release_mem_region(info->window_start, info->window_size);
--#endif /* REQUEST_MEM_REGION */
-+	amd76xrom_cleanup(window);
- }
- 
- static struct pci_device_id amd76xrom_pci_tbl[] = {
-@@ -173,7 +286,7 @@
- 
- #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,
-@@ -184,15 +297,14 @@
- {
- 	struct pci_dev *pdev;
- 	struct pci_device_id *id;
--	pdev = 0;
-+	pdev = NULL;
- 	for(id = amd76xrom_pci_tbl; id->vendor; id++) {
--		pdev = pci_find_device(id->vendor, id->device, 0);
-+		pdev = pci_find_device(id->vendor, id->device, NULL);
- 		if (pdev) {
- 			break;
- 		}
- 	}
- 	if (pdev) {
--		amd76xrom_map.pdev = pdev;
- 		return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]);
- 	}
- 	return -ENXIO;
-@@ -203,7 +315,7 @@
- 
- static void __exit cleanup_amd76xrom(void)
- {
--	amd76xrom_remove_one(amd76xrom_map.pdev);
-+	amd76xrom_remove_one(amd76xrom_window.pdev);
- }
- 
- module_init(init_amd76xrom);
-Index: linux-2.6.5/drivers/mtd/maps/arctic-mtd.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/arctic-mtd.c	2004-04-03 22:36:55.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/arctic-mtd.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.12 2004/09/16 23:27:12 gleixner 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,
- };
- 
-@@ -98,7 +98,7 @@
- {
- 	printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
- 
--	arctic_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE);
-+	arctic_mtd_map.virt = (void __iomem *) ioremap(PADDR, SIZE);
- 
- 	if (!arctic_mtd_map.virt) {
- 		printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-Index: linux-2.6.5/drivers/mtd/maps/autcpu12-nvram.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/autcpu12-nvram.c	2004-04-03 22:38:17.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/autcpu12-nvram.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.7 2004/09/16 23:27: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 as published by
-@@ -39,7 +39,7 @@
- struct map_info autcpu12_sram_map = {
- 	.name = "SRAM",
- 	.size = 32768,
--	.buswidth = 4,
-+	.bankwidth = 4,
- 	.phys = 0x12000000,
- };
- 
-@@ -47,7 +47,7 @@
- {
- 	int err, save0, save1;
- 
--	autcpu12_sram_map.virt = (unsigned long)ioremap(0x12000000, SZ_128K);
-+	autcpu12_sram_map.virt = (void __iomem *)ioremap(0x12000000, SZ_128K);
- 	if (!autcpu12_sram_map.virt) {
- 		printk("Failed to ioremap autcpu12 NV-RAM space\n");
- 		err = -EIO;
-@@ -76,7 +76,7 @@
- 	/* We have a 128K found, restore 0x10000 and set size
- 	 * to 128K
- 	 */
--	ma[_write32(&autcpu12_sram_map,save1,0x10000);
-+	map_write32(&autcpu12_sram_map,save1,0x10000);
- 	autcpu12_sram_map.size = SZ_128K;
- 
- map:
-Index: linux-2.6.5/drivers/mtd/maps/beech-mtd.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/beech-mtd.c	2004-04-03 22:37:36.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/beech-mtd.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.9 2004/09/16 23:27:12 gleixner 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
- };
- 
-@@ -74,7 +74,7 @@
- {
- 	printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
- 
--	beech_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE);
-+	beech_mtd_map.virt = (void __iomem *) ioremap(PADDR, SIZE);
- 
- 	if (!beech_mtd_map.virt) {
- 		printk("%s: failed to ioremap 0x%x\n", NAME, PADDR);
-Index: linux-2.6.5/drivers/mtd/maps/cdb89712.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/cdb89712.c	2004-04-03 22:38:26.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/cdb89712.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.9 2004/09/16 23:27:12 gleixner Exp $
-  */
- 
- #include <linux/module.h>
-@@ -23,7 +23,7 @@
- struct map_info cdb89712_flash_map = {
- 	.name = "flash",
- 	.size = FLASH_SIZE,
--	.buswidth = FLASH_WIDTH,
-+	.bankwidth = FLASH_WIDTH,
- 	.phys = FLASH_START,
- };
- 
-@@ -44,7 +44,7 @@
- 		goto out;
- 	}
- 	
--	cdb89712_flash_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-+	cdb89712_flash_map.virt = (void __iomem *)ioremap(FLASH_START, FLASH_SIZE);
- 	if (!cdb89712_flash_map.virt) {
- 		printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n");
- 		err = -EIO;
-@@ -93,7 +93,7 @@
- struct map_info cdb89712_sram_map = {
- 	.name = "SRAM",
- 	.size = SRAM_SIZE,
--	.buswidth = SRAM_WIDTH,
-+	.bankwidth = SRAM_WIDTH,
- 	.phys = SRAM_START,
- };
- 
-@@ -114,7 +114,7 @@
- 		goto out;
- 	}
- 	
--	cdb89712_sram_map.virt = (unsigned long)ioremap(SRAM_START, SRAM_SIZE);
-+	cdb89712_sram_map.virt = (void __iomem *)ioremap(SRAM_START, SRAM_SIZE);
- 	if (!cdb89712_sram_map.virt) {
- 		printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n");
- 		err = -EIO;
-@@ -161,7 +161,7 @@
- struct map_info cdb89712_bootrom_map = {
- 	.name = "BootROM",
- 	.size = BOOTROM_SIZE,
--	.buswidth = BOOTROM_WIDTH,
-+	.bankwidth = BOOTROM_WIDTH,
- 	.phys = BOOTROM_START,
- };
- 
-@@ -182,7 +182,7 @@
- 		goto out;
- 	}
- 	
--	cdb89712_bootrom_map.virt = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE);
-+	cdb89712_bootrom_map.virt = (void __iomem *)ioremap(BOOTROM_START, BOOTROM_SIZE);
- 	if (!cdb89712_bootrom_map.virt) {
- 		printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n");
- 		err = -EIO;
-Index: linux-2.6.5/drivers/mtd/maps/ceiva.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/ceiva.c	2004-04-03 22:36:55.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/ceiva.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.11 2004/09/16 23:27:12 gleixner Exp $
-  */
- 
- #include <linux/config.h>
-@@ -150,8 +150,8 @@
- 			break;
- 		}
- 
--		clps[i].map->virt = (unsigned long)clps[i].vbase;
--		clps[i].map->buswidth = clps[i].width;
-+		clps[i].map->virt = (void __iomem *)clps[i].vbase;
-+		clps[i].map->bankwidth = clps[i].width;
- 		clps[i].map->size = clps[i].size;
- 
- 		simple_map_init(&clps[i].map);
-Index: linux-2.6.5/drivers/mtd/maps/cfi_flagadm.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/cfi_flagadm.c	2004-04-03 22:36:13.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/cfi_flagadm.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.13 2004/09/16 23:27: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 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[] = {
-@@ -96,7 +96,7 @@
- 			FLASH_SIZE, FLASH_PHYS_ADDR);
- 	
- 	flagadm_map.phys = FLASH_PHYS_ADDR;
--	flagadm_map.virt = (unsigned long)ioremap(FLASH_PHYS_ADDR,
-+	flagadm_map.virt = (void __iomem *s)ioremap(FLASH_PHYS_ADDR,
- 					FLASH_SIZE);
- 
- 	if (!flagadm_map.virt) {
-Index: linux-2.6.5/drivers/mtd/maps/cstm_mips_ixx.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/cstm_mips_ixx.c	2004-04-03 22:36:25.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/cstm_mips_ixx.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.11 2004/09/16 23:27:12 gleixner 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 @@
- 	char *name;
- 	unsigned long window_addr;
- 	unsigned long window_size;
--	int buswidth;
-+	int bankwidth;
- 	int num_partitions;
- };
- 
-@@ -116,7 +116,7 @@
-         "big flash",     // name
- 	0x08000000,      // window_addr
- 	0x02000000,      // window_size
--        4,               // buswidth
-+        4,               // bankwidth
- 	1,               // num_partitions
-     }
- 
-@@ -138,7 +138,7 @@
-         "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
-     },
- 
-@@ -170,14 +170,14 @@
- 
- 
- 		cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
--		cstm_mips_ixx_map[i].virt = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
-+		cstm_mips_ixx_map[i].virt = (void __iomem *)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
- 		if (!cstm_mips_ixx_map[i].virt) {
- 			printk(KERN_WARNING "Failed to ioremap\n");
- 			return -EIO;
- 	        }
- 		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: linux-2.6.5/drivers/mtd/maps/db1550-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/db1550-flash.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/db1550-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,188 @@
-+/*
-+ * Flash memory access on Alchemy Db1550 board
-+ * 
-+ * $Id: db1550-flash.c,v 1.4 2004/09/16 23:27:12 gleixner Exp $
-+ *
-+ * (C) 2004 Embedded Edge, LLC, based on db1550-flash.c:
-+ * (C) 2003 Pete Popov <pete_popov@yahoo.com>
-+ * 
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/au1000.h>
-+
-+#ifdef 	DEBUG_RW
-+#define	DBG(x...)	printk(x)
-+#else
-+#define	DBG(x...)	
-+#endif
-+
-+static unsigned long window_addr;
-+static unsigned long window_size;
-+
-+
-+static struct map_info db1550_map = {
-+	.name =	"Db1550 flash",
-+};
-+
-+static unsigned char flash_bankwidth = 4;
-+
-+/* 
-+ * Support only 64MB NOR Flash parts
-+ */
-+
-+#if defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-+#define DB1550_BOTH_BANKS
-+#elif defined(CONFIG_MTD_DB1550_BOOT) && !defined(CONFIG_MTD_DB1550_USER)
-+#define DB1550_BOOT_ONLY
-+#elif !defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-+#define DB1550_USER_ONLY
-+#endif
-+
-+#ifdef DB1550_BOTH_BANKS
-+/* both banks will be used. Combine the first bank and the first 
-+ * part of the second bank together into a single jffs/jffs2
-+ * partition.
-+ */
-+static struct mtd_partition db1550_partitions[] = {
-+	/* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-+	 * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-+	 * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-+	 */
-+        {
-+                .name = "User FS",
-+                .size =   (0x1FC00000 - 0x18000000),
-+                .offset = 0x0000000
-+        },{
-+                .name = "yamon",
-+                .size = 0x0100000,
-+		.offset = MTDPART_OFS_APPEND,
-+                .mask_flags = MTD_WRITEABLE
-+        },{
-+                .name = "raw kernel",
-+		.size = (0x300000 - 0x40000), /* last 256KB is yamon env */
-+		.offset = MTDPART_OFS_APPEND,
-+        }
-+};
-+#elif defined(DB1550_BOOT_ONLY)
-+static struct mtd_partition db1550_partitions[] = {
-+	/* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-+	 * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-+	 */
-+        {
-+                .name = "User FS",
-+                .size =   0x03c00000,
-+                .offset = 0x0000000
-+        },{
-+                .name = "yamon",
-+                .size = 0x0100000,
-+		.offset = MTDPART_OFS_APPEND,
-+                .mask_flags = MTD_WRITEABLE
-+        },{
-+                .name = "raw kernel",
-+		.size = (0x300000-0x40000), /* last 256KB is yamon env */
-+		.offset = MTDPART_OFS_APPEND,
-+        }
-+};
-+#elif defined(DB1550_USER_ONLY)
-+static struct mtd_partition db1550_partitions[] = {
-+	/* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-+	 * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-+	 */
-+        {
-+                .name = "User FS",
-+                .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
-+                .offset = 0x0000000
-+        },{
-+                .name = "raw kernel",
-+		.size = MTDPART_SIZ_FULL,
-+		.offset = MTDPART_OFS_APPEND,
-+        }
-+};
-+#else
-+#error MTD_DB1550 define combo error /* should never happen */
-+#endif
-+
-+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-+
-+static struct mtd_info *mymtd;
-+
-+/*
-+ * Probe the flash density and setup window address and size
-+ * based on user CONFIG options. There are times when we don't
-+ * want the MTD driver to be probing the boot or user flash,
-+ * so having the option to enable only one bank is important.
-+ */
-+int setup_flash_params(void)
-+{
-+#if defined(DB1550_BOTH_BANKS)
-+			window_addr = 0x18000000;
-+			window_size = 0x8000000; 
-+#elif defined(DB1550_BOOT_ONLY)
-+			window_addr = 0x1C000000;
-+			window_size = 0x4000000; 
-+#else /* USER ONLY */
-+			window_addr = 0x1E000000;
-+			window_size = 0x4000000; 
-+#endif
-+	return 0;
-+}
-+
-+int __init db1550_mtd_init(void)
-+{
-+	struct mtd_partition *parts;
-+	int nb_parts = 0;
-+	
-+	/* Default flash bankwidth */
-+	db1550_map.bankwidth = flash_bankwidth;
-+
-+	if (setup_flash_params()) 
-+		return -ENXIO;
-+
-+	/*
-+	 * Static partition definition selection
-+	 */
-+	parts = db1550_partitions;
-+	nb_parts = NB_OF(db1550_partitions);
-+	db1550_map.size = window_size;
-+
-+	/*
-+	 * Now let's probe for the actual flash.  Do it here since
-+	 * specific machine settings might have been set above.
-+	 */
-+	printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", 
-+			db1550_map.bankwidth*8);
-+	db1550_map.virt = 
-+		(void __iomem *)ioremap(window_addr, window_size);
-+	mymtd = do_map_probe("cfi_probe", &db1550_map);
-+	if (!mymtd) return -ENXIO;
-+	mymtd->owner = THIS_MODULE;
-+
-+	add_mtd_partitions(mymtd, parts, nb_parts);
-+	return 0;
-+}
-+
-+static void __exit db1550_mtd_cleanup(void)
-+{
-+	if (mymtd) {
-+		del_mtd_partitions(mymtd);
-+		map_destroy(mymtd);
-+	}
-+}
-+
-+module_init(db1550_mtd_init);
-+module_exit(db1550_mtd_cleanup);
-+
-+MODULE_AUTHOR("Embedded Edge, LLC");
-+MODULE_DESCRIPTION("Db1550 mtd map driver");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.5/drivers/mtd/maps/db1x00-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/db1x00-flash.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/db1x00-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,219 @@
-+/*
-+ * Flash memory access on Alchemy Db1xxx boards
-+ * 
-+ * $Id: db1x00-flash.c,v 1.4 2004/09/16 23:27:12 gleixner Exp $
-+ *
-+ * (C) 2003 Pete Popov <ppopov@pacbell.net>
-+ * 
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/au1000.h>
-+#include <asm/db1x00.h>
-+
-+#ifdef 	DEBUG_RW
-+#define	DBG(x...)	printk(x)
-+#else
-+#define	DBG(x...)	
-+#endif
-+
-+static unsigned long window_addr;
-+static unsigned long window_size;
-+static unsigned long flash_size;
-+
-+static BCSR * const bcsr = (BCSR *)0xAE000000;
-+static unsigned char flash_bankwidth = 4;
-+
-+/* 
-+ * The Db1x boards support different flash densities. We setup
-+ * the mtd_partition structures below for default of 64Mbit 
-+ * flash densities, and override the partitions sizes, if
-+ * necessary, after we check the board status register.
-+ */
-+
-+#ifdef DB1X00_BOTH_BANKS
-+/* both banks will be used. Combine the first bank and the first 
-+ * part of the second bank together into a single jffs/jffs2
-+ * partition.
-+ */
-+static struct mtd_partition db1x00_partitions[] = {
-+        {
-+                .name         =  "User FS",
-+                .size         =  0x1c00000,
-+                .offset       =  0x0000000
-+        },{
-+                .name         =  "yamon",
-+                .size         =  0x0100000,
-+		.offset       =  MTDPART_OFS_APPEND,
-+                .mask_flags   =  MTD_WRITEABLE
-+        },{
-+                .name         =  "raw kernel",
-+		.size         =  (0x300000-0x40000), /* last 256KB is env */
-+		.offset       =  MTDPART_OFS_APPEND,
-+        }
-+};
-+#elif defined(DB1X00_BOOT_ONLY)
-+static struct mtd_partition db1x00_partitions[] = {
-+        {
-+                .name         =  "User FS",
-+                .size         =  0x00c00000,
-+                .offset       =  0x0000000
-+        },{
-+                .name         =  "yamon",
-+                .size         =  0x0100000,
-+		.offset       =  MTDPART_OFS_APPEND,
-+                .mask_flags   =  MTD_WRITEABLE
-+        },{
-+                .name         =  "raw kernel",
-+		.size         =  (0x300000-0x40000), /* last 256KB is env */
-+		.offset       =  MTDPART_OFS_APPEND,
-+        }
-+};
-+#elif defined(DB1X00_USER_ONLY)
-+static struct mtd_partition db1x00_partitions[] = {
-+        {
-+                .name         =  "User FS",
-+                .size         =  0x0e00000,
-+                .offset       =  0x0000000
-+        },{
-+                .name         =  "raw kernel",
-+		.size         =  MTDPART_SIZ_FULL,
-+		.offset       =  MTDPART_OFS_APPEND,
-+        }
-+};
-+#else
-+#error MTD_DB1X00 define combo error /* should never happen */
-+#endif
-+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-+
-+#define NAME     	"Db1x00 Linux Flash"
-+
-+static struct map_info db1xxx_mtd_map = {
-+	.name		= NAME,
-+};
-+
-+static struct mtd_partition *parsed_parts;
-+static struct mtd_info *db1xxx_mtd;
-+
-+/*
-+ * Probe the flash density and setup window address and size
-+ * based on user CONFIG options. There are times when we don't
-+ * want the MTD driver to be probing the boot or user flash,
-+ * so having the option to enable only one bank is important.
-+ */
-+int setup_flash_params(void)
-+{
-+	switch ((bcsr->status >> 14) & 0x3) {
-+		case 0: /* 64Mbit devices */
-+			flash_size = 0x800000; /* 8MB per part */
-+#if defined(DB1X00_BOTH_BANKS)
-+			window_addr = 0x1E000000;
-+			window_size = 0x2000000; 
-+#elif defined(DB1X00_BOOT_ONLY)
-+			window_addr = 0x1F000000;
-+			window_size = 0x1000000; 
-+#else /* USER ONLY */
-+			window_addr = 0x1E000000;
-+			window_size = 0x1000000; 
-+#endif
-+			break;
-+		case 1:
-+			/* 128 Mbit devices */
-+			flash_size = 0x1000000; /* 16MB per part */
-+#if defined(DB1X00_BOTH_BANKS)
-+			window_addr = 0x1C000000;
-+			window_size = 0x4000000;
-+			/* USERFS from 0x1C00 0000 to 0x1FC0 0000 */
-+			db1x00_partitions[0].size = 0x3C00000;
-+#elif defined(DB1X00_BOOT_ONLY)
-+			window_addr = 0x1E000000;
-+			window_size = 0x2000000;
-+			/* USERFS from 0x1E00 0000 to 0x1FC0 0000 */
-+			db1x00_partitions[0].size = 0x1C00000;
-+#else /* USER ONLY */
-+			window_addr = 0x1C000000;
-+			window_size = 0x2000000;
-+			/* USERFS from 0x1C00 0000 to 0x1DE00000 */
-+			db1x00_partitions[0].size = 0x1DE0000;
-+#endif
-+			break;
-+		case 2:
-+			/* 256 Mbit devices */
-+			flash_size = 0x4000000; /* 64MB per part */
-+#if defined(DB1X00_BOTH_BANKS)
-+			return 1;
-+#elif defined(DB1X00_BOOT_ONLY)
-+			/* Boot ROM flash bank only; no user bank */
-+			window_addr = 0x1C000000;
-+			window_size = 0x4000000;
-+			/* USERFS from 0x1C00 0000 to 0x1FC00000 */
-+			db1x00_partitions[0].size = 0x3C00000;
-+#else /* USER ONLY */
-+			return 1;
-+#endif
-+			break;
-+		default:
-+			return 1;
-+	}
-+	db1xxx_mtd_map.size = window_size;
-+	db1xxx_mtd_map.bankwidth = flash_bankwidth;
-+	db1xxx_mtd_map.phys = window_addr;
-+	db1xxx_mtd_map.bankwidth = flash_bankwidth;
-+	return 0;
-+}
-+
-+int __init db1x00_mtd_init(void)
-+{
-+	struct mtd_partition *parts;
-+	int nb_parts = 0;
-+	
-+	if (setup_flash_params()) 
-+		return -ENXIO;
-+
-+	/*
-+	 * Static partition definition selection
-+	 */
-+	parts = db1x00_partitions;
-+	nb_parts = NB_OF(db1x00_partitions);
-+
-+	/*
-+	 * Now let's probe for the actual flash.  Do it here since
-+	 * specific machine settings might have been set above.
-+	 */
-+	printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n", 
-+			db1xxx_mtd_map.bankwidth*8);
-+	db1xxx_mtd_map.virt = (void __iomem *)ioremap(window_addr, window_size);
-+	db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map);
-+	if (!db1xxx_mtd) return -ENXIO;
-+	db1xxx_mtd->owner = THIS_MODULE;
-+
-+	add_mtd_partitions(db1xxx_mtd, parts, nb_parts);
-+	return 0;
-+}
-+
-+static void __exit db1x00_mtd_cleanup(void)
-+{
-+	if (db1xxx_mtd) {
-+		del_mtd_partitions(db1xxx_mtd);
-+		map_destroy(db1xxx_mtd);
-+		if (parsed_parts)
-+			kfree(parsed_parts);
-+	}
-+}
-+
-+module_init(db1x00_mtd_init);
-+module_exit(db1x00_mtd_cleanup);
-+
-+MODULE_AUTHOR("Pete Popov");
-+MODULE_DESCRIPTION("Db1x00 mtd map driver");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.5/drivers/mtd/maps/dbox2-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/dbox2-flash.c	2004-04-03 22:38:21.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/dbox2-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.12 2004/09/16 23:27:12 gleixner 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 @@
- 	.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,14 +68,14 @@
- struct map_info dbox2_flash_map = {
- 	.name		= "D-Box 2 flash memory",
- 	.size		= WINDOW_SIZE,
--	.buswidth	= 4,
-+	.bankwidth	= 4,
- 	.phys		= WINDOW_ADDR,
- };
- 
- int __init init_dbox2_flash(void)
- {
-        	printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR);
--	dbox2_flash_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+	dbox2_flash_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE);
- 
- 	if (!dbox2_flash_map.virt) {
- 		printk("Failed to ioremap\n");
-@@ -86,7 +87,7 @@
- 	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: linux-2.6.5/drivers/mtd/maps/dc21285.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/dc21285.c	2004-04-03 22:36:57.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/dc21285.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.21 2004/09/16 23:27:13 gleixner 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>
-@@ -19,91 +20,117 @@
- 
- #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,81 +140,97 @@
- 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));
-+#ifdef CONFIG_MTD_PARTITIONS
-+	int nrparts;
-+#endif
- 
--	/* Determine buswidth */
-+	/* 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);
-+	dc21285_map.map_priv_1 = (void __iomem *)ioremap(DC21285_FLASH, 16*1024*1024);
- 	if (!dc21285_map.map_priv_1) {
- 		printk("Failed to ioremap\n");
- 		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: linux-2.6.5/drivers/mtd/maps/dilnetpc.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/dilnetpc.c	2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/dilnetpc.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.14 2004/09/16 23:27:13 gleixner 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 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
- };
-@@ -403,7 +403,7 @@
- 	printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", 
- 		is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys);
- 
--	dnpc_map.virt = (unsigned long)ioremap_nocache(dnpc_map.phys, dnpc_map.size);
-+	dnpc_map.virt = (void __iomem *)ioremap_nocache(dnpc_map.phys, dnpc_map.size);
- 
- 	dnpc_map_flash(dnpc_map.phys, dnpc_map.size);
- 
-Index: linux-2.6.5/drivers/mtd/maps/dmv182.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/dmv182.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/dmv182.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,150 @@
-+
-+/*
-+ * drivers/mtd/maps/svme182.c
-+ * 
-+ * Flash map driver for the Dy4 SVME182 board
-+ * 
-+ * $Id: dmv182.c,v 1.4 2004/09/16 23:27:13 gleixner Exp $
-+ *
-+ * Copyright 2003-2004, TimeSys Corporation
-+ *
-+ * Based on the SVME181 flash map, by Tom Nelson, Dot4, Inc. for TimeSys Corp.
-+ *
-+ * 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 <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/errno.h>
-+
-+/*
-+ * This driver currently handles only the 16MiB user flash bank 1 on the
-+ * board.  It does not provide access to bank 0 (contains the Dy4 FFW), bank 2
-+ * (VxWorks boot), or the optional 48MiB expansion flash.
-+ *
-+ * scott.wood@timesys.com: On the newer boards with 128MiB flash, it
-+ * now supports the first 96MiB (the boot flash bank containing FFW
-+ * is excluded).  The VxWorks loader is in partition 1.
-+ */
-+
-+#define FLASH_BASE_ADDR 0xf0000000
-+#define FLASH_BANK_SIZE (128*1024*1024)
-+
-+MODULE_AUTHOR("Scott Wood, TimeSys Corporation <scott.wood@timesys.com>");
-+MODULE_DESCRIPTION("User-programmable flash device on the Dy4 SVME182 board");
-+MODULE_LICENSE("GPL");
-+
-+static struct map_info svme182_map = {
-+	.name		= "Dy4 SVME182",
-+	.bankwidth	= 32,
-+	.size		=  128 * 1024 * 1024
-+};
-+
-+#define BOOTIMAGE_PART_SIZE		((6*1024*1024)-RESERVED_PART_SIZE)
-+
-+// Allow 6MiB for the kernel
-+#define NEW_BOOTIMAGE_PART_SIZE  (6 * 1024 * 1024)
-+// Allow 1MiB for the bootloader
-+#define NEW_BOOTLOADER_PART_SIZE (1024 * 1024)
-+// Use the remaining 9MiB at the end of flash for the RFS
-+#define NEW_RFS_PART_SIZE        (0x01000000 - NEW_BOOTLOADER_PART_SIZE - \
-+                                  NEW_BOOTIMAGE_PART_SIZE)
-+
-+static struct mtd_partition svme182_partitions[] = {
-+	// The Lower PABS is only 128KiB, but the partition code doesn't
-+	// like partitions that don't end on the largest erase block
-+	// size of the device, even if all of the erase blocks in the
-+	// partition are small ones.  The hardware should prevent
-+	// writes to the actual PABS areas.
-+	{
-+		name:       "Lower PABS and CPU 0 bootloader or kernel",
-+		size:       6*1024*1024,
-+		offset:     0,
-+	},
-+	{
-+		name:       "Root Filesystem",
-+		size:       10*1024*1024,
-+		offset:     MTDPART_OFS_NXTBLK
-+	},
-+	{
-+		name:       "CPU1 Bootloader",
-+		size:       1024*1024,
-+		offset:     MTDPART_OFS_NXTBLK,
-+	},
-+	{
-+		name:       "Extra",
-+		size:       110*1024*1024,
-+		offset:     MTDPART_OFS_NXTBLK
-+	},
-+	{
-+		name:       "Foundation Firmware and Upper PABS",
-+		size:       1024*1024,
-+		offset:     MTDPART_OFS_NXTBLK,
-+		mask_flags: MTD_WRITEABLE // read-only
-+	}
-+};
-+
-+static struct mtd_info *this_mtd;
-+
-+static int __init init_svme182(void)
-+{
-+	struct mtd_partition *partitions;
-+	int num_parts = sizeof(svme182_partitions) / sizeof(struct mtd_partition);
-+
-+	partitions = svme182_partitions;
-+
-+	svme182_map.virt = 
-+		(void __iomem *)ioremap(FLASH_BASE_ADDR, svme182_map.size);
-+		
-+	if (svme182_map.virt == 0) {
-+		printk("Failed to ioremap FLASH memory area.\n");
-+		return -EIO;
-+	}
-+
-+	simple_map_init(&svme182_map);
-+
-+	this_mtd = do_map_probe("cfi_probe", &svme182_map);
-+	if (!this_mtd)
-+	{
-+		iounmap((void *)svme182_map.virt);
-+		return -ENXIO;
-+	}
-+
-+	printk(KERN_NOTICE "SVME182 flash device: %dMiB at 0x%08x\n",
-+		   this_mtd->size >> 20, FLASH_BASE_ADDR);
-+
-+	this_mtd->owner = THIS_MODULE;
-+	add_mtd_partitions(this_mtd, partitions, num_parts);
-+
-+	return 0;
-+}
-+
-+static void __exit cleanup_svme182(void)
-+{
-+	if (this_mtd)
-+	{
-+		del_mtd_partitions(this_mtd);
-+		map_destroy(this_mtd);
-+	}
-+
-+	if (svme182_map.virt)
-+	{
-+		iounmap((void *)svme182_map.virt);
-+		svme182_map.virt = 0;
-+	}
-+
-+	return;
-+}
-+
-+module_init(init_svme182);
-+module_exit(cleanup_svme182);
-Index: linux-2.6.5/drivers/mtd/maps/ebony.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/ebony.c	2004-04-03 22:37:59.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/ebony.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,11 +1,11 @@
- /*
-- * $Id: ebony.c,v 1.8 2003/06/23 11:48:18 dwmw2 Exp $
-+ * $Id: ebony.c,v 1.12 2004/09/16 23:27:13 gleixner Exp $
-  * 
-  * Mapping for Ebony user flash
-  *
-- * Matt Porter <mporter@mvista.com>
-+ * Matt Porter <mporter@kernel.crashing.org>
-  *
-- * Copyright 2002 MontaVista Software Inc.
-+ * Copyright 2002-2004 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
-@@ -21,22 +21,23 @@
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
- #include <linux/config.h>
-+#include <linux/version.h>
- #include <asm/io.h>
--#include <asm/ibm440.h>
--#include <platforms/ebony.h>
-+#include <asm/ibm44x.h>
-+#include <platforms/4xx/ebony.h>
- 
- 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[] = {
-@@ -63,7 +64,7 @@
- int __init init_ebony(void)
- {
- 	u8 fpga0_reg;
--	unsigned long fpga0_adr;
-+	u8 *fpga0_adr;
- 	unsigned long long small_flash_base, large_flash_base;
- 
- 	fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16);
-@@ -71,7 +72,7 @@
- 		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))
-@@ -93,7 +94,7 @@
- 
- 	ebony_small_map.phys = small_flash_base;
- 	ebony_small_map.virt =
--		(unsigned long)ioremap64(small_flash_base,
-+		(void __iomem *)ioremap64(small_flash_base,
- 					 ebony_small_map.size);
- 
- 	if (!ebony_small_map.virt) {
-@@ -160,5 +161,5 @@
- module_exit(cleanup_ebony);
- 
- MODULE_LICENSE("GPL");
--MODULE_AUTHOR("Matt Porter <mporter@mvista.com>");
-+MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
- MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards");
-Index: linux-2.6.5/drivers/mtd/maps/edb7312.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/edb7312.c	2004-04-03 22:38:27.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/edb7312.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: edb7312.c,v 1.9 2003/06/23 11:48:18 dwmw2 Exp $
-+ * $Id: edb7312.c,v 1.12 2004/09/16 23:27:13 gleixner 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 @@
- struct map_info edb7312nor_map = {
- 	.name = "NOR flash on EDB7312",
- 	.size = WINDOW_SIZE,
--	.buswidth = BUSWIDTH,
-+	.bankwidth = BUSWIDTH,
- 	.phys = WINDOW_ADDR,
- };
- 
-@@ -82,8 +82,8 @@
- 
-        	printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", 
- 	       WINDOW_SIZE, WINDOW_ADDR);
--	edb7312nor_map.virt = (unsigned long)
--	  ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+	edb7312nor_map.virt = (void __iomem *)
-+		ioremap(WINDOW_ADDR, WINDOW_SIZE);
- 
- 	if (!edb7312nor_map.virt) {
- 		printk(MSG_PREFIX "failed to ioremap\n");
-Index: linux-2.6.5/drivers/mtd/maps/elan-104nc.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/elan-104nc.c	2004-04-03 22:37:06.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/elan-104nc.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.22 2004/09/16 23:27:13 gleixner 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.
-@@ -53,7 +53,7 @@
- #define PAGE_IO_SIZE 2
- 
- static volatile int page_in_window = -1; // Current page in window.
--static unsigned long iomapadr;
-+static void __iomem *iomapadr;
- static spinlock_t elan_104nc_spin = SPIN_LOCK_UNLOCKED;
- 
- /* partition_info gives details on the logical partitions that the split the 
-@@ -107,39 +107,19 @@
- }
- 
- 
--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_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 @@
- 	.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
- };
- 
-@@ -230,7 +190,7 @@
- 	/* Urg! We use I/O port 0x22 without request_region()ing it,
- 	   because it's already allocated to the PIC. */
- 
--  	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
-+  	iomapadr = (void __iomem *)ioremap(WINDOW_START, WINDOW_LENGTH);
- 	if (!iomapadr) {
- 		printk( KERN_ERR"%s: failed to ioremap memory region\n",
- 			elan_104nc_map.name );
-Index: linux-2.6.5/drivers/mtd/maps/epxa10db-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/epxa10db-flash.c	2004-04-03 22:37:39.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/epxa10db-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.12 2004/09/16 23:27:13 gleixner 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 struct map_info epxa_map = {
- 	.name =		"EPXA flash",
- 	.size =		FLASH_SIZE,
--	.buswidth =	2,
-+	.bankwidth =	2,
- 	.phys =		FLASH_START,
- };
- 
-@@ -62,7 +62,7 @@
- 	
- 	printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
- 
--	epxa_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
-+	epxa_map.virt = (void __iomem *)ioremap(FLASH_START, FLASH_SIZE);
- 	if (!epxa_map.virt) {
- 		printk("Failed to ioremap %s flash\n",BOARD_NAME);
- 		return -EIO;
-Index: linux-2.6.5/drivers/mtd/maps/fortunet.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/fortunet.c	2004-04-03 22:36:27.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/fortunet.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.8 2004/09/16 23:27:13 gleixner 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 @@
- 
- 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 @@
- 	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 @@
- 		&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 @@
- 	}
- 	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 @@
- 				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");
-@@ -210,7 +210,7 @@
- 			map_regions[ix].map_info.phys =	map_regions[ix].window_addr_physical,
- 
- 			map_regions[ix].map_info.virt =
--				(int)ioremap_nocache(
-+				(void __iomem *)ioremap_nocache(
- 				map_regions[ix].window_addr_physical,
- 				map_regions[ix].map_info.size);
- 			if(!map_regions[ix].map_info.virt)
-@@ -227,13 +227,13 @@
- 			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: linux-2.6.5/drivers/mtd/maps/h720x-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/h720x-flash.c	2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/h720x-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -2,9 +2,11 @@
-  * Flash memory access on Hynix GMS30C7201/HMS30C7202 based 
-  * evaluation boards
-  * 
-+ * $Id: h720x-flash.c,v 1.10 2004/09/16 23:27:13 gleixner 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 map_info h720x_map = {
- 	.name =		"H720X",
--	.buswidth =	4,
-+	.bankwidth =	4,
- 	.size =		FLASH_SIZE,
- 	.phys =		FLASH_PHYS,
- };
-@@ -71,7 +73,7 @@
- 
- 	char	*part_type = NULL;
- 	
--	h720x_map.virt = (unsigned long)ioremap(FLASH_PHYS, FLASH_SIZE);
-+	h720x_map.virt = (void __iomem *)ioremap(FLASH_PHYS, FLASH_SIZE);
- 
- 	if (!h720x_map.virt) {
- 		printk(KERN_ERR "H720x-MTD: ioremap failed\n");
-@@ -80,13 +82,13 @@
- 
- 	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: linux-2.6.5/drivers/mtd/maps/ichxrom.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/ichxrom.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/ichxrom.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,380 @@
-+/*
-+ * ichxrom.c
-+ *
-+ * Normal mappings of chips in physical memory
-+ * $Id: ichxrom.c,v 1.13 2004/09/17 11:45:06 eric Exp $
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/cfi.h>
-+#include <linux/mtd/flashchip.h>
-+#include <linux/config.h>
-+#include <linux/pci.h>
-+#include <linux/pci_ids.h>
-+#include <linux/list.h>
-+
-+#define xstr(s) str(s)
-+#define str(s) #s
-+#define MOD_NAME xstr(KBUILD_BASENAME)
-+
-+#define ADDRESS_NAME_LEN 18
-+
-+#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
-+
-+#define BIOS_CNTL	0x4e
-+#define FWH_DEC_EN1	0xE3
-+#define FWH_DEC_EN2	0xF0
-+#define FWH_SEL1	0xE8
-+#define FWH_SEL2	0xEE
-+
-+struct ichxrom_window {
-+	void __iomem* virt;
-+	unsigned long phys;
-+	unsigned long size;
-+	struct list_head maps;
-+	struct resource rsrc;
-+	struct pci_dev *pdev;
-+};
-+
-+struct ichxrom_map_info {
-+	struct list_head list;
-+	struct map_info map;
-+	struct mtd_info *mtd;
-+	struct resource rsrc;
-+	char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
-+};
-+
-+static struct ichxrom_window ichxrom_window = {
-+	.maps = LIST_HEAD_INIT(ichxrom_window.maps),
-+};
-+
-+static void ichxrom_cleanup(struct ichxrom_window *window)
-+{
-+	struct ichxrom_map_info *map, *scratch;
-+	u16 word;
-+
-+	/* Disable writes through the rom window */
-+	pci_read_config_word(window->pdev, BIOS_CNTL, &word);
-+	pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
-+
-+	/* Free all of the mtd devices */
-+	list_for_each_entry_safe(map, scratch, &window->maps, list) {
-+		if (map->rsrc.parent)
-+			release_resource(&map->rsrc);
-+		del_mtd_device(map->mtd);
-+		map_destroy(map->mtd);
-+		list_del(&map->list);
-+		kfree(map);
-+	}
-+	if (window->rsrc.parent)
-+		release_resource(&window->rsrc);
-+	if (window->virt) {
-+		iounmap(window->virt);
-+		window->virt = NULL;
-+		window->phys = 0;
-+		window->size = 0;
-+		window->pdev = NULL;
-+	}
-+}
-+
-+
-+static int __devinit ichxrom_init_one (struct pci_dev *pdev,
-+	const struct pci_device_id *ent)
-+{
-+	static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
-+	struct ichxrom_window *window = &ichxrom_window;
-+	struct ichxrom_map_info *map = 0;
-+	unsigned long map_top;
-+	u8 byte;
-+	u16 word;
-+
-+	/* For now I just handle the ichx and I assume there
-+	 * are not a lot of resources up at the top of the address
-+	 * space.  It is possible to handle other devices in the
-+	 * top 16MB but it is very painful.  Also since
-+	 * you can only really attach a FWH to an ICHX there
-+	 * a number of simplifications you can make.
-+	 *
-+	 * Also you can page firmware hubs if an 8MB window isn't enough 
-+	 * but don't currently handle that case either.
-+	 */
-+	window->pdev = pdev;
-+
-+	/* Find a region continuous to the end of the ROM window  */
-+	window->phys = 0;
-+	pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
-+	if (byte == 0xff) {
-+		window->phys = 0xffc00000;
-+		pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
-+		if ((byte & 0x0f) == 0x0f) {
-+			window->phys = 0xff400000;
-+		}
-+		else if ((byte & 0x0e) == 0x0e) {
-+			window->phys = 0xff500000;
-+		}
-+		else if ((byte & 0x0c) == 0x0c) {
-+			window->phys = 0xff600000;
-+		}
-+		else if ((byte & 0x08) == 0x08) {
-+			window->phys = 0xff700000;
-+		}
-+	}
-+	else if ((byte & 0xfe) == 0xfe) {
-+		window->phys = 0xffc80000;
-+	}
-+	else if ((byte & 0xfc) == 0xfc) {
-+		window->phys = 0xffd00000;
-+	}
-+	else if ((byte & 0xf8) == 0xf8) {
-+		window->phys = 0xffd80000;
-+	}
-+	else if ((byte & 0xf0) == 0xf0) {
-+		window->phys = 0xffe00000;
-+	}
-+	else if ((byte & 0xe0) == 0xe0) {
-+		window->phys = 0xffe80000;
-+	}
-+	else if ((byte & 0xc0) == 0xc0) {
-+		window->phys = 0xfff00000;
-+	}
-+	else if ((byte & 0x80) == 0x80) {
-+		window->phys = 0xfff80000; 
-+	}
-+
-+	if (window->phys == 0) {
-+		printk(KERN_ERR MOD_NAME ": Rom window is closed\n");
-+		goto out;
-+	}
-+	window->phys -= 0x400000UL;
-+	window->size = (0xffffffffUL - window->phys) + 1UL;
-+
-+	/* Enable writes through the rom window */
-+	pci_read_config_word(pdev, BIOS_CNTL, &word);
-+	if (!(word & 1)  && (word & (1<<1))) {
-+		/* The BIOS will generate an error if I enable
-+		 * this device, so don't even try.
-+		 */
-+		printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
-+		goto out;
-+	}
-+	pci_write_config_word(pdev, BIOS_CNTL, word | 1);
-+
-+	/*
-+	 * Try to reserve the window mem region.  If this fails then
-+	 * it is likely due to the window being "reseved" by the BIOS.
-+	 */
-+	window->rsrc.name = MOD_NAME;
-+	window->rsrc.start = window->phys;
-+	window->rsrc.end   = window->phys + window->size - 1;
-+	window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+	if (request_resource(&iomem_resource, &window->rsrc)) {
-+		window->rsrc.parent = NULL;
-+		printk(KERN_DEBUG MOD_NAME
-+			": %s(): Unable to register resource"
-+			" 0x%.08lx-0x%.08lx - kernel bug?\n",
-+			__func__,
-+			window->rsrc.start, window->rsrc.end);
-+	}
-+
-+	/* Map the firmware hub into my address space. */
-+	window->virt = ioremap_nocache(window->phys, window->size);
-+	if (!window->virt) {
-+		printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
-+			window->phys, window->size);
-+		goto out;
-+	}
-+
-+	/* Get the first address to look for an rom chip at */
-+	map_top = window->phys;
-+	if ((window->phys & 0x3fffff) != 0) {
-+		map_top = window->phys + 0x400000;
-+	}
-+#if 1
-+	/* The probe sequence run over the firmware hub lock
-+	 * registers sets them to 0x7 (no access).
-+	 * Probe at most the last 4M of the address space.
-+	 */
-+	if (map_top < 0xffc00000) {
-+		map_top = 0xffc00000;
-+	}
-+#endif
-+	/* Loop through and look for rom chips */
-+	while((map_top - 1) < 0xffffffffUL) {
-+		struct cfi_private *cfi;
-+		unsigned long offset;
-+		int i;
-+
-+		if (!map) {
-+			map = kmalloc(sizeof(*map), GFP_KERNEL);
-+		}
-+		if (!map) {
-+			printk(KERN_ERR MOD_NAME ": kmalloc failed");
-+			goto out;
-+		}
-+		memset(map, 0, sizeof(*map));
-+		INIT_LIST_HEAD(&map->list);
-+		map->map.name = map->map_name;
-+		map->map.phys = map_top;
-+		offset = map_top - window->phys;
-+		map->map.virt = (void __iomem *)
-+			(((unsigned long)(window->virt)) + offset);
-+		map->map.size = 0xffffffffUL - map_top + 1UL;
-+		/* Set the name of the map to the address I am trying */
-+		sprintf(map->map_name, "%s @%08lx",
-+			MOD_NAME, map->map.phys);
-+
-+		/* Firmware hubs only use vpp when being programmed
-+		 * in a factory setting.  So in-place programming
-+		 * needs to use a different method.
-+		 */
-+		for(map->map.bankwidth = 32; map->map.bankwidth; 
-+			map->map.bankwidth >>= 1)
-+		{
-+			char **probe_type;
-+			/* Skip bankwidths that are not supported */
-+			if (!map_bankwidth_supported(map->map.bankwidth))
-+				continue;
-+
-+			/* Setup the map methods */
-+			simple_map_init(&map->map);
-+
-+			/* Try all of the probe methods */
-+			probe_type = rom_probe_types;
-+			for(; *probe_type; probe_type++) {
-+				map->mtd = do_map_probe(*probe_type, &map->map);
-+				if (map->mtd)
-+					goto found;
-+			}
-+		}
-+		map_top += ROM_PROBE_STEP_SIZE;
-+		continue;
-+	found:
-+		/* Trim the size if we are larger than the map */
-+		if (map->mtd->size > map->map.size) {
-+			printk(KERN_WARNING MOD_NAME
-+				" rom(%u) larger than window(%lu). fixing...\n",
-+				map->mtd->size, map->map.size);
-+			map->mtd->size = map->map.size;
-+		}
-+		if (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.
-+			 */
-+			map->rsrc.name  = map->map_name;
-+			map->rsrc.start = map->map.phys;
-+			map->rsrc.end   = map->map.phys + map->mtd->size - 1;
-+			map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-+			if (request_resource(&window->rsrc, &map->rsrc)) {
-+				printk(KERN_ERR MOD_NAME
-+					": cannot reserve MTD resource\n");
-+				map->rsrc.parent = NULL;
-+			}
-+		}
-+
-+		/* Make the whole region visible in the map */
-+		map->map.virt = window->virt;
-+		map->map.phys = window->phys;
-+		cfi = map->map.fldrv_priv;
-+		for(i = 0; i < cfi->numchips; i++) {
-+			cfi->chips[i].start += offset;
-+		}
-+		
-+		/* Now that the mtd devices is complete claim and export it */
-+		map->mtd->owner = THIS_MODULE;
-+		add_mtd_device(map->mtd);
-+
-+
-+		/* Calculate the new value of map_top */
-+		map_top += map->mtd->size;
-+
-+		/* File away the map structure */
-+		list_add(&map->list, &window->maps);
-+		map = 0;
-+	}
-+
-+ out:
-+	/* Free any left over map structures */
-+	if (map) {
-+		kfree(map);
-+	}
-+	/* See if I have any map structures */
-+	if (list_empty(&window->maps)) {
-+		ichxrom_cleanup(window);
-+		return -ENODEV;
-+	}
-+	return 0;
-+
-+}
-+
-+
-+static void __devexit ichxrom_remove_one (struct pci_dev *pdev)
-+{
-+	struct ichxrom_window *window = &ichxrom_window;
-+	ichxrom_cleanup(window);
-+}
-+
-+static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
-+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, 
-+	  PCI_ANY_ID, PCI_ANY_ID, },
-+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, 
-+	  PCI_ANY_ID, PCI_ANY_ID, },
-+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, 
-+	  PCI_ANY_ID, PCI_ANY_ID, },
-+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
-+	  PCI_ANY_ID, PCI_ANY_ID, },
-+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,
-+	  PCI_ANY_ID, PCI_ANY_ID, },
-+	{ 0, },
-+};
-+
-+MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl);
-+
-+#if 0
-+static struct pci_driver ichxrom_driver = {
-+	.name =		MOD_NAME,
-+	.id_table =	ichxrom_pci_tbl,
-+	.probe =	ichxrom_init_one,
-+	.remove =	ichxrom_remove_one,
-+};
-+#endif
-+
-+int __init init_ichxrom(void)
-+{
-+	struct pci_dev *pdev;
-+	struct pci_device_id *id;
-+
-+	pdev = NULL;
-+	for (id = ichxrom_pci_tbl; id->vendor; id++) {
-+		pdev = pci_find_device(id->vendor, id->device, NULL);
-+		if (pdev) {
-+			break;
-+		}
-+	}
-+	if (pdev) {
-+		return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]);
-+	}
-+	return -ENXIO;
-+#if 0
-+	return pci_module_init(&ichxrom_driver);
-+#endif
-+}
-+
-+static void __exit cleanup_ichxrom(void)
-+{
-+	ichxrom_remove_one(ichxrom_window.pdev);
-+}
-+
-+module_init(init_ichxrom);
-+module_exit(cleanup_ichxrom);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>");
-+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICHX southbridge");
-Index: linux-2.6.5/drivers/mtd/maps/impa7.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/impa7.c	2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/impa7.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: impa7.c,v 1.9 2003/06/23 11:47:43 dwmw2 Exp $
-+ * $Id: impa7.c,v 1.12 2004/09/16 23:27:13 gleixner Exp $
-  *
-  * Handle mapping of the NOR flash on implementa A7 boards
-  *
-@@ -30,25 +30,25 @@
- #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,
- 	},
- };
- 
-@@ -91,7 +91,7 @@
- 		       pt[i].size, pt[i].addr);
- 
- 		impa7_map[i].phys = pt[i].addr;
--		impa7_map[i].virt = (unsigned long)
-+		impa7_map[i].virt = (void __iomem *)
- 		  ioremap(pt[i].addr, pt[i].size);
- 		if (!impa7_map[i].virt) {
- 			printk(MSG_PREFIX "failed to ioremap\n");
-Index: linux-2.6.5/drivers/mtd/maps/integrator-flash-v24.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/integrator-flash-v24.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/integrator-flash-v24.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,258 @@
-+/*======================================================================
-+
-+    drivers/mtd/maps/armflash.c: ARM Flash Layout/Partitioning
-+  
-+    Copyright (C) 2000 ARM Limited
-+  
-+   This program is free software; you can redistribute it and/or modify
-+   it under the terms of the GNU General Public License as published by
-+   the Free Software Foundation; either version 2 of the License, or
-+   (at your option) any later version.
-+  
-+   This program is distributed in the hope that it will be useful,
-+   but WITHOUT ANY WARRANTY; without even the implied warranty of
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU General Public License for more details.
-+  
-+   You should have received a copy of the GNU General Public License
-+   along with this program; if not, write to the Free Software
-+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+  
-+   This is access code for flashes using ARM's flash partitioning 
-+   standards.
-+
-+   $Id: integrator-flash-v24.c,v 1.14 2004/09/16 23:27:13 gleixner Exp $
-+
-+======================================================================*/
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-+
-+// board specific stuff - sorry, it should be in arch/arm/mach-*.
-+#ifdef CONFIG_ARCH_INTEGRATOR
-+
-+#define FLASH_BASE	INTEGRATOR_FLASH_BASE
-+#define FLASH_SIZE	INTEGRATOR_FLASH_SIZE
-+
-+#define FLASH_PART_SIZE 0x400000
-+
-+#define SC_CTRLC	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
-+#define SC_CTRLS	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
-+#define EBI_CSR1	(IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET)
-+#define EBI_LOCK	(IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET)
-+
-+/*
-+ * Initialise the flash access systems:
-+ *  - Disable VPP
-+ *  - Assert WP
-+ *  - Set write enable bit in EBI reg
-+ */
-+static void armflash_flash_init(void)
-+{
-+	unsigned int tmp;
-+
-+	__raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
-+
-+	tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE;
-+	__raw_writel(tmp, EBI_CSR1);
-+
-+	if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) {
-+		__raw_writel(0xa05f, EBI_LOCK);
-+		__raw_writel(tmp, EBI_CSR1);
-+		__raw_writel(0, EBI_LOCK);
-+	}
-+}
-+
-+/*
-+ * Shutdown the flash access systems:
-+ *  - Disable VPP
-+ *  - Assert WP
-+ *  - Clear write enable bit in EBI reg
-+ */
-+static void armflash_flash_exit(void)
-+{
-+	unsigned int tmp;
-+
-+	__raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC);
-+
-+	/*
-+	 * Clear the write enable bit in system controller EBI register.
-+	 */
-+	tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE;
-+	__raw_writel(tmp, EBI_CSR1);
-+
-+	if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) {
-+		__raw_writel(0xa05f, EBI_LOCK);
-+		__raw_writel(tmp, EBI_CSR1);
-+		__raw_writel(0, EBI_LOCK);
-+	}
-+}
-+
-+static void armflash_flash_wp(int on)
-+{
-+	unsigned int reg;
-+
-+	if (on)
-+		reg = SC_CTRLC;
-+	else
-+		reg = SC_CTRLS;
-+
-+	__raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg);
-+}
-+
-+static void armflash_set_vpp(struct map_info *map, int on)
-+{
-+	unsigned int reg;
-+
-+	if (on)
-+		reg = SC_CTRLS;
-+	else
-+		reg = SC_CTRLC;
-+
-+	__raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
-+}
-+#endif
-+
-+#ifdef CONFIG_ARCH_P720T
-+
-+#define FLASH_BASE		(0x04000000)
-+#define FLASH_SIZE		(64*1024*1024)
-+
-+#define FLASH_PART_SIZE 	(4*1024*1024)
-+#define FLASH_BLOCK_SIZE	(128*1024)
-+
-+static void armflash_flash_init(void)
-+{
-+}
-+
-+static void armflash_flash_exit(void)
-+{
-+}
-+
-+static void armflash_flash_wp(int on)
-+{
-+}
-+
-+static void armflash_set_vpp(struct map_info *map, int on)
-+{
-+}
-+#endif
-+
-+
-+static struct map_info armflash_map =
-+{
-+	.name =		"AFS",
-+	.set_vpp =	armflash_set_vpp,
-+	.phys =		FLASH_BASE,
-+};
-+
-+static struct mtd_info *mtd;
-+static struct mtd_partition *parts;
-+static const char *probes[] = { "RedBoot", "afs", NULL };
-+
-+static int __init armflash_cfi_init(void *base, u_int size)
-+{
-+	int ret;
-+
-+	armflash_flash_init();
-+	armflash_flash_wp(1);
-+
-+	/*
-+	 * look for CFI based flash parts fitted to this board
-+	 */
-+	armflash_map.size       = size;
-+	armflash_map.bankwidth   = 4;
-+	armflash_map.virt = (void __iomem *) base;
-+
-+	simple_map_init(&armflash_map);
-+
-+	/*
-+	 * Also, the CFI layer automatically works out what size
-+	 * of chips we have, and does the necessary identification
-+	 * for us automatically.
-+	 */
-+	mtd = do_map_probe("cfi_probe", &armflash_map);
-+	if (!mtd)
-+		return -ENXIO;
-+
-+	mtd->owner = THIS_MODULE;
-+
-+	ret = parse_mtd_partitions(mtd, probes, &parts, (void *)0);
-+	if (ret > 0) {
-+		ret = add_mtd_partitions(mtd, parts, ret);
-+		if (ret)
-+			printk(KERN_ERR "mtd partition registration "
-+				"failed: %d\n", ret);
-+	}
-+
-+	/*
-+	 * If we got an error, free all resources.
-+	 */
-+	if (ret < 0) {
-+		del_mtd_partitions(mtd);
-+		map_destroy(mtd);
-+	}
-+
-+	return ret;
-+}
-+
-+static void armflash_cfi_exit(void)
-+{
-+	if (mtd) {
-+		del_mtd_partitions(mtd);
-+		map_destroy(mtd);
-+	}
-+	if (parts)
-+		kfree(parts);
-+}
-+
-+static int __init armflash_init(void)
-+{
-+	int err = -EBUSY;
-+	void *base;
-+
-+	if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL)
-+		goto out;
-+
-+	base = ioremap(FLASH_BASE, FLASH_SIZE);
-+	err = -ENOMEM;
-+	if (base == NULL)
-+		goto release;
-+
-+	err = armflash_cfi_init(base, FLASH_SIZE);
-+	if (err) {
-+		iounmap(base);
-+release:
-+		release_mem_region(FLASH_BASE, FLASH_SIZE);
-+	}
-+out:
-+	return err;
-+}
-+
-+static void __exit armflash_exit(void)
-+{
-+	armflash_cfi_exit();
-+	iounmap((void *)armflash_map.virt);
-+	release_mem_region(FLASH_BASE, FLASH_SIZE);
-+	armflash_flash_exit();
-+}
-+
-+module_init(armflash_init);
-+module_exit(armflash_exit);
-+
-+MODULE_AUTHOR("ARM Ltd");
-+MODULE_DESCRIPTION("ARM Integrator CFI map driver");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.5/drivers/mtd/maps/integrator-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/integrator-flash.c	2004-04-03 22:37:41.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/integrator-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.17 2004/09/16 23:27:13 gleixner Exp $
- 
- ======================================================================*/
- 
-@@ -108,9 +108,9 @@
- 	 * 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.virt		= (void __iomem *) base;
- 	info->map.name		= dev->dev.bus_id;
- 	info->map.set_vpp	= armflash_set_vpp;
- 
-Index: linux-2.6.5/drivers/mtd/maps/ipaq-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/ipaq-flash.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/ipaq-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,464 @@
-+/*
-+ * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based)
-+ * 
-+ * (C) 2000 Nicolas Pitre <nico@cam.org>
-+ * (C) 2002 Hewlett-Packard Company <jamey.hicks@hp.com>
-+ * (C) 2003 Christian Pellegrin <chri@ascensit.com>, <chri@infis.univ.ts.it>: concatenation of multiple flashes
-+ * 
-+ * $Id: ipaq-flash.c,v 1.2 2004/09/16 23:27:13 gleixner Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/spinlock.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <asm/page.h>
-+#include <asm/mach-types.h>
-+#include <asm/system.h>
-+#include <asm/errno.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#ifdef CONFIG_MTD_CONCAT
-+#include <linux/mtd/concat.h>
-+#endif
-+
-+#include <asm/hardware.h>
-+#include <asm/arch-sa1100/h3600.h>
-+#include <asm/io.h>
-+
-+
-+#ifndef CONFIG_IPAQ_HANDHELD
-+#error This is for iPAQ Handhelds only
-+#endif
-+#ifdef CONFIG_SA1100_JORNADA56X
-+
-+static void jornada56x_set_vpp(struct map_info *map, int vpp)
-+{
-+	if (vpp)
-+		GPSR = GPIO_GPIO26;
-+	else
-+		GPCR = GPIO_GPIO26;
-+	GPDR |= GPIO_GPIO26;
-+}
-+
-+#endif
-+
-+#ifdef CONFIG_SA1100_JORNADA720
-+
-+static void jornada720_set_vpp(struct map_info *map, int vpp)
-+{
-+	if (vpp)
-+		PPSR |= 0x80;
-+	else
-+		PPSR &= ~0x80;
-+	PPDR |= 0x80;
-+}
-+
-+#endif
-+
-+#define MAX_IPAQ_CS 2		/* Number of CS we are going to test */
-+
-+#define IPAQ_MAP_INIT(X) \
-+	{ \
-+		name:		"IPAQ flash " X, \
-+	}
-+
-+
-+static struct map_info ipaq_map[MAX_IPAQ_CS] = {
-+	IPAQ_MAP_INIT("bank 1"),
-+	IPAQ_MAP_INIT("bank 2")
-+};
-+
-+static struct mtd_info *my_sub_mtd[MAX_IPAQ_CS] = {
-+	NULL,
-+	NULL
-+};
-+
-+/*
-+ * Here are partition information for all known IPAQ-based devices.
-+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
-+ * structure.
-+ *
-+ * The *_max_flash_size is the maximum possible mapped flash size which
-+ * is not necessarily the actual flash size.  It must be no more than
-+ * the value specified in the "struct map_desc *_io_desc" mapping
-+ * definition for the corresponding machine.
-+ *
-+ * Please keep these in alphabetical order, and formatted as per existing
-+ * entries.  Thanks.
-+ */
-+
-+#ifdef CONFIG_IPAQ_HANDHELD
-+static unsigned long h3xxx_max_flash_size = 0x04000000;
-+static struct mtd_partition h3xxx_partitions[] = {
-+	{
-+		name:		"H3XXX boot firmware",
-+#ifndef CONFIG_LAB
-+		size:		0x00040000,
-+#else
-+		size:		0x00080000,
-+#endif
-+		offset:		0,
-+#ifndef CONFIG_LAB
-+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
-+#endif
-+	}, 
-+	{
-+		name:		"H3XXX root jffs2",
-+#ifndef CONFIG_LAB
-+		size:		0x2000000 - 2*0x40000, /* Warning, this is fixed later */
-+		offset:		0x00040000,
-+#else
-+		size:		0x2000000 - 0x40000 - 0x80000, /* Warning, this is fixed later */
-+		offset:		0x00080000,
-+#endif
-+	},
-+	{
-+		name:		"asset",
-+		size:		0x40000,
-+		offset:		0x2000000 - 0x40000, /* Warning, this is fixed later */
-+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
-+	}
-+};
-+
-+#ifndef CONFIG_MTD_CONCAT
-+static struct mtd_partition h3xxx_partitions_bank2[] = {
-+	/* this is used only on 2 CS machines when concat is not present */
-+	{
-+		name:		"second H3XXX root jffs2",
-+		size:		0x1000000 - 0x40000, /* Warning, this is fixed later */
-+		offset:		0x00000000,
-+	},
-+	{
-+		name:		"second asset",
-+		size:		0x40000,
-+		offset:		0x1000000 - 0x40000, /* Warning, this is fixed later */
-+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
-+	}
-+};
-+#endif
-+
-+static spinlock_t ipaq_vpp_lock = SPIN_LOCK_UNLOCKED;
-+
-+static void h3xxx_set_vpp(struct map_info *map, int vpp)
-+{
-+	static int nest = 0;
-+	
-+	spin_lock(&ipaq_vpp_lock);
-+	if (vpp)
-+		nest++;
-+	else
-+		nest--;
-+	if (nest)
-+		assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 1);
-+	else
-+		assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, 0);
-+	spin_unlock(&ipaq_vpp_lock);
-+}
-+
-+#endif
-+
-+#if defined(CONFIG_SA1100_JORNADA56X) || defined(CONFIG_SA1100_JORNADA720)
-+static unsigned long jornada_max_flash_size = 0x02000000;
-+static struct mtd_partition jornada_partitions[] = {
-+	{
-+		name:		"Jornada boot firmware",
-+		size:		0x00040000,
-+		offset:		0,
-+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
-+	}, {
-+		name:		"Jornada root jffs2",
-+		size:		MTDPART_SIZ_FULL,
-+		offset:		0x00040000,
-+	}
-+};
-+#endif
-+
-+
-+static struct mtd_partition *parsed_parts;
-+static struct mtd_info *mymtd;
-+
-+static unsigned long cs_phys[] = {
-+#ifdef CONFIG_ARCH_SA1100
-+	SA1100_CS0_PHYS,
-+	SA1100_CS1_PHYS,
-+	SA1100_CS2_PHYS,
-+	SA1100_CS3_PHYS,
-+	SA1100_CS4_PHYS,
-+	SA1100_CS5_PHYS,
-+#else 
-+	PXA_CS0_PHYS,
-+	PXA_CS1_PHYS,
-+	PXA_CS2_PHYS,
-+	PXA_CS3_PHYS,
-+	PXA_CS4_PHYS,
-+	PXA_CS5_PHYS,
-+#endif
-+};
-+
-+static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
-+
-+static int __init h1900_special_case(void);
-+
-+int __init ipaq_mtd_init(void)
-+{
-+	struct mtd_partition *parts = NULL;
-+	int nb_parts = 0;
-+	int parsed_nr_parts = 0;
-+	const char *part_type;
-+	int i; /* used when we have >1 flash chips */
-+	unsigned long tot_flashsize = 0; /* used when we have >1 flash chips */
-+
-+	/* Default flash bankwidth */
-+	// ipaq_map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
-+	
-+	if (machine_is_h1900())
-+	{
-+		/* For our intents, the h1900 is not a real iPAQ, so we special-case it. */
-+		return h1900_special_case();
-+	}
-+
-+	if (machine_is_h3100() || machine_is_h1900())
-+		for(i=0; i<MAX_IPAQ_CS; i++)
-+			ipaq_map[i].bankwidth = 2;
-+	else
-+		for(i=0; i<MAX_IPAQ_CS; i++)
-+			ipaq_map[i].bankwidth = 4;
-+			
-+	/*
-+	 * Static partition definition selection
-+	 */
-+	part_type = "static";
-+
-+	simple_map_init(&ipaq_map[0]);
-+	simple_map_init(&ipaq_map[1]);
-+
-+#ifdef CONFIG_IPAQ_HANDHELD
-+	if (machine_is_ipaq()) {
-+		parts = h3xxx_partitions;
-+		nb_parts = ARRAY_SIZE(h3xxx_partitions);
-+		for(i=0; i<MAX_IPAQ_CS; i++) {
-+			ipaq_map[i].size = h3xxx_max_flash_size;
-+			ipaq_map[i].set_vpp = h3xxx_set_vpp;
-+			ipaq_map[i].phys = cs_phys[i];
-+			ipaq_map[i].virt = (void __iomem *)__ioremap(cs_phys[i], 0x04000000, 0, 1);
-+			if (machine_is_h3100 () || machine_is_h1900())
-+				ipaq_map[i].bankwidth = 2;
-+		}
-+		if (machine_is_h3600()) {
-+			/* No asset partition here */
-+			h3xxx_partitions[1].size += 0x40000;
-+			nb_parts--;
-+		}
-+	}
-+#endif
-+#ifdef CONFIG_ARCH_H5400
-+	if (machine_is_h5400()) {
-+		ipaq_map[0].size = 0x02000000;
-+		ipaq_map[1].size = 0x02000000;
-+		ipaq_map[1].phys = 0x02000000;
-+		ipaq_map[1].virt = ipaq_map[0].virt + 0x02000000;
-+	}
-+#endif
-+#ifdef CONFIG_ARCH_H1900
-+	if (machine_is_h1900()) {
-+		ipaq_map[0].size = 0x00400000;
-+		ipaq_map[1].size = 0x02000000;
-+		ipaq_map[1].phys = 0x00080000;
-+		ipaq_map[1].virt = ipaq_map[0].virt + 0x00080000;
-+	}
-+#endif
-+
-+#ifdef CONFIG_SA1100_JORNADA56X
-+	if (machine_is_jornada56x()) {
-+		parts = jornada_partitions;
-+		nb_parts = ARRAY_SIZE(jornada_partitions);
-+		ipaq_map[0].size = jornada_max_flash_size;
-+		ipaq_map[0].set_vpp = jornada56x_set_vpp;
-+		ipaq_map[0].virt = (__u32)__ioremap(0x0, 0x04000000, 0, 1);
-+	}
-+#endif
-+#ifdef CONFIG_SA1100_JORNADA720
-+	if (machine_is_jornada720()) {
-+		parts = jornada_partitions;
-+		nb_parts = ARRAY_SIZE(jornada_partitions);
-+		ipaq_map[0].size = jornada_max_flash_size;
-+		ipaq_map[0].set_vpp = jornada720_set_vpp;
-+	}
-+#endif
-+
-+
-+	if (machine_is_ipaq()) { /* for iPAQs only */
-+		for(i=0; i<MAX_IPAQ_CS; i++) {
-+			printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with CFI.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);
-+			my_sub_mtd[i] = do_map_probe("cfi_probe", &ipaq_map[i]);
-+			if (!my_sub_mtd[i]) {
-+				printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[i].bankwidth*8, ipaq_map[i].virt);
-+				my_sub_mtd[i] = do_map_probe("jedec_probe", &ipaq_map[i]);
-+			}
-+			if (!my_sub_mtd[i]) {
-+				printk(KERN_NOTICE "iPAQ flash: failed to find flash.\n");
-+				if (i)
-+					break;
-+				else
-+					return -ENXIO;
-+			} else
-+				printk(KERN_NOTICE "iPAQ flash: found %d bytes\n", my_sub_mtd[i]->size);
-+			
-+			/* do we really need this debugging? --joshua 20030703 */
-+			// printk("my_sub_mtd[%d]=%p\n", i, my_sub_mtd[i]);
-+			my_sub_mtd[i]->owner = THIS_MODULE;
-+			tot_flashsize += my_sub_mtd[i]->size;
-+		}
-+#ifdef CONFIG_MTD_CONCAT
-+		/* fix the asset location */
-+#	ifdef CONFIG_LAB
-+		h3xxx_partitions[1].size = tot_flashsize - 0x40000 - 0x80000 /* extra big boot block */;
-+#	else
-+		h3xxx_partitions[1].size = tot_flashsize - 2 * 0x40000;
-+#	endif
-+		h3xxx_partitions[2].offset = tot_flashsize - 0x40000;
-+		/* and concat the devices */
-+		mymtd = mtd_concat_create(&my_sub_mtd[0], i,
-+					  "ipaq");
-+		if (!mymtd) {
-+			printk("Cannot create iPAQ concat device\n");
-+			return -ENXIO;
-+		}
-+#else
-+		mymtd = my_sub_mtd[0];
-+
-+		/* 
-+		 *In the very near future, command line partition parsing
-+		 * will use the device name as 'mtd-id' instead of a value
-+		 * passed to the parse_cmdline_partitions() routine. Since
-+		 * the bootldr says 'ipaq', make sure it continues to work. 
-+		 */
-+		mymtd->name = "ipaq";
-+
-+		if ((machine_is_h3600())) {
-+#	ifdef CONFIG_LAB
-+			h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x80000;
-+#	else
-+			h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000;
-+#	endif
-+			nb_parts = 2;
-+		} else {
-+#	ifdef CONFIG_LAB
-+			h3xxx_partitions[1].size = my_sub_mtd[0]->size - 0x40000 - 0x80000; /* extra big boot block */
-+#	else
-+			h3xxx_partitions[1].size = my_sub_mtd[0]->size - 2*0x40000;
-+#	endif
-+			h3xxx_partitions[2].offset = my_sub_mtd[0]->size - 0x40000;
-+		}
-+
-+		if (my_sub_mtd[1]) {
-+#	ifdef CONFIG_LAB
-+			h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x80000;
-+#	else
-+			h3xxx_partitions_bank2[0].size = my_sub_mtd[1]->size - 0x40000;
-+#	endif
-+			h3xxx_partitions_bank2[1].offset = my_sub_mtd[1]->size - 0x40000;
-+		}
-+#endif
-+	}
-+	else {
-+		/*
-+		 * Now let's probe for the actual flash.  Do it here since
-+		 * specific machine settings might have been set above.
-+		 */
-+		printk(KERN_NOTICE "IPAQ flash: probing %d-bit flash bus, window=%lx\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
-+		mymtd = do_map_probe("cfi_probe", &ipaq_map[0]);
-+		if (!mymtd)
-+			return -ENXIO;
-+		mymtd->owner = THIS_MODULE;
-+	}
-+
-+
-+	/*
-+	 * Dynamic partition selection stuff (might override the static ones)
-+	 */
-+
-+	 i = parse_mtd_partitions(mymtd, part_probes, &parsed_parts, 0);
-+			
-+	 if (i > 0) {
-+		 nb_parts = parsed_nr_parts = i;
-+		 parts = parsed_parts;
-+		 part_type = "dynamic";
-+	 }
-+
-+	 if (!parts) {
-+		 printk(KERN_NOTICE "IPAQ flash: no partition info available, registering whole flash at once\n");
-+		 add_mtd_device(mymtd);
-+#ifndef CONFIG_MTD_CONCAT
-+		 if (my_sub_mtd[1])
-+			 add_mtd_device(my_sub_mtd[1]);
-+#endif
-+	 } else {
-+		 printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-+		 add_mtd_partitions(mymtd, parts, nb_parts);
-+#ifndef CONFIG_MTD_CONCAT
-+		 if (my_sub_mtd[1])
-+			 add_mtd_partitions(my_sub_mtd[1], h3xxx_partitions_bank2, ARRAY_SIZE(h3xxx_partitions_bank2));
-+#endif
-+	 }
-+
-+	 return 0;
-+}
-+
-+static void __exit ipaq_mtd_cleanup(void)
-+{
-+	int i;
-+
-+	if (mymtd) {
-+		del_mtd_partitions(mymtd);
-+#ifndef CONFIG_MTD_CONCAT
-+		if (my_sub_mtd[1])
-+			del_mtd_partitions(my_sub_mtd[1]);
-+#endif
-+		map_destroy(mymtd);
-+#ifdef CONFIG_MTD_CONCAT
-+		for(i=0; i<MAX_IPAQ_CS; i++) 
-+#else
-+			for(i=1; i<MAX_IPAQ_CS; i++) 
-+#endif		  
-+			{
-+				if (my_sub_mtd[i])
-+					map_destroy(my_sub_mtd[i]);
-+			}
-+		if (parsed_parts)
-+			kfree(parsed_parts);
-+	}
-+}
-+
-+static int __init h1900_special_case(void)
-+{
-+	/* The iPAQ h1900 is a special case - it has weird ROM. */
-+	simple_map_init(&ipaq_map[0]);
-+	ipaq_map[0].size = 0x80000;
-+	ipaq_map[0].set_vpp = h3xxx_set_vpp;
-+	ipaq_map[0].phys = 0x0;
-+	ipaq_map[0].virt = (void __iomem *)__ioremap(0x0, 0x04000000, 0, 1);
-+	ipaq_map[0].bankwidth = 2;
-+	
-+	printk(KERN_NOTICE "iPAQ flash: probing %d-bit flash bus, window=%lx with JEDEC.\n", ipaq_map[0].bankwidth*8, ipaq_map[0].virt);
-+	mymtd = do_map_probe("jedec_probe", &ipaq_map[0]);
-+	if (!mymtd)
-+		return -ENODEV;
-+	add_mtd_device(mymtd);
-+	printk(KERN_NOTICE "iPAQ flash: registered h1910 flash\n");
-+	
-+	return 0;
-+}
-+
-+module_init(ipaq_mtd_init);
-+module_exit(ipaq_mtd_cleanup);
-+
-+MODULE_AUTHOR("Jamey Hicks");
-+MODULE_DESCRIPTION("IPAQ CFI map driver");
-+MODULE_LICENSE("MIT");
-Index: linux-2.6.5/drivers/mtd/maps/iq80310.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/iq80310.c	2004-04-03 22:38:15.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/iq80310.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: iq80310.c,v 1.17 2003/06/23 11:48:18 dwmw2 Exp $
-+ * $Id: iq80310.c,v 1.19 2004/09/16 23:27:13 gleixner Exp $
-  *
-  * Mapping for the Intel XScale IQ80310 evaluation board
-  *
-@@ -31,7 +31,7 @@
- static struct map_info iq80310_map = {
- 	.name = "IQ80310 flash",
- 	.size = WINDOW_SIZE,
--	.buswidth = BUSWIDTH,
-+	.bankwidth = BUSWIDTH,
- 	.phys = WINDOW_ADDR
- };
- 
-@@ -68,7 +68,7 @@
- 	int parsed_nr_parts = 0;
- 	int ret;
- 
--	iq80310_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+	iq80310_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE);
- 	if (!iq80310_map.virt) {
- 		printk("Failed to ioremap\n");
- 		return -EIO;
-Index: linux-2.6.5/drivers/mtd/maps/ixp2000.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/ixp2000.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/ixp2000.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,281 @@
-+/*
-+ * $Id: ixp2000.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $
-+ *
-+ * drivers/mtd/maps/ixp2000.c
-+ *
-+ * Mapping for the Intel XScale IXP2000 based systems
-+ *
-+ * Copyright (C) 2002 Intel Corp.
-+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
-+ *
-+ * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
-+ * Maintainer: Deepak Saxena <dsaxena@plexity.net>
-+ *
-+ * 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/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+
-+#include <asm/io.h>
-+#include <asm/hardware.h>
-+#include <asm/mach-types.h>
-+#include <asm/mach/flash.h>
-+
-+#include <linux/reboot.h>
-+
-+struct ixp2000_flash_info {
-+	struct		mtd_info *mtd;
-+	struct		map_info map;
-+	struct		mtd_partition *partitions;
-+	struct		resource *res;
-+	int		nr_banks;
-+};
-+
-+static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
-+{	
-+	unsigned long (*set_bank)(unsigned long) = 
-+		(unsigned long(*)(unsigned long))map->map_priv_2;
-+
-+	return (set_bank ? set_bank(ofs) : ofs);
-+}
-+
-+#ifdef __ARMEB__
-+/*
-+ * Rev A0 and A1 of IXP2400 silicon have a broken addressing unit which 
-+ * causes the lower address bits to be XORed with 0x11 on 8 bit accesses 
-+ * and XORed with 0x10 on 16 bit accesses. See the spec update, erratum 44.
-+ */
-+static int erratum44_workaround = 0;
-+
-+static inline unsigned long address_fix8_write(unsigned long addr)
-+{
-+	if (erratum44_workaround) {
-+		return (addr ^ 3);
-+	}
-+	return addr;
-+}
-+#else
-+
-+#define address_fix8_write(x)	(x)
-+#endif
-+
-+static map_word ixp2000_flash_read8(struct map_info *map, unsigned long ofs)
-+{
-+	map_word val;
-+
-+	val.x[0] =  *((u8 *)(map->map_priv_1 + flash_bank_setup(map, ofs)));
-+	return val;
-+}
-+
-+/*
-+ * We can't use the standard memcpy due to the broken SlowPort
-+ * address translation on rev A0 and A1 silicon and the fact that
-+ * we have banked flash.
-+ */
-+static void ixp2000_flash_copy_from(struct map_info *map, void *to,
-+			      unsigned long from, ssize_t len)
-+{
-+	from = flash_bank_setup(map, from);
-+	while(len--) 
-+		*(__u8 *) to++ = *(__u8 *)(map->map_priv_1 + from++);
-+}
-+
-+static void ixp2000_flash_write8(struct map_info *map, map_word d, unsigned long ofs)
-+{
-+	*(__u8 *) (address_fix8_write(map->map_priv_1 +
-+				      flash_bank_setup(map, ofs))) = d.x[0];
-+}
-+
-+static void ixp2000_flash_copy_to(struct map_info *map, unsigned long to,
-+			    const void *from, ssize_t len)
-+{
-+	to = flash_bank_setup(map, to);
-+	while(len--) {
-+		unsigned long tmp = address_fix8_write(map->map_priv_1 + to++);
-+		*(__u8 *)(tmp) = *(__u8 *)(from++);
-+	}
-+}
-+
-+
-+static int ixp2000_flash_remove(struct device *_dev)
-+{
-+	struct platform_device *dev = to_platform_device(_dev);
-+	struct flash_platform_data *plat = dev->dev.platform_data;
-+	struct ixp2000_flash_info *info = dev_get_drvdata(&dev->dev);
-+
-+	dev_set_drvdata(&dev->dev, NULL);
-+
-+	if(!info)
-+		return 0;
-+
-+	if (info->mtd) {
-+		del_mtd_partitions(info->mtd);
-+		map_destroy(info->mtd);
-+	}
-+	if (info->map.map_priv_1)
-+		iounmap((void *) info->map.map_priv_1);
-+
-+	if (info->partitions) {
-+		kfree(info->partitions); }
-+
-+	if (info->res) {
-+		release_resource(info->res);
-+		kfree(info->res);
-+	}
-+
-+	if (plat->exit)
-+		plat->exit();
-+
-+	return 0;
-+}
-+
-+
-+static int ixp2000_flash_probe(struct device *_dev)
-+{
-+	static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+	struct platform_device *dev = to_platform_device(_dev);
-+	struct ixp2000_flash_data *ixp_data = dev->dev.platform_data;
-+	struct flash_platform_data *plat; 
-+	struct ixp2000_flash_info *info;
-+	unsigned long window_size;
-+	int err = -1;
-+	
-+	if (!ixp_data)
-+		return -ENODEV;
-+
-+	plat = ixp_data->platform_data;
-+	if (!plat)
-+		return -ENODEV;
-+
-+	window_size = dev->resource->end - dev->resource->start + 1;
-+	dev_info(_dev, "Probe of IXP2000 flash(%d banks x %dMiB)\n", 
-+			ixp_data->nr_banks, ((u32)window_size >> 20));
-+
-+	if (plat->width != 1) {
-+		dev_err(_dev, "IXP2000 MTD map only supports 8-bit mode, asking for %d\n",
-+				plat->width * 8);
-+		return -EIO;
-+	}
-+
-+	info = kmalloc(sizeof(struct ixp2000_flash_info), GFP_KERNEL);
-+	if(!info) {
-+		err = -ENOMEM;
-+		goto Error;
-+	}	
-+	memzero(info, sizeof(struct ixp2000_flash_info));
-+
-+	dev_set_drvdata(&dev->dev, info);
-+
-+	/*
-+	 * Tell the MTD layer we're not 1:1 mapped so that it does
-+	 * not attempt to do a direct access on us.
-+	 */
-+	info->map.phys = NO_XIP;
-+	
-+	info->nr_banks = ixp_data->nr_banks;
-+	info->map.size = ixp_data->nr_banks * window_size;
-+	info->map.bankwidth = 1;
-+
-+	/*
-+ 	 * map_priv_2 is used to store a ptr to to the bank_setup routine
-+ 	 */
-+	info->map.map_priv_2 = (void __iomem *) ixp_data->bank_setup;
-+
-+	info->map.name = dev->dev.bus_id;
-+	info->map.read = ixp2000_flash_read8;
-+	info->map.write = ixp2000_flash_write8;
-+	info->map.copy_from = ixp2000_flash_copy_from;
-+	info->map.copy_to = ixp2000_flash_copy_to;
-+
-+	info->res = request_mem_region(dev->resource->start, 
-+			dev->resource->end - dev->resource->start + 1, 
-+			dev->dev.bus_id);
-+	if (!info->res) {
-+		dev_err(_dev, "Could not reserve memory region\n");
-+		err = -ENOMEM;
-+		goto Error;
-+	}
-+
-+	info->map.map_priv_1 =
-+	    (void __iomem *) ioremap(dev->resource->start, 
-+				    dev->resource->end - dev->resource->start + 1);
-+	if (!info->map.map_priv_1) {
-+		dev_err(_dev, "Failed to ioremap flash region\n");
-+		err = -EIO;
-+		goto Error;
-+	}
-+
-+	/*
-+	 * Setup read mode for FLASH
-+	 */
-+	*IXP2000_SLOWPORT_FRM = 1;
-+
-+#if defined(__ARMEB__)
-+	/*
-+	 * Enable erratum 44 workaround for NPUs with broken slowport
-+	 */
-+
-+	errata44_workaround = ixp2000_has_broken_slowport();
-+	dev_info(_dev, "Erratum 44 workaround %s\n",
-+	       erratum44_workaround ? "enabled" : "disabled");
-+#endif
-+
-+	info->mtd = do_map_probe(plat->map_name, &info->map);
-+	if (!info->mtd) {
-+		dev_err(_dev, "map_probe failed\n");
-+		err = -ENXIO;
-+		goto Error;
-+	}
-+	info->mtd->owner = THIS_MODULE;
-+
-+	err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
-+	if (err > 0) {
-+		err = add_mtd_partitions(info->mtd, info->partitions, err);
-+		if(err)
-+			dev_err(_dev, "Could not parse partitions\n");
-+	}
-+
-+	if (err)
-+		goto Error;
-+
-+	return 0;
-+
-+Error:
-+	ixp2000_flash_remove(_dev);
-+	return err;
-+}
-+
-+static struct device_driver ixp2000_flash_driver = {
-+	.name		= "IXP2000-Flash",
-+	.bus		= &platform_bus_type,
-+	.probe		= &ixp2000_flash_probe,
-+	.remove		= &ixp2000_flash_remove
-+};
-+
-+static int __init ixp2000_flash_init(void)
-+{
-+	return driver_register(&ixp2000_flash_driver);
-+}
-+
-+static void __exit ixp2000_flash_exit(void)
-+{
-+	driver_unregister(&ixp2000_flash_driver);
-+}
-+
-+module_init(ixp2000_flash_init);
-+module_exit(ixp2000_flash_exit);
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-+
-Index: linux-2.6.5/drivers/mtd/maps/ixp4xx.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/ixp4xx.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/ixp4xx.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,260 @@
-+/*
-+ * $Id: ixp4xx.c,v 1.6 2004/09/17 00:25:06 gleixner Exp $
-+ *
-+ * drivers/mtd/maps/ixp4xx.c
-+ *
-+ * MTD Map file for IXP4XX based systems. Please do not make per-board
-+ * changes in here. If your board needs special setup, do it in your
-+ * platform level code in arch/arm/mach-ixp4xx/board-setup.c
-+ *
-+ * Original Author: Intel Corporation
-+ * Maintainer: Deepak Saxena <dsaxena@mvista.com>
-+ *
-+ * Copyright (C) 2002 Intel Corporation
-+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/ioport.h>
-+#include <linux/device.h>
-+#include <asm/io.h>
-+#include <asm/mach-types.h>
-+#include <asm/mach/flash.h>
-+
-+#include <linux/reboot.h>
-+
-+#ifndef __ARMEB__
-+#define	BYTE0(h)	((h) & 0xFF)
-+#define	BYTE1(h)	(((h) >> 8) & 0xFF)
-+#else
-+#define	BYTE0(h)	(((h) >> 8) & 0xFF)
-+#define	BYTE1(h)	((h) & 0xFF)
-+#endif
-+
-+static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
-+{
-+	map_word val;
-+	val.x[0] = *(__u16 *) (map->map_priv_1 + ofs);
-+	return val;
-+}
-+
-+/*
-+ * The IXP4xx expansion bus only allows 16-bit wide acceses
-+ * when attached to a 16-bit wide device (such as the 28F128J3A),
-+ * so we can't just memcpy_fromio().
-+ */
-+static void ixp4xx_copy_from(struct map_info *map, void *to,
-+			     unsigned long from, ssize_t len)
-+{
-+	int i;
-+	u8 *dest = (u8 *) to;
-+	u16 *src = (u16 *) (map->map_priv_1 + from);
-+	u16 data;
-+
-+	for (i = 0; i < (len / 2); i++) {
-+		data = src[i];
-+		dest[i * 2] = BYTE0(data);
-+		dest[i * 2 + 1] = BYTE1(data);
-+	}
-+
-+	if (len & 1)
-+		dest[len - 1] = BYTE0(src[i]);
-+}
-+
-+/* 
-+ * Unaligned writes are ignored, causing the 8-bit
-+ * probe to fail and proceed to the 16-bit probe (which succeeds).
-+ */
-+static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
-+{
-+	if (!(adr & 1))
-+	       *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
-+}
-+
-+/* 
-+ * Fast write16 function without the probing check above
-+ */
-+static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
-+{
-+       *(__u16 *) (map->map_priv_1 + adr) = d.x[0];
-+}
-+
-+struct ixp4xx_flash_info {
-+	struct mtd_info *mtd;
-+	struct map_info map;
-+	struct mtd_partition *partitions;
-+	struct resource *res;
-+};
-+
-+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-+
-+static int ixp4xx_flash_remove(struct device *_dev)
-+{
-+	struct platform_device *dev = to_platform_device(_dev);
-+	struct flash_platform_data *plat = dev->dev.platform_data;
-+	struct ixp4xx_flash_info *info = dev_get_drvdata(&dev->dev);
-+	map_word d;
-+
-+	dev_set_drvdata(&dev->dev, NULL);
-+
-+	if(!info)
-+		return 0;
-+
-+	/*
-+	 * This is required for a soft reboot to work.
-+	 */
-+	d.x[0] = 0xff;
-+	ixp4xx_write16(&info->map, d, 0x55 * 0x2);
-+
-+	if (info->mtd) {
-+		del_mtd_partitions(info->mtd);
-+		map_destroy(info->mtd);
-+	}
-+	if (info->map.map_priv_1)
-+		iounmap((void *) info->map.map_priv_1);
-+
-+	if (info->partitions)
-+		kfree(info->partitions);
-+
-+	if (info->res) {
-+		release_resource(info->res);
-+		kfree(info->res);
-+	}
-+
-+	if (plat->exit)
-+		plat->exit();
-+
-+	/* Disable flash write */
-+	*IXP4XX_EXP_CS0 &= ~IXP4XX_FLASH_WRITABLE;
-+
-+	return 0;
-+}
-+
-+static int ixp4xx_flash_probe(struct device *_dev)
-+{
-+	struct platform_device *dev = to_platform_device(_dev);
-+	struct flash_platform_data *plat = dev->dev.platform_data;
-+	struct ixp4xx_flash_info *info;
-+	int err = -1;
-+
-+	if (!plat)
-+		return -ENODEV;
-+
-+	if (plat->init) {
-+		err = plat->init();
-+		if (err)
-+			return err;
-+	}
-+
-+	info = kmalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL);
-+	if(!info) {
-+		err = -ENOMEM;
-+		goto Error;
-+	}	
-+	memzero(info, sizeof(struct ixp4xx_flash_info));
-+
-+	dev_set_drvdata(&dev->dev, info);
-+
-+	/* 
-+	 * Enable flash write 
-+	 * TODO: Move this out to board specific code
-+	 */
-+	*IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
-+
-+	/*
-+	 * Tell the MTD layer we're not 1:1 mapped so that it does
-+	 * not attempt to do a direct access on us.
-+	 */
-+	info->map.phys = NO_XIP;
-+	info->map.size = dev->resource->end - dev->resource->start + 1;
-+
-+	/*
-+	 * We only support 16-bit accesses for now. If and when
-+	 * any board use 8-bit access, we'll fixup the driver to
-+	 * handle that.
-+	 */
-+	info->map.bankwidth = 2;
-+	info->map.name = dev->dev.bus_id;
-+	info->map.read = ixp4xx_read16,
-+	info->map.write = ixp4xx_probe_write16,
-+	info->map.copy_from = ixp4xx_copy_from,
-+
-+	info->res = request_mem_region(dev->resource->start, 
-+			dev->resource->end - dev->resource->start + 1, 
-+			"IXP4XXFlash");
-+	if (!info->res) {
-+		printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n");
-+		err = -ENOMEM;
-+		goto Error;
-+	}
-+
-+	info->map.map_priv_1 =
-+	    (void __iomem *) ioremap(dev->resource->start, 
-+				    dev->resource->end - dev->resource->start + 1);
-+	if (!info->map.map_priv_1) {
-+		printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
-+		err = -EIO;
-+		goto Error;
-+	}
-+
-+	info->mtd = do_map_probe(plat->map_name, &info->map);
-+	if (!info->mtd) {
-+		printk(KERN_ERR "IXP4XXFlash: map_probe failed\n");
-+		err = -ENXIO;
-+		goto Error;
-+	}
-+	info->mtd->owner = THIS_MODULE;
-+	
-+	/* Use the fast version */
-+	info->map.write = ixp4xx_write16,
-+
-+	err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
-+	if (err > 0) {
-+		err = add_mtd_partitions(info->mtd, info->partitions, err);
-+		if(err)
-+			printk(KERN_ERR "Could not parse partitions\n");
-+	}
-+
-+	if (err)
-+		goto Error;
-+
-+	return 0;
-+
-+Error:
-+	ixp4xx_flash_remove(_dev);
-+	return err;
-+}
-+
-+static struct device_driver ixp4xx_flash_driver = {
-+	.name		= "IXP4XX-Flash",
-+	.bus		= &platform_bus_type,
-+	.probe		= ixp4xx_flash_probe,
-+	.remove		= ixp4xx_flash_remove,
-+};
-+
-+static int __init ixp4xx_flash_init(void)
-+{
-+	return driver_register(&ixp4xx_flash_driver);
-+}
-+
-+static void __exit ixp4xx_flash_exit(void)
-+{
-+	driver_unregister(&ixp4xx_flash_driver);
-+}
-+
-+
-+module_init(ixp4xx_flash_init);
-+module_exit(ixp4xx_flash_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("MTD map driver for Intel IXP4xx systems")
-+MODULE_AUTHOR("Deepak Saxena");
-+
-Index: linux-2.6.5/drivers/mtd/maps/l440gx.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/l440gx.c	2004-04-03 22:37:59.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/l440gx.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: l440gx.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
-+ * $Id: l440gx.c,v 1.14 2004/09/16 23:27:13 gleixner Exp $
-  *
-  * BIOS Flash chip on Intel 440GX board.
-  *
-@@ -46,7 +46,7 @@
- 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 
-@@ -73,7 +73,7 @@
- 		return -ENODEV;
- 	}
- 
--	l440gx_map.virt = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
-+	l440gx_map.virt = (void __iomem *)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
- 
- 	if (!l440gx_map.virt) {
- 		printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
-Index: linux-2.6.5/drivers/mtd/maps/lasat.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/lasat.c	2004-04-03 22:36:25.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/lasat.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.8 2004/09/16 23:27:13 gleixner Exp $
-  *
-  */
- 
-@@ -22,44 +21,53 @@
- #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;
--
--	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;
-+	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
-+};
- 
--	simple_map_init(&sp_map);
-+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));
-+
-+	lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
-+	lasat_map.virt = (void __iomem *)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 @@
- 			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: linux-2.6.5/drivers/mtd/maps/lubbock-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/lubbock-flash.c	2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/lubbock-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.17 2004/09/16 23:27:13 gleixner Exp $
-  *
-  * Map driver for the Lubbock developer platform.
-  *
-@@ -15,11 +15,12 @@
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
--#include <asm/io.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-+#include <asm/io.h>
- #include <asm/hardware.h>
-+#include <asm/arch/lubbock.h>
- 
- 
- #define ROM_ADDR	0x00000000
-@@ -27,12 +28,19 @@
- 
- #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[] = {
-@@ -60,10 +68,10 @@
- 
- static int __init init_lubbock(void)
- {
--	int flashboot = (CONF_SWITCHES & 1);
-+	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 */
-@@ -74,23 +82,28 @@
- 	lubbock_maps[flashboot].name = "Lubbock Boot ROM";
- 
- 	for (i = 0; i < 2; i++) {
--		lubbock_maps[i].virt = (unsigned long)ioremap(lubbock_maps[i].phys, WINDOW_SIZE);
-+		lubbock_maps[i].virt = (void __iomem *)ioremap(lubbock_maps[i].phys, WINDOW_SIZE);
- 		if (!lubbock_maps[i].virt) {
- 			printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name);
- 			if (!ret)
- 				ret = -ENOMEM;
- 			continue;
- 		}
-+		lubbock_maps[i].cached = ioremap_cached(lubbock_maps[i].phys, WINDOW_SIZE);
-+		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;
-@@ -137,6 +150,8 @@
- 
- 		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: linux-2.6.5/drivers/mtd/maps/map_funcs.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/map_funcs.c	2005-02-01 16:55:39.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/map_funcs.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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, (char *)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((char *)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: linux-2.6.5/drivers/mtd/maps/mbx860.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/mbx860.c	2004-04-03 22:36:54.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/mbx860.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: mbx860.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $
-+ * $Id: mbx860.c,v 1.7 2004/09/16 23:27:13 gleixner Exp $
-  *
-  * Handle mapping of the flash on MBX860 boards
-  *
-@@ -54,13 +54,13 @@
- 	.name = "MBX flash",
- 	.size = WINDOW_SIZE,
- 	.phys = WINDOW_ADDR,
--	.buswidth = 4,
-+	.bankwidth = 4,
- };
- 
- int __init init_mbx(void)
- {
- 	printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR);
--	mbx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-+	mbx_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
- 
- 	if (!mbx_map.virt) {
- 		printk("Failed to ioremap\n");
-Index: linux-2.6.5/drivers/mtd/maps/mpc1211.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/mpc1211.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/mpc1211.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,81 @@
-+/*
-+ * Flash on MPC-1211
-+ *
-+ * $Id: mpc1211.c,v 1.4 2004/09/16 23:27:13 gleixner Exp $
-+ *
-+ * (C) 2002 Interface, Saito.K & Jeanne
-+ *
-+ * GPL'd
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+
-+static struct mtd_info *flash_mtd;
-+static struct mtd_partition *parsed_parts;
-+
-+struct map_info mpc1211_flash_map = {
-+	.name		= "MPC-1211 FLASH",
-+	.size		= 0x80000,
-+	.bankwidth	= 1,
-+};
-+
-+static struct mtd_partition mpc1211_partitions[] = {
-+	{
-+		.name	= "IPL & ETH-BOOT",
-+		.offset	= 0x00000000,
-+		.size	= 0x10000,
-+	},
-+	{
-+		.name	= "Flash FS",
-+		.offset	= 0x00010000,
-+		.size	= MTDPART_SIZ_FULL,
-+	}
-+};
-+
-+static int __init init_mpc1211_maps(void)
-+{
-+	int nr_parts;
-+
-+	mpc1211_flash_map.phys = 0;
-+	mpc1211_flash_map.virt = (void __iomem *)P2SEGADDR(0);
-+
-+	simple_map_init(&mpc1211_flash_map);
-+
-+	printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n");
-+	flash_mtd = do_map_probe("jedec_probe", &mpc1211_flash_map);
-+	if (!flash_mtd) {
-+		printk(KERN_NOTICE "Flash chips not detected at either possible location.\n");
-+		return -ENXIO;
-+	}
-+	printk(KERN_NOTICE "MPC-1211: Flash at 0x%08lx\n", mpc1211_flash_map.virt & 0x1fffffff);
-+	flash_mtd->module = THIS_MODULE;
-+
-+	parsed_parts = mpc1211_partitions;
-+	nr_parts = ARRAY_SIZE(mpc1211_partitions);
-+
-+	add_mtd_partitions(flash_mtd, parsed_parts, nr_parts);
-+	return 0;
-+}
-+
-+static void __exit cleanup_mpc1211_maps(void)
-+{
-+	if (parsed_parts)
-+		del_mtd_partitions(flash_mtd);
-+	else
-+		del_mtd_device(flash_mtd);
-+	map_destroy(flash_mtd);
-+}
-+
-+module_init(init_mpc1211_maps);
-+module_exit(cleanup_mpc1211_maps);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Saito.K & Jeanne <ksaito@interface.co.jp>");
-+MODULE_DESCRIPTION("MTD map driver for MPC-1211 boards. Interface");
-Index: linux-2.6.5/drivers/mtd/maps/netsc520.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/netsc520.c	2004-04-03 22:37:41.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/netsc520.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.11 2004/09/16 23:27:13 gleixner 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 map_info netsc520_map = {
- 	.name = "netsc520 Flash Bank",
- 	.size = WINDOW_SIZE,
--	.buswidth = 4,
-+	.bankwidth = 4,
- 	.phys = WINDOW_ADDR,
- };
- 
-@@ -95,7 +95,7 @@
- static int __init init_netsc520(void)
- {
- 	printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys);
--	netsc520_map.virt = (unsigned long)ioremap_nocache(netsc520_map.phys, netsc520_map.size);
-+	netsc520_map.virt = (void __iomem *)ioremap_nocache(netsc520_map.phys, netsc520_map.size);
- 
- 	if (!netsc520_map.virt) {
- 		printk("Failed to ioremap_nocache\n");
-Index: linux-2.6.5/drivers/mtd/maps/nettel.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/nettel.c	2004-04-03 22:36:52.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/nettel.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.6 2004/09/16 23:27:13 gleixner Exp $
-  */
- 
- /****************************************************************************/
-@@ -65,7 +65,7 @@
- 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 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[] = {
-@@ -273,8 +273,7 @@
- 	__asm__ ("wbinvd");
- 
- 	nettel_amd_map.phys = amdaddr;
--	nettel_amd_map.virt = (unsigned long)
--		ioremap_nocache(amdaddr, maxsize);
-+	nettel_amd_map.virt = (void __iomem *) ioremap_nocache(amdaddr, maxsize);
- 	if (!nettel_amd_map.virt) {
- 		printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
- 		return(-EIO);
-Index: linux-2.6.5/drivers/mtd/maps/ocelot.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/ocelot.c	2004-04-03 22:38:22.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/ocelot.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: ocelot.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $
-+ * $Id: ocelot.c,v 1.14 2004/09/16 23:27:13 gleixner Exp $
-  *
-  * Flash on Momenco Ocelot
-  */
-@@ -49,14 +49,14 @@
- 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,
- };
- 
-@@ -81,7 +81,7 @@
- 	iounmap(pld);
- 
- 	/* Now ioremap the NVRAM space */
--	ocelot_nvram_map.virt = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
-+	ocelot_nvram_map.virt = (void __iomem *)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE);
- 	if (!ocelot_nvram_map.virt) {
- 		printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n");
- 		return -EIO;
-@@ -101,7 +101,7 @@
- 	nvram_mtd->write = ocelot_ram_write;
- 
- 	/* Now map the flash space */
--	ocelot_flash_map.virt = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
-+	ocelot_flash_map.virt = (void __iomem *)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE);
- 	if (!ocelot_flash_map.virt) {
- 		printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n");
- 		goto fail_2;
-Index: linux-2.6.5/drivers/mtd/maps/ocotea.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/ocotea.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/ocotea.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,156 @@
-+/*
-+ * Mapping for Ocotea user flash
-+ *
-+ * Matt Porter <mporter@kernel.crashing.org>
-+ *
-+ * Copyright 2002-2004 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 <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/config.h>
-+#include <linux/version.h>
-+#include <asm/io.h>
-+#include <asm/ibm44x.h>
-+#include <platforms/4xx/ocotea.h>
-+
-+static struct mtd_info *flash;
-+
-+static struct map_info ocotea_small_map = {
-+	.name =		"Ocotea small flash",
-+	.size =		OCOTEA_SMALL_FLASH_SIZE,
-+	.buswidth =	1,
-+};
-+
-+static struct map_info ocotea_large_map = {
-+	.name =		"Ocotea large flash",
-+	.size =		OCOTEA_LARGE_FLASH_SIZE,
-+	.buswidth =	1,
-+};
-+
-+static struct mtd_partition ocotea_small_partitions[] = {
-+	{
-+		.name =   "pibs",
-+		.offset = 0x0,
-+		.size =   0x100000,
-+	}
-+};
-+
-+static struct mtd_partition ocotea_large_partitions[] = {
-+	{
-+		.name =   "fs",
-+		.offset = 0,
-+		.size =   0x300000,
-+	},
-+	{
-+		.name =   "firmware",
-+		.offset = 0x300000,
-+		.size =   0x100000,
-+	}
-+};
-+
-+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-+
-+int __init init_ocotea(void)
-+{
-+	u8 fpga0_reg;
-+	u8 *fpga0_adr;
-+	unsigned long long small_flash_base, large_flash_base;
-+
-+	fpga0_adr = ioremap64(OCOTEA_FPGA_ADDR, 16);
-+	if (!fpga0_adr)
-+		return -ENOMEM;
-+
-+	fpga0_reg = readb((unsigned long)fpga0_adr);
-+	iounmap(fpga0_adr);
-+
-+	if (OCOTEA_BOOT_LARGE_FLASH(fpga0_reg)) {
-+		small_flash_base = OCOTEA_SMALL_FLASH_HIGH;
-+		large_flash_base = OCOTEA_LARGE_FLASH_LOW;
-+	}
-+	else {
-+		small_flash_base = OCOTEA_SMALL_FLASH_LOW;
-+		large_flash_base = OCOTEA_LARGE_FLASH_HIGH;
-+	}
-+
-+	ocotea_small_map.phys = small_flash_base;
-+	ocotea_small_map.virt =
-+		(void __iomem *)ioremap64(small_flash_base,
-+					 ocotea_small_map.size);
-+
-+	if (!ocotea_small_map.virt) {
-+		printk("Failed to ioremap flash\n");
-+		return -EIO;
-+	}
-+
-+	simple_map_init(&ocotea_small_map);
-+
-+	flash = do_map_probe("map_rom", &ocotea_small_map);
-+	if (flash) {
-+		flash->owner = THIS_MODULE;
-+		add_mtd_partitions(flash, ocotea_small_partitions,
-+					NB_OF(ocotea_small_partitions));
-+	} else {
-+		printk("map probe failed for flash\n");
-+		return -ENXIO;
-+	}
-+
-+	ocotea_large_map.phys = large_flash_base;
-+	ocotea_large_map.virt =
-+		(void __iomem *)ioremap64(large_flash_base,
-+					 ocotea_large_map.size);
-+
-+	if (!ocotea_large_map.virt) {
-+		printk("Failed to ioremap flash\n");
-+		return -EIO;
-+	}
-+
-+	simple_map_init(&ocotea_large_map);
-+
-+	flash = do_map_probe("cfi_probe", &ocotea_large_map);
-+	if (flash) {
-+		flash->owner = THIS_MODULE;
-+		add_mtd_partitions(flash, ocotea_large_partitions,
-+					NB_OF(ocotea_large_partitions));
-+	} else {
-+		printk("map probe failed for flash\n");
-+		return -ENXIO;
-+	}
-+
-+	return 0;
-+}
-+
-+static void __exit cleanup_ocotea(void)
-+{
-+	if (flash) {
-+		del_mtd_partitions(flash);
-+		map_destroy(flash);
-+	}
-+
-+	if (ocotea_small_map.virt) {
-+		iounmap((void *)ocotea_small_map.virt);
-+		ocotea_small_map.virt = 0;
-+	}
-+
-+	if (ocotea_large_map.virt) {
-+		iounmap((void *)ocotea_large_map.virt);
-+		ocotea_large_map.virt = 0;
-+	}
-+}
-+
-+module_init(init_ocotea);
-+module_exit(cleanup_ocotea);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
-+MODULE_DESCRIPTION("MTD map and partitions for IBM 440GX Ocotea boards");
-Index: linux-2.6.5/drivers/mtd/maps/octagon-5066.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/octagon-5066.c	2004-04-03 22:36:25.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/octagon-5066.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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 __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_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 @@
- 		.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 @@
- 		.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: linux-2.6.5/drivers/mtd/maps/omap-toto-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/omap-toto-flash.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/omap-toto-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,137 @@
-+/*
-+ * NOR Flash memory access on TI Toto board
-+ *
-+ * jzhang@ti.com (C) 2003 Texas Instruments.
-+ *
-+ *  (C) 2002 MontVista Software, Inc.
-+ *
-+ * $Id: omap-toto-flash.c,v 1.3 2004/09/16 23:27:13 gleixner Exp $
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/io.h>
-+
-+
-+#ifndef CONFIG_ARCH_OMAP
-+#error This is for OMAP architecture only
-+#endif
-+
-+//these lines need be moved to a hardware header file
-+#define OMAP_TOTO_FLASH_BASE 0xd8000000
-+#define OMAP_TOTO_FLASH_SIZE 0x80000
-+
-+static struct map_info omap_toto_map_flash = {
-+	.name =		"OMAP Toto flash",
-+	.bankwidth =	2,
-+	.virt =		(void __iomem *)OMAP_TOTO_FLASH_BASE,
-+};
-+
-+ 
-+static struct mtd_partition toto_flash_partitions[] = {
-+	{
-+		.name =		"BootLoader",
-+		.size =		0x00040000,     /* hopefully u-boot will stay 128k + 128*/
-+		.offset =	0,
-+		.mask_flags =	MTD_WRITEABLE,  /* force read-only */
-+	}, {
-+		.name =		"ReservedSpace",
-+		.size =		0x00030000,
-+		.offset =	MTDPART_OFS_APPEND,
-+		//mask_flags:	MTD_WRITEABLE,  /* force read-only */
-+	}, {
-+		.name =		"EnvArea",      /* bottom 64KiB for env vars */
-+		.size =		MTDPART_SIZ_FULL,
-+		.offset =	MTDPART_OFS_APPEND,
-+	} 
-+};
-+
-+static struct mtd_partition *parsed_parts;
-+
-+static struct mtd_info *flash_mtd;
-+ 
-+static int __init init_flash (void)   
-+{
-+
-+	struct mtd_partition *parts;
-+	int nb_parts = 0;
-+	int parsed_nr_parts = 0;
-+	const char *part_type;
-+ 
-+	/*
-+	 * Static partition definition selection
-+	 */
-+	part_type = "static";
-+
-+ 	parts = toto_flash_partitions;
-+	nb_parts = ARRAY_SIZE(toto_flash_partitions);
-+	omap_toto_map_flash.size = OMAP_TOTO_FLASH_SIZE;
-+	omap_toto_map_flash.phys = virt_to_phys(OMAP_TOTO_FLASH_BASE);
-+
-+	simple_map_init(&omap_toto_map_flash);
-+	/*
-+	 * Now let's probe for the actual flash.  Do it here since
-+	 * specific machine settings might have been set above.
-+	 */
-+	printk(KERN_NOTICE "OMAP toto flash: probing %d-bit flash bus\n",
-+		omap_toto_map_flash.bankwidth*8);
-+	flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash);
-+	if (!flash_mtd)
-+		return -ENXIO;
-+ 
-+ 	if (parsed_nr_parts > 0) {
-+		parts = parsed_parts;
-+		nb_parts = parsed_nr_parts;
-+	}
-+
-+	if (nb_parts == 0) {
-+		printk(KERN_NOTICE "OMAP toto flash: no partition info available,"
-+			"registering whole flash at once\n");
-+		if (add_mtd_device(flash_mtd)){
-+            return -ENXIO;
-+        }
-+	} else {
-+		printk(KERN_NOTICE "Using %s partition definition\n",
-+			part_type);
-+		return add_mtd_partitions(flash_mtd, parts, nb_parts);
-+	}
-+	return 0;
-+}
-+ 
-+int __init omap_toto_mtd_init(void)  
-+{
-+	int status;
-+
-+ 	if (status = init_flash()) {
-+		printk(KERN_ERR "OMAP Toto Flash: unable to init map for toto flash\n");
-+	}
-+    return status;
-+}
-+
-+static void  __exit omap_toto_mtd_cleanup(void)  
-+{
-+	if (flash_mtd) {
-+		del_mtd_partitions(flash_mtd);
-+		map_destroy(flash_mtd);
-+		if (parsed_parts)
-+			kfree(parsed_parts);
-+	}
-+}
-+
-+module_init(omap_toto_mtd_init);
-+module_exit(omap_toto_mtd_cleanup);
-+
-+MODULE_AUTHOR("Jian Zhang");
-+MODULE_DESCRIPTION("OMAP Toto board map driver");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.5/drivers/mtd/maps/pb1550-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/pb1550-flash.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/pb1550-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,204 @@
-+/*
-+ * Flash memory access on Alchemy Pb1550 board
-+ * 
-+ * $Id: pb1550-flash.c,v 1.5 2004/09/16 23:27:13 gleixner Exp $
-+ *
-+ * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c:
-+ * (C) 2003 Pete Popov <ppopov@pacbell.net>
-+ * 
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/au1000.h>
-+#include <asm/pb1550.h>
-+
-+#ifdef 	DEBUG_RW
-+#define	DBG(x...)	printk(x)
-+#else
-+#define	DBG(x...)	
-+#endif
-+
-+static unsigned long window_addr;
-+static unsigned long window_size;
-+
-+
-+static struct map_info pb1550_map = {
-+	.name =	"Pb1550 flash",
-+};
-+
-+static unsigned char flash_bankwidth = 4;
-+
-+/* 
-+ * Support only 64MB NOR Flash parts
-+ */
-+
-+#ifdef PB1550_BOTH_BANKS
-+/* both banks will be used. Combine the first bank and the first 
-+ * part of the second bank together into a single jffs/jffs2
-+ * partition.
-+ */
-+static struct mtd_partition pb1550_partitions[] = {
-+	/* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-+	 * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-+	 * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-+	 */
-+        {
-+                .name = "User FS",
-+                .size =   (0x1FC00000 - 0x18000000),
-+                .offset = 0x0000000
-+        },{
-+                .name = "yamon",
-+                .size = 0x0100000,
-+		.offset = MTDPART_OFS_APPEND,
-+                .mask_flags = MTD_WRITEABLE
-+        },{
-+                .name = "raw kernel",
-+		.size = (0x300000 - 0x40000), /* last 256KB is yamon env */
-+		.offset = MTDPART_OFS_APPEND,
-+        }
-+};
-+#elif defined(PB1550_BOOT_ONLY)
-+static struct mtd_partition pb1550_partitions[] = {
-+	/* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-+	 * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
-+	 */
-+        {
-+                .name = "User FS",
-+                .size =   0x03c00000,
-+                .offset = 0x0000000
-+        },{
-+                .name = "yamon",
-+                .size = 0x0100000,
-+		.offset = MTDPART_OFS_APPEND,
-+                .mask_flags = MTD_WRITEABLE
-+        },{
-+                .name = "raw kernel",
-+		.size = (0x300000-0x40000), /* last 256KB is yamon env */
-+		.offset = MTDPART_OFS_APPEND,
-+        }
-+};
-+#elif defined(PB1550_USER_ONLY)
-+static struct mtd_partition pb1550_partitions[] = {
-+	/* assume boot[2:0]:swap is '0000' or '1000', which translates to:
-+	 * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
-+	 */
-+        {
-+                .name = "User FS",
-+                .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
-+                .offset = 0x0000000
-+        },{
-+                .name = "raw kernel",
-+		.size = MTDPART_SIZ_FULL,
-+		.offset = MTDPART_OFS_APPEND,
-+        }
-+};
-+#else
-+#error MTD_PB1550 define combo error /* should never happen */
-+#endif
-+
-+#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-+
-+static struct mtd_info *mymtd;
-+
-+/*
-+ * Probe the flash density and setup window address and size
-+ * based on user CONFIG options. There are times when we don't
-+ * want the MTD driver to be probing the boot or user flash,
-+ * so having the option to enable only one bank is important.
-+ */
-+int setup_flash_params(void)
-+{
-+	u16 boot_swapboot;
-+	boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | 
-+		((bcsr->status >> 6)  & 0x1);
-+	printk("Pb1550 MTD: boot:swap %d\n", boot_swapboot);
-+
-+	switch (boot_swapboot) {
-+		case 0: /* 512Mbit devices, both enabled */
-+		case 1: 
-+		case 8:
-+		case 9: 
-+#if defined(PB1550_BOTH_BANKS)
-+			window_addr = 0x18000000;
-+			window_size = 0x8000000; 
-+#elif defined(PB1550_BOOT_ONLY)
-+			window_addr = 0x1C000000;
-+			window_size = 0x4000000; 
-+#else /* USER ONLY */
-+			window_addr = 0x1E000000;
-+			window_size = 0x4000000; 
-+#endif
-+			break;
-+		case 0xC:
-+		case 0xD:
-+		case 0xE:
-+		case 0xF: 
-+			/* 64 MB Boot NOR Flash is disabled */
-+			/* and the start address is moved to 0x0C00000 */
-+			window_addr = 0x0C000000;
-+			window_size = 0x4000000; 
-+		default:
-+			printk("Pb1550 MTD: unsupported boot:swap setting\n");
-+			return 1;
-+	}
-+	return 0;
-+}
-+
-+int __init pb1550_mtd_init(void)
-+{
-+	struct mtd_partition *parts;
-+	int nb_parts = 0;
-+	
-+	/* Default flash bankwidth */
-+	pb1550_map.bankwidth = flash_bankwidth;
-+
-+	if (setup_flash_params()) 
-+		return -ENXIO;
-+
-+	/*
-+	 * Static partition definition selection
-+	 */
-+	parts = pb1550_partitions;
-+	nb_parts = NB_OF(pb1550_partitions);
-+	pb1550_map.size = window_size;
-+
-+	/*
-+	 * Now let's probe for the actual flash.  Do it here since
-+	 * specific machine settings might have been set above.
-+	 */
-+	printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n", 
-+			pb1550_map.bankwidth*8);
-+	pb1550_map.virt = 
-+		(void __iomem *)ioremap(window_addr, window_size);
-+	mymtd = do_map_probe("cfi_probe", &pb1550_map);
-+	if (!mymtd) return -ENXIO;
-+	mymtd->owner = THIS_MODULE;
-+
-+	add_mtd_partitions(mymtd, parts, nb_parts);
-+	return 0;
-+}
-+
-+static void __exit pb1550_mtd_cleanup(void)
-+{
-+	if (mymtd) {
-+		del_mtd_partitions(mymtd);
-+		map_destroy(mymtd);
-+	}
-+}
-+
-+module_init(pb1550_mtd_init);
-+module_exit(pb1550_mtd_cleanup);
-+
-+MODULE_AUTHOR("Embedded Edge, LLC");
-+MODULE_DESCRIPTION("Pb1550 mtd map driver");
-+MODULE_LICENSE("GPL");
-Index: linux-2.6.5/drivers/mtd/maps/pb1xxx-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/pb1xxx-flash.c	2004-04-03 22:38:24.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/pb1xxx-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.12 2004/09/16 23:27:13 gleixner 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>
-@@ -26,102 +26,87 @@
- #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 = "yamon",
--                .size = 0x0100000,
--                .offset = 0x3c00000,
--                .mask_flags = MTD_WRITEABLE
--        },{
--                .name = "raw kernel",
--                .size = 0x02c0000,
--                .offset = 0x3d00000
-+                .name         =   "User FS",
-+                .size         =   0x3c00000,
-+                .offset       =   0x0000000
-+        },{
-+                .name         =   "yamon",
-+                .size         =   0x0100000,
-+                .offset       =   0x3c00000,
-+                .mask_flags   =   MTD_WRITEABLE
-+        },{
-+                .name         =   "raw kernel",
-+                .size         =   0x02c0000,
-+                .offset       =   0x3d00000
-         }
- };
- #elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
--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 = "yamon",
--                .size = 0x0100000,
--                .offset = 0x1c00000,
--                .mask_flags = MTD_WRITEABLE
--        },{
--                .name = "raw kernel",
--                .size = 0x02c0000,
--                .offset = 0x1d00000
-+                .name         =   "User FS",
-+                .size         =   0x1c00000,
-+                .offset       =   0x0000000
-+        },{
-+                .name         =   "yamon",
-+                .size         =   0x0100000,
-+                .offset       =   0x1c00000,
-+                .mask_flags   =   MTD_WRITEABLE
-+        },{
-+                .name         =   "raw kernel",
-+                .size         =   0x02c0000,
-+                .offset       =   0x1d00000
-         }
- };
- #elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
--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 = "raw kernel",
--                .size = 0x0200000,
--                .offset = 0x1e00000,
-+                .name         =   "User FS",
-+                .size         =    0x1e00000,
-+                .offset       =    0x0000000
-+        },{
-+                .name         =    "raw kernel",
-+                .size         =    0x0200000,
-+                .offset       =    0x1e00000,
-         }
- };
- #else
-@@ -131,8 +116,20 @@
- #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 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);
--
--	simple_map_init(&pb1xxx_map);
--
--	mymtd = do_map_probe("cfi_probe", &pb1xxx_map);
--	if (!mymtd) {
--		iounmap(pb1xxx_map.virt);
--		return -ENXIO;
--	}
--	mymtd->owner = THIS_MODULE;
-+			BUSWIDTH*8);
-+	pb1xxx_mtd_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+
-+	simple_map_init(&pb1xxx_mtd_map);
-+
-+	pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map);
-+	if (!pb1xxx_mtd) return -ENXIO;
-+	pb1xxx_mtd->owner = THIS_MODULE;
- 
--	add_mtd_partitions(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: linux-2.6.5/drivers/mtd/maps/pci.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/pci.c	2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/pci.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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 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 @@
- {
- 	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 @@
- 	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 @@
-  * 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: linux-2.6.5/drivers/mtd/maps/pcmciamtd.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/pcmciamtd.c	2004-04-03 22:36:19.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/pcmciamtd.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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 @@
- 
- 
- #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 @@
- /* 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 @@
- 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 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_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 @@
- 
- #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 @@
- 		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 @@
- 	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 @@
- 	}
- 
- 	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 @@
- 	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 @@
- 	   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 @@
- 		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 @@
- {
- 	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: linux-2.6.5/drivers/mtd/maps/physmap.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/physmap.c	2004-04-03 22:37:25.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/physmap.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,7 +1,12 @@
- /*
-- * $Id: physmap.c,v 1.29 2003/05/29 09:24:10 dwmw2 Exp $
-+ * $Id: physmap.c,v 1.35 2004/09/16 23:27:13 gleixner 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>
-@@ -15,62 +20,38 @@
- #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,
-+	.name = "phys_mapped_flash",
-+	.phys = CONFIG_MTD_PHYSMAP_START,
-+	.size = CONFIG_MTD_PHYSMAP_LEN,
-+	.bankwidth = CONFIG_MTD_PHYSMAP_BANKWIDTH,
- };
- 
- #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", 0 };
-+	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 = (void __iomem *)ioremap(physmap_map.phys, physmap_map.size);
- 
- 	if (!physmap_map.virt) {
- 		printk("Failed to ioremap\n");
-@@ -79,7 +60,7 @@
- 
- 	simple_map_init(&physmap_map);
- 
--	mymtd = 0;
-+	mymtd = NULL;
- 	type = rom_probe_types;
- 	for(; !mymtd && *type; type++) {
- 		mymtd = do_map_probe(*type, &physmap_map);
-@@ -97,11 +78,11 @@
- 			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 +102,7 @@
- 	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: linux-2.6.5/drivers/mtd/maps/pnc2000.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/pnc2000.c	2004-04-03 22:37:06.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/pnc2000.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.16 2004/09/16 23:27:13 gleixner Exp $
-  */
- 
- #include <linux/module.h>
-@@ -29,9 +29,9 @@
- struct map_info pnc_map = {
- 	.name = "PNC-2000",
- 	.size = WINDOW_SIZE,
--	.buswidth = 4,
-+	.bankwidth = 4,
- 	.phys = 0xFFFFFFFF,
--	.virt = WINDOW_ADDR,
-+	.virt = (void __iomem *)WINDOW_ADDR,
- };
- 
- 
-Index: linux-2.6.5/drivers/mtd/maps/redwood.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/redwood.c	2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/redwood.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,14 +1,13 @@
- /*
-- * $Id: redwood.c,v 1.6 2003/05/21 12:45:19 dwmw2 Exp $
-+ * $Id: redwood.c,v 1.9 2004/09/16 23:27:13 gleixner 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[] = {
- 	{
--		.name = "Redwood kernel",
-+		.name = "Redwood filesystem",
- 		.offset = RW_PART0_OF,
- 		.size = RW_PART0_SZ
- 	},
-@@ -100,7 +99,7 @@
- 		.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 @@
- struct map_info redwood_flash_map = {
- 	.name = "IBM Redwood",
- 	.size = WINDOW_SIZE,
--	.buswidth = 2,
-+	.bankwidth = 2,
- 	.phys = WINDOW_ADDR,
- };
- 
-@@ -133,7 +132,7 @@
- 			WINDOW_SIZE, WINDOW_ADDR);
- 
- 	redwood_flash_map.virt =
--		(unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
-+		(void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE);
- 
- 	if (!redwood_flash_map.virt) {
- 		printk("init_redwood_flash: failed to ioremap\n");
-@@ -167,5 +166,5 @@
- 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: linux-2.6.5/drivers/mtd/maps/rpxlite.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/rpxlite.c	2004-04-03 22:38:23.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/rpxlite.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: rpxlite.c,v 1.19 2003/05/21 12:45:19 dwmw2 Exp $
-+ * $Id: rpxlite.c,v 1.21 2004/09/16 23:27:13 gleixner Exp $
-  *
-  * Handle mapping of the flash on the RPX Lite and CLLF boards
-  */
-@@ -21,14 +21,14 @@
- static struct map_info rpxlite_map = {
- 	.name = "RPX",
- 	.size = WINDOW_SIZE,
--	.buswidth = 4,
-+	.bankwidth = 4,
- 	.phys = WINDOW_ADDR,
- };
- 
- int __init init_rpxlite(void)
- {
- 	printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR);
--	rpxlite_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
-+	rpxlite_map.virt = (void __iomem *)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4);
- 
- 	if (!rpxlite_map.virt) {
- 		printk("Failed to ioremap\n");
-Index: linux-2.6.5/drivers/mtd/maps/sa1100-flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/sa1100-flash.c	2004-04-03 22:36:51.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/sa1100-flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.41 2004/09/16 23:27:13 gleixner Exp $
-  */
- 
- #include <linux/config.h>
-@@ -496,6 +496,32 @@
- };
- #endif
- 
-+#ifdef CONFIG_SA1100_JORNADA56X
-+static struct mtd_partition jornada56x_partitions[] = {
-+	{
-+		.name		= "bootldr",
-+		.size		= 0x00040000,
-+		.offset		= 0,
-+		.mask_flags	= MTD_WRITEABLE,
-+	}, {
-+		.name		= "rootfs",
-+		.size		= MTDPART_SIZ_FULL,
-+		.offset		= MTDPART_OFS_APPEND,
-+	}
-+};
-+
-+static void jornada56x_set_vpp(struct map_info *map, int vpp)
-+{
-+	if (vpp)
-+		GPSR = GPIO_GPIO26;
-+	else
-+		GPCR = GPIO_GPIO26;
-+	GPDR |= GPIO_GPIO26;
-+}
-+#else
-+#define jornada56x_set_vpp NULL
-+#endif
-+
- #ifdef CONFIG_SA1100_JORNADA720
- static struct mtd_partition jornada720_partitions[] = {
- 	{
-@@ -822,6 +848,12 @@
- 		nb_parts     = ARRAY_SIZE(huw_webpanel_partitions);
- 	}
- #endif
-+#ifdef CONFIG_SA1100_JORNADA56X
-+	if (machine_is_jornada56x()) {
-+		*parts       = jornada56x_partitions;
-+		nb_parts     = ARRAY_SIZE(jornada56x_partitions);
-+	}
-+#endif
- #ifdef CONFIG_SA1100_JORNADA720
- 	if (machine_is_jornada720()) {
- 		*parts       = jornada720_partitions;
-@@ -932,10 +964,10 @@
- 			break;
- 		}
- 
--		sa[i].map->virt = (unsigned long)sa[i].vbase;
-+		sa[i].map->virt = (void __iomem *)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,10 +1098,10 @@
- 		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);
-+	sa1100_probe_map.virt = (void __iomem *)ioremap(phys, SZ_1M);
- 	if (sa1100_probe_map.virt == 0)
- 		goto fail;
- 	simple_map_init(&sa1100_probe_map);
-@@ -1160,7 +1192,7 @@
- 		info[0].size = SZ_16M;
- 		nr = 1;
- 	}
--	if (machine_is_h3xxx()) {
-+	if (machine_is_ipaq()) {
- 		info[0].set_vpp = h3xxx_set_vpp;
- 		info[0].base = SA1100_CS0_PHYS;
- 		info[0].size = SZ_32M;
-@@ -1176,6 +1208,12 @@
- 		info[0].size = SZ_32M;
- 		nr = 1;
- 	}
-+	if (machine_is_jornada56x()) {
-+		info[0].set_vpp = jornada56x_set_vpp;
-+		info[0].base = SA1100_CS0_PHYS;
-+		info[0].size = SZ_32M;
-+		nr = 1;
-+	}
- 	if (machine_is_jornada720()) {
- 		info[0].set_vpp = jornada720_set_vpp;
- 		info[0].base = SA1100_CS0_PHYS;
-@@ -1253,7 +1291,7 @@
- 		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: linux-2.6.5/drivers/mtd/maps/sbc8240.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/sbc8240.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/sbc8240.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,247 @@
-+/*
-+ * Handle mapping of the flash memory access routines on the SBC8240 board.
-+ *
-+ * Carolyn Smith, Tektronix, Inc.
-+ *
-+ * This code is GPLed
-+ *
-+ * $Id: sbc8240.c,v 1.4 2004/07/12 22:38:29 dwmw2 Exp $
-+ *
-+ */
-+
-+/*
-+ * The SBC8240 has 2 flash banks.
-+ * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors.
-+ * It contains the U-Boot code (7 sectors) and the environment (1 sector).
-+ * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector,
-+ * 2 x 8 KiB sectors, 1 x 16 KiB sectors.
-+ * Both parts are JEDEC compatible.
-+ */
-+
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/io.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/cfi.h>
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+#include <linux/mtd/partitions.h>
-+#endif
-+
-+#define	DEBUG
-+
-+#ifdef	DEBUG
-+# define debugk(fmt,args...)	printk(fmt ,##args)
-+#else
-+# define debugk(fmt,args...)
-+#endif
-+
-+
-+#define WINDOW_ADDR0	0xFFF00000		/* 512 KiB */
-+#define WINDOW_SIZE0	0x00080000
-+#define BUSWIDTH0	1
-+
-+#define WINDOW_ADDR1	0xFF000000		/* 4 MiB */
-+#define WINDOW_SIZE1	0x00400000
-+#define BUSWIDTH1	8
-+
-+#define MSG_PREFIX "sbc8240:"	/* prefix for our printk()'s */
-+#define MTDID	   "sbc8240-%d"	/* for mtdparts= partitioning */
-+
-+
-+static struct map_info sbc8240_map[2] = {
-+	{
-+		.name           = "sbc8240 Flash Bank #0",
-+		.size           = WINDOW_SIZE0,
-+		.bankwidth       = BUSWIDTH0,
-+	},
-+	{
-+		.name           = "sbc8240 Flash Bank #1",
-+		.size           = WINDOW_SIZE1,
-+		.bankwidth       = BUSWIDTH1,
-+	}
-+};
-+
-+#define NUM_FLASH_BANKS	(sizeof(sbc8240_map) / sizeof(struct map_info))
-+
-+/*
-+ * The following defines the partition layout of SBC8240 boards.
-+ *
-+ * See include/linux/mtd/partitions.h for definition of the
-+ * mtd_partition structure.
-+ *
-+ * The *_max_flash_size is the maximum possible mapped flash size
-+ * which is not necessarily the actual flash size. It must correspond
-+ * to the value specified in the mapping definition defined by the
-+ * "struct map_desc *_io_desc" for the corresponding machine.
-+ */
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+
-+static struct mtd_partition sbc8240_uboot_partitions [] = {
-+	/* Bank 0 */
-+	{
-+		.name =	"U-boot",			/* U-Boot Firmware	*/
-+		.offset =	0,
-+		.size =	0x00070000,			/*  7 x 64 KiB sectors 	*/
-+		.mask_flags = MTD_WRITEABLE,		/*  force read-only	*/
-+	},
-+	{
-+		.name =	"environment",			/* U-Boot environment	*/
-+		.offset =	0x00070000,
-+		.size =	0x00010000,			/*  1 x 64 KiB sector	*/
-+	},
-+};
-+
-+static struct mtd_partition sbc8240_fs_partitions [] = {
-+	{
-+		.name =	"jffs",				/* JFFS  filesystem	*/
-+		.offset =	0,
-+		.size =	0x003C0000,			/*  4 * 15 * 64KiB	*/
-+	},
-+	{
-+		.name =	"tmp32",
-+		.offset =	0x003C0000,
-+		.size =	0x00020000,			/*  4 * 32KiB		*/
-+	},
-+	{
-+		.name =	"tmp8a",
-+		.offset =	0x003E0000,
-+		.size =	0x00008000,			/*  4 * 8KiB		*/
-+	},
-+	{
-+		.name =	"tmp8b",
-+		.offset =	0x003E8000,
-+		.size =	0x00008000,			/*  4 * 8KiB		*/
-+	},
-+	{
-+		.name =	"tmp16",
-+		.offset =	0x003F0000,
-+		.size =	0x00010000,			/*  4 * 16KiB		*/
-+	}
-+};
-+
-+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
-+
-+/* trivial struct to describe partition information */
-+struct mtd_part_def
-+{
-+	int nums;
-+	unsigned char *type;
-+	struct mtd_partition* mtd_part;
-+};
-+
-+static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS];
-+static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS];
-+
-+
-+#endif	/* CONFIG_MTD_PARTITIONS */
-+
-+
-+int __init init_sbc8240_mtd (void)
-+{
-+	static struct _cjs {
-+		u_long addr;
-+		u_long size;
-+	} pt[NUM_FLASH_BANKS] = {
-+		{
-+			.addr = WINDOW_ADDR0,
-+			.size = WINDOW_SIZE0
-+		},
-+		{
-+			.addr = WINDOW_ADDR1,
-+			.size = WINDOW_SIZE1
-+		},
-+	};
-+
-+	int devicesfound = 0;
-+	int i;
-+
-+	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+		printk (KERN_NOTICE MSG_PREFIX
-+			"Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr);
-+
-+		sbc8240_map[i].map_priv_1 =
-+			(unsigned long) ioremap (pt[i].addr, pt[i].size);
-+		if (!sbc8240_map[i].map_priv_1) {
-+			printk (MSG_PREFIX "failed to ioremap\n");
-+			return -EIO;
-+		}
-+		simple_map_init(&sbc8240_mtd[i]);
-+
-+		sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]);
-+
-+		if (sbc8240_mtd[i]) {
-+			sbc8240_mtd[i]->module = THIS_MODULE;
-+			devicesfound++;
-+		}
-+	}
-+
-+	if (!devicesfound) {
-+		printk(KERN_NOTICE MSG_PREFIX
-+		       "No suppported flash chips found!\n");
-+		return -ENXIO;
-+	}
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+	sbc8240_part_banks[0].mtd_part   = sbc8240_uboot_partitions;
-+	sbc8240_part_banks[0].type       = "static image";
-+	sbc8240_part_banks[0].nums       = NB_OF(sbc8240_uboot_partitions);
-+	sbc8240_part_banks[1].mtd_part   = sbc8240_fs_partitions;
-+	sbc8240_part_banks[1].type       = "static file system";
-+	sbc8240_part_banks[1].nums       = NB_OF(sbc8240_fs_partitions);
-+
-+	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+
-+		if (!sbc8240_mtd[i]) continue;
-+		if (sbc8240_part_banks[i].nums == 0) {
-+			printk (KERN_NOTICE MSG_PREFIX
-+				"No partition info available, registering whole device\n");
-+			add_mtd_device(sbc8240_mtd[i]);
-+		} else {
-+			printk (KERN_NOTICE MSG_PREFIX
-+				"Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name);
-+			add_mtd_partitions (sbc8240_mtd[i], 
-+					    sbc8240_part_banks[i].mtd_part,
-+					    sbc8240_part_banks[i].nums);
-+		}
-+	}
-+#else
-+	printk(KERN_NOTICE MSG_PREFIX
-+	       "Registering %d flash banks at once\n", devicesfound);
-+
-+	for (i = 0; i < devicesfound; i++) {
-+		add_mtd_device(sbc8240_mtd[i]);
-+	}
-+#endif	/* CONFIG_MTD_PARTITIONS */
-+
-+	return devicesfound == 0 ? -ENXIO : 0;
-+}
-+
-+static void __exit cleanup_sbc8240_mtd (void)
-+{
-+	int i;
-+
-+	for (i = 0; i < NUM_FLASH_BANKS; i++) {
-+		if (sbc8240_mtd[i]) {
-+			del_mtd_device (sbc8240_mtd[i]);
-+			map_destroy (sbc8240_mtd[i]);
-+		}
-+		if (sbc8240_map[i].map_priv_1) {
-+			iounmap ((void *) sbc8240_map[i].map_priv_1);
-+			sbc8240_map[i].map_priv_1 = 0;
-+		}
-+	}
-+}
-+
-+module_init (init_sbc8240_mtd);
-+module_exit (cleanup_sbc8240_mtd);
-+
-+MODULE_LICENSE ("GPL");
-+MODULE_AUTHOR ("Carolyn Smith <carolyn.smith@tektronix.com>");
-+MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards");
-+
-Index: linux-2.6.5/drivers/mtd/maps/sbc_gxx.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/sbc_gxx.c	2004-04-03 22:37:23.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/sbc_gxx.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.30 2004/09/16 23:27:14 gleixner Exp $
- 
- The SBC-MediaGX / SBC-GXx has up to 16 MiB of 
- Intel StrataFlash (28F320/28F640) in x8 mode.  
-@@ -84,7 +84,7 @@
- // Globals
- 
- static volatile int page_in_window = -1; // Current page in window.
--static unsigned long iomapadr;
-+static void __iomem *iomapadr;
- static spinlock_t sbc_gxx_spin = SPIN_LOCK_UNLOCKED;
- 
- /* partition_info gives details on the logical partitions that the split the 
-@@ -114,32 +114,12 @@
- }
- 
- 
--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_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 @@
- 	.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
- };
- 
-@@ -235,7 +195,7 @@
- 
- int __init init_sbc_gxx(void)
- {
--  	iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
-+  	iomapadr = (void __iomem *)ioremap(WINDOW_START, WINDOW_LENGTH);
- 	if (!iomapadr) {
- 		printk( KERN_ERR"%s: failed to ioremap memory region\n",
- 			sbc_gxx_map.name );
-Index: linux-2.6.5/drivers/mtd/maps/sc520cdp.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/sc520cdp.c	2004-04-03 22:38:17.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/sc520cdp.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.17 2004/09/16 23:27:14 gleixner Exp $
-  *
-  *
-  * The SC520CDP is an evaluation board for the Elan SC520 processor available
-@@ -90,19 +90,19 @@
- 	{
- 		.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
- 	},
- };
-@@ -241,7 +241,7 @@
- 		printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n",
- 		       sc520cdp_map[i].size, sc520cdp_map[i].phys);
- 
--		sc520cdp_map[i].virt = (unsigned long)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size);
-+		sc520cdp_map[i].virt = (void __iomem *)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size);
- 
- 		if (!sc520cdp_map[i].virt) {
- 			printk("Failed to ioremap_nocache\n");
-Index: linux-2.6.5/drivers/mtd/maps/scb2_flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/scb2_flash.c	2004-04-03 22:37:23.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/scb2_flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.9 2004/09/16 23:27:14 gleixner Exp $
-  * Copyright (C) 2002 Sun Microsystems, Inc.
-  * Tim Hockin <thockin@sun.com>
-  *
-@@ -67,7 +67,7 @@
- struct map_info scb2_map = {
- 	.name =      "SCB2 BIOS Flash",
- 	.size =      0,
--	.buswidth =  1,
-+	.bankwidth =  1,
- };
- static int region_fail;
- 
-@@ -163,7 +163,7 @@
- 	}
- 
- 	scb2_map.phys = SCB2_ADDR;
--	scb2_map.virt = (unsigned long)scb2_ioaddr;
-+	scb2_map.virt = (void __iomem *)scb2_ioaddr;
- 	scb2_map.size = SCB2_WINDOW;
- 
- 	simple_map_init(&scb2_map);
-Index: linux-2.6.5/drivers/mtd/maps/scx200_docflash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/scx200_docflash.c	2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/scx200_docflash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.7 2004/09/16 23:27:14 gleixner Exp $ 
- 
-    National Semiconductor SCx200 flash mapped with DOCCS
- */
-@@ -173,14 +173,14 @@
- 
- 	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);
- 
- 	scx200_docflash_map.phys = docmem.start;
--	scx200_docflash_map.virt = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
-+	scx200_docflash_map.virt = (void __iomem *)ioremap(docmem.start, scx200_docflash_map.size);
- 	if (!scx200_docflash_map.virt) {
- 		printk(KERN_ERR NAME ": failed to ioremap the flash\n");
- 		release_resource(&docmem);
-Index: linux-2.6.5/drivers/mtd/maps/solutionengine.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/solutionengine.c	2004-04-03 22:38:18.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/solutionengine.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: solutionengine.c,v 1.10 2003/05/21 12:45:20 dwmw2 Exp $
-+ * $Id: solutionengine.c,v 1.14 2004/09/16 23:27:14 gleixner 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 @@
- 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 };
-@@ -62,9 +62,9 @@
- 
- 	/* First probe at offset 0 */
- 	soleng_flash_map.phys = 0;
--	soleng_flash_map.virt = P2SEGADDR(0);
-+	soleng_flash_map.virt = (void __iomem *)P2SEGADDR(0);
- 	soleng_eprom_map.phys = 0x01000000;
--	soleng_eprom_map.virt = P1SEGADDR(0x01000000);
-+	soleng_eprom_map.virt = (void __iomem *)P1SEGADDR(0x01000000);
- 	simple_map_init(&soleng_eprom_map);
- 	simple_map_init(&soleng_flash_map);
- 	
-Index: linux-2.6.5/drivers/mtd/maps/sun_uflash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/sun_uflash.c	2004-04-03 22:37:36.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/sun_uflash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.10 2004/09/16 23:27:14 gleixner Exp $
-  *
-  * sun_uflash - Driver implementation for user-programmable flash
-  * present on many Sun Microsystems SME boardsets.
-@@ -51,7 +51,7 @@
- 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)
-@@ -97,7 +97,7 @@
- 	}
- 	pdev->map.phys = edev->resource[0].start;
- 	pdev->map.virt = 
--		(unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size);
-+		(void __iomem *)ioremap_nocache(edev->resource[0].start, pdev->map.size);
- 	if(0 == pdev->map.virt) {
- 		printk("%s: failed to map device\n", __FUNCTION__);
- 		kfree(pdev->name);
-Index: linux-2.6.5/drivers/mtd/maps/tqm8xxl.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/tqm8xxl.c	2004-04-03 22:36:26.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/tqm8xxl.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.12 2004/09/16 23:27:14 gleixner Exp $
-  *
-  * based on rpxlite.c
-  *
-@@ -105,7 +105,7 @@
- 	  .name = "jffs",
- 	  .offset = 0x00200000,
- 	  .size = 0x00200000,
--	  .//size = MTDPART_SIZ_FULL,
-+	  //.size = MTDPART_SIZ_FULL,
- 	}
- };
- #endif
-@@ -151,11 +151,11 @@
- 		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]);
- 
--		map_banks[idx]->virt = start_scan_addr;
-+		map_banks[idx]->virt = (void __iomem *)start_scan_addr;
- 		map_banks[idx]->phys = flash_addr;
- 		/* FIXME: This looks utterly bogus, but I'm trying to
- 		   preserve the behaviour of the original (shown here)...
-Index: linux-2.6.5/drivers/mtd/maps/tsunami_flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/tsunami_flash.c	2004-04-03 22:38:16.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/tsunami_flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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>
-@@ -15,14 +15,16 @@
- #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 @@
- 	.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 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: linux-2.6.5/drivers/mtd/maps/uclinux.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/uclinux.c	2004-04-03 22:38:16.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/uclinux.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.8 2004/09/16 23:27:14 gleixner Exp $
-  */
- 
- /****************************************************************************/
-@@ -17,6 +17,7 @@
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/major.h>
-+#include <linux/root_dev.h>
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/map.h>
- #include <linux/mtd/partitions.h>
-@@ -63,12 +64,12 @@
- 	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);
- 
--	mapp->virt = (unsigned long)
-+	mapp->virt = (void __iomem *)
- 		ioremap_nocache(mapp->phys, mapp->size);
- 
- 	if (mapp->virt == 0) {
-Index: linux-2.6.5/drivers/mtd/maps/vmax301.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/vmax301.c	2004-04-03 22:36:54.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/vmax301.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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 @@
- 		__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_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 @@
- 		.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 @@
- 		.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: linux-2.6.5/drivers/mtd/maps/wr_sbc82xx_flash.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/maps/wr_sbc82xx_flash.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/maps/wr_sbc82xx_flash.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,181 @@
-+/*
-+ * $Id: wr_sbc82xx_flash.c,v 1.6 2004/09/16 23:27:14 gleixner Exp $
-+ *
-+ * Map for flash chips on Wind River PowerQUICC II SBC82xx board.
-+ *
-+ * Copyright (C) 2004 Red Hat, Inc.
-+ *
-+ * Author: David Woodhouse <dwmw2@infradead.org>
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <asm/io.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/config.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/immap_cpm2.h>
-+
-+static struct mtd_info *sbcmtd[3];
-+static struct mtd_partition *sbcmtd_parts[3];
-+
-+struct map_info sbc82xx_flash_map[3] = {
-+	{.name = "Boot flash"},
-+	{.name = "Alternate boot flash"},
-+	{.name = "User flash"}
-+};
-+
-+static struct mtd_partition smallflash_parts[] = {
-+	{
-+		.name =		"space",
-+		.size =		0x100000,
-+		.offset =	0,
-+	}, {
-+		.name =		"bootloader",
-+		.size =		MTDPART_SIZ_FULL,
-+		.offset =	MTDPART_OFS_APPEND,
-+	}
-+};
-+
-+static struct mtd_partition bigflash_parts[] = {
-+	{
-+		.name =		"bootloader",
-+		.size =		0x00100000,
-+		.offset =	0,
-+	}, {
-+		.name =		"file system",
-+		.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;
-+	int bigflash;
-+	int i;
-+
-+#ifdef CONFIG_SBC8560
-+	mc = ioremap(0xff700000 + 0x5000, sizeof(memctl_cpm2_t));
-+#else
-+	mc = &cpm2_immr->im_memctl;
-+#endif
-+
-+	bigflash = 1;
-+	if ((mc->memc_br0 & 0x00001800) == 0x00001800)
-+		bigflash = 0;
-+
-+	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);
-+
-+#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]);
-+		if (!sbc82xx_flash_map[i].phys) {
-+			/* We know it can't be at zero. */
-+			printk("): disabled by bootloader.\n");
-+			continue;
-+		}
-+		printk(" at %08lx)\n",  sbc82xx_flash_map[i].phys);
-+
-+		sbc82xx_flash_map[i].virt = (void __iomem *)ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size);
-+
-+		if (!sbc82xx_flash_map[i].virt) {
-+			printk("Failed to ioremap\n");
-+			continue;
-+		}
-+
-+		simple_map_init(&sbc82xx_flash_map[i]);
-+
-+		sbcmtd[i] = do_map_probe("cfi_probe", &sbc82xx_flash_map[i]);
-+
-+		if (!sbcmtd[i])
-+			continue;
-+
-+		sbcmtd[i]->owner = THIS_MODULE;
-+
-+		nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes,
-+						&sbcmtd_parts[i], 0);
-+		if (nr_parts > 0) {
-+			add_mtd_partitions (sbcmtd[i], sbcmtd_parts[i], nr_parts);
-+			continue;
-+		}
-+
-+		/* No partitioning detected. Use default */
-+		if (i == 2) {
-+			add_mtd_device(sbcmtd[i]);
-+		} else if (i == bigflash) {
-+			add_mtd_partitions (sbcmtd[i], bigflash_parts, ARRAY_SIZE(bigflash_parts));
-+		} else {
-+			add_mtd_partitions (sbcmtd[i], smallflash_parts, ARRAY_SIZE(smallflash_parts));
-+		}
-+	}
-+	return 0;
-+}
-+
-+static void __exit cleanup_sbc82xx_flash(void)
-+{
-+	int i;
-+
-+	for (i=0; i<3; i++) {
-+		if (!sbcmtd[i])
-+			continue;
-+
-+		if (i<2 || sbcmtd_parts[i])
-+			del_mtd_partitions(sbcmtd[i]);
-+		else
-+			del_mtd_device(sbcmtd[i]);
-+			
-+		kfree(sbcmtd_parts[i]);
-+		map_destroy(sbcmtd[i]);
-+		
-+		iounmap((void *)sbc82xx_flash_map[i].virt);
-+		sbc82xx_flash_map[i].virt = 0;
-+	}
-+}
-+
-+module_init(init_sbc82xx_flash);
-+module_exit(cleanup_sbc82xx_flash);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_DESCRIPTION("Flash map driver for WindRiver PowerQUICC II");
-Index: linux-2.6.5/drivers/mtd/mtd_blkdevs-24.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/mtd_blkdevs-24.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtd_blkdevs-24.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,692 @@
-+/*
-+ * $Id: mtd_blkdevs-24.c,v 1.16 2004/08/11 15:29:24 dmarlin Exp $
-+ *
-+ * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-+ *
-+ * Interface to Linux 2.4 block layer for MTD 'translation layers'.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/list.h>
-+#include <linux/fs.h>
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/blkdev.h>
-+#include <linux/blk.h>
-+#include <linux/blkpg.h>
-+#include <linux/spinlock.h>
-+#include <linux/hdreg.h>
-+#include <linux/init.h>
-+#include <asm/semaphore.h>
-+#include <asm/uaccess.h>
-+
-+static LIST_HEAD(blktrans_majors);
-+
-+extern struct semaphore mtd_table_mutex;
-+extern struct mtd_info *mtd_table[];
-+
-+struct mtd_blkcore_priv {
-+	devfs_handle_t devfs_dir_handle;
-+	int blksizes[256];
-+	int sizes[256];
-+	struct hd_struct part_table[256];
-+	struct gendisk gd;
-+	spinlock_t devs_lock; /* See comment in _request function */
-+	struct completion thread_dead;
-+	int exiting;
-+	wait_queue_head_t thread_wq;
-+};
-+
-+static inline struct mtd_blktrans_dev *tr_get_dev(struct mtd_blktrans_ops *tr,
-+					   int devnum)
-+{
-+	struct list_head *this;
-+	struct mtd_blktrans_dev *d;
-+
-+	list_for_each(this, &tr->devs) {
-+		d = list_entry(this, struct mtd_blktrans_dev, list);
-+
-+		if (d->devnum == devnum)
-+			return d;
-+	}
-+	return NULL;
-+}
-+
-+static inline struct mtd_blktrans_ops *get_tr(int major)
-+{
-+	struct list_head *this;
-+	struct mtd_blktrans_ops *t;
-+
-+	list_for_each(this, &blktrans_majors) {
-+		t = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+		if (t->major == major)
-+			return t;
-+	}
-+	return NULL;
-+}
-+
-+static int do_blktrans_request(struct mtd_blktrans_ops *tr,
-+			       struct mtd_blktrans_dev *dev,
-+			       struct request *req)
-+{
-+	unsigned long block, nsect;
-+	char *buf;
-+	int minor;
-+
-+	minor = MINOR(req->rq_dev);
-+	block = req->sector;
-+	nsect = req->current_nr_sectors;
-+	buf = req->buffer;
-+
-+	if (block + nsect > tr->blkcore_priv->part_table[minor].nr_sects) {
-+		printk(KERN_WARNING "Access beyond end of device.\n");
-+		return 0;
-+	}
-+	block += tr->blkcore_priv->part_table[minor].start_sect;
-+
-+	switch(req->cmd) {
-+	case READ:
-+		for (; nsect > 0; nsect--, block++, buf += 512)
-+			if (tr->readsect(dev, block, buf))
-+				return 0;
-+		return 1;
-+
-+	case WRITE:
-+		if (!tr->writesect)
-+			return 0;
-+
-+		for (; nsect > 0; nsect--, block++, buf += 512)
-+			if (tr->writesect(dev, block, buf))
-+				return 0;
-+		return 1;
-+
-+	default:
-+		printk(KERN_NOTICE "Unknown request cmd %d\n", req->cmd);
-+		return 0;
-+	}
-+}
-+
-+static int mtd_blktrans_thread(void *arg)
-+{
-+	struct mtd_blktrans_ops *tr = arg;
-+	struct request_queue *rq = BLK_DEFAULT_QUEUE(tr->major);
-+
-+	/* we might get involved when memory gets low, so use PF_MEMALLOC */
-+	current->flags |= PF_MEMALLOC;
-+
-+	snprintf(current->comm, sizeof(current->comm), "%sd", tr->name);
-+
-+	/* daemonize() doesn't do this for us since some kernel threads
-+	   actually want to deal with signals. We can't just call 
-+	   exit_sighand() since that'll cause an oops when we finally
-+	   do exit. */
-+	spin_lock_irq(&current->sigmask_lock);
-+	sigfillset(&current->blocked);
-+	recalc_sigpending();
-+	spin_unlock_irq(&current->sigmask_lock);
-+
-+	daemonize("%sd", tr->name);
-+
-+	while (!tr->blkcore_priv->exiting) {
-+		struct request *req;
-+		struct mtd_blktrans_dev *dev;
-+		int devnum;
-+		int res = 0;
-+		DECLARE_WAITQUEUE(wait, current);
-+
-+		spin_lock_irq(&io_request_lock);
-+
-+		if (list_empty(&rq->queue_head)) {
-+
-+			add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+			set_current_state(TASK_INTERRUPTIBLE);
-+
-+			spin_unlock_irq(&io_request_lock);
-+
-+			schedule();
-+			remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);
-+
-+			continue;
-+		}
-+
-+		req = blkdev_entry_next_request(&rq->queue_head);
-+
-+		devnum = MINOR(req->rq_dev) >> tr->part_bits;
-+
-+		/* The ll_rw_blk code knows not to touch the request
-+		   at the head of the queue */
-+		spin_unlock_irq(&io_request_lock);
-+
-+		/* FIXME: Where can we store the dev, on which
-+		   we already have a refcount anyway? We need to
-+		   lock against concurrent addition/removal of devices,
-+		   but if we use the mtd_table_mutex we deadlock when
-+		   grok_partitions is called from the registration
-+		   callbacks. */
-+		spin_lock(&tr->blkcore_priv->devs_lock);
-+		dev = tr_get_dev(tr, devnum);
-+		spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+		BUG_ON(!dev);
-+
-+		/* Ensure serialisation of requests */
-+		down(&dev->sem);
-+
-+		res = do_blktrans_request(tr, dev, req);
-+		up(&dev->sem);
-+
-+		if (!end_that_request_first(req, res, tr->name)) {
-+			spin_lock_irq(&io_request_lock);
-+			blkdev_dequeue_request(req);
-+			end_that_request_last(req);
-+			spin_unlock_irq(&io_request_lock);
-+		}
-+	}
-+	complete_and_exit(&tr->blkcore_priv->thread_dead, 0);
-+}
-+
-+static void mtd_blktrans_request(struct request_queue *rq)
-+{
-+	struct mtd_blktrans_ops *tr = rq->queuedata;
-+	wake_up(&tr->blkcore_priv->thread_wq);
-+}
-+
-+int blktrans_open(struct inode *i, struct file *f)
-+{
-+	struct mtd_blktrans_ops *tr = NULL;
-+	struct mtd_blktrans_dev *dev = NULL;
-+	int major_nr = MAJOR(i->i_rdev);
-+	int minor_nr = MINOR(i->i_rdev);
-+	int devnum;
-+	int ret = -ENODEV;
-+
-+	if (is_read_only(i->i_rdev) && (f->f_mode & FMODE_WRITE))
-+		return -EROFS;
-+
-+	down(&mtd_table_mutex);
-+
-+	tr = get_tr(major_nr);
-+
-+	if (!tr)
-+		goto out;
-+ 
-+	devnum = minor_nr >> tr->part_bits;
-+
-+	dev = tr_get_dev(tr, devnum);
-+
-+	if (!dev)
-+		goto out;
-+
-+	if (!tr->blkcore_priv->part_table[minor_nr].nr_sects) {
-+		ret = -ENODEV;
-+		goto out;
-+	}
-+
-+	if (!try_inc_mod_count(dev->mtd->owner))
-+		goto out;
-+
-+	if (!try_inc_mod_count(tr->owner))
-+		goto out_tr;
-+
-+	dev->mtd->usecount++;
-+
-+	ret = 0;
-+	if (tr->open && (ret = tr->open(dev))) {
-+		dev->mtd->usecount--;
-+		if (dev->mtd->owner)
-+			__MOD_DEC_USE_COUNT(dev->mtd->owner);
-+	out_tr:
-+		if (tr->owner)
-+			__MOD_DEC_USE_COUNT(tr->owner);
-+	}
-+ out:
-+	up(&mtd_table_mutex);
-+
-+	return ret;
-+}
-+
-+int blktrans_release(struct inode *i, struct file *f)
-+{
-+	struct mtd_blktrans_dev *dev;
-+	struct mtd_blktrans_ops *tr;
-+	int ret = 0;
-+	int devnum;
-+
-+	down(&mtd_table_mutex);
-+
-+	tr = get_tr(MAJOR(i->i_rdev));
-+	if (!tr) {
-+		up(&mtd_table_mutex);
-+		return -ENODEV;
-+	}
-+
-+	devnum = MINOR(i->i_rdev) >> tr->part_bits;
-+	dev = tr_get_dev(tr, devnum);
-+
-+	if (!dev) {
-+		up(&mtd_table_mutex);
-+		return -ENODEV;
-+	}
-+
-+	if (tr->release)
-+		ret = tr->release(dev);
-+
-+	if (!ret) {
-+		dev->mtd->usecount--;
-+		if (dev->mtd->owner)
-+			__MOD_DEC_USE_COUNT(dev->mtd->owner);
-+		if (tr->owner)
-+			__MOD_DEC_USE_COUNT(tr->owner);
-+	}
-+	
-+	up(&mtd_table_mutex);
-+
-+	return ret;
-+}
-+
-+static int mtd_blktrans_rrpart(kdev_t rdev, struct mtd_blktrans_ops *tr,
-+			       struct mtd_blktrans_dev *dev)
-+{
-+	struct gendisk *gd = &(tr->blkcore_priv->gd);
-+	int i;
-+	int minor = MINOR(rdev);
-+
-+	if (minor & ((1<<tr->part_bits)-1) || !tr->part_bits) {
-+		/* BLKRRPART on a partition. Go away. */
-+		return -ENOTTY;
-+	}
-+
-+	if (!capable(CAP_SYS_ADMIN))
-+	    return -EACCES;
-+
-+	/* We are required to prevent simultaneous open() ourselves.
-+	   The core doesn't do that for us. Did I ever mention how
-+	   much the Linux block layer sucks? Sledgehammer approach... */
-+	down(&mtd_table_mutex);
-+
-+	for (i=0; i < (1<<tr->part_bits); i++) {
-+		invalidate_device(MKDEV(tr->major, minor+i), 1);
-+		gd->part[minor + i].start_sect = 0;
-+		gd->part[minor + i].nr_sects = 0;
-+	}
-+
-+	grok_partitions(gd, minor, 1 << tr->part_bits, 
-+			tr->blkcore_priv->sizes[minor]);
-+	up(&mtd_table_mutex);
-+
-+	return 0;
-+}
-+
-+static int blktrans_ioctl(struct inode *inode, struct file *file, 
-+			      unsigned int cmd, unsigned long arg)
-+{
-+	struct mtd_blktrans_dev *dev;
-+	struct mtd_blktrans_ops *tr;
-+	int devnum;
-+
-+	switch(cmd) {
-+	case BLKGETSIZE:
-+        case BLKGETSIZE64:
-+        case BLKBSZSET:
-+        case BLKBSZGET:
-+        case BLKROSET:
-+        case BLKROGET:
-+        case BLKRASET:
-+        case BLKRAGET:
-+        case BLKPG:
-+        case BLKELVGET:
-+        case BLKELVSET:
-+		return blk_ioctl(inode->i_rdev, cmd, arg);
-+	}
-+
-+	down(&mtd_table_mutex);
-+
-+	tr = get_tr(MAJOR(inode->i_rdev));
-+	if (!tr) {
-+		up(&mtd_table_mutex);
-+		return -ENODEV;
-+	}
-+
-+	devnum = MINOR(inode->i_rdev) >> tr->part_bits;
-+	dev = tr_get_dev(tr, devnum);
-+
-+	up(&mtd_table_mutex);
-+
-+	if (!dev)
-+		return -ENODEV;
-+
-+	switch(cmd) {
-+	case BLKRRPART:
-+		return mtd_blktrans_rrpart(inode->i_rdev, tr, dev);
-+		
-+        case BLKFLSBUF:
-+		blk_ioctl(inode->i_rdev, cmd, arg);
-+		if (tr->flush)
-+			return tr->flush(dev);
-+		/* The core code did the work, we had nothing to do. */
-+		return 0;
-+
-+	case HDIO_GETGEO:
-+		if (tr->getgeo) {
-+			struct hd_geometry g;
-+			struct gendisk *gd = &(tr->blkcore_priv->gd);
-+			int ret;
-+
-+			memset(&g, 0, sizeof(g));
-+			ret = tr->getgeo(dev, &g);
-+			if (ret)
-+				return ret;
-+
-+			g.start = gd->part[MINOR(inode->i_rdev)].start_sect;
-+			if (copy_to_user((void *)arg, &g, sizeof(g)))
-+				return -EFAULT;
-+			return 0;
-+		} /* else */
-+	default:
-+		return -ENOTTY;
-+	}
-+}
-+
-+struct block_device_operations mtd_blktrans_ops = {
-+	.owner		= THIS_MODULE,
-+	.open		= blktrans_open,
-+	.release	= blktrans_release,
-+	.ioctl		= blktrans_ioctl,
-+};
-+
-+int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
-+{
-+	struct mtd_blktrans_ops *tr = new->tr;
-+	struct list_head *this;
-+	int last_devnum = -1;
-+	int i;
-+
-+	if (!down_trylock(&mtd_table_mutex)) {
-+		up(&mtd_table_mutex);
-+		BUG();
-+	}
-+
-+	spin_lock(&tr->blkcore_priv->devs_lock);
-+
-+	list_for_each(this, &tr->devs) {
-+		struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list);
-+		if (new->devnum == -1) {
-+			/* Use first free number */
-+			if (d->devnum != last_devnum+1) {
-+				/* Found a free devnum. Plug it in here */
-+				new->devnum = last_devnum+1;
-+				list_add_tail(&new->list, &d->list);
-+				goto added;
-+			}
-+		} else if (d->devnum == new->devnum) {
-+			/* Required number taken */
-+			spin_unlock(&tr->blkcore_priv->devs_lock);
-+			return -EBUSY;
-+		} else if (d->devnum > new->devnum) {
-+			/* Required number was free */
-+			list_add_tail(&new->list, &d->list);
-+			goto added;
-+		} 
-+		last_devnum = d->devnum;
-+	}
-+	if (new->devnum == -1)
-+		new->devnum = last_devnum+1;
-+
-+	if ((new->devnum << tr->part_bits) > 256) {
-+		spin_unlock(&tr->blkcore_priv->devs_lock);
-+		return -EBUSY;
-+	}
-+
-+	init_MUTEX(&new->sem);
-+	list_add_tail(&new->list, &tr->devs);
-+ added:
-+	spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+	if (!tr->writesect)
-+		new->readonly = 1;
-+
-+	for (i = new->devnum << tr->part_bits;
-+	     i < (new->devnum+1) << tr->part_bits; 
-+	     i++) {
-+		set_device_ro(MKDEV(tr->major, i), new->readonly);
-+		tr->blkcore_priv->blksizes[i] = new->blksize;
-+		tr->blkcore_priv->sizes[i] = 0;
-+		tr->blkcore_priv->part_table[i].nr_sects = 0;
-+		tr->blkcore_priv->part_table[i].start_sect = 0;
-+	}
-+
-+	/*
-+	  <viro_zzz> dwmw2: BLOCK_SIZE_BITS has nothing to do with block devices
-+	  <viro> dwmw2: any code which sets blk_size[][] should be 
-+			size >> 10 /+ 2.4 and its dumb units */
-+
-+	tr->blkcore_priv->sizes[new->devnum << tr->part_bits] = 
-+		(new->size * new->blksize) >> 10; /* 2.4 and its dumb units */
-+
-+	/* But this is still in device's sectors? $DEITY knows */
-+	tr->blkcore_priv->part_table[new->devnum << tr->part_bits].nr_sects = new->size;
-+
-+	if (tr->part_bits) {
-+		grok_partitions(&tr->blkcore_priv->gd, new->devnum,
-+				1 << tr->part_bits, new->size);
-+	}
-+#ifdef CONFIG_DEVFS_FS
-+	if (!tr->part_bits) {
-+		char name[2];
-+
-+		name[0] = '0' + new->devnum;
-+		name[1] = 0;
-+
-+		new->blkcore_priv = 
-+			devfs_register(tr->blkcore_priv->devfs_dir_handle,
-+				       name, DEVFS_FL_DEFAULT, tr->major,
-+				       new->devnum, S_IFBLK|S_IRUGO|S_IWUGO,
-+				       &mtd_blktrans_ops, NULL);
-+	}
-+#endif
-+	return 0;
-+}
-+
-+int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
-+{
-+	struct mtd_blktrans_ops *tr = old->tr;
-+	int i;
-+
-+	if (!down_trylock(&mtd_table_mutex)) {
-+		up(&mtd_table_mutex);
-+		BUG();
-+	}
-+
-+#ifdef CONFIG_DEVFS_FS
-+	if (!tr->part_bits) {
-+		devfs_unregister(old->blkcore_priv);
-+		old->blkcore_priv = NULL;
-+	} else {
-+		devfs_register_partitions(&tr->blkcore_priv->gd,
-+					  old->devnum << tr->part_bits, 1);
-+	}
-+#endif
-+	spin_lock(&tr->blkcore_priv->devs_lock);
-+	list_del(&old->list);
-+	spin_unlock(&tr->blkcore_priv->devs_lock);
-+
-+	for (i = (old->devnum << tr->part_bits); 
-+	     i < ((old->devnum+1) << tr->part_bits); i++) {
-+		tr->blkcore_priv->sizes[i] = 0;
-+		tr->blkcore_priv->part_table[i].nr_sects = 0;
-+		tr->blkcore_priv->part_table[i].start_sect = 0;
-+	}
-+
-+	return 0;
-+}
-+
-+void blktrans_notify_remove(struct mtd_info *mtd)
-+{
-+	struct list_head *this, *this2, *next;
-+
-+	list_for_each(this, &blktrans_majors) {
-+		struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+		list_for_each_safe(this2, next, &tr->devs) {
-+			struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list);
-+
-+			if (dev->mtd == mtd)
-+				tr->remove_dev(dev);
-+		}
-+	}
-+}
-+
-+void blktrans_notify_add(struct mtd_info *mtd)
-+{
-+	struct list_head *this;
-+
-+	if (mtd->type == MTD_ABSENT)
-+		return;
-+
-+	list_for_each(this, &blktrans_majors) {
-+		struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);
-+
-+		tr->add_mtd(tr, mtd);
-+	}
-+
-+}
-+
-+static struct mtd_notifier blktrans_notifier = {
-+	.add = blktrans_notify_add,
-+	.remove = blktrans_notify_remove,
-+};
-+      
-+int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+	int ret, i;
-+
-+	/* Register the notifier if/when the first device type is 
-+	   registered, to prevent the link/init ordering from fucking
-+	   us over. */
-+	if (!blktrans_notifier.list.next)
-+		register_mtd_user(&blktrans_notifier);
-+
-+	tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
-+	if (!tr->blkcore_priv)
-+		return -ENOMEM;
-+
-+	memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
-+
-+	down(&mtd_table_mutex);
-+
-+	ret = devfs_register_blkdev(tr->major, tr->name, &mtd_blktrans_ops);
-+	if (ret) {
-+		printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n",
-+		       tr->name, tr->major, ret);
-+		kfree(tr->blkcore_priv);
-+		up(&mtd_table_mutex);
-+		return ret;
-+	}
-+
-+	blk_init_queue(BLK_DEFAULT_QUEUE(tr->major), &mtd_blktrans_request);
-+	(BLK_DEFAULT_QUEUE(tr->major))->queuedata = tr;
-+	
-+	init_completion(&tr->blkcore_priv->thread_dead);
-+	init_waitqueue_head(&tr->blkcore_priv->thread_wq);
-+
-+	ret = kernel_thread(mtd_blktrans_thread, tr, 
-+			  CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
-+	if (ret < 0) {
-+		blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
-+		devfs_unregister_blkdev(tr->major, tr->name);
-+		kfree(tr->blkcore_priv);
-+		up(&mtd_table_mutex);
-+		return ret;
-+	} 
-+
-+	tr->blkcore_priv->devfs_dir_handle = 
-+			devfs_mk_dir(NULL, tr->name, NULL);
-+
-+	blksize_size[tr->major] = tr->blkcore_priv->blksizes;
-+	blk_size[tr->major] = tr->blkcore_priv->sizes;
-+
-+	tr->blkcore_priv->gd.major = tr->major;
-+	tr->blkcore_priv->gd.major_name = tr->name;
-+	tr->blkcore_priv->gd.minor_shift = tr->part_bits;
-+	tr->blkcore_priv->gd.max_p = (1<<tr->part_bits) - 1;
-+	tr->blkcore_priv->gd.part = tr->blkcore_priv->part_table;
-+	tr->blkcore_priv->gd.sizes = tr->blkcore_priv->sizes;
-+	tr->blkcore_priv->gd.nr_real = 256 >> tr->part_bits;
-+
-+	spin_lock_init(&tr->blkcore_priv->devs_lock);
-+
-+	add_gendisk(&tr->blkcore_priv->gd);
-+
-+	INIT_LIST_HEAD(&tr->devs);
-+	list_add(&tr->list, &blktrans_majors);
-+
-+	for (i=0; i<MAX_MTD_DEVICES; i++) {
-+		if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)
-+			tr->add_mtd(tr, mtd_table[i]);
-+	}
-+	up(&mtd_table_mutex);
-+
-+	return 0;
-+}
-+
-+int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr)
-+{
-+	struct list_head *this, *next;
-+
-+	down(&mtd_table_mutex);
-+
-+	/* Clean up the kernel thread */
-+	tr->blkcore_priv->exiting = 1;
-+	wake_up(&tr->blkcore_priv->thread_wq);
-+	wait_for_completion(&tr->blkcore_priv->thread_dead);
-+	
-+	/* Remove it from the list of active majors */
-+	list_del(&tr->list);
-+
-+	/* Remove each of its devices */
-+	list_for_each_safe(this, next, &tr->devs) {
-+		struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list);
-+		tr->remove_dev(dev);
-+	}
-+
-+	blksize_size[tr->major] = NULL;
-+	blk_size[tr->major] = NULL;
-+
-+	del_gendisk(&tr->blkcore_priv->gd);
-+
-+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major));
-+	devfs_unregister_blkdev(tr->major, tr->name);
-+
-+	devfs_unregister(tr->blkcore_priv->devfs_dir_handle);
-+
-+	up(&mtd_table_mutex);
-+
-+	kfree(tr->blkcore_priv);
-+
-+	if (!list_empty(&tr->devs))
-+		BUG();
-+	return 0;
-+}
-+
-+static void __exit mtd_blktrans_exit(void)
-+{
-+	/* No race here -- if someone's currently in register_mtd_blktrans
-+	   we're screwed anyway. */
-+	if (blktrans_notifier.list.next)
-+		unregister_mtd_user(&blktrans_notifier);
-+}
-+
-+module_exit(mtd_blktrans_exit);
-+
-+EXPORT_SYMBOL_GPL(register_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(deregister_mtd_blktrans);
-+EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev);
-+EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev);
-+
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'");
-Index: linux-2.6.5/drivers/mtd/mtd_blkdevs.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/mtd_blkdevs.c	2004-04-03 22:36:14.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtd_blkdevs.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.23 2004/08/19 01:54:36 tpoynor Exp $
-  *
-  * (C) 2003 David Woodhouse <dwmw2@infradead.org>
-  *
-@@ -220,7 +220,7 @@
- 				return ret;
- 
- 			g.start = get_start_sect(inode->i_bdev);
--			if (copy_to_user((void *)arg, &g, sizeof(g)))
-+			if (copy_to_user((void __user *)arg, &g, sizeof(g)))
- 				return -EFAULT;
- 			return 0;
- 		} /* else */
-@@ -295,7 +295,10 @@
- 	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: linux-2.6.5/drivers/mtd/mtdblock.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/mtdblock.c	2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtdblock.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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>
-@@ -275,7 +275,7 @@
- 	
- 	/* OK, it's not open. Create cache info for it */
- 	mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
--	if (!mtdblks)
-+	if (!mtdblk)
- 		return -ENOMEM;
- 
- 	memset(mtdblk, 0, sizeof(*mtdblk));
-Index: linux-2.6.5/drivers/mtd/mtdchar.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/mtdchar.c	2005-02-01 16:55:50.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtdchar.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: mtdchar.c,v 1.54 2003/05/21 10:50:43 dwmw2 Exp $
-+ * $Id: mtdchar.c,v 1.64 2004/08/09 13:59:46 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>
-@@ -16,22 +17,52 @@
- 
- #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)
- {
- 	struct mtd_info *mtd=(struct mtd_info *)file->private_data;
- 
--
--	down(&mtd->mutex);
- 	switch (orig) {
- 	case 0:
- 		/* SEEK_SET */
-@@ -46,16 +77,14 @@
- 		file->f_pos =mtd->size + offset;
- 		break;
- 	default:
--		up(&mtd->mutex);
- 		return -EINVAL;
- 	}
- 
--	/* XXX Should return -EINVAL surely ?? */
- 	if (file->f_pos < 0)
- 		file->f_pos = 0;
- 	else if (file->f_pos >= mtd->size)
- 		file->f_pos = mtd->size - 1;
--	up(&mtd->mutex);
-+
- 	return file->f_pos;
- }
- 
-@@ -120,7 +149,7 @@
- */
- #define MAX_KMALLOC_SIZE 0x20000
- 
--static ssize_t mtd_read(struct file *file, char *buf, size_t count,loff_t *ppos)
-+static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
- {
- 	struct mtd_info *mtd = (struct mtd_info *)file->private_data;
- 	size_t retlen=0;
-@@ -131,16 +160,11 @@
- 	
- 	DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
- 
--	down(&mtd->mutex);
--	
--	if (count > mtd->size - *ppos)
-+	if (*ppos + count > mtd->size)
- 		count = mtd->size - *ppos;
- 
- 	if (!count)
--	{
--		up(&mtd->mutex);
- 		return 0;
--	}
- 	
- 	/* FIXME: Use kiovec in 2.5 to lock down the user's buffers
- 	   and pass them directly to the MTD functions */
-@@ -152,18 +176,13 @@
- 
- 		kbuf=kmalloc(len,GFP_KERNEL);
- 		if (!kbuf)
--		{
--			up(&mtd->mutex);
--			/* API error - should return I/O done so far if > 0 */
- 			return -ENOMEM;
--		}		
-+		
- 		ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
- 		if (!ret) {
- 			*ppos += retlen;
- 			if (copy_to_user(buf, kbuf, retlen)) {
- 			        kfree(kbuf);
--			        up(&mtd->mutex);
--				/* API error - should return I/O done so far if > 0 */
- 				return -EFAULT;
- 			}
- 			else
-@@ -174,17 +193,16 @@
- 		}
- 		else {
- 			kfree(kbuf);
--			up(&mtd->mutex);
- 			return ret;
- 		}
- 		
- 		kfree(kbuf);
- 	}
--	up(&mtd->mutex);	
-+	
- 	return total_retlen;
- } /* mtd_read */
- 
--static ssize_t mtd_write(struct file *file, const char *buf, size_t count,loff_t *ppos)
-+static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
- {
- 	struct mtd_info *mtd = (struct mtd_info *)file->private_data;
- 	char *kbuf;
-@@ -194,22 +212,15 @@
- 	int len;
- 
- 	DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
--
--	down(&mtd->mutex);	
--	if (*ppos >= mtd->size)
--	{
--		up(&mtd->mutex);
-+	
-+	if (*ppos == mtd->size)
- 		return -ENOSPC;
--	}
- 	
--	if (count > mtd->size - *ppos)
-+	if (*ppos + count > mtd->size)
- 		count = mtd->size - *ppos;
- 
- 	if (!count)
--	{
--		up(&mtd->mutex);
- 		return 0;
--	}
- 
- 	while (count) {
- 		if (count > MAX_KMALLOC_SIZE) 
-@@ -219,14 +230,11 @@
- 
- 		kbuf=kmalloc(len,GFP_KERNEL);
- 		if (!kbuf) {
--//			printk("kmalloc is null\n");
--			/* API bug should report I/O completed */
--			up(&mtd->mutex);
-+			printk("kmalloc is null\n");
- 			return -ENOMEM;
- 		}
- 
- 		if (copy_from_user(kbuf, buf, len)) {
--			up(&mtd->mutex);
- 			kfree(kbuf);
- 			return -EFAULT;
- 		}
-@@ -239,15 +247,13 @@
- 			buf += retlen;
- 		}
- 		else {
--			up(&mtd->mutex);
- 			kfree(kbuf);
--			/* API bug ?? */
- 			return ret;
- 		}
- 		
- 		kfree(kbuf);
- 	}
--	up(&mtd->mutex);
-+
- 	return total_retlen;
- } /* mtd_write */
- 
-@@ -256,7 +262,7 @@
-     IOCTL calls for getting device parameters.
- 
- ======================================================================*/
--static void mtd_erase_callback (struct erase_info *instr)
-+static void mtdchar_erase_callback (struct erase_info *instr)
- {
- 	wake_up((wait_queue_head_t *)instr->priv);
- }
-@@ -265,6 +271,7 @@
- 		     u_int cmd, u_long arg)
- {
- 	struct mtd_info *mtd = (struct mtd_info *)file->private_data;
-+	void __user *argp = (void __user *)arg;
- 	int ret = 0;
- 	u_long size;
- 	
-@@ -272,17 +279,17 @@
- 
- 	size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
- 	if (cmd & IOC_IN) {
--		ret = verify_area(VERIFY_READ, (char *)arg, size);
-+		ret = verify_area(VERIFY_READ, argp, size);
- 		if (ret) return ret;
- 	}
- 	if (cmd & IOC_OUT) {
--		ret = verify_area(VERIFY_WRITE, (char *)arg, size);
-+		ret = verify_area(VERIFY_WRITE, argp, size);
- 		if (ret) return ret;
- 	}
- 	
- 	switch (cmd) {
- 	case MEMGETREGIONCOUNT:
--		if (copy_to_user((int *) arg, &(mtd->numeraseregions), sizeof(int)))
-+		if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
- 			return -EFAULT;
- 		break;
- 
-@@ -290,24 +297,19 @@
- 	{
- 		struct region_info_user ur;
- 
--		if (copy_from_user(	&ur, 
--					(struct region_info_user *)arg, 
--					sizeof(struct region_info_user))) {
-+		if (copy_from_user(&ur, argp, sizeof(struct region_info_user)))
- 			return -EFAULT;
--		}
- 
- 		if (ur.regionindex >= mtd->numeraseregions)
- 			return -EINVAL;
--		if (copy_to_user((struct mtd_erase_region_info *) arg, 
--				&(mtd->eraseregions[ur.regionindex]),
-+		if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]),
- 				sizeof(struct mtd_erase_region_info)))
- 			return -EFAULT;
- 		break;
- 	}
- 
- 	case MEMGETINFO:
--		if (copy_to_user((struct mtd_info *)arg, mtd,
--				 sizeof(struct mtd_info_user)))
-+		if (copy_to_user(argp, mtd, sizeof(struct mtd_info_user)))
- 			return -EFAULT;
- 		break;
- 
-@@ -328,13 +330,13 @@
- 			init_waitqueue_head(&waitq);
- 
- 			memset (erase,0,sizeof(struct erase_info));
--			if (copy_from_user(&erase->addr, (u_long *)arg,
--					   2 * sizeof(u_long))) {
-+			if (copy_from_user(&erase->addr, argp,
-+				    sizeof(struct erase_info_user))) {
- 				kfree(erase);
- 				return -EFAULT;
- 			}
- 			erase->mtd = mtd;
--			erase->callback = mtd_erase_callback;
-+			erase->callback = mtdchar_erase_callback;
- 			erase->priv = (unsigned long)&waitq;
- 			
- 			/*
-@@ -372,7 +374,7 @@
- 		if(!(file->f_mode & 2))
- 			return -EPERM;
- 
--		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
-+		if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
- 			return -EFAULT;
- 		
- 		if (buf.length > 0x4096)
-@@ -381,7 +383,7 @@
- 		if (!mtd->write_oob)
- 			ret = -EOPNOTSUPP;
- 		else
--			ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length);
-+			ret = verify_area(VERIFY_READ, buf.ptr, buf.length);
- 
- 		if (ret)
- 			return ret;
-@@ -397,7 +399,7 @@
- 
- 		ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
- 
--		if (copy_to_user((void *)arg + 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);
-@@ -411,7 +413,7 @@
- 		void *databuf;
- 		ssize_t retlen;
- 
--		if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf)))
-+		if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
- 			return -EFAULT;
- 		
- 		if (buf.length > 0x4096)
-@@ -420,7 +422,7 @@
- 		if (!mtd->read_oob)
- 			ret = -EOPNOTSUPP;
- 		else
--			ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length);
-+			ret = verify_area(VERIFY_WRITE, buf.ptr, buf.length);
- 
- 		if (ret)
- 			return ret;
-@@ -431,7 +433,7 @@
- 		
- 		ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
- 
--		if (copy_to_user((void *)arg + 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;
-@@ -442,41 +444,73 @@
- 
- 	case MEMLOCK:
- 	{
--		unsigned long adrs[2];
-+		struct erase_info_user info;
- 
--		if (copy_from_user(adrs ,(void *)arg, 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, (void *)arg, 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;
- 	}
- 
- 	case MEMSETOOBSEL:
- 	{
--		if (copy_from_user(&mtd->oobinfo ,(void *)arg, sizeof(struct nand_oobinfo)))
-+		if (copy_from_user(&mtd->oobinfo, argp, sizeof(struct nand_oobinfo)))
-+			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;
- 	}
- 
-@@ -493,30 +527,6 @@
- 	.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)) {
-@@ -525,20 +535,13 @@
- 		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: linux-2.6.5/drivers/mtd/mtdconcat.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/mtdconcat.c	2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtdconcat.c	2005-02-01 17:11:17.000000000 -0500
-@@ -7,7 +7,7 @@
-  *
-  * This code is GPL
-  *
-- * $Id: mtdconcat.c,v 1.4 2003/03/07 17:44:59 rkaiser Exp $
-+ * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $
-  */
- 
- #include <linux/module.h>
-@@ -26,7 +26,7 @@
-  */
- struct mtd_concat {
- 	struct mtd_info mtd;
--	int             num_subdev;
-+	int num_subdev;
- 	struct mtd_info **subdev;
- };
- 
-@@ -37,21 +37,20 @@
- #define SIZEOF_STRUCT_MTD_CONCAT(num_subdev)	\
- 	((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
- 
--
- /*
-  * Given a pointer to the MTD object in the mtd_concat structure,
-  * we can retrieve the pointer to that structure with this macro.
-  */
- #define CONCAT(x)  ((struct mtd_concat *)(x))
- 
--	
- /* 
-  * MTD methods which look up the relevant subdevice, translate the
-  * effective address and pass through to the subdevice.
-  */
- 
--static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, 
--			size_t *retlen, u_char *buf)
-+static int
-+concat_read(struct mtd_info *mtd, loff_t from, size_t len,
-+	    size_t * retlen, u_char * buf)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int err = -EINVAL;
-@@ -59,43 +58,43 @@
- 
- 	*retlen = 0;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		size_t size, retsize;
- 
--		if (from >= subdev->size)
--		{   /* Not destined for this subdev */
--			size  = 0;
-+		if (from >= subdev->size) {
-+			/* Not destined for this subdev */
-+			size = 0;
- 			from -= subdev->size;
-+			continue;
- 		}
-+		if (from + len > subdev->size)
-+			/* First part goes into this subdev */
-+			size = subdev->size - from;
- 		else
--		{
--			if (from + len > subdev->size)
--				size = subdev->size - from; /* First part goes into this subdev */
--			else
--				size = len; /* Entire transaction goes into this subdev */
--
--			err = subdev->read(subdev, from, size, &retsize, buf);
--
--			if(err)
--				break;
--
--			*retlen += retsize;
--			len -= size;
--			if(len == 0)
--				break;
-+			/* Entire transaction goes into this subdev */
-+			size = len;
- 
--			err = -EINVAL;
--			buf += size;
--			from = 0;
--		}
-+		err = subdev->read(subdev, from, size, &retsize, buf);
-+
-+		if (err)
-+			break;
-+
-+		*retlen += retsize;
-+		len -= size;
-+		if (len == 0)
-+			break;
-+
-+		err = -EINVAL;
-+		buf += size;
-+		from = 0;
- 	}
- 	return err;
- }
- 
--static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
--			size_t *retlen, const u_char *buf)
-+static int
-+concat_write(struct mtd_info *mtd, loff_t to, size_t len,
-+	     size_t * retlen, const u_char * buf)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int err = -EINVAL;
-@@ -106,46 +105,44 @@
- 
- 	*retlen = 0;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		size_t size, retsize;
- 
--		if (to >= subdev->size)
--		{
--			size  = 0;
-+		if (to >= subdev->size) {
-+			size = 0;
- 			to -= subdev->size;
-+			continue;
- 		}
-+		if (to + len > subdev->size)
-+			size = subdev->size - to;
- 		else
--		{
--			if (to + len > subdev->size)
--				size = subdev->size - to;
--			else
--				size = len;
--
--			if (!(subdev->flags & MTD_WRITEABLE))
--				err = -EROFS;
--			else
--				err = subdev->write(subdev, to, size, &retsize, buf);
--
--			if(err)
--				break;
--
--			*retlen += retsize;
--			len -= size;
--			if(len == 0)
--				break;
-+			size = len;
- 
--			err = -EINVAL;
--			buf += size;
--			to = 0;
--		}
-+		if (!(subdev->flags & MTD_WRITEABLE))
-+			err = -EROFS;
-+		else
-+			err = subdev->write(subdev, to, size, &retsize, buf);
-+
-+		if (err)
-+			break;
-+
-+		*retlen += retsize;
-+		len -= size;
-+		if (len == 0)
-+			break;
-+
-+		err = -EINVAL;
-+		buf += size;
-+		to = 0;
- 	}
- 	return err;
- }
- 
--static int concat_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
-+concat_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)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int err = -EINVAL;
-@@ -153,53 +150,56 @@
- 
- 	*retlen = 0;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		size_t size, retsize;
--        
--		if (from >= subdev->size)
--		{   /* Not destined for this subdev */
--			size  = 0;
-+
-+		if (from >= subdev->size) {
-+			/* Not destined for this subdev */
-+			size = 0;
- 			from -= subdev->size;
-+			continue;
- 		}
-+
-+		if (from + len > subdev->size)
-+			/* First part goes into this subdev */
-+			size = subdev->size - from;
- 		else
--		{
--			if (from + len > subdev->size)
--				size = subdev->size - from; /* First part goes into this subdev */
--			else
--				size = len; /* Entire transaction goes into this subdev */
--            
--            if (subdev->read_ecc)
--    			err = subdev->read_ecc(subdev, from, size, &retsize, buf, eccbuf, oobsel);
--            else
--                err = -EINVAL;
--
--			if(err)
--				break;
--
--			*retlen += retsize;
--			len -= size;
--			if(len == 0)
--				break;
-+			/* Entire transaction goes into this subdev */
-+			size = len;
- 
-+		if (subdev->read_ecc)
-+			err = subdev->read_ecc(subdev, from, size,
-+					       &retsize, buf, eccbuf, oobsel);
-+		else
- 			err = -EINVAL;
--			buf += size;
--            if (eccbuf)
--            {
--                eccbuf += subdev->oobsize;
--                /* in nand.c at least, eccbufs are tagged with 2 (int)eccstatus',
--                   we must account for these */
--                eccbuf += 2 * (sizeof(int)); 
--            }
--			from = 0;
-+
-+		if (err)
-+			break;
-+
-+		*retlen += retsize;
-+		len -= size;
-+		if (len == 0)
-+			break;
-+
-+		err = -EINVAL;
-+		buf += size;
-+		if (eccbuf) {
-+			eccbuf += subdev->oobsize;
-+			/* in nand.c at least, eccbufs are
-+			   tagged with 2 (int)eccstatus'; we
-+			   must account for these */
-+			eccbuf += 2 * (sizeof (int));
- 		}
-+		from = 0;
- 	}
- 	return err;
- }
- 
--static int concat_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
-+concat_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)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int err = -EINVAL;
-@@ -210,50 +210,48 @@
- 
- 	*retlen = 0;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		size_t size, retsize;
--        
--		if (to >= subdev->size)
--		{
--			size  = 0;
-+
-+		if (to >= subdev->size) {
-+			size = 0;
- 			to -= subdev->size;
-+			continue;
- 		}
-+		if (to + len > subdev->size)
-+			size = subdev->size - to;
- 		else
--		{
--			if (to + len > subdev->size)
--				size = subdev->size - to;
--			else
--				size = len;
--
--			if (!(subdev->flags & MTD_WRITEABLE))
--				err = -EROFS;
--			else if (subdev->write_ecc)
--				err = subdev->write_ecc(subdev, to, size, &retsize, buf, eccbuf, oobsel);
--            else
--                err = -EINVAL;
--
--			if(err)
--				break;
--
--			*retlen += retsize;
--			len -= size;
--			if(len == 0)
--				break;
-+			size = len;
- 
-+		if (!(subdev->flags & MTD_WRITEABLE))
-+			err = -EROFS;
-+		else if (subdev->write_ecc)
-+			err = subdev->write_ecc(subdev, to, size,
-+						&retsize, buf, eccbuf, oobsel);
-+		else
- 			err = -EINVAL;
--			buf += size;
--            if (eccbuf)
--                eccbuf += subdev->oobsize;
--			to = 0;
--		}
-+
-+		if (err)
-+			break;
-+
-+		*retlen += retsize;
-+		len -= size;
-+		if (len == 0)
-+			break;
-+
-+		err = -EINVAL;
-+		buf += size;
-+		if (eccbuf)
-+			eccbuf += subdev->oobsize;
-+		to = 0;
- 	}
- 	return err;
- }
- 
--static int concat_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
--            size_t *retlen, u_char *buf)
-+static int
-+concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
-+		size_t * retlen, u_char * buf)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int err = -EINVAL;
-@@ -261,46 +259,47 @@
- 
- 	*retlen = 0;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		size_t size, retsize;
--        
--		if (from >= subdev->size)
--		{   /* Not destined for this subdev */
--			size  = 0;
-+
-+		if (from >= subdev->size) {
-+			/* Not destined for this subdev */
-+			size = 0;
- 			from -= subdev->size;
-+			continue;
- 		}
-+		if (from + len > subdev->size)
-+			/* First part goes into this subdev */
-+			size = subdev->size - from;
-+		else
-+			/* Entire transaction goes into this subdev */
-+			size = len;
-+
-+		if (subdev->read_oob)
-+			err = subdev->read_oob(subdev, from, size,
-+					       &retsize, buf);
- 		else
--		{
--			if (from + len > subdev->size)
--				size = subdev->size - from; /* First part goes into this subdev */
--			else
--				size = len; /* Entire transaction goes into this subdev */
--            
--            if (subdev->read_oob)
--    			err = subdev->read_oob(subdev, from, size, &retsize, buf);
--            else
--                err = -EINVAL;
--
--			if(err)
--				break;
--
--			*retlen += retsize;
--			len -= size;
--			if(len == 0)
--				break;
--
- 			err = -EINVAL;
--			buf += size;
--			from = 0;
--		}
-+
-+		if (err)
-+			break;
-+
-+		*retlen += retsize;
-+		len -= size;
-+		if (len == 0)
-+			break;
-+
-+		err = -EINVAL;
-+		buf += size;
-+		from = 0;
- 	}
- 	return err;
- }
- 
--static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len, 
--            size_t *retlen, const u_char *buf)
-+static int
-+concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
-+		 size_t * retlen, const u_char * buf)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int err = -EINVAL;
-@@ -311,50 +310,46 @@
- 
- 	*retlen = 0;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		size_t size, retsize;
--        
--		if (to >= subdev->size)
--		{
--			size  = 0;
-+
-+		if (to >= subdev->size) {
-+			size = 0;
- 			to -= subdev->size;
-+			continue;
- 		}
-+		if (to + len > subdev->size)
-+			size = subdev->size - to;
- 		else
--		{
--			if (to + len > subdev->size)
--				size = subdev->size - to;
--			else
--				size = len;
--
--			if (!(subdev->flags & MTD_WRITEABLE))
--				err = -EROFS;
--			else if (subdev->write_oob)
--				err = subdev->write_oob(subdev, to, size, &retsize, buf);
--            else
--                err = -EINVAL;
--
--			if(err)
--				break;
--
--			*retlen += retsize;
--			len -= size;
--			if(len == 0)
--				break;
-+			size = len;
- 
-+		if (!(subdev->flags & MTD_WRITEABLE))
-+			err = -EROFS;
-+		else if (subdev->write_oob)
-+			err = subdev->write_oob(subdev, to, size, &retsize,
-+						buf);
-+		else
- 			err = -EINVAL;
--			buf += size;
--			to = 0;
--		}
-+
-+		if (err)
-+			break;
-+
-+		*retlen += retsize;
-+		len -= size;
-+		if (len == 0)
-+			break;
-+
-+		err = -EINVAL;
-+		buf += size;
-+		to = 0;
- 	}
- 	return err;
- }
- 
--
--static void concat_erase_callback (struct erase_info *instr)
-+static void concat_erase_callback(struct erase_info *instr)
- {
--	wake_up((wait_queue_head_t *)instr->priv);
-+	wake_up((wait_queue_head_t *) instr->priv);
- }
- 
- static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
-@@ -370,18 +365,18 @@
- 
- 	erase->mtd = mtd;
- 	erase->callback = concat_erase_callback;
--	erase->priv = (unsigned long)&waitq;
--			
-+	erase->priv = (unsigned long) &waitq;
-+
- 	/*
- 	 * FIXME: Allow INTERRUPTIBLE. Which means
- 	 * not having the wait_queue head on the stack.
- 	 */
- 	err = mtd->erase(mtd, erase);
--	if (!err)
--	{
-+	if (!err) {
- 		set_current_state(TASK_UNINTERRUPTIBLE);
- 		add_wait_queue(&waitq, &wait);
--		if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
-+		if (erase->state != MTD_ERASE_DONE
-+		    && erase->state != MTD_ERASE_FAILED)
- 			schedule();
- 		remove_wait_queue(&waitq, &wait);
- 		set_current_state(TASK_RUNNING);
-@@ -391,21 +386,21 @@
- 	return err;
- }
- 
--static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
-+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))
- 		return -EROFS;
- 
--	if(instr->addr > concat->mtd.size)
-+	if (instr->addr > concat->mtd.size)
- 		return -EINVAL;
- 
--	if(instr->len + instr->addr > concat->mtd.size)
-+	if (instr->len + instr->addr > concat->mtd.size)
- 		return -EINVAL;
- 
- 	/*
-@@ -414,23 +409,22 @@
- 	 * region info rather than looking at each particular sub-device
- 	 * in turn.
- 	 */
--	if (!concat->mtd.numeraseregions)
--	{	/* the easy case: device has uniform erase block size */
--		if(instr->addr & (concat->mtd.erasesize - 1))
-+	if (!concat->mtd.numeraseregions) {
-+		/* the easy case: device has uniform erase block size */
-+		if (instr->addr & (concat->mtd.erasesize - 1))
- 			return -EINVAL;
--		if(instr->len & (concat->mtd.erasesize - 1))
-+		if (instr->len & (concat->mtd.erasesize - 1))
- 			return -EINVAL;
--	}
--	else
--	{	/* device has variable erase size */
--		struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
-+	} else {
-+		/* device has variable erase size */
-+		struct mtd_erase_region_info *erase_regions =
-+		    concat->mtd.eraseregions;
- 
- 		/*
- 		 * Find the erase region where the to-be-erased area begins:
- 		 */
--		for(i = 0; i < concat->mtd.numeraseregions && 
--		           instr->addr >= erase_regions[i].offset; i++)
--			;
-+		for (i = 0; i < concat->mtd.numeraseregions &&
-+		     instr->addr >= erase_regions[i].offset; i++) ;
- 		--i;
- 
- 		/*
-@@ -438,25 +432,28 @@
- 		 * to-be-erased area begins. Verify that the starting
- 		 * offset is aligned to this region's erase size:
- 		 */
--		if (instr->addr & (erase_regions[i].erasesize-1))
-+		if (instr->addr & (erase_regions[i].erasesize - 1))
- 			return -EINVAL;
- 
- 		/*
- 		 * now find the erase region where the to-be-erased area ends:
- 		 */
--		for(; i < concat->mtd.numeraseregions && 
--		      (instr->addr + instr->len) >=  erase_regions[i].offset ; ++i)
--			;
-+		for (; i < concat->mtd.numeraseregions &&
-+		     (instr->addr + instr->len) >= erase_regions[i].offset;
-+		     ++i) ;
- 		--i;
- 		/*
- 		 * check if the ending offset is aligned to this region's erase size
- 		 */
--		if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
-+		if ((instr->addr + instr->len) & (erase_regions[i].erasesize -
-+						  1))
- 			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);
-+	erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
- 
- 	if (!erase)
- 		return -ENOMEM;
-@@ -468,39 +465,44 @@
- 	 * find the subdevice where the to-be-erased area begins, adjust
- 	 * starting offset to be relative to the subdevice start
- 	 */
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	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;
--    }
--	if(i >= concat->num_subdev)	/* must never happen since size */
--		BUG();					/* limit has been verified above */
-+		}
-+	}
-+
-+	/* must never happen since size limit has been verified above */
-+	if (i >= concat->num_subdev)
-+		BUG();
- 
- 	/* now do the erase: */
- 	err = 0;
--	for(;length > 0; i++)	/* loop for all subevices affected by this request */
--	{
--		subdev = concat->subdev[i];		/* get current subdevice */
-+	for (; length > 0; i++) {
-+		/* loop for all subdevices affected by this request */
-+		subdev = concat->subdev[i];	/* get current subdevice */
- 
- 		/* limit length to subdevice's size: */
--		if(erase->addr + length > subdev->size)
-+		if (erase->addr + length > subdev->size)
- 			erase->len = subdev->size - erase->addr;
- 		else
- 			erase->len = length;
- 
--		if (!(subdev->flags & MTD_WRITEABLE))
--		{
-+		if (!(subdev->flags & MTD_WRITEABLE)) {
- 			err = -EROFS;
- 			break;
- 		}
- 		length -= erase->len;
--		if ((err = concat_dev_erase(subdev, erase)))
--		{
--			if(err == -EINVAL)	/* sanity check: must never happen since */
--				BUG();			/* block alignment has been checked above */
-+		if ((err = concat_dev_erase(subdev, erase))) {
-+			/* sanity check: should never happen since
-+			 * block alignment has been checked above */
-+			if (err == -EINVAL)
-+				BUG();
-+			if (erase->fail_addr != 0xffffffff)
-+				instr->fail_addr = erase->fail_addr + offset;
- 			break;
- 		}
- 		/*
-@@ -512,96 +514,91 @@
- 		 * 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;
- }
- 
--static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
-+static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int i, err = -EINVAL;
- 
--	if ((len + ofs) > mtd->size) 
-+	if ((len + ofs) > mtd->size)
- 		return -EINVAL;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		size_t size;
- 
--		if (ofs >= subdev->size)
--		{
--			size  = 0;
-+		if (ofs >= subdev->size) {
-+			size = 0;
- 			ofs -= subdev->size;
-+			continue;
- 		}
-+		if (ofs + len > subdev->size)
-+			size = subdev->size - ofs;
- 		else
--		{
--			if (ofs + len > subdev->size)
--				size = subdev->size - ofs;
--			else
--				size = len;
--
--			err = subdev->lock(subdev, ofs, size);
--
--			if(err)
--				break;
--
--			len -= size;
--			if(len == 0)
--				break;
-+			size = len;
- 
--			err = -EINVAL;
--			ofs = 0;
--		}
-+		err = subdev->lock(subdev, ofs, size);
-+
-+		if (err)
-+			break;
-+
-+		len -= size;
-+		if (len == 0)
-+			break;
-+
-+		err = -EINVAL;
-+		ofs = 0;
- 	}
-+
- 	return err;
- }
- 
--static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
-+static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int i, err = 0;
- 
--	if ((len + ofs) > mtd->size) 
-+	if ((len + ofs) > mtd->size)
- 		return -EINVAL;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		size_t size;
- 
--		if (ofs >= subdev->size)
--		{
--			size  = 0;
-+		if (ofs >= subdev->size) {
-+			size = 0;
- 			ofs -= subdev->size;
-+			continue;
- 		}
-+		if (ofs + len > subdev->size)
-+			size = subdev->size - ofs;
- 		else
--		{
--			if (ofs + len > subdev->size)
--				size = subdev->size - ofs;
--			else
--				size = len;
--
--			err = subdev->unlock(subdev, ofs, size);
--
--			if(err)
--				break;
--
--			len -= size;
--			if(len == 0)
--				break;
-+			size = len;
- 
--			err = -EINVAL;
--			ofs = 0;
--		}
-+		err = subdev->unlock(subdev, ofs, size);
-+
-+		if (err)
-+			break;
-+
-+		len -= size;
-+		if (len == 0)
-+			break;
-+
-+		err = -EINVAL;
-+		ofs = 0;
- 	}
-+
- 	return err;
- }
- 
-@@ -610,8 +607,7 @@
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int i;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		subdev->sync(subdev);
- 	}
-@@ -622,10 +618,9 @@
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int i, rc = 0;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
--		if((rc = subdev->suspend(subdev)) < 0)
-+		if ((rc = subdev->suspend(subdev)) < 0)
- 			return rc;
- 	}
- 	return rc;
-@@ -636,8 +631,7 @@
- 	struct mtd_concat *concat = CONCAT(mtd);
- 	int i;
- 
--	for(i = 0; i < concat->num_subdev; i++)
--	{
-+	for (i = 0; i < concat->num_subdev; i++) {
- 		struct mtd_info *subdev = concat->subdev[i];
- 		subdev->resume(subdev);
- 	}
-@@ -649,11 +643,10 @@
-  * stored to *new_dev upon success. This function does _not_
-  * register any devices: this is the caller's responsibility.
-  */
--struct mtd_info *mtd_concat_create(
--	struct mtd_info *subdev[],	/* subdevices to concatenate */
--	int num_devs,				/* number of subdevices      */
--	char *name)					/* name for the new device   */
--{
-+struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to concatenate */
-+				   int num_devs,	/* number of subdevices      */
-+				   char *name)
-+{				/* name for the new device   */
- 	int i;
- 	size_t size;
- 	struct mtd_concat *concat;
-@@ -661,94 +654,103 @@
- 	int num_erase_region;
- 
- 	printk(KERN_NOTICE "Concatenating MTD devices:\n");
--	for(i = 0; i < num_devs; i++)
-+	for (i = 0; i < num_devs; i++)
- 		printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
- 	printk(KERN_NOTICE "into device \"%s\"\n", name);
- 
- 	/* allocate the device structure */
- 	size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
--	concat = kmalloc (size, GFP_KERNEL);
--	if(!concat)
--	{
--		printk ("memory allocation error while creating concatenated device \"%s\"\n",
--				name);
--			return NULL;
-+	concat = kmalloc(size, GFP_KERNEL);
-+	if (!concat) {
-+		printk
-+		    ("memory allocation error while creating concatenated device \"%s\"\n",
-+		     name);
-+		return NULL;
- 	}
- 	memset(concat, 0, size);
--	concat->subdev = (struct mtd_info **)(concat + 1);
-+	concat->subdev = (struct mtd_info **) (concat + 1);
- 
- 	/*
- 	 * Set up the new "super" device's MTD object structure, check for
- 	 * incompatibilites between the subdevices.
- 	 */
--	concat->mtd.type      = subdev[0]->type;
--	concat->mtd.flags     = subdev[0]->flags;
--	concat->mtd.size      = subdev[0]->size;
-+	concat->mtd.type = subdev[0]->type;
-+	concat->mtd.flags = subdev[0]->flags;
-+	concat->mtd.size = subdev[0]->size;
- 	concat->mtd.erasesize = subdev[0]->erasesize;
--	concat->mtd.oobblock  = subdev[0]->oobblock;
--	concat->mtd.oobsize   = subdev[0]->oobsize;
--	concat->mtd.ecctype   = subdev[0]->ecctype;
--	concat->mtd.eccsize   = subdev[0]->eccsize;
--
--	concat->subdev[0]   = subdev[0];
--
--	for(i = 1; i < num_devs; i++)
--	{
--		if(concat->mtd.type != subdev[i]->type)
--		{
-+	concat->mtd.oobblock = subdev[0]->oobblock;
-+	concat->mtd.oobsize = subdev[0]->oobsize;
-+	concat->mtd.ecctype = subdev[0]->ecctype;
-+	concat->mtd.eccsize = subdev[0]->eccsize;
-+	if (subdev[0]->read_ecc)
-+		concat->mtd.read_ecc = concat_read_ecc;
-+	if (subdev[0]->write_ecc)
-+		concat->mtd.write_ecc = concat_write_ecc;
-+	if (subdev[0]->read_oob)
-+		concat->mtd.read_oob = concat_read_oob;
-+	if (subdev[0]->write_oob)
-+		concat->mtd.write_oob = concat_write_oob;
-+
-+	concat->subdev[0] = subdev[0];
-+
-+	for (i = 1; i < num_devs; i++) {
-+		if (concat->mtd.type != subdev[i]->type) {
- 			kfree(concat);
--			printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
-+			printk("Incompatible device type on \"%s\"\n",
-+			       subdev[i]->name);
- 			return NULL;
- 		}
--		if(concat->mtd.flags != subdev[i]->flags)
--		{	/*
--			 * Expect all flags except MTD_WRITEABLE to be equal on
--			 * all subdevices.
-+		if (concat->mtd.flags != subdev[i]->flags) {
-+			/*
-+			 * Expect all flags except MTD_WRITEABLE to be
-+			 * equal on all subdevices.
- 			 */
--			if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
--			{
-+			if ((concat->mtd.flags ^ subdev[i]->
-+			     flags) & ~MTD_WRITEABLE) {
- 				kfree(concat);
--				printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
-+				printk("Incompatible device flags on \"%s\"\n",
-+				       subdev[i]->name);
- 				return NULL;
--			}
--			else	/* if writeable attribute differs, make super device writeable */
--				concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
-+			} else
-+				/* if writeable attribute differs,
-+				   make super device writeable */
-+				concat->mtd.flags |=
-+				    subdev[i]->flags & MTD_WRITEABLE;
- 		}
- 		concat->mtd.size += subdev[i]->size;
--		if(concat->mtd.oobblock != subdev[i]->oobblock ||
--		   concat->mtd.oobsize  != subdev[i]->oobsize  ||
--		   concat->mtd.ecctype  != subdev[i]->ecctype  ||
--		   concat->mtd.eccsize  != subdev[i]->eccsize)
--		{
-+		if (concat->mtd.oobblock   !=  subdev[i]->oobblock ||
-+		    concat->mtd.oobsize    !=  subdev[i]->oobsize ||
-+		    concat->mtd.ecctype    !=  subdev[i]->ecctype ||
-+		    concat->mtd.eccsize    !=  subdev[i]->eccsize ||
-+		    !concat->mtd.read_ecc  != !subdev[i]->read_ecc ||
-+		    !concat->mtd.write_ecc != !subdev[i]->write_ecc ||
-+		    !concat->mtd.read_oob  != !subdev[i]->read_oob ||
-+		    !concat->mtd.write_oob != !subdev[i]->write_oob) {
- 			kfree(concat);
--			printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
-+			printk("Incompatible OOB or ECC data on \"%s\"\n",
-+			       subdev[i]->name);
- 			return NULL;
- 		}
- 		concat->subdev[i] = subdev[i];
--		
-+
- 	}
- 
--	concat->num_subdev  = num_devs;
--	concat->mtd.name    = name;
-+	concat->num_subdev = num_devs;
-+	concat->mtd.name = name;
- 
- 	/*
- 	 * NOTE: for now, we do not provide any readv()/writev() methods
- 	 *       because they are messy to implement and they are not
- 	 *       used to a great extent anyway.
- 	 */
--	concat->mtd.erase     = concat_erase;
--	concat->mtd.read      = concat_read;    
--	concat->mtd.write     = concat_write;
--	concat->mtd.read_ecc  = concat_read_ecc;    
--	concat->mtd.write_ecc = concat_write_ecc;
--	concat->mtd.read_oob  = concat_read_oob;    
--	concat->mtd.write_oob = concat_write_oob;
--	concat->mtd.sync      = concat_sync;
--	concat->mtd.lock      = concat_lock;
--	concat->mtd.unlock    = concat_unlock;
--	concat->mtd.suspend   = concat_suspend;
--	concat->mtd.resume    = concat_resume;
--
-+	concat->mtd.erase = concat_erase;
-+	concat->mtd.read = concat_read;
-+	concat->mtd.write = concat_write;
-+	concat->mtd.sync = concat_sync;
-+	concat->mtd.lock = concat_lock;
-+	concat->mtd.unlock = concat_unlock;
-+	concat->mtd.suspend = concat_suspend;
-+	concat->mtd.resume = concat_resume;
- 
- 	/*
- 	 * Combine the erase block size info of the subdevices:
-@@ -758,44 +760,44 @@
- 	 */
- 	max_erasesize = curr_erasesize = subdev[0]->erasesize;
- 	num_erase_region = 1;
--	for(i = 0; i < num_devs; i++)
--	{
--		if(subdev[i]->numeraseregions == 0)
--		{	/* current subdevice has uniform erase size */
--			if(subdev[i]->erasesize != curr_erasesize)
--			{	/* if it differs from the last subdevice's erase size, count it */
-+	for (i = 0; i < num_devs; i++) {
-+		if (subdev[i]->numeraseregions == 0) {
-+			/* current subdevice has uniform erase size */
-+			if (subdev[i]->erasesize != curr_erasesize) {
-+				/* if it differs from the last subdevice's erase size, count it */
- 				++num_erase_region;
- 				curr_erasesize = subdev[i]->erasesize;
--				if(curr_erasesize > max_erasesize)
-+				if (curr_erasesize > max_erasesize)
- 					max_erasesize = curr_erasesize;
- 			}
--		}
--		else
--		{	/* current subdevice has variable erase size */
-+		} else {
-+			/* current subdevice has variable erase size */
- 			int j;
--			for(j = 0; j < subdev[i]->numeraseregions; j++)
--			{	/* walk the list of erase regions, count any changes */
--				if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
--				{
-+			for (j = 0; j < subdev[i]->numeraseregions; j++) {
-+
-+				/* walk the list of erase regions, count any changes */
-+				if (subdev[i]->eraseregions[j].erasesize !=
-+				    curr_erasesize) {
- 					++num_erase_region;
--					curr_erasesize = subdev[i]->eraseregions[j].erasesize;
--					if(curr_erasesize > max_erasesize)
-+					curr_erasesize =
-+					    subdev[i]->eraseregions[j].
-+					    erasesize;
-+					if (curr_erasesize > max_erasesize)
- 						max_erasesize = curr_erasesize;
- 				}
- 			}
- 		}
- 	}
- 
--	if(num_erase_region == 1)
--	{	/*
-+	if (num_erase_region == 1) {
-+		/*
- 		 * All subdevices have the same uniform erase size.
- 		 * This is easy:
- 		 */
- 		concat->mtd.erasesize = curr_erasesize;
- 		concat->mtd.numeraseregions = 0;
--	}
--	else
--	{	/*
-+	} else {
-+		/*
- 		 * erase block size varies across the subdevices: allocate
- 		 * space to store the data describing the variable erase regions
- 		 */
-@@ -804,13 +806,14 @@
- 
- 		concat->mtd.erasesize = max_erasesize;
- 		concat->mtd.numeraseregions = num_erase_region;
--		concat->mtd.eraseregions = erase_region_p = kmalloc (
--		     num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
--		if(!erase_region_p)
--		{
-+		concat->mtd.eraseregions = erase_region_p =
-+		    kmalloc(num_erase_region *
-+			    sizeof (struct mtd_erase_region_info), GFP_KERNEL);
-+		if (!erase_region_p) {
- 			kfree(concat);
--			printk ("memory allocation error while creating erase region list"
--			        " for device \"%s\"\n", name);
-+			printk
-+			    ("memory allocation error while creating erase region list"
-+			     " for device \"%s\"\n", name);
- 			return NULL;
- 		}
- 
-@@ -820,46 +823,53 @@
- 		 */
- 		curr_erasesize = subdev[0]->erasesize;
- 		begin = position = 0;
--		for(i = 0; i < num_devs; i++)
--		{
--			if(subdev[i]->numeraseregions == 0)
--			{	/* current subdevice has uniform erase size */
--				if(subdev[i]->erasesize != curr_erasesize)
--				{	/*
-+		for (i = 0; i < num_devs; i++) {
-+			if (subdev[i]->numeraseregions == 0) {
-+				/* current subdevice has uniform erase size */
-+				if (subdev[i]->erasesize != curr_erasesize) {
-+					/*
- 					 *  fill in an mtd_erase_region_info structure for the area
- 					 *  we have walked so far:
- 					 */
--					erase_region_p->offset    = begin;
--					erase_region_p->erasesize = curr_erasesize;
--					erase_region_p->numblocks = (position - begin) / curr_erasesize;
-+					erase_region_p->offset = begin;
-+					erase_region_p->erasesize =
-+					    curr_erasesize;
-+					erase_region_p->numblocks =
-+					    (position - begin) / curr_erasesize;
- 					begin = position;
- 
- 					curr_erasesize = subdev[i]->erasesize;
- 					++erase_region_p;
- 				}
- 				position += subdev[i]->size;
--			}
--			else
--			{	/* current subdevice has variable erase size */
-+			} else {
-+				/* current subdevice has variable erase size */
- 				int j;
--				for(j = 0; j < subdev[i]->numeraseregions; j++)
--				{	/* walk the list of erase regions, count any changes */
--					if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
--					{
--						erase_region_p->offset    = begin;
--						erase_region_p->erasesize = curr_erasesize;
--						erase_region_p->numblocks = (position - begin) / curr_erasesize;
-+				for (j = 0; j < subdev[i]->numeraseregions; j++) {
-+					/* walk the list of erase regions, count any changes */
-+					if (subdev[i]->eraseregions[j].
-+					    erasesize != curr_erasesize) {
-+						erase_region_p->offset = begin;
-+						erase_region_p->erasesize =
-+						    curr_erasesize;
-+						erase_region_p->numblocks =
-+						    (position -
-+						     begin) / curr_erasesize;
- 						begin = position;
- 
--						curr_erasesize = subdev[i]->eraseregions[j].erasesize;
-+						curr_erasesize =
-+						    subdev[i]->eraseregions[j].
-+						    erasesize;
- 						++erase_region_p;
- 					}
--					position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
-+					position +=
-+					    subdev[i]->eraseregions[j].
-+					    numblocks * curr_erasesize;
- 				}
- 			}
- 		}
- 		/* Now write the final entry */
--		erase_region_p->offset    = begin;
-+		erase_region_p->offset = begin;
- 		erase_region_p->erasesize = curr_erasesize;
- 		erase_region_p->numblocks = (position - begin) / curr_erasesize;
- 	}
-@@ -874,16 +884,14 @@
- void mtd_concat_destroy(struct mtd_info *mtd)
- {
- 	struct mtd_concat *concat = CONCAT(mtd);
--	if(concat->mtd.numeraseregions)
-+	if (concat->mtd.numeraseregions)
- 		kfree(concat->mtd.eraseregions);
- 	kfree(concat);
- }
- 
--
- EXPORT_SYMBOL(mtd_concat_create);
- EXPORT_SYMBOL(mtd_concat_destroy);
- 
--
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
- MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
-Index: linux-2.6.5/drivers/mtd/mtdcore.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/mtdcore.c	2005-02-01 16:55:50.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtdcore.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,12 +1,11 @@
- /*
-- * $Id: mtdcore.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $
-+ * $Id: mtdcore.c,v 1.43 2004/07/23 15:20:46 dwmw2 Exp $
-  *
-  * Core registration and callback routines for MTD
-  * drivers and users.
-  *
-  */
- 
--#include <linux/version.h>
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
-@@ -59,7 +58,6 @@
- 			mtd_table[i] = mtd;
- 			mtd->index = i;
- 			mtd->usecount = 0;
--			init_MUTEX(&mtd->mutex);
- 
- 			DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
- 			/* No need to get a refcount on the module containing
-@@ -233,7 +231,7 @@
-  *			dont implement their own
-  */
- 
--int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
- 		       unsigned long count, loff_t to, size_t *retlen)
- {
- 	unsigned long i;
-@@ -263,7 +261,7 @@
-  *		       implement their own
-  */
- 
--int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
-+int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
- 		      unsigned long count, loff_t from, size_t *retlen)
- {
- 	unsigned long i;
-@@ -335,10 +333,7 @@
- /* 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)
- {
-@@ -351,13 +346,8 @@
- 		       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;
-@@ -377,9 +367,7 @@
-                 }
-         }
- 
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-         *eof = 1;
--#endif
- 
- done:
- 	up(&mtd_table_mutex);
-@@ -389,18 +377,6 @@
-         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 */
- 
- /*====================================================================*/
-@@ -409,16 +385,8 @@
- 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, 0 )))
--	  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();
-+	if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
-+		proc_mtd->read_proc = mtd_read_proc;
- #endif
- 
- #ifdef CONFIG_PM
-@@ -437,12 +405,8 @@
- #endif
- 
- #ifdef CONFIG_PROC_FS
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-         if (proc_mtd)
--          remove_proc_entry( "mtd", 0);
--#else
--        proc_unregister(&proc_root,mtd_proc_entry.low_ino);
--#endif
-+		remove_proc_entry( "mtd", NULL);
- #endif
- }
- 
-Index: linux-2.6.5/drivers/mtd/mtdpart.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/mtdpart.c	2004-04-03 22:37:38.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/mtdpart.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.50 2004/08/10 16:18:34 dwmw2 Exp $
-  *
-  * 	02-21-2002	Thomas Gleixner <gleixner@autronix.de>
-  *			added support for read_oob, write_oob
-@@ -182,7 +182,7 @@
- 					len, retlen, buf);
- }
- 
--static int part_writev (struct mtd_info *mtd,  const struct iovec *vecs,
-+static int part_writev (struct mtd_info *mtd,  const struct kvec *vecs,
- 			 unsigned long count, loff_t to, size_t *retlen)
- {
- 	struct mtd_part *part = PART(mtd);
-@@ -197,7 +197,7 @@
- 					NULL, &mtd->oobinfo);
- }
- 
--static int part_readv (struct mtd_info *mtd,  struct iovec *vecs,
-+static int part_readv (struct mtd_info *mtd,  struct kvec *vecs,
- 			 unsigned long count, loff_t from, size_t *retlen)
- {
- 	struct mtd_part *part = PART(mtd);
-@@ -210,7 +210,7 @@
- 					NULL, &mtd->oobinfo);
- }
- 
--static int part_writev_ecc (struct mtd_info *mtd,  const struct iovec *vecs,
-+static int part_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)
- {
-@@ -224,7 +224,7 @@
- 					eccbuf, oobsel);
- }
- 
--static int part_readv_ecc (struct mtd_info *mtd,  struct iovec *vecs,
-+static int part_readv_ecc (struct mtd_info *mtd,  struct kvec *vecs,
- 			 unsigned long count, loff_t from, size_t *retlen,
- 			 u_char *eccbuf,  struct nand_oobinfo *oobsel)
- {
-@@ -239,13 +239,29 @@
- 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);
-+	return ret;
-+}
-+
-+void mtd_erase_callback(struct erase_info *instr)
-+{
-+	if (instr->mtd->erase == part_erase) {
-+		struct mtd_part *part = PART(instr->mtd);
-+
-+		if (instr->fail_addr != 0xffffffff)
-+			instr->fail_addr -= part->offset;
-+		instr->addr -= part->offset;
-+	}
-+	if (instr->callback)
-+		instr->callback(instr);
- }
-+EXPORT_SYMBOL_GPL(mtd_erase_callback);
- 
- static int part_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
- {
-@@ -281,6 +297,26 @@
- 	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 +352,7 @@
-  */
- 
- 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 +427,10 @@
- 			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 +501,9 @@
- 				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: linux-2.6.5/drivers/mtd/nand/Kconfig
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/Kconfig	2004-04-03 22:37:41.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/Kconfig	2005-02-01 17:11:17.000000000 -0500
-@@ -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.19 2004/09/16 23:23:42 gleixner Exp $
- 
- menu "NAND Flash Device Drivers"
- 	depends on MTD!=n
-@@ -9,8 +9,8 @@
- 	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 www.linux-mtd.infradead.org/tech/nand.html.
-+	  devices. For further information see
-+	  <http://www.linux-mtd.infradead.org/tech/nand.html>.
- 
- config MTD_NAND_VERIFY_WRITE
- 	bool "Verify NAND page writes"
-@@ -36,16 +36,129 @@
- 	  This enables the driver for the Cirrus Logic EBD7312 evaluation 
- 	  board to access the onboard NAND Flash.
- 
-+config MTD_NAND_H1900
-+	tristate "iPAQ H1900 flash"
-+	depends on ARM && MTD_NAND && ARCH_PXA && MTD_PARTITIONS
-+	help
-+	  This enables the driver for the iPAQ h1900 flash.
-+
- config MTD_NAND_SPIA
- 	tristate "NAND Flash device on SPIA board"
- 	depends on ARM && ARCH_P720T && MTD_NAND
- 	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_RTC_FROM4
-+	tristate "Renesas Flash ROM 4-slot interface board (FROM_BOARD4)"
-+	depends on MTD_NAND && SH_SOLUTION_ENGINE
-+	help
-+	  This enables the driver for the Renesas Technology AG-AND 
-+	  flash interface board (FROM_BOARD4)
-+
-+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, Millennium and Millennium Plus (NAND reimplementation) (EXPERIMENTAL)"
-+	depends on MTD_NAND && EXPERIMENTAL
-+	select REED_SOLOMON
-+	help
-+	  This is a reimplementation of M-Systems DiskOnChip 2000,
-+	  Millennium and Millennium Plus 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_PROBE_ADVANCED
-+        bool "Advanced detection options for DiskOnChip"
-+        depends on MTD_NAND_DISKONCHIP
-+        help
-+          This option allows you to specify nonstandard address at which to
-+          probe for a DiskOnChip, or to change the detection options.  You
-+          are unlikely to need any of this unless you are using LinuxBIOS.
-+          Say 'N'.
-+
-+config MTD_NAND_DISKONCHIP_PROBE_ADDRESS
-+        hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-+        depends on MTD_NAND_DISKONCHIP
-+        default "0"
-+        ---help---
-+        By default, the probe for DiskOnChip devices will look for a
-+        DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-+        This option allows you to specify a single address at which to probe
-+        for the device, which is useful if you have other devices in that
-+        range which get upset when they are probed.
-+
-+        (Note that on PowerPC, the normal probe will only check at
-+        0xE4000000.)
-+
-+        Normally, you should leave this set to zero, to allow the probe at
-+        the normal addresses.
-+
-+config MTD_NAND_DISKONCHIP_PROBE_HIGH
-+        bool "Probe high addresses"
-+        depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED
-+        help
-+          By default, the probe for DiskOnChip devices will look for a
-+          DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-+          This option changes to make it probe between 0xFFFC8000 and
-+          0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
-+          useful to you.  Say 'N'.
-+
-+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: linux-2.6.5/drivers/mtd/nand/Makefile
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/Makefile	2004-04-03 22:36:14.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/Makefile	2005-02-01 17:11:17.000000000 -0500
-@@ -1,10 +1,21 @@
- #
- # linux/drivers/nand/Makefile
- #
--# $Id: Makefile.common,v 1.2 2003/05/28 11:38:54 dwmw2 Exp $
-+# $Id: Makefile.common,v 1.11 2004/09/16 23:23:42 gleixner 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
-+obj-$(CONFIG_MTD_NAND_H1900)		+= h1910.o
-+obj-$(CONFIG_MTD_NAND_FROM4)		+= rtc_from4.o
-+
-+nand-objs = nand_base.o nand_bbt.o
-Index: linux-2.6.5/drivers/mtd/nand/au1550nd.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/au1550nd.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/au1550nd.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,481 @@
-+/*
-+ *  drivers/mtd/nand/au1550nd.c
-+ *
-+ *  Copyright (C) 2004 Embedded Edge, LLC
-+ *
-+ * $Id: au1550nd.c,v 1.8 2004/09/16 23:27:14 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/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/au1000.h>
-+#ifdef CONFIG_MIPS_PB1550
-+#include <asm/pb1550.h> 
-+#endif
-+#ifdef CONFIG_MIPS_DB1550
-+#include <asm/db1x00.h> 
-+#endif
-+
-+
-+/*
-+ * MTD structure for NAND controller
-+ */
-+static struct mtd_info *au1550_mtd = NULL;
-+static void __iomem *p_nand;
-+static int nand_width = 1; /* default x8*/
-+
-+/*
-+ * Define partitions for flash device
-+ */
-+const static struct mtd_partition partition_info[] = {
-+#ifdef CONFIG_MIPS_PB1550
-+#define NUM_PARTITIONS            2
-+	{ 
-+		.name = "Pb1550 NAND FS 0",
-+	  	.offset = 0,
-+	  	.size = 8*1024*1024 
-+	},
-+	{ 
-+		.name = "Pb1550 NAND FS 1",
-+		.offset =  MTDPART_OFS_APPEND,
-+ 		.size =    MTDPART_SIZ_FULL
-+	}
-+#endif
-+#ifdef CONFIG_MIPS_DB1550
-+#define NUM_PARTITIONS            2
-+	{ 
-+		.name = "Db1550 NAND FS 0",
-+	  	.offset = 0,
-+	  	.size = 8*1024*1024 
-+	},
-+	{ 
-+		.name = "Db1550 NAND FS 1",
-+		.offset =  MTDPART_OFS_APPEND,
-+ 		.size =    MTDPART_SIZ_FULL
-+	}
-+#endif
-+};
-+
-+
-+/**
-+ * au_read_byte -  read one byte from the chip
-+ * @mtd:	MTD device structure
-+ *
-+ *  read function for 8bit buswith
-+ */
-+static u_char au_read_byte(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	u_char ret = readb(this->IO_ADDR_R);
-+	au_sync();
-+	return ret;
-+}
-+
-+/**
-+ * au_write_byte -  write one byte to the chip
-+ * @mtd:	MTD device structure
-+ * @byte:	pointer to data byte to write
-+ *
-+ *  write function for 8it buswith
-+ */
-+static void au_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	writeb(byte, this->IO_ADDR_W);
-+	au_sync();
-+}
-+
-+/**
-+ * au_read_byte16 -  read one byte endianess aware from the chip
-+ * @mtd:	MTD device structure
-+ *
-+ *  read function for 16bit buswith with 
-+ * endianess conversion
-+ */
-+static u_char au_read_byte16(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	u_char ret = (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
-+	au_sync();
-+	return ret;
-+}
-+
-+/**
-+ * au_write_byte16 -  write one byte endianess aware to the chip
-+ * @mtd:	MTD device structure
-+ * @byte:	pointer to data byte to write
-+ *
-+ *  write function for 16bit buswith with
-+ * endianess conversion
-+ */
-+static void au_write_byte16(struct mtd_info *mtd, u_char byte)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
-+	au_sync();
-+}
-+
-+/**
-+ * au_read_word -  read one word from the chip
-+ * @mtd:	MTD device structure
-+ *
-+ *  read function for 16bit buswith without 
-+ * endianess conversion
-+ */
-+static u16 au_read_word(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	u16 ret = readw(this->IO_ADDR_R);
-+	au_sync();
-+	return ret;
-+}
-+
-+/**
-+ * au_write_word -  write one word to the chip
-+ * @mtd:	MTD device structure
-+ * @word:	data word to write
-+ *
-+ *  write function for 16bit buswith without 
-+ * endianess conversion
-+ */
-+static void au_write_word(struct mtd_info *mtd, u16 word)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	writew(word, this->IO_ADDR_W);
-+	au_sync();
-+}
-+
-+/**
-+ * au_write_buf -  write buffer to chip
-+ * @mtd:	MTD device structure
-+ * @buf:	data buffer
-+ * @len:	number of bytes to write
-+ *
-+ *  write function for 8bit buswith
-+ */
-+static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++) {
-+		writeb(buf[i], this->IO_ADDR_W);
-+		au_sync();
-+	}
-+}
-+
-+/**
-+ * au_read_buf -  read chip data into buffer 
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer to store date
-+ * @len:	number of bytes to read
-+ *
-+ *  read function for 8bit buswith
-+ */
-+static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++) {
-+		buf[i] = readb(this->IO_ADDR_R);
-+		au_sync();	
-+	}
-+}
-+
-+/**
-+ * au_verify_buf -  Verify chip data against buffer 
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer containing the data to compare
-+ * @len:	number of bytes to compare
-+ *
-+ *  verify function for 8bit buswith
-+ */
-+static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++) {
-+		if (buf[i] != readb(this->IO_ADDR_R))
-+			return -EFAULT;
-+		au_sync();
-+	}
-+
-+	return 0;
-+}
-+
-+/**
-+ * au_write_buf16 -  write buffer to chip
-+ * @mtd:	MTD device structure
-+ * @buf:	data buffer
-+ * @len:	number of bytes to write
-+ *
-+ *  write function for 16bit buswith
-+ */
-+static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+	u16 *p = (u16 *) buf;
-+	len >>= 1;
-+	
-+	for (i=0; i<len; i++) {
-+		writew(p[i], this->IO_ADDR_W);
-+		au_sync();
-+	}
-+		
-+}
-+
-+/**
-+ * au_read_buf16 -  read chip data into buffer 
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer to store date
-+ * @len:	number of bytes to read
-+ *
-+ *  read function for 16bit buswith
-+ */
-+static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+	u16 *p = (u16 *) buf;
-+	len >>= 1;
-+
-+	for (i=0; i<len; i++) {
-+		p[i] = readw(this->IO_ADDR_R);
-+		au_sync();
-+	}
-+}
-+
-+/**
-+ * au_verify_buf16 -  Verify chip data against buffer 
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer containing the data to compare
-+ * @len:	number of bytes to compare
-+ *
-+ *  verify function for 16bit buswith
-+ */
-+static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+	u16 *p = (u16 *) buf;
-+	len >>= 1;
-+
-+	for (i=0; i<len; i++) {
-+		if (p[i] != readw(this->IO_ADDR_R))
-+			return -EFAULT;
-+		au_sync();
-+	}
-+	return 0;
-+}
-+
-+
-+static void au1550_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+	register struct nand_chip *this = mtd->priv;
-+
-+	switch(cmd){
-+
-+	case NAND_CTL_SETCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_CMD; break;
-+	case NAND_CTL_CLRCLE: this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; break;
-+
-+	case NAND_CTL_SETALE: this->IO_ADDR_W = p_nand + MEM_STNAND_ADDR; break;
-+	case NAND_CTL_CLRALE: 
-+		this->IO_ADDR_W = p_nand + MEM_STNAND_DATA; 
-+		/* FIXME: Nobody knows why this is neccecary, 
-+		 * but it works onlythat way */
-+		udelay(1); 
-+		break;
-+
-+	case NAND_CTL_SETNCE: 
-+		/* assert (force assert) chip enable */
-+		au_writel(au_readl(MEM_STNDCTL) | 0x20 , MEM_STNDCTL);
-+		break;
-+
-+	case NAND_CTL_CLRNCE: 
-+ 		/* deassert chip enable */
-+		au_writel(au_readl(MEM_STNDCTL) & ~0x20 , MEM_STNDCTL);
-+		break;
-+	}
-+
-+	this->IO_ADDR_R = this->IO_ADDR_W;
-+	
-+	/* Drain the writebuffer */
-+	au_sync();
-+}
-+
-+int au1550_device_ready(struct mtd_info *mtd)
-+{
-+	int ret = (au_readl(MEM_STSTAT) & 0x1) ? 1 : 0;
-+	au_sync();
-+	return ret;
-+}
-+
-+/*
-+ * Main initialization routine
-+ */
-+int __init au1550_init (void)
-+{
-+	struct nand_chip *this;
-+	u16 boot_swapboot = 0; /* default value */
-+	u32 mem_time;
-+	int retval;
-+
-+	/* Allocate memory for MTD device structure and private data */
-+	au1550_mtd = kmalloc (sizeof(struct mtd_info) + 
-+			sizeof (struct nand_chip), GFP_KERNEL);
-+	if (!au1550_mtd) {
-+		printk ("Unable to allocate NAND MTD dev structure.\n");
-+		return -ENOMEM;
-+	}
-+
-+	/* Get pointer to private data */
-+	this = (struct nand_chip *) (&au1550_mtd[1]);
-+
-+	/* Initialize structures */
-+	memset((char *) au1550_mtd, 0, sizeof(struct mtd_info));
-+	memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+	/* Link the private data with the MTD structure */
-+	au1550_mtd->priv = this;
-+
-+	/* disable interrupts */
-+	au_writel(au_readl(MEM_STNDCTL) & ~(1<<8), MEM_STNDCTL);
-+
-+	/* disable NAND boot */
-+	au_writel(au_readl(MEM_STNDCTL) & ~(1<<0), MEM_STNDCTL);
-+
-+#ifdef CONFIG_MIPS_PB1550
-+	/* set gpio206 high */
-+	au_writel(au_readl(GPIO2_DIR) & ~(1<<6), GPIO2_DIR);
-+
-+	boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) | 
-+		((bcsr->status >> 6)  & 0x1);
-+	switch (boot_swapboot) {
-+		case 0:
-+		case 2:
-+		case 8:
-+		case 0xC:
-+		case 0xD:
-+			/* x16 NAND Flash */
-+			nand_width = 0;
-+			break;
-+		case 1:
-+		case 9:
-+		case 3:
-+		case 0xE:
-+		case 0xF:
-+			/* x8 NAND Flash */
-+			nand_width = 1;
-+			break;
-+		default:
-+			printk("Pb1550 NAND: bad boot:swap\n");
-+			retval = -EINVAL;
-+			goto outmem;
-+	}
-+
-+	/* Configure RCE1 - should be done by YAMON */
-+	au_writel(0x5 | (nand_width << 22), MEM_STCFG1);
-+	au_writel(NAND_TIMING, MEM_STTIME1);
-+	mem_time = au_readl(MEM_STTIME1);
-+	au_sync();
-+
-+	/* setup and enable chip select */
-+	/* we really need to decode offsets only up till 0x20 */
-+	au_writel((1<<28) | (NAND_PHYS_ADDR>>4) | 
-+			(((NAND_PHYS_ADDR + 0x1000)-1) & (0x3fff<<18)>>18), 
-+			MEM_STADDR1);
-+	au_sync();
-+#endif
-+
-+#ifdef CONFIG_MIPS_DB1550
-+	/* FIXME: should be done by the bootloader
-+	 *  
-+	 * tglx: stcfg1 was set to 0x00400005. I changed
-+	 * this as it does not work with all chips.
-+	 * someone should look into the correct timing
-+	 * values, as bit 8 does a clock / 4 prescale
-+	*/
-+	au_writel(0x00400105, MEM_STCFG1);
-+	au_writel(0x00007774, MEM_STTIME1);
-+	au_writel(0x12003FFF, MEM_STADDR1);
-+#endif
-+
-+	p_nand = (void __iomem *)ioremap(NAND_PHYS_ADDR, 0x1000);
-+
-+	/* Set address of hardware control function */
-+	this->hwcontrol = au1550_hwcontrol;
-+	this->dev_ready = au1550_device_ready;
-+	/* 30 us command delay time */
-+	this->chip_delay = 30;		
-+	this->eccmode = NAND_ECC_SOFT;
-+
-+	this->options = NAND_NO_AUTOINCR;
-+
-+	if (!nand_width)
-+		this->options |= NAND_BUSWIDTH_16;
-+
-+	this->read_byte = (!nand_width) ? au_read_byte16 : au_read_byte;
-+	this->write_byte = (!nand_width) ? au_write_byte16 : au_write_byte;
-+	this->write_word = au_write_word;
-+	this->read_word = au_read_word;
-+	this->write_buf = (!nand_width) ? au_write_buf16 : au_write_buf;
-+	this->read_buf = (!nand_width) ? au_read_buf16 : au_read_buf;
-+	this->verify_buf = (!nand_width) ? au_verify_buf16 : au_verify_buf;
-+
-+	/* Scan to find existence of the device */
-+	if (nand_scan (au1550_mtd, 1)) {
-+		retval = -ENXIO;
-+		goto outio;
-+	}
-+
-+	/* Register the partitions */
-+	add_mtd_partitions(au1550_mtd, partition_info, NUM_PARTITIONS);
-+
-+	return 0;
-+
-+ outio:
-+	iounmap ((void *)p_nand);
-+	
-+ outmem:
-+	kfree (au1550_mtd);
-+	return retval;
-+}
-+
-+module_init(au1550_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+#ifdef MODULE
-+static void __exit au1550_cleanup (void)
-+{
-+	struct nand_chip *this = (struct nand_chip *) &au1550_mtd[1];
-+
-+	/* Release resources, unregister device */
-+	nand_release (au1550_mtd);
-+
-+	/* Free the MTD device structure */
-+	kfree (au1550_mtd);
-+
-+	/* Unmap */
-+	iounmap ((void *)p_nand);
-+}
-+module_exit(au1550_cleanup);
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Embedded Edge, LLC");
-+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Pb1550 board");
-Index: linux-2.6.5/drivers/mtd/nand/autcpu12.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/autcpu12.c	2004-04-03 22:36:25.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/autcpu12.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.21 2004/09/16 23:27:14 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
-@@ -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
-@@ -44,19 +44,11 @@
-  */
- static struct mtd_info *autcpu12_mtd = NULL;
- 
--/*
-- * Module stuff
-- */
--#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
--#define autcpu12_init init_module
--#define autcpu12_cleanup cleanup_module
--#endif
--
- static int autcpu12_io_base = CS89712_VIRT_BASE;
- static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC;
- static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET;
- static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET;
--static int autcpu12_fio_base;
-+static void __iomem * autcpu12_fio_base;
- 
- #ifdef MODULE
- MODULE_PARM(autcpu12_fio_pbase, "i");
-@@ -71,42 +63,40 @@
- /*
-  * 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 +106,7 @@
- /* 
-  *	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 +125,13 @@
- /*
- *	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
-  */
-@@ -159,7 +150,7 @@
- 	}
- 
- 	/* map physical adress */
--	autcpu12_fio_base=(unsigned long)ioremap(autcpu12_fio_pbase,SZ_1K);
-+	autcpu12_fio_base=(void __iomem *)ioremap(autcpu12_fio_pbase,SZ_1K);
- 	if(!autcpu12_fio_base){
- 		printk("Ioremap autcpu12 SmartMedia Card failed\n");
- 		err = -EIO;
-@@ -185,20 +176,18 @@
- 	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 +197,11 @@
- 		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 +218,12 @@
- #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: linux-2.6.5/drivers/mtd/nand/diskonchip.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/diskonchip.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/diskonchip.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,1637 @@
-+/* 
-+ * drivers/mtd/nand/diskonchip.c
-+ *
-+ * (C) 2003 Red Hat, Inc.
-+ * (C) 2004 Dan Brown <dan_brown@ieee.org>
-+ * (C) 2004 Kalev Lember <kalev@smartlink.ee>
-+ *
-+ * Author: David Woodhouse <dwmw2@infradead.org>
-+ * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
-+ * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
-+ *
-+ * Interface to generic NAND code for M-Systems DiskOnChip devices
-+ *
-+ * $Id: diskonchip.c,v 1.35 2004/09/16 23:27:14 gleixner Exp $
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <asm/io.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/doc2000.h>
-+#include <linux/mtd/compatmac.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/mtd/inftl.h>
-+
-+/* Where to look for the devices? */
-+#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
-+#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
-+#endif
-+
-+static unsigned long __initdata doc_locations[] = {
-+#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-+#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
-+	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 
-+	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
-+	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, 
-+	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 
-+	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
-+#else /*  CONFIG_MTD_DOCPROBE_HIGH */
-+	0xc8000, 0xca000, 0xcc000, 0xce000, 
-+	0xd0000, 0xd2000, 0xd4000, 0xd6000,
-+	0xd8000, 0xda000, 0xdc000, 0xde000, 
-+	0xe0000, 0xe2000, 0xe4000, 0xe6000, 
-+	0xe8000, 0xea000, 0xec000, 0xee000,
-+#endif /*  CONFIG_MTD_DOCPROBE_HIGH */
-+#elif defined(__PPC__)
-+	0xe4000000,
-+#elif defined(CONFIG_MOMENCO_OCELOT)
-+	0x2f000000,
-+        0xff000000,
-+#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
-+        0xff000000,
-+##else
-+#warning Unknown architecture for DiskOnChip. No default probe locations defined
-+#endif
-+	0xffffffff };
-+
-+static struct mtd_info *doclist = NULL;
-+
-+struct doc_priv {
-+	void __iomem *virtadr;
-+	unsigned long physadr;
-+	u_char ChipID;
-+	u_char CDSNControl;
-+	int chips_per_floor; /* The number of chips detected on each floor */
-+	int curfloor;
-+	int curchip;
-+	int mh0_page;
-+	int mh1_page;
-+	struct mtd_info *nextdoc;
-+};
-+
-+/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
-+   MediaHeader.  The spec says to just keep going, I think, but that's just
-+   silly. */
-+#define MAX_MEDIAHEADER_SCAN 8
-+
-+/* This is the syndrome computed by the HW ecc generator upon reading an empty
-+   page, one with all 0xff for data and stored ecc code. */
-+static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
-+/* This is the ecc value computed by the HW ecc generator upon writing an empty
-+   page, one with all 0xff for data. */
-+static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
-+
-+#define INFTL_BBT_RESERVED_BLOCKS 4
-+
-+#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
-+#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
-+#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
-+
-+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd);
-+static void doc200x_select_chip(struct mtd_info *mtd, int chip);
-+
-+static int debug=0;
-+MODULE_PARM(debug, "i");
-+
-+static int try_dword=1;
-+MODULE_PARM(try_dword, "i");
-+
-+static int no_ecc_failures=0;
-+MODULE_PARM(no_ecc_failures, "i");
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+static int no_autopart=0;
-+MODULE_PARM(no_autopart, "i");
-+#endif
-+
-+#ifdef MTD_NAND_DISKONCHIP_BBTWRITE
-+static int inftl_bbt_write=1;
-+#else
-+static int inftl_bbt_write=0;
-+#endif
-+MODULE_PARM(inftl_bbt_write, "i");
-+
-+static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
-+MODULE_PARM(doc_config_location, "l");
-+MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
-+
-+static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
-+{
-+	volatile char dummy;
-+	int i;
-+	
-+	for (i = 0; i < cycles; i++) {
-+		if (DoC_is_Millennium(doc))
-+			dummy = ReadDOC(doc->virtadr, NOP);
-+		else if (DoC_is_MillenniumPlus(doc))
-+			dummy = ReadDOC(doc->virtadr, Mplus_NOP);
-+		else
-+			dummy = ReadDOC(doc->virtadr, DOCStatus);
-+	}
-+	
-+}
-+
-+#define CDSN_CTRL_FR_B_MASK	(CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
-+
-+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
-+static int _DoC_WaitReady(struct doc_priv *doc)
-+{
-+        void __iomem *docptr = doc->virtadr;
-+	unsigned long timeo = jiffies + (HZ * 10);
-+
-+	if(debug) printk("_DoC_WaitReady...\n");
-+	/* Out-of-line routine to wait for chip response */
-+	if (DoC_is_MillenniumPlus(doc)) {
-+		while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
-+			if (time_after(jiffies, timeo)) {
-+				printk("_DoC_WaitReady timed out.\n");
-+				return -EIO;
-+			}
-+			udelay(1);
-+			cond_resched();
-+		}
-+	} else {
-+		while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
-+			if (time_after(jiffies, timeo)) {
-+				printk("_DoC_WaitReady timed out.\n");
-+				return -EIO;
-+			}
-+			udelay(1);
-+			cond_resched();
-+		}
-+	}
-+
-+	return 0;
-+}
-+
-+static inline int DoC_WaitReady(struct doc_priv *doc)
-+{
-+        void __iomem *docptr = doc->virtadr;
-+	int ret = 0;
-+
-+	if (DoC_is_MillenniumPlus(doc)) {
-+		DoC_Delay(doc, 4);
-+
-+		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
-+			/* Call the out-of-line routine to wait */
-+			ret = _DoC_WaitReady(doc);
-+	} else {
-+		DoC_Delay(doc, 4);
-+
-+		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
-+			/* Call the out-of-line routine to wait */
-+			ret = _DoC_WaitReady(doc);
-+		DoC_Delay(doc, 2);
-+	}
-+
-+	if(debug) printk("DoC_WaitReady OK\n");
-+	return ret;
-+}
-+
-+static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+
-+	if(debug)printk("write_byte %02x\n", datum);
-+	WriteDOC(datum, docptr, CDSNSlowIO);
-+	WriteDOC(datum, docptr, 2k_CDSN_IO);
-+}
-+
-+static u_char doc2000_read_byte(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	u_char ret;
-+
-+	ReadDOC(docptr, CDSNSlowIO);
-+	DoC_Delay(doc, 2);
-+	ret = ReadDOC(docptr, 2k_CDSN_IO);
-+	if (debug) printk("read_byte returns %02x\n", ret);
-+	return ret;
-+}
-+
-+static void doc2000_writebuf(struct mtd_info *mtd, 
-+			     const u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+	if (debug)printk("writebuf of %d bytes: ", len);
-+	for (i=0; i < len; i++) {
-+		WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
-+		if (debug && i < 16)
-+			printk("%02x ", buf[i]);
-+	}
-+	if (debug) printk("\n");
-+}
-+
-+static void doc2000_readbuf(struct mtd_info *mtd, 
-+			    u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+ 	int i;
-+
-+	if (debug)printk("readbuf of %d bytes: ", len);
-+
-+	for (i=0; i < len; i++) {
-+		buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
-+	}
-+}
-+
-+static void doc2000_readbuf_dword(struct mtd_info *mtd, 
-+			    u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+ 	int i;
-+
-+	if (debug) printk("readbuf_dword of %d bytes: ", len);
-+
-+	if (unlikely((((unsigned long)buf)|len) & 3)) {
-+		for (i=0; i < len; i++) {
-+			*(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i);
-+		}
-+	} else {
-+		for (i=0; i < len; i+=4) {
-+			*(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i);
-+		}
-+	}
-+}
-+
-+static int doc2000_verifybuf(struct mtd_info *mtd, 
-+			      const u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+
-+	for (i=0; i < len; i++)
-+		if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO))
-+			return -EFAULT;
-+	return 0;
-+}
-+
-+static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+	uint16_t ret;
-+
-+	doc200x_select_chip(mtd, nr);
-+	doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
-+	this->write_byte(mtd, NAND_CMD_READID);
-+	doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
-+	doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
-+	this->write_byte(mtd, 0);
-+	doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-+
-+	ret = this->read_byte(mtd) << 8;
-+	ret |= this->read_byte(mtd);
-+
-+	if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
-+		/* First chip probe. See if we get same results by 32-bit access */
-+		union {
-+			uint32_t dword;
-+			uint8_t byte[4];
-+		} ident;
-+		void __iomem *docptr = doc->virtadr;
-+
-+		doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
-+		doc2000_write_byte(mtd, NAND_CMD_READID);
-+		doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE);
-+		doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
-+		doc2000_write_byte(mtd, 0);
-+		doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-+
-+		ident.dword = readl(docptr + DoC_2k_CDSN_IO);
-+		if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
-+			printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
-+			this->read_buf = &doc2000_readbuf_dword;
-+		}
-+	}
-+		
-+	return ret;
-+}
-+
-+static void __init doc2000_count_chips(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+	uint16_t mfrid;
-+	int i;
-+
-+	/* Max 4 chips per floor on DiskOnChip 2000 */
-+	doc->chips_per_floor = 4;
-+
-+	/* Find out what the first chip is */
-+	mfrid = doc200x_ident_chip(mtd, 0);
-+
-+	/* Find how many chips in each floor. */
-+	for (i = 1; i < 4; i++) {
-+		if (doc200x_ident_chip(mtd, i) != mfrid)
-+			break;
-+	}
-+	doc->chips_per_floor = i;
-+	printk(KERN_DEBUG "Detected %d chips per floor.\n", i);
-+}
-+
-+static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
-+{
-+	struct doc_priv *doc = (void *)this->priv;
-+
-+	int status;
-+	
-+	DoC_WaitReady(doc);
-+	this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
-+	DoC_WaitReady(doc);
-+	status = (int)this->read_byte(mtd);
-+
-+	return status;
-+}
-+
-+static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+
-+	WriteDOC(datum, docptr, CDSNSlowIO);
-+	WriteDOC(datum, docptr, Mil_CDSN_IO);
-+	WriteDOC(datum, docptr, WritePipeTerm);
-+}
-+
-+static u_char doc2001_read_byte(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+
-+	//ReadDOC(docptr, CDSNSlowIO);
-+	/* 11.4.5 -- delay twice to allow extended length cycle */
-+	DoC_Delay(doc, 2);
-+	ReadDOC(docptr, ReadPipeInit);
-+	//return ReadDOC(docptr, Mil_CDSN_IO);
-+	return ReadDOC(docptr, LastDataRead);
-+}
-+
-+static void doc2001_writebuf(struct mtd_info *mtd, 
-+			     const u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+
-+	for (i=0; i < len; i++)
-+		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
-+	/* Terminate write pipeline */
-+	WriteDOC(0x00, docptr, WritePipeTerm);
-+}
-+
-+static void doc2001_readbuf(struct mtd_info *mtd, 
-+			    u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+
-+	/* Start read pipeline */
-+	ReadDOC(docptr, ReadPipeInit);
-+
-+	for (i=0; i < len-1; i++)
-+		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
-+
-+	/* Terminate read pipeline */
-+	buf[i] = ReadDOC(docptr, LastDataRead);
-+}
-+
-+static int doc2001_verifybuf(struct mtd_info *mtd, 
-+			     const u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+
-+	/* Start read pipeline */
-+	ReadDOC(docptr, ReadPipeInit);
-+
-+	for (i=0; i < len-1; i++)
-+		if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
-+			ReadDOC(docptr, LastDataRead);
-+			return i;
-+		}
-+	if (buf[i] != ReadDOC(docptr, LastDataRead))
-+		return i;
-+	return 0;
-+}
-+
-+static u_char doc2001plus_read_byte(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	u_char ret;
-+
-+        ReadDOC(docptr, Mplus_ReadPipeInit);
-+        ReadDOC(docptr, Mplus_ReadPipeInit);
-+        ret = ReadDOC(docptr, Mplus_LastDataRead);
-+	if (debug) printk("read_byte returns %02x\n", ret);
-+	return ret;
-+}
-+
-+static void doc2001plus_writebuf(struct mtd_info *mtd, 
-+			     const u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+
-+	if (debug)printk("writebuf of %d bytes: ", len);
-+	for (i=0; i < len; i++) {
-+		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
-+		if (debug && i < 16)
-+			printk("%02x ", buf[i]);
-+	}
-+	if (debug) printk("\n");
-+}
-+
-+static void doc2001plus_readbuf(struct mtd_info *mtd, 
-+			    u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+
-+	if (debug)printk("readbuf of %d bytes: ", len);
-+
-+	/* Start read pipeline */
-+	ReadDOC(docptr, Mplus_ReadPipeInit);
-+	ReadDOC(docptr, Mplus_ReadPipeInit);
-+
-+	for (i=0; i < len-2; i++) {
-+		buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
-+		if (debug && i < 16)
-+			printk("%02x ", buf[i]);
-+	}
-+
-+	/* Terminate read pipeline */
-+	buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
-+	if (debug && i < 16)
-+		printk("%02x ", buf[len-2]);
-+	buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
-+	if (debug && i < 16)
-+		printk("%02x ", buf[len-1]);
-+	if (debug) printk("\n");
-+}
-+
-+static int doc2001plus_verifybuf(struct mtd_info *mtd, 
-+			     const u_char *buf, int len)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+
-+	if (debug)printk("verifybuf of %d bytes: ", len);
-+
-+	/* Start read pipeline */
-+	ReadDOC(docptr, Mplus_ReadPipeInit);
-+	ReadDOC(docptr, Mplus_ReadPipeInit);
-+
-+	for (i=0; i < len-2; i++)
-+		if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) {
-+			ReadDOC(docptr, Mplus_LastDataRead);
-+			ReadDOC(docptr, Mplus_LastDataRead);
-+			return i;
-+		}
-+	if (buf[len-2] != ReadDOC(docptr, Mplus_LastDataRead))
-+		return len-2;
-+	if (buf[len-1] != ReadDOC(docptr, Mplus_LastDataRead))
-+		return len-1;
-+	return 0;
-+}
-+
-+static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int floor = 0;
-+
-+	if(debug)printk("select chip (%d)\n", chip);
-+
-+	if (chip == -1) {
-+		/* Disable flash internally */
-+		WriteDOC(0, docptr, Mplus_FlashSelect);
-+		return;
-+	}
-+
-+	floor = chip / doc->chips_per_floor;
-+	chip -= (floor *  doc->chips_per_floor);
-+
-+	/* Assert ChipEnable and deassert WriteProtect */
-+	WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect);
-+	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-+
-+	doc->curchip = chip;
-+	doc->curfloor = floor;
-+}
-+
-+static void doc200x_select_chip(struct mtd_info *mtd, int chip)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int floor = 0;
-+
-+	if(debug)printk("select chip (%d)\n", chip);
-+
-+	if (chip == -1)
-+		return;
-+
-+	floor = chip / doc->chips_per_floor;
-+	chip -= (floor *  doc->chips_per_floor);
-+
-+	/* 11.4.4 -- deassert CE before changing chip */
-+	doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE);
-+
-+	WriteDOC(floor, docptr, FloorSelect);
-+	WriteDOC(chip, docptr, CDSNDeviceSelect);
-+
-+	doc200x_hwcontrol(mtd, NAND_CTL_SETNCE);
-+
-+	doc->curchip = chip;
-+	doc->curfloor = floor;
-+}
-+
-+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+
-+	switch(cmd) {
-+	case NAND_CTL_SETNCE:
-+		doc->CDSNControl |= CDSN_CTRL_CE;
-+		break;
-+	case NAND_CTL_CLRNCE:
-+		doc->CDSNControl &= ~CDSN_CTRL_CE;
-+		break;
-+	case NAND_CTL_SETCLE:
-+		doc->CDSNControl |= CDSN_CTRL_CLE;
-+		break;
-+	case NAND_CTL_CLRCLE:
-+		doc->CDSNControl &= ~CDSN_CTRL_CLE;
-+		break;
-+	case NAND_CTL_SETALE:
-+		doc->CDSNControl |= CDSN_CTRL_ALE;
-+		break;
-+	case NAND_CTL_CLRALE:
-+		doc->CDSNControl &= ~CDSN_CTRL_ALE;
-+		break;
-+	case NAND_CTL_SETWP:
-+		doc->CDSNControl |= CDSN_CTRL_WP;
-+		break;
-+	case NAND_CTL_CLRWP:
-+		doc->CDSNControl &= ~CDSN_CTRL_WP;
-+		break;
-+	}
-+	if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl);
-+	WriteDOC(doc->CDSNControl, docptr, CDSNControl);
-+	/* 11.4.3 -- 4 NOPs after CSDNControl write */
-+	DoC_Delay(doc, 4);
-+}
-+
-+static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+
-+	/*
-+	 * Must terminate write pipeline before sending any commands
-+	 * to the device.
-+	 */
-+	if (command == NAND_CMD_PAGEPROG) {
-+		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+		WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
-+	}
-+
-+	/*
-+	 * Write out the command to the device.
-+	 */
-+	if (command == NAND_CMD_SEQIN) {
-+		int readcmd;
-+
-+		if (column >= mtd->oobblock) {
-+			/* OOB area */
-+			column -= mtd->oobblock;
-+			readcmd = NAND_CMD_READOOB;
-+		} else if (column < 256) {
-+			/* First 256 bytes --> READ0 */
-+			readcmd = NAND_CMD_READ0;
-+		} else {
-+			column -= 256;
-+			readcmd = NAND_CMD_READ1;
-+		}
-+		WriteDOC(readcmd, docptr, Mplus_FlashCmd);
-+	}
-+	WriteDOC(command, docptr, Mplus_FlashCmd);
-+	WriteDOC(0, docptr, Mplus_WritePipeTerm);
-+	WriteDOC(0, docptr, Mplus_WritePipeTerm);
-+
-+	if (column != -1 || page_addr != -1) {
-+		/* Serially input address */
-+		if (column != -1) {
-+			/* Adjust columns for 16 bit buswidth */
-+			if (this->options & NAND_BUSWIDTH_16)
-+				column >>= 1;
-+			WriteDOC(column, docptr, Mplus_FlashAddress);
-+		}
-+		if (page_addr != -1) {
-+			WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress);
-+			WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress);
-+			/* One more address cycle for higher density devices */
-+			if (this->chipsize & 0x0c000000) {
-+				WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress);
-+				printk("high density\n");
-+			}
-+		}
-+		WriteDOC(0, docptr, Mplus_WritePipeTerm);
-+		WriteDOC(0, docptr, Mplus_WritePipeTerm);
-+		/* deassert ALE */
-+		if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID)
-+			WriteDOC(0, docptr, Mplus_FlashControl);
-+	}
-+
-+	/* 
-+	 * program and erase have their own busy handlers
-+	 * status and sequential in needs no delay
-+	*/
-+	switch (command) {
-+
-+	case NAND_CMD_PAGEPROG:
-+	case NAND_CMD_ERASE1:
-+	case NAND_CMD_ERASE2:
-+	case NAND_CMD_SEQIN:
-+	case NAND_CMD_STATUS:
-+		return;
-+
-+	case NAND_CMD_RESET:
-+		if (this->dev_ready)
-+			break;
-+		udelay(this->chip_delay);
-+		WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd);
-+		WriteDOC(0, docptr, Mplus_WritePipeTerm);
-+		WriteDOC(0, docptr, Mplus_WritePipeTerm);
-+		while ( !(this->read_byte(mtd) & 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;
-+		}
-+	}
-+
-+	/* Apply this short delay always to ensure that we do wait tWB in
-+	 * any case on any machine. */
-+	ndelay (100);
-+	/* wait until command is processed */
-+	while (!this->dev_ready(mtd));
-+}
-+
-+static int doc200x_dev_ready(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+
-+	if (DoC_is_MillenniumPlus(doc)) {
-+		/* 11.4.2 -- must NOP four times before checking FR/B# */
-+		DoC_Delay(doc, 4);
-+		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
-+			if(debug)
-+				printk("not ready\n");
-+			return 0;
-+		}
-+		if (debug)printk("was ready\n");
-+		return 1;
-+	} else {
-+		/* 11.4.2 -- must NOP four times before checking FR/B# */
-+		DoC_Delay(doc, 4);
-+		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
-+			if(debug)
-+				printk("not ready\n");
-+			return 0;
-+		}
-+		/* 11.4.2 -- Must NOP twice if it's ready */
-+		DoC_Delay(doc, 2);
-+		if (debug)printk("was ready\n");
-+		return 1;
-+	}
-+}
-+
-+static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
-+{
-+	/* This is our last resort if we couldn't find or create a BBT.  Just
-+	   pretend all blocks are good. */
-+	return 0;
-+}
-+
-+static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+
-+	/* Prime the ECC engine */
-+	switch(mode) {
-+	case NAND_ECC_READ:
-+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-+		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
-+		break;
-+	case NAND_ECC_WRITE:
-+		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-+		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
-+		break;
-+	}
-+}
-+
-+static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+
-+	/* Prime the ECC engine */
-+	switch(mode) {
-+	case NAND_ECC_READ:
-+		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
-+		break;
-+	case NAND_ECC_WRITE:
-+		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
-+		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
-+		break;
-+	}
-+}
-+
-+/* This code is only called on write */
-+static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
-+				 unsigned char *ecc_code)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	int i;
-+	int emptymatch = 1;
-+
-+	/* flush the pipeline */
-+	if (DoC_is_2000(doc)) {
-+		WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
-+		WriteDOC(0, docptr, 2k_CDSN_IO);
-+		WriteDOC(0, docptr, 2k_CDSN_IO);
-+		WriteDOC(0, docptr, 2k_CDSN_IO);
-+		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
-+	} else if (DoC_is_MillenniumPlus(doc)) {
-+		WriteDOC(0, docptr, Mplus_NOP);
-+		WriteDOC(0, docptr, Mplus_NOP);
-+		WriteDOC(0, docptr, Mplus_NOP);
-+	} else {
-+		WriteDOC(0, docptr, NOP);
-+		WriteDOC(0, docptr, NOP);
-+		WriteDOC(0, docptr, NOP);
-+	}
-+
-+	for (i = 0; i < 6; i++) {
-+		if (DoC_is_MillenniumPlus(doc))
-+			ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
-+		else 
-+			ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
-+		if (ecc_code[i] != empty_write_ecc[i])
-+			emptymatch = 0;
-+	}
-+	if (DoC_is_MillenniumPlus(doc))
-+		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
-+	else
-+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-+#if 0
-+	/* If emptymatch=1, we might have an all-0xff data buffer.  Check. */
-+	if (emptymatch) {
-+		/* Note: this somewhat expensive test should not be triggered
-+		   often.  It could be optimized away by examining the data in
-+		   the writebuf routine, and remembering the result. */
-+		for (i = 0; i < 512; i++) {
-+			if (dat[i] == 0xff) continue;
-+			emptymatch = 0;
-+			break;
-+		}
-+	}
-+	/* If emptymatch still =1, we do have an all-0xff data buffer.
-+	   Return all-0xff ecc value instead of the computed one, so
-+	   it'll look just like a freshly-erased page. */
-+	if (emptymatch) memset(ecc_code, 0xff, 6);
-+#endif
-+	return 0;
-+}
-+
-+static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
-+{
-+	int i, ret = 0;
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+        void __iomem *docptr = doc->virtadr;
-+	volatile u_char dummy;
-+	int emptymatch = 1;
-+	
-+	/* flush the pipeline */
-+	if (DoC_is_2000(doc)) {
-+		dummy = ReadDOC(docptr, 2k_ECCStatus);
-+		dummy = ReadDOC(docptr, 2k_ECCStatus);
-+		dummy = ReadDOC(docptr, 2k_ECCStatus);
-+	} else if (DoC_is_MillenniumPlus(doc)) {
-+		dummy = ReadDOC(docptr, Mplus_ECCConf);
-+		dummy = ReadDOC(docptr, Mplus_ECCConf);
-+		dummy = ReadDOC(docptr, Mplus_ECCConf);
-+	} else {
-+		dummy = ReadDOC(docptr, ECCConf);
-+		dummy = ReadDOC(docptr, ECCConf);
-+		dummy = ReadDOC(docptr, ECCConf);
-+	}
-+	
-+	/* Error occured ? */
-+	if (dummy & 0x80) {
-+		for (i = 0; i < 6; i++) {
-+			if (DoC_is_MillenniumPlus(doc))
-+				calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
-+			else
-+				calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
-+			if (calc_ecc[i] != empty_read_syndrome[i])
-+				emptymatch = 0;
-+		}
-+		/* If emptymatch=1, the read syndrome is consistent with an
-+		   all-0xff data and stored ecc block.  Check the stored ecc. */
-+		if (emptymatch) {
-+			for (i = 0; i < 6; i++) {
-+				if (read_ecc[i] == 0xff) continue;
-+				emptymatch = 0;
-+				break;
-+			}
-+		}
-+		/* If emptymatch still =1, check the data block. */
-+		if (emptymatch) {
-+		/* Note: this somewhat expensive test should not be triggered
-+		   often.  It could be optimized away by examining the data in
-+		   the readbuf routine, and remembering the result. */
-+			for (i = 0; i < 512; i++) {
-+				if (dat[i] == 0xff) continue;
-+				emptymatch = 0;
-+				break;
-+			}
-+		}
-+		/* If emptymatch still =1, this is almost certainly a freshly-
-+		   erased block, in which case the ECC will not come out right.
-+		   We'll suppress the error and tell the caller everything's
-+		   OK.  Because it is. */
-+		if (!emptymatch) ret = doc_decode_ecc (dat, calc_ecc);
-+		if (ret > 0)
-+			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
-+	}	
-+	if (DoC_is_MillenniumPlus(doc))
-+		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
-+	else
-+		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-+	if (no_ecc_failures && (ret == -1)) {
-+		printk(KERN_ERR "suppressing ECC failure\n");
-+		ret = 0;
-+	}
-+	return ret;
-+}
-+		
-+//u_char mydatabuf[528];
-+
-+static struct nand_oobinfo doc200x_oobinfo = {
-+        .useecc = MTD_NANDECC_AUTOPLACE,
-+        .eccbytes = 6,
-+        .eccpos = {0, 1, 2, 3, 4, 5},
-+        .oobfree = { {8, 8} }
-+};
-+ 
-+/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
-+   On sucessful return, buf will contain a copy of the media header for
-+   further processing.  id is the string to scan for, and will presumably be
-+   either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media
-+   header.  The page #s of the found media headers are placed in mh0_page and
-+   mh1_page in the DOC private structure. */
-+static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
-+				     const char *id, int findmirror)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+	unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
-+	int ret;
-+	size_t retlen;
-+
-+	end = min(end, mtd->size); // paranoia
-+	for (offs = 0; offs < end; offs += mtd->erasesize) {
-+		ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
-+		if (retlen != mtd->oobblock) continue;
-+		if (ret) {
-+			printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n",
-+				offs);
-+		}
-+		if (memcmp(buf, id, 6)) continue;
-+		printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
-+		if (doc->mh0_page == -1) {
-+			doc->mh0_page = offs >> this->page_shift;
-+			if (!findmirror) return 1;
-+			continue;
-+		}
-+		doc->mh1_page = offs >> this->page_shift;
-+		return 2;
-+	}
-+	if (doc->mh0_page == -1) {
-+		printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id);
-+		return 0;
-+	}
-+	/* Only one mediaheader was found.  We want buf to contain a
-+	   mediaheader on return, so we'll have to re-read the one we found. */
-+	offs = doc->mh0_page << this->page_shift;
-+	ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
-+	if (retlen != mtd->oobblock) {
-+		/* Insanity.  Give up. */
-+		printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n");
-+		return 0;
-+	}
-+	return 1;
-+}
-+
-+static inline int __init nftl_partscan(struct mtd_info *mtd,
-+				struct mtd_partition *parts)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+	int ret = 0;
-+	u_char *buf;
-+	struct NFTLMediaHeader *mh;
-+	const unsigned psize = 1 << this->page_shift;
-+	unsigned blocks, maxblocks;
-+	int offs, numheaders;
-+
-+	buf = (u_char *) kmalloc(mtd->oobblock, GFP_KERNEL);
-+	if (!buf) {
-+		printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
-+		return 0;
-+	}
-+	if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
-+	mh = (struct NFTLMediaHeader *) buf;
-+
-+//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+//	if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+	printk(KERN_INFO "    DataOrgID        = %s\n"
-+			 "    NumEraseUnits    = %d\n"
-+			 "    FirstPhysicalEUN = %d\n"
-+			 "    FormattedSize    = %d\n"
-+			 "    UnitSizeFactor   = %d\n",
-+		mh->DataOrgID, mh->NumEraseUnits,
-+		mh->FirstPhysicalEUN, mh->FormattedSize,
-+		mh->UnitSizeFactor);
-+//#endif
-+
-+	blocks = mtd->size >> this->phys_erase_shift;
-+	maxblocks = min(32768U, mtd->erasesize - psize);
-+
-+	if (mh->UnitSizeFactor == 0x00) {
-+		/* Auto-determine UnitSizeFactor.  The constraints are:
-+		   - There can be at most 32768 virtual blocks.
-+		   - There can be at most (virtual block size - page size)
-+		     virtual blocks (because MediaHeader+BBT must fit in 1).
-+		*/
-+		mh->UnitSizeFactor = 0xff;
-+		while (blocks > maxblocks) {
-+			blocks >>= 1;
-+			maxblocks = min(32768U, (maxblocks << 1) + psize);
-+			mh->UnitSizeFactor--;
-+		}
-+		printk(KERN_WARNING "UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
-+	}
-+
-+	/* NOTE: The lines below modify internal variables of the NAND and MTD
-+	   layers; variables with have already been configured by nand_scan.
-+	   Unfortunately, we didn't know before this point what these values
-+	   should be.  Thus, this code is somewhat dependant on the exact
-+	   implementation of the NAND layer.  */
-+	if (mh->UnitSizeFactor != 0xff) {
-+		this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
-+		mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
-+		printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize);
-+		blocks = mtd->size >> this->bbt_erase_shift;
-+		maxblocks = min(32768U, mtd->erasesize - psize);
-+	}
-+
-+	if (blocks > maxblocks) {
-+		printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);
-+		goto out;
-+	}
-+
-+	/* Skip past the media headers. */
-+	offs = max(doc->mh0_page, doc->mh1_page);
-+	offs <<= this->page_shift;
-+	offs += mtd->erasesize;
-+
-+	//parts[0].name = " DiskOnChip Boot / Media Header partition";
-+	//parts[0].offset = 0;
-+	//parts[0].size = offs;
-+
-+	parts[0].name = " DiskOnChip BDTL partition";
-+	parts[0].offset = offs;
-+	parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
-+
-+	offs += parts[0].size;
-+	if (offs < mtd->size) {
-+		parts[1].name = " DiskOnChip Remainder partition";
-+		parts[1].offset = offs;
-+		parts[1].size = mtd->size - offs;
-+		ret = 2;
-+		goto out;
-+	}
-+	ret = 1;
-+out:
-+	kfree(buf);
-+	return ret;
-+}
-+
-+/* This is a stripped-down copy of the code in inftlmount.c */
-+static inline int __init inftl_partscan(struct mtd_info *mtd,
-+				 struct mtd_partition *parts)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+	int ret = 0;
-+	u_char *buf;
-+	struct INFTLMediaHeader *mh;
-+	struct INFTLPartition *ip;
-+	int numparts = 0;
-+	int blocks;
-+	int vshift, lastvunit = 0;
-+	int i;
-+	int end = mtd->size;
-+
-+	if (inftl_bbt_write)
-+		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
-+
-+	buf = (u_char *) kmalloc(mtd->oobblock, GFP_KERNEL);
-+	if (!buf) {
-+		printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
-+		return 0;
-+	}
-+
-+	if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out;
-+	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
-+	mh = (struct INFTLMediaHeader *) buf;
-+
-+	mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
-+	mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
-+	mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
-+	mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits);
-+	mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
-+	mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
-+ 
-+//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+//	if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+	printk(KERN_INFO "    bootRecordID          = %s\n"
-+			 "    NoOfBootImageBlocks   = %d\n"
-+			 "    NoOfBinaryPartitions  = %d\n"
-+			 "    NoOfBDTLPartitions    = %d\n"
-+			 "    BlockMultiplerBits    = %d\n"
-+			 "    FormatFlgs            = %d\n"
-+			 "    OsakVersion           = %d.%d.%d.%d\n"
-+			 "    PercentUsed           = %d\n",
-+		mh->bootRecordID, mh->NoOfBootImageBlocks,
-+		mh->NoOfBinaryPartitions,
-+		mh->NoOfBDTLPartitions,
-+		mh->BlockMultiplierBits, mh->FormatFlags,
-+		((unsigned char *) &mh->OsakVersion)[0] & 0xf,
-+		((unsigned char *) &mh->OsakVersion)[1] & 0xf,
-+		((unsigned char *) &mh->OsakVersion)[2] & 0xf,
-+		((unsigned char *) &mh->OsakVersion)[3] & 0xf,
-+		mh->PercentUsed);
-+//#endif
-+
-+	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
-+
-+	blocks = mtd->size >> vshift;
-+	if (blocks > 32768) {
-+		printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);
-+		goto out;
-+	}
-+
-+	blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
-+	if (inftl_bbt_write && (blocks > mtd->erasesize)) {
-+		printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");
-+		goto out;
-+	}
-+
-+	/* Scan the partitions */
-+	for (i = 0; (i < 4); i++) {
-+		ip = &(mh->Partitions[i]);
-+		ip->virtualUnits = le32_to_cpu(ip->virtualUnits);
-+		ip->firstUnit = le32_to_cpu(ip->firstUnit);
-+		ip->lastUnit = le32_to_cpu(ip->lastUnit);
-+		ip->flags = le32_to_cpu(ip->flags);
-+		ip->spareUnits = le32_to_cpu(ip->spareUnits);
-+		ip->Reserved0 = le32_to_cpu(ip->Reserved0);
-+
-+//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-+//		if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
-+		printk(KERN_INFO	"    PARTITION[%d] ->\n"
-+			"        virtualUnits    = %d\n"
-+			"        firstUnit       = %d\n"
-+			"        lastUnit        = %d\n"
-+			"        flags           = 0x%x\n"
-+			"        spareUnits      = %d\n",
-+			i, ip->virtualUnits, ip->firstUnit,
-+			ip->lastUnit, ip->flags,
-+			ip->spareUnits);
-+//#endif
-+
-+/*
-+		if ((i == 0) && (ip->firstUnit > 0)) {
-+			parts[0].name = " DiskOnChip IPL / Media Header partition";
-+			parts[0].offset = 0;
-+			parts[0].size = mtd->erasesize * ip->firstUnit;
-+			numparts = 1;
-+		}
-+*/
-+
-+		if (ip->flags & INFTL_BINARY)
-+			parts[numparts].name = " DiskOnChip BDK partition";
-+		else
-+			parts[numparts].name = " DiskOnChip BDTL partition";
-+		parts[numparts].offset = ip->firstUnit << vshift;
-+		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
-+		numparts++;
-+		if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit;
-+		if (ip->flags & INFTL_LAST) break;
-+	}
-+	lastvunit++;
-+	if ((lastvunit << vshift) < end) {
-+		parts[numparts].name = " DiskOnChip Remainder partition";
-+		parts[numparts].offset = lastvunit << vshift;
-+		parts[numparts].size = end - parts[numparts].offset;
-+		numparts++;
-+	}
-+	ret = numparts;
-+out:
-+	kfree(buf);
-+	return ret;
-+}
-+
-+static int __init nftl_scan_bbt(struct mtd_info *mtd)
-+{
-+	int ret, numparts;
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+	struct mtd_partition parts[2];
-+
-+	memset((char *) parts, 0, sizeof(parts));
-+	/* On NFTL, we have to find the media headers before we can read the
-+	   BBTs, since they're stored in the media header eraseblocks. */
-+	numparts = nftl_partscan(mtd, parts);
-+	if (!numparts) return -EIO;
-+	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
-+				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
-+				NAND_BBT_VERSION;
-+	this->bbt_td->veroffs = 7;
-+	this->bbt_td->pages[0] = doc->mh0_page + 1;
-+	if (doc->mh1_page != -1) {
-+		this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
-+					NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
-+					NAND_BBT_VERSION;
-+		this->bbt_md->veroffs = 7;
-+		this->bbt_md->pages[0] = doc->mh1_page + 1;
-+	} else {
-+		this->bbt_md = NULL;
-+	}
-+
-+	/* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.
-+	   At least as nand_bbt.c is currently written. */
-+	if ((ret = nand_scan_bbt(mtd, NULL)))
-+		return ret;
-+	add_mtd_device(mtd);
-+#ifdef CONFIG_MTD_PARTITIONS
-+	if (!no_autopart)
-+		add_mtd_partitions(mtd, parts, numparts);
-+#endif
-+	return 0;
-+}
-+
-+static int __init inftl_scan_bbt(struct mtd_info *mtd)
-+{
-+	int ret, numparts;
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+	struct mtd_partition parts[5];
-+
-+	if (this->numchips > doc->chips_per_floor) {
-+		printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n");
-+		return -EIO;
-+	}
-+
-+	if (DoC_is_MillenniumPlus(doc)) {
-+		this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
-+		if (inftl_bbt_write)
-+			this->bbt_td->options |= NAND_BBT_WRITE;
-+		this->bbt_td->pages[0] = 2;
-+		this->bbt_md = NULL;
-+	} else {
-+		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
-+					NAND_BBT_VERSION;
-+		if (inftl_bbt_write)
-+			this->bbt_td->options |= NAND_BBT_WRITE;
-+		this->bbt_td->offs = 8;
-+		this->bbt_td->len = 8;
-+		this->bbt_td->veroffs = 7;
-+		this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
-+		this->bbt_td->reserved_block_code = 0x01;
-+		this->bbt_td->pattern = "MSYS_BBT";
-+
-+		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT |
-+					NAND_BBT_VERSION;
-+		if (inftl_bbt_write)
-+			this->bbt_md->options |= NAND_BBT_WRITE;
-+		this->bbt_md->offs = 8;
-+		this->bbt_md->len = 8;
-+		this->bbt_md->veroffs = 7;
-+		this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
-+		this->bbt_md->reserved_block_code = 0x01;
-+		this->bbt_md->pattern = "TBB_SYSM";
-+	}
-+
-+	/* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set.
-+	   At least as nand_bbt.c is currently written. */
-+	if ((ret = nand_scan_bbt(mtd, NULL)))
-+		return ret;
-+	memset((char *) parts, 0, sizeof(parts));
-+	numparts = inftl_partscan(mtd, parts);
-+	/* At least for now, require the INFTL Media Header.  We could probably
-+	   do without it for non-INFTL use, since all it gives us is
-+	   autopartitioning, but I want to give it more thought. */
-+	if (!numparts) return -EIO;
-+	add_mtd_device(mtd);
-+#ifdef CONFIG_MTD_PARTITIONS
-+	if (!no_autopart)
-+		add_mtd_partitions(mtd, parts, numparts);
-+#endif
-+	return 0;
-+}
-+
-+static inline int __init doc2000_init(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+
-+	this->write_byte = doc2000_write_byte;
-+	this->read_byte = doc2000_read_byte;
-+	this->write_buf = doc2000_writebuf;
-+	this->read_buf = doc2000_readbuf;
-+	this->verify_buf = doc2000_verifybuf;
-+	this->scan_bbt = nftl_scan_bbt;
-+
-+	doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
-+	doc2000_count_chips(mtd);
-+	mtd->name = "DiskOnChip 2000 (NFTL Model)";
-+	return (4 * doc->chips_per_floor);
-+}
-+
-+static inline int __init doc2001_init(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+
-+	this->write_byte = doc2001_write_byte;
-+	this->read_byte = doc2001_read_byte;
-+	this->write_buf = doc2001_writebuf;
-+	this->read_buf = doc2001_readbuf;
-+	this->verify_buf = doc2001_verifybuf;
-+
-+	ReadDOC(doc->virtadr, ChipID);
-+	ReadDOC(doc->virtadr, ChipID);
-+	ReadDOC(doc->virtadr, ChipID);
-+	if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
-+		/* It's not a Millennium; it's one of the newer
-+		   DiskOnChip 2000 units with a similar ASIC. 
-+		   Treat it like a Millennium, except that it
-+		   can have multiple chips. */
-+		doc2000_count_chips(mtd);
-+		mtd->name = "DiskOnChip 2000 (INFTL Model)";
-+		this->scan_bbt = inftl_scan_bbt;
-+		return (4 * doc->chips_per_floor);
-+	} else {
-+		/* Bog-standard Millennium */
-+		doc->chips_per_floor = 1;
-+		mtd->name = "DiskOnChip Millennium";
-+		this->scan_bbt = nftl_scan_bbt;
-+		return 1;
-+	}
-+}
-+
-+static inline int __init doc2001plus_init(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct doc_priv *doc = (void *)this->priv;
-+
-+	this->write_byte = NULL;
-+	this->read_byte = doc2001plus_read_byte;
-+	this->write_buf = doc2001plus_writebuf;
-+	this->read_buf = doc2001plus_readbuf;
-+	this->verify_buf = doc2001plus_verifybuf;
-+	this->scan_bbt = inftl_scan_bbt;
-+	this->hwcontrol = NULL;
-+	this->select_chip = doc2001plus_select_chip;
-+	this->cmdfunc = doc2001plus_command;
-+	this->enable_hwecc = doc2001plus_enable_hwecc;
-+
-+	doc->chips_per_floor = 1;
-+	mtd->name = "DiskOnChip Millennium Plus";
-+
-+	return 1;
-+}
-+
-+static inline int __init doc_probe(unsigned long physadr)
-+{
-+	unsigned char ChipID;
-+	struct mtd_info *mtd;
-+	struct nand_chip *nand;
-+	struct doc_priv *doc;
-+	void __iomem *virtadr;
-+	unsigned char save_control;
-+	unsigned char tmp, tmpb, tmpc;
-+	int reg, len, numchips;
-+	int ret = 0;
-+
-+	virtadr = (void __iomem *)ioremap(physadr, DOC_IOREMAP_LEN);
-+	if (!virtadr) {
-+		printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
-+		return -EIO;
-+	}
-+
-+	/* It's not possible to cleanly detect the DiskOnChip - the
-+	 * bootup procedure will put the device into reset mode, and
-+	 * it's not possible to talk to it without actually writing
-+	 * to the DOCControl register. So we store the current contents
-+	 * of the DOCControl register's location, in case we later decide
-+	 * that it's not a DiskOnChip, and want to put it back how we
-+	 * found it. 
-+	 */
-+	save_control = ReadDOC(virtadr, DOCControl);
-+
-+	/* Reset the DiskOnChip ASIC */
-+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
-+		 virtadr, DOCControl);
-+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, 
-+		 virtadr, DOCControl);
-+
-+	/* Enable the DiskOnChip ASIC */
-+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
-+		 virtadr, DOCControl);
-+	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, 
-+		 virtadr, DOCControl);
-+
-+	ChipID = ReadDOC(virtadr, ChipID);
-+
-+	switch(ChipID) {
-+	case DOC_ChipID_Doc2k:
-+		reg = DoC_2k_ECCStatus;
-+		break;
-+	case DOC_ChipID_DocMil:
-+		reg = DoC_ECCConf;
-+		break;
-+	case DOC_ChipID_DocMilPlus16:
-+	case DOC_ChipID_DocMilPlus32:
-+	case 0:
-+		/* Possible Millennium Plus, need to do more checks */
-+		/* Possibly release from power down mode */
-+		for (tmp = 0; (tmp < 4); tmp++)
-+			ReadDOC(virtadr, Mplus_Power);
-+
-+		/* Reset the Millennium Plus ASIC */
-+		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
-+			DOC_MODE_BDECT;
-+		WriteDOC(tmp, virtadr, Mplus_DOCControl);
-+		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
-+
-+		mdelay(1);
-+		/* Enable the Millennium Plus ASIC */
-+		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT |
-+			DOC_MODE_BDECT;
-+		WriteDOC(tmp, virtadr, Mplus_DOCControl);
-+		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
-+		mdelay(1);
-+
-+		ChipID = ReadDOC(virtadr, ChipID);
-+
-+		switch (ChipID) {
-+		case DOC_ChipID_DocMilPlus16:
-+			reg = DoC_Mplus_Toggle;
-+			break;
-+		case DOC_ChipID_DocMilPlus32:
-+			printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
-+		default:
-+			ret = -ENODEV;
-+			goto notfound;
-+		}
-+		break;
-+
-+	default:
-+		ret = -ENODEV;
-+		goto notfound;
-+	}
-+	/* Check the TOGGLE bit in the ECC register */
-+	tmp  = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
-+	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
-+	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
-+	if ((tmp == tmpb) || (tmp != tmpc)) {
-+		printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
-+		ret = -ENODEV;
-+		goto notfound;
-+	}
-+
-+	for (mtd = doclist; mtd; mtd = doc->nextdoc) {
-+		unsigned char oldval;
-+		unsigned char newval;
-+		nand = mtd->priv;
-+		doc = (void *)nand->priv;
-+		/* Use the alias resolution register to determine if this is
-+		   in fact the same DOC aliased to a new address.  If writes
-+		   to one chip's alias resolution register change the value on
-+		   the other chip, they're the same chip. */
-+		if (ChipID == DOC_ChipID_DocMilPlus16) {
-+			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
-+			newval = ReadDOC(virtadr, Mplus_AliasResolution);
-+		} else {
-+			oldval = ReadDOC(doc->virtadr, AliasResolution);
-+			newval = ReadDOC(virtadr, AliasResolution);
-+		}
-+		if (oldval != newval)
-+			continue;
-+		if (ChipID == DOC_ChipID_DocMilPlus16) {
-+			WriteDOC(~newval, virtadr, Mplus_AliasResolution);
-+			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
-+			WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
-+		} else {
-+			WriteDOC(~newval, virtadr, AliasResolution);
-+			oldval = ReadDOC(doc->virtadr, AliasResolution);
-+			WriteDOC(newval, virtadr, AliasResolution); // restore it
-+		}
-+		newval = ~newval;
-+		if (oldval == newval) {
-+			printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr);
-+			goto notfound;
-+		}
-+	}
-+
-+	printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr);
-+
-+	len = sizeof(struct mtd_info) +
-+	      sizeof(struct nand_chip) +
-+	      sizeof(struct doc_priv) +
-+	      (2 * sizeof(struct nand_bbt_descr));
-+	mtd = (struct mtd_info *) kmalloc(len, GFP_KERNEL);
-+	if (!mtd) {
-+		printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
-+		ret = -ENOMEM;
-+		goto fail;
-+	}
-+	memset(mtd, 0, len);
-+
-+	nand			= (struct nand_chip *) (mtd + 1);
-+	doc			= (struct doc_priv *) (nand + 1);
-+	nand->bbt_td		= (struct nand_bbt_descr *) (doc + 1);
-+	nand->bbt_md		= nand->bbt_td + 1;
-+
-+	mtd->priv		= (void *) nand;
-+	mtd->owner		= THIS_MODULE;
-+
-+	nand->priv		= (void *) doc;
-+	nand->select_chip	= doc200x_select_chip;
-+	nand->hwcontrol		= doc200x_hwcontrol;
-+	nand->dev_ready		= doc200x_dev_ready;
-+	nand->waitfunc		= doc200x_wait;
-+	nand->block_bad		= doc200x_block_bad;
-+	nand->enable_hwecc	= doc200x_enable_hwecc;
-+	nand->calculate_ecc	= doc200x_calculate_ecc;
-+	nand->correct_data	= doc200x_correct_data;
-+
-+	nand->autooob		= &doc200x_oobinfo;
-+	nand->eccmode		= NAND_ECC_HW6_512;
-+	nand->options		= NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
-+
-+	doc->physadr		= physadr;
-+	doc->virtadr		= virtadr;
-+	doc->ChipID		= ChipID;
-+	doc->curfloor		= -1;
-+	doc->curchip		= -1;
-+	doc->mh0_page		= -1;
-+	doc->mh1_page		= -1;
-+	doc->nextdoc		= doclist;
-+
-+	if (ChipID == DOC_ChipID_Doc2k)
-+		numchips = doc2000_init(mtd);
-+	else if (ChipID == DOC_ChipID_DocMilPlus16)
-+		numchips = doc2001plus_init(mtd);
-+	else
-+		numchips = doc2001_init(mtd);
-+
-+	if ((ret = nand_scan(mtd, numchips))) {
-+		/* DBB note: i believe nand_release is necessary here, as
-+		   buffers may have been allocated in nand_base.  Check with
-+		   Thomas. FIX ME! */
-+		/* nand_release will call del_mtd_device, but we haven't yet
-+		   added it.  This is handled without incident by
-+		   del_mtd_device, as far as I can tell. */
-+		nand_release(mtd);
-+		kfree(mtd);
-+		goto fail;
-+	}
-+
-+	/* Success! */
-+	doclist = mtd;
-+	return 0;
-+
-+notfound:
-+	/* Put back the contents of the DOCControl register, in case it's not
-+	   actually a DiskOnChip.  */
-+	WriteDOC(save_control, virtadr, DOCControl);
-+fail:
-+	iounmap((void *)virtadr);
-+	return ret;
-+}
-+
-+int __init init_nanddoc(void)
-+{
-+	int i;
-+
-+	if (doc_config_location) {
-+		printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
-+		return doc_probe(doc_config_location);
-+	} else {
-+		for (i=0; (doc_locations[i] != 0xffffffff); i++) {
-+			doc_probe(doc_locations[i]);
-+		}
-+	}
-+	/* No banner message any more. Print a message if no DiskOnChip
-+	   found, so the user knows we at least tried. */
-+	if (!doclist) {
-+		printk(KERN_INFO "No valid DiskOnChip devices found\n");
-+		return -ENODEV;
-+	}
-+	return 0;
-+}
-+
-+void __exit cleanup_nanddoc(void)
-+{
-+	struct mtd_info *mtd, *nextmtd;
-+	struct nand_chip *nand;
-+	struct doc_priv *doc;
-+
-+	for (mtd = doclist; mtd; mtd = nextmtd) {
-+		nand = mtd->priv;
-+		doc = (void *)nand->priv;
-+
-+		nextmtd = doc->nextdoc;
-+		nand_release(mtd);
-+		iounmap((void *)doc->virtadr);
-+		kfree(mtd);
-+	}
-+}
-+
-+module_init(init_nanddoc);
-+module_exit(cleanup_nanddoc);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-+MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n");
-Index: linux-2.6.5/drivers/mtd/nand/edb7312.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/edb7312.c	2004-04-03 22:38:22.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/edb7312.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.9 2004/09/16 23:27:14 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
-@@ -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>
-@@ -52,9 +53,9 @@
-  * Module stuff
-  */
- 
--static int ep7312_fio_pbase = EP7312_FIO_PBASE;
--static int ep7312_pxdr = EP7312_PXDR;
--static int ep7312_pxddr = EP7312_PXDDR;
-+static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE;
-+static void __iomem * ep7312_pxdr = (void __iomem *) EP7312_PXDR;
-+static void __iomem * ep7312_pxddr = (void __iomem *) EP7312_PXDDR;
- 
- #ifdef MODULE
- MODULE_PARM(ep7312_fio_pbase, "i");
-@@ -83,7 +84,7 @@
- /* 
-  *	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 @@
- /*
-  *	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
-@@ -127,10 +131,10 @@
- 	const char *part_type = 0;
- 	int mtd_parts_nb = 0;
- 	struct mtd_partition *mtd_parts = 0;
--	int ep7312_fio_base;
-+	void __iomem * ep7312_fio_base;
- 	
- 	/* Allocate memory for MTD device structure and private data */
--	ep7312_mtd = kmalloc(sizeof(struct mtd_info) + 
-+	ep7312_mtd = (struct mtd_info *) kmalloc(sizeof(struct mtd_info) + 
- 			     sizeof(struct nand_chip),
- 			     GFP_KERNEL);
- 	if (!ep7312_mtd) {
-@@ -139,7 +143,7 @@
- 	}
- 	
- 	/* map physical adress */
--	ep7312_fio_base = (unsigned long)ioremap(ep7312_fio_pbase, SZ_1K);
-+	ep7312_fio_base = (void __iomem *)ioremap(ep7312_fio_pbase, SZ_1K);
- 	if(!ep7312_fio_base) {
- 		printk("ioremap EDB7312 NAND flash failed\n");
- 		kfree(ep7312_mtd);
-@@ -171,31 +175,22 @@
- 	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;
- 	}
- 	
--	/* Allocate memory for internal data buffer */
--	this->data_buf = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL);
--	if (!this->data_buf) {
--		printk("Unable to allocate NAND data buffer for EDB7312.\n");
--		iounmap((void *)ep7312_fio_base);
--		kfree (ep7312_mtd);
--		return -ENOMEM;
--	}
--	
--#ifdef CONFIG_MTD_CMDLINE_PARTS
--	mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts, 
--						"edb7312-nand");
-+#ifdef CONFIG_MTD_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";
-@@ -217,8 +212,8 @@
- {
- 	struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1];
- 	
--	/* Unregister the device */
--	del_mtd_device (ep7312_mtd);
-+	/* Release resources, unregister device */
-+	nand_release (ap7312_mtd);
- 	
- 	/* Free internal data buffer */
- 	kfree (this->data_buf);
-Index: linux-2.6.5/drivers/mtd/nand/h1910.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/h1910.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/h1910.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,208 @@
-+/*
-+ *  drivers/mtd/nand/h1910.c
-+ *
-+ *  Copyright (C) 2003 Joshua Wise (joshua@joshuawise.com)
-+ *
-+ *  Derived from drivers/mtd/nand/edb7312.c
-+ *       Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
-+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
-+ *
-+ * $Id: h1910.c,v 1.3 2004/09/16 23:27:14 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.
-+ *
-+ *  Overview:
-+ *   This is a device driver for the NAND flash device found on the
-+ *   iPAQ h1910 board which utilizes the Samsung K9F2808 part. This is
-+ *   a 128Mibit (16MiB x 8 bits) NAND flash device.
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */
-+#include <asm/sizes.h>
-+#include <asm/arch/h1900-gpio.h>
-+#include <asm/arch/ipaq.h>
-+
-+/*
-+ * MTD structure for EDB7312 board
-+ */
-+static struct mtd_info *h1910_nand_mtd = NULL;
-+
-+/*
-+ * Module stuff
-+ */
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+/*
-+ * Define static partitions for flash device
-+ */
-+static struct mtd_partition partition_info[] = {
-+	{ name: "h1910 NAND Flash",
-+		  offset: 0,
-+		  size: 16*1024*1024 }
-+};
-+#define NUM_PARTITIONS 1
-+
-+#endif
-+
-+
-+/* 
-+ *	hardware specific access to control-lines
-+ */
-+static void h1910_hwcontrol(struct mtd_info *mtd, int cmd) 
-+{
-+	struct nand_chip* this = (struct nand_chip *) (mtd->priv);
-+	
-+	switch(cmd) {
-+		
-+	case NAND_CTL_SETCLE: 
-+		this->IO_ADDR_R |= (1 << 2);
-+		this->IO_ADDR_W |= (1 << 2);
-+		break;
-+	case NAND_CTL_CLRCLE: 
-+		this->IO_ADDR_R &= ~(1 << 2);
-+		this->IO_ADDR_W &= ~(1 << 2);
-+		break;
-+		
-+	case NAND_CTL_SETALE:
-+		this->IO_ADDR_R |= (1 << 3);
-+		this->IO_ADDR_W |= (1 << 3);
-+		break;
-+	case NAND_CTL_CLRALE:
-+		this->IO_ADDR_R &= ~(1 << 3);
-+		this->IO_ADDR_W &= ~(1 << 3);
-+		break;
-+		
-+	case NAND_CTL_SETNCE:
-+		break;
-+	case NAND_CTL_CLRNCE:
-+		break;
-+	}
-+}
-+
-+/*
-+ *	read device ready pin
-+ */
-+#if 0
-+static int h1910_device_ready(struct mtd_info *mtd)
-+{
-+	return (GPLR(55) & GPIO_bit(55));
-+}
-+#endif
-+
-+/*
-+ * Main initialization routine
-+ */
-+static int __init h1910_init (void)
-+{
-+	struct nand_chip *this;
-+	const char *part_type = 0;
-+	int mtd_parts_nb = 0;
-+	struct mtd_partition *mtd_parts = 0;
-+	void __iomem *nandaddr;
-+	
-+	if (!machine_is_h1900())
-+		return -ENODEV;
-+		
-+	nandaddr = (void __iomem *)__ioremap(0x08000000, 0x1000, 0, 1);
-+	if (!nandaddr) {
-+		printk("Failed to ioremap nand flash.\n");
-+		return -ENOMEM;
-+	}
-+	
-+	/* Allocate memory for MTD device structure and private data */
-+	h1910_nand_mtd = (struct mtd_info *) kmalloc(sizeof(struct mtd_info) + 
-+			     sizeof(struct nand_chip),
-+			     GFP_KERNEL);
-+	if (!h1910_nand_mtd) {
-+		printk("Unable to allocate h1910 NAND MTD device structure.\n");
-+		iounmap ((void *) nandaddr);
-+		return -ENOMEM;
-+	}
-+	
-+	/* Get pointer to private data */
-+	this = (struct nand_chip *) (&h1910_nand_mtd[1]);
-+	
-+	/* Initialize structures */
-+	memset((char *) h1910_nand_mtd, 0, sizeof(struct mtd_info));
-+	memset((char *) this, 0, sizeof(struct nand_chip));
-+	
-+	/* Link the private data with the MTD structure */
-+	h1910_nand_mtd->priv = this;
-+	
-+	/*
-+	 * Enable VPEN
-+	 */
-+	GPSR(37) = GPIO_bit(37);
-+	
-+	/* insert callbacks */
-+	this->IO_ADDR_R = nandaddr;
-+	this->IO_ADDR_W = nandaddr;
-+	this->hwcontrol = h1910_hwcontrol;
-+	this->dev_ready = NULL;	/* unknown whether that was correct or not so we will just do it like this */
-+	/* 15 us command delay time */
-+	this->chip_delay = 50;
-+	this->eccmode = NAND_ECC_SOFT;
-+	this->options = NAND_NO_AUTOINCR;
-+	
-+	/* Scan to find existence of the device */
-+	if (nand_scan (h1910_nand_mtd, 1)) {
-+		printk(KERN_NOTICE "No NAND device - returning -ENXIO\n");
-+		kfree (h1910_nand_mtd);
-+		iounmap ((void *) nandaddr);
-+		return -ENXIO;
-+	}
-+	
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+	mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, 
-+						"h1910-nand");
-+	if (mtd_parts_nb > 0)
-+	  part_type = "command line";
-+	else
-+	  mtd_parts_nb = 0;
-+#endif
-+	if (mtd_parts_nb == 0)
-+	{
-+		mtd_parts = partition_info;
-+		mtd_parts_nb = NUM_PARTITIONS;
-+		part_type = "static";
-+	}
-+	
-+	/* Register the partitions */
-+	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-+	add_mtd_partitions(h1910_nand_mtd, mtd_parts, mtd_parts_nb);
-+	
-+	/* Return happy */
-+	return 0;
-+}
-+module_init(h1910_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit h1910_cleanup (void)
-+{
-+	struct nand_chip *this = (struct nand_chip *) &h1910_nand_mtd[1];
-+	
-+	/* Release resources, unregister device */
-+	nand_release (h1910_nand_mtd);
-+
-+	/* Release io resource */
-+	iounmap ((void *) this->IO_ADDR_W);
-+
-+	/* Free the MTD device structure */
-+	kfree (h1910_nand_mtd);
-+}
-+module_exit(h1910_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Joshua Wise <joshua at joshuawise dot com>");
-+MODULE_DESCRIPTION("NAND flash driver for iPAQ h1910");
-Index: linux-2.6.5/drivers/mtd/nand/nand_base.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/nand_base.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/nand_base.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,2581 @@
-+/*
-+ *  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.
-+ *   Basic support for AG-AND chips is provided.
-+ *   
-+ *	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)
-+ *
-+ *  02-08-2004  tglx: support for strange chips, which cannot auto increment 
-+ *		pages on read / read_oob
-+ *
-+ *  03-17-2004  tglx: Check ready before auto increment check. Simon Bayes
-+ *		pointed this out, as he marked an auto increment capable chip
-+ *		as NOAUTOINCR in the board driver.
-+ *		Make reads over block boundaries work too
-+ *
-+ *  04-14-2004	tglx: first working version for 2k page size chips
-+ *  
-+ *  05-19-2004  tglx: Basic support for Renesas AG-AND chips
-+ *
-+ * Credits:
-+ *	David Woodhouse for adding multichip support  
-+ *	
-+ *	Aleph One Ltd. and Toby Churchill Ltd. for supporting the
-+ *	rework for 2K page size chips
-+ *
-+ * TODO:
-+ *	Enable cached programming for 2k page size chips
-+ *	Check, if mtd->ecctype should be set to MTD_ECC_HW
-+ *	if we have HW ecc support.
-+ *	The AG-AND chips have nice features for speed improvement,
-+ *	which are not supported yet. Read / program 4 pages in one go.
-+ *
-+ * $Id: nand_base.c,v 1.116 2004/08/30 18:00:45 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/slab.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 <linux/bitops.h>
-+#include <asm/io.h>
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+#include <linux/mtd/partitions.h>
-+#endif
-+
-+/* Define default oob placement schemes for large and small page devices */
-+static struct nand_oobinfo nand_oob_8 = {
-+	.useecc = MTD_NANDECC_AUTOPLACE,
-+	.eccbytes = 3,
-+	.eccpos = {0, 1, 2},
-+	.oobfree = { {3, 2}, {6, 2} }
-+};
-+
-+static struct nand_oobinfo nand_oob_16 = {
-+	.useecc = MTD_NANDECC_AUTOPLACE,
-+	.eccbytes = 6,
-+	.eccpos = {0, 1, 2, 3, 6, 7},
-+	.oobfree = { {8, 8} }
-+};
-+
-+static struct nand_oobinfo nand_oob_64 = {
-+	.useecc = MTD_NANDECC_AUTOPLACE,
-+	.eccbytes = 24,
-+	.eccpos = {
-+		40, 41, 42, 43, 44, 45, 46, 47, 
-+		48, 49, 50, 51, 52, 53, 54, 55, 
-+		56, 57, 58, 59, 60, 61, 62, 63},
-+	.oobfree = { {2, 38} }
-+};
-+
-+/* This is used for padding purposes in nand_write_oob */
-+static u_char ffchars[] = {
-+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-+};
-+
-+/*
-+ * NAND low-level MTD interface functions
-+ */
-+static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len);
-+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len);
-+static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len);
-+
-+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);
-+
-+/* Some internal functions */
-+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf,
-+		struct nand_oobinfo *oobsel, int mode);
-+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-+static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 
-+	u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode);
-+#else
-+#define nand_verify_pages(...) (0)
-+#endif
-+		
-+static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state);
-+
-+/**
-+ * nand_release_chip - [GENERIC] release chip
-+ * @mtd:	MTD device structure
-+ * 
-+ * Deselect, release chip lock and wake up anyone waiting on the device 
-+ */
-+static void nand_release_chip (struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+
-+	/* De-select the NAND device */
-+	this->select_chip(mtd, -1);
-+	/* Release the chip */
-+	spin_lock_bh (&this->chip_lock);
-+	this->state = FL_READY;
-+	wake_up (&this->wq);
-+	spin_unlock_bh (&this->chip_lock);
-+}
-+
-+/**
-+ * nand_read_byte - [DEFAULT] read one byte from the chip
-+ * @mtd:	MTD device structure
-+ *
-+ * Default read function for 8bit buswith
-+ */
-+static u_char nand_read_byte(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	return readb(this->IO_ADDR_R);
-+}
-+
-+/**
-+ * nand_write_byte - [DEFAULT] write one byte to the chip
-+ * @mtd:	MTD device structure
-+ * @byte:	pointer to data byte to write
-+ *
-+ * Default write function for 8it buswith
-+ */
-+static void nand_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	writeb(byte, this->IO_ADDR_W);
-+}
-+
-+/**
-+ * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip
-+ * @mtd:	MTD device structure
-+ *
-+ * Default read function for 16bit buswith with 
-+ * endianess conversion
-+ */
-+static u_char nand_read_byte16(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	return (u_char) cpu_to_le16(readw(this->IO_ADDR_R));
-+}
-+
-+/**
-+ * nand_write_byte16 - [DEFAULT] write one byte endianess aware to the chip
-+ * @mtd:	MTD device structure
-+ * @byte:	pointer to data byte to write
-+ *
-+ * Default write function for 16bit buswith with
-+ * endianess conversion
-+ */
-+static void nand_write_byte16(struct mtd_info *mtd, u_char byte)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	writew(le16_to_cpu((u16) byte), this->IO_ADDR_W);
-+}
-+
-+/**
-+ * nand_read_word - [DEFAULT] read one word from the chip
-+ * @mtd:	MTD device structure
-+ *
-+ * Default read function for 16bit buswith without 
-+ * endianess conversion
-+ */
-+static u16 nand_read_word(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	return readw(this->IO_ADDR_R);
-+}
-+
-+/**
-+ * nand_write_word - [DEFAULT] write one word to the chip
-+ * @mtd:	MTD device structure
-+ * @word:	data word to write
-+ *
-+ * Default write function for 16bit buswith without 
-+ * endianess conversion
-+ */
-+static void nand_write_word(struct mtd_info *mtd, u16 word)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	writew(word, this->IO_ADDR_W);
-+}
-+
-+/**
-+ * nand_select_chip - [DEFAULT] control CE line
-+ * @mtd:	MTD device structure
-+ * @chip:	chipnumber to select, -1 for deselect
-+ *
-+ * Default select function for 1 chip devices.
-+ */
-+static void nand_select_chip(struct mtd_info *mtd, int chip)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	switch(chip) {
-+	case -1:
-+		this->hwcontrol(mtd, NAND_CTL_CLRNCE);	
-+		break;
-+	case 0:
-+		this->hwcontrol(mtd, NAND_CTL_SETNCE);
-+		break;
-+
-+	default:
-+		BUG();
-+	}
-+}
-+
-+/**
-+ * nand_write_buf - [DEFAULT] write buffer to chip
-+ * @mtd:	MTD device structure
-+ * @buf:	data buffer
-+ * @len:	number of bytes to write
-+ *
-+ * Default write function for 8bit buswith
-+ */
-+static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		writeb(buf[i], this->IO_ADDR_W);
-+}
-+
-+/**
-+ * nand_read_buf - [DEFAULT] read chip data into buffer 
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer to store date
-+ * @len:	number of bytes to read
-+ *
-+ * Default read function for 8bit buswith
-+ */
-+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		buf[i] = readb(this->IO_ADDR_R);
-+}
-+
-+/**
-+ * nand_verify_buf - [DEFAULT] Verify chip data against buffer 
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer containing the data to compare
-+ * @len:	number of bytes to compare
-+ *
-+ * Default verify function for 8bit buswith
-+ */
-+static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		if (buf[i] != readb(this->IO_ADDR_R))
-+			return -EFAULT;
-+
-+	return 0;
-+}
-+
-+/**
-+ * nand_write_buf16 - [DEFAULT] write buffer to chip
-+ * @mtd:	MTD device structure
-+ * @buf:	data buffer
-+ * @len:	number of bytes to write
-+ *
-+ * Default write function for 16bit buswith
-+ */
-+static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+	u16 *p = (u16 *) buf;
-+	len >>= 1;
-+	
-+	for (i=0; i<len; i++)
-+		writew(p[i], this->IO_ADDR_W);
-+		
-+}
-+
-+/**
-+ * nand_read_buf16 - [DEFAULT] read chip data into buffer 
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer to store date
-+ * @len:	number of bytes to read
-+ *
-+ * Default read function for 16bit buswith
-+ */
-+static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+	u16 *p = (u16 *) buf;
-+	len >>= 1;
-+
-+	for (i=0; i<len; i++)
-+		p[i] = readw(this->IO_ADDR_R);
-+}
-+
-+/**
-+ * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer 
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer containing the data to compare
-+ * @len:	number of bytes to compare
-+ *
-+ * Default verify function for 16bit buswith
-+ */
-+static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+	u16 *p = (u16 *) buf;
-+	len >>= 1;
-+
-+	for (i=0; i<len; i++)
-+		if (p[i] != readw(this->IO_ADDR_R))
-+			return -EFAULT;
-+
-+	return 0;
-+}
-+
-+/**
-+ * nand_block_bad - [DEFAULT] Read bad block marker from the chip
-+ * @mtd:	MTD device structure
-+ * @ofs:	offset from device start
-+ * @getchip:	0, if the chip is already selected
-+ *
-+ * Check, if the block is bad. 
-+ */
-+static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
-+{
-+	int page, chipnr, res = 0;
-+	struct nand_chip *this = mtd->priv;
-+	u16 bad;
-+
-+	if (getchip) {
-+		page = (int)(ofs >> this->page_shift);
-+		chipnr = (int)(ofs >> this->chip_shift);
-+
-+		/* Grab the lock and see if the device is available */
-+		nand_get_chip (this, mtd, FL_READING);
-+
-+		/* Select the NAND device */
-+		this->select_chip(mtd, chipnr);
-+	} else 
-+		page = (int) ofs;	
-+
-+	if (this->options & NAND_BUSWIDTH_16) {
-+		this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask);
-+		bad = cpu_to_le16(this->read_word(mtd));
-+		if (this->badblockpos & 0x1)
-+			bad >>= 1;
-+		if ((bad & 0xFF) != 0xff)
-+			res = 1;
-+	} else {
-+		this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos, page & this->pagemask);
-+		if (this->read_byte(mtd) != 0xff)
-+			res = 1;
-+	}
-+		
-+	if (getchip) {
-+		/* Deselect and wake up anyone waiting on the device */
-+		nand_release_chip(mtd);
-+	}	
-+	
-+	return res;
-+}
-+
-+/**
-+ * nand_default_block_markbad - [DEFAULT] mark a block bad
-+ * @mtd:	MTD device structure
-+ * @ofs:	offset from device start
-+ *
-+ * This is the default implementation, which can be overridden by
-+ * a hardware specific driver.
-+*/
-+static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	u_char buf[2] = {0, 0};
-+	size_t	retlen;
-+	int block;
-+	
-+	/* Get block number */
-+	block = ((int) ofs) >> this->bbt_erase_shift;
-+	this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
-+
-+	/* Do we have a flash based bad block table ? */
-+	if (this->options & NAND_USE_FLASH_BBT)
-+		return nand_update_bbt (mtd, ofs);
-+		
-+	/* We write two bytes, so we dont have to mess with 16 bit access */
-+	ofs += mtd->oobsize + (this->badblockpos & ~0x01);
-+	return nand_write_oob (mtd, ofs , 2, &retlen, buf);
-+}
-+
-+/** 
-+ * nand_check_wp - [GENERIC] check if the chip is write protected
-+ * @mtd:	MTD device structure
-+ * Check, if the device is write protected 
-+ *
-+ * The function expects, that the device is already selected 
-+ */
-+static int nand_check_wp (struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	/* Check the WP bit */
-+	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
-+	return (this->read_byte(mtd) & 0x80) ? 0 : 1; 
-+}
-+
-+/**
-+ * nand_block_checkbad - [GENERIC] Check if a block is marked bad
-+ * @mtd:	MTD device structure
-+ * @ofs:	offset from device start
-+ * @getchip:	0, if the chip is already selected
-+ * @allowbbt:	1, if its allowed to access the bbt area
-+ *
-+ * Check, if the block is bad. Either by reading the bad block table or
-+ * calling of the scan function.
-+ */
-+static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	
-+	if (!this->bbt)
-+		return this->block_bad(mtd, ofs, getchip);
-+	
-+	/* Return info from the table */
-+	return nand_isbad_bbt (mtd, ofs, allowbbt);
-+}
-+
-+/**
-+ * nand_command - [DEFAULT] Send command to NAND device
-+ * @mtd:	MTD device structure
-+ * @command:	the command to be sent
-+ * @column:	the column address for this command, -1 if none
-+ * @page_addr:	the page address for this command, -1 if none
-+ *
-+ * Send command to NAND device. This function is used for small page
-+ * devices (256/512 Bytes per page)
-+ */
-+static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-+{
-+	register struct nand_chip *this = mtd->priv;
-+
-+	/* Begin command latch cycle */
-+	this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+	/*
-+	 * Write out the command to the device.
-+	 */
-+	if (command == NAND_CMD_SEQIN) {
-+		int readcmd;
-+
-+		if (column >= mtd->oobblock) {
-+			/* OOB area */
-+			column -= mtd->oobblock;
-+			readcmd = NAND_CMD_READOOB;
-+		} else if (column < 256) {
-+			/* First 256 bytes --> READ0 */
-+			readcmd = NAND_CMD_READ0;
-+		} else {
-+			column -= 256;
-+			readcmd = NAND_CMD_READ1;
-+		}
-+		this->write_byte(mtd, readcmd);
-+	}
-+	this->write_byte(mtd, command);
-+
-+	/* Set ALE and clear CLE to start address cycle */
-+	this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+
-+	if (column != -1 || page_addr != -1) {
-+		this->hwcontrol(mtd, NAND_CTL_SETALE);
-+
-+		/* Serially input address */
-+		if (column != -1) {
-+			/* Adjust columns for 16 bit buswidth */
-+			if (this->options & NAND_BUSWIDTH_16)
-+				column >>= 1;
-+			this->write_byte(mtd, column);
-+		}
-+		if (page_addr != -1) {
-+			this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
-+			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
-+			/* One more address cycle for higher density devices */
-+			if (this->chipsize & 0x0c000000) 
-+				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
-+		}
-+		/* Latch in address */
-+		this->hwcontrol(mtd, 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;
-+		udelay(this->chip_delay);
-+		this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+		this->write_byte(mtd, NAND_CMD_STATUS);
-+		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+		while ( !(this->read_byte(mtd) & 0x40));
-+		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;
-+		}	
-+	}
-+	
-+	/* Apply this short delay always to ensure that we do wait tWB in
-+	 * any case on any machine. */
-+	ndelay (100);
-+	/* wait until command is processed */
-+	while (!this->dev_ready(mtd));
-+}
-+
-+/**
-+ * nand_command_lp - [DEFAULT] Send command to NAND large page device
-+ * @mtd:	MTD device structure
-+ * @command:	the command to be sent
-+ * @column:	the column address for this command, -1 if none
-+ * @page_addr:	the page address for this command, -1 if none
-+ *
-+ * Send command to NAND device. This is the version for the new large page devices
-+ * We dont have the seperate regions as we have in the small page devices.
-+ * We must emulate NAND_CMD_READOOB to keep the code compatible.
-+ *
-+ */
-+static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-+{
-+	register struct nand_chip *this = mtd->priv;
-+
-+	/* Emulate NAND_CMD_READOOB */
-+	if (command == NAND_CMD_READOOB) {
-+		column += mtd->oobblock;
-+		command = NAND_CMD_READ0;
-+	}
-+	
-+		
-+	/* Begin command latch cycle */
-+	this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+	/* Write out the command to the device. */
-+	this->write_byte(mtd, command);
-+	/* End command latch cycle */
-+	this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+
-+	if (column != -1 || page_addr != -1) {
-+		this->hwcontrol(mtd, NAND_CTL_SETALE);
-+
-+		/* Serially input address */
-+		if (column != -1) {
-+			/* Adjust columns for 16 bit buswidth */
-+			if (this->options & NAND_BUSWIDTH_16)
-+				column >>= 1;
-+			this->write_byte(mtd, column & 0xff);
-+			this->write_byte(mtd, column >> 8);
-+		}	
-+		if (page_addr != -1) {
-+			this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
-+			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
-+			/* One more address cycle for devices > 128MiB */
-+			if (this->chipsize > (128 << 20))
-+				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff));
-+		}
-+		/* Latch in address */
-+		this->hwcontrol(mtd, NAND_CTL_CLRALE);
-+	}
-+	
-+	/* 
-+	 * program and erase have their own busy handlers 
-+	 * status and sequential in needs no delay
-+	*/
-+	switch (command) {
-+			
-+	case NAND_CMD_CACHEDPROG:
-+	case NAND_CMD_PAGEPROG:
-+	case NAND_CMD_ERASE1:
-+	case NAND_CMD_ERASE2:
-+	case NAND_CMD_SEQIN:
-+	case NAND_CMD_STATUS:
-+		return;
-+
-+
-+	case NAND_CMD_RESET:
-+		if (this->dev_ready)	
-+			break;
-+		udelay(this->chip_delay);
-+		this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+		this->write_byte(mtd, NAND_CMD_STATUS);
-+		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+		while ( !(this->read_byte(mtd) & 0x40));
-+		return;
-+
-+	case NAND_CMD_READ0:
-+		/* Begin command latch cycle */
-+		this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+		/* Write out the start read command */
-+		this->write_byte(mtd, NAND_CMD_READSTART);
-+		/* End command latch cycle */
-+		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+		/* Fall through into ready check */
-+		
-+	/* 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;
-+		}	
-+	}
-+	
-+	/* Apply this short delay always to ensure that we do wait tWB in
-+	 * any case on any machine. */
-+	ndelay (100);
-+	/* wait until command is processed */
-+	while (!this->dev_ready(mtd));
-+}
-+
-+/**
-+ * nand_get_chip - [GENERIC] Get chip for selected access
-+ * @this:	the nand chip descriptor
-+ * @mtd:	MTD device structure
-+ * @new_state:	the state which is requested 
-+ *
-+ * Get the device and lock it for exclusive access
-+ */
-+static void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state)
-+{
-+
-+	DECLARE_WAITQUEUE (wait, current);
-+
-+	/* 
-+	 * Grab the lock and see if the device is available 
-+	*/
-+retry:
-+	spin_lock_bh (&this->chip_lock);
-+
-+	if (this->state == FL_READY) {
-+		this->state = new_state;
-+		spin_unlock_bh (&this->chip_lock);
-+		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;
-+}
-+
-+/**
-+ * nand_wait - [DEFAULT]  wait until the command is done
-+ * @mtd:	MTD device structure
-+ * @this:	NAND chip structure
-+ * @state:	state to select the max. timeout value
-+ *
-+ * 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;
-+
-+	/* Apply this short delay always to ensure that we do wait tWB in
-+	 * any case on any machine. */
-+	ndelay (100);
-+
-+	spin_lock_bh (&this->chip_lock);
-+	if ((state == FL_ERASING) && (this->options & NAND_IS_AND))
-+		this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1);
-+	else	
-+		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(mtd))
-+				break;	
-+		} else {
-+			if (this->read_byte(mtd) & NAND_STATUS_READY)
-+				break;
-+		}
-+		spin_unlock_bh (&this->chip_lock);
-+		yield ();
-+		spin_lock_bh (&this->chip_lock);
-+	}
-+	status = (int) this->read_byte(mtd);
-+	spin_unlock_bh (&this->chip_lock);
-+
-+	return status;
-+}
-+
-+/**
-+ * nand_write_page - [GENERIC] write one page
-+ * @mtd:	MTD device structure
-+ * @this:	NAND chip structure
-+ * @page: 	startpage inside the chip, must be called with (page & this->pagemask)
-+ * @oob_buf:	out of band data buffer
-+ * @oobsel:	out of band selecttion structre
-+ * @cached:	1 = enable cached programming if supported by chip
-+ *
-+ * 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 :)
-+ *
-+ * Cached programming is not supported yet.
-+ */
-+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, 
-+	u_char *oob_buf,  struct nand_oobinfo *oobsel, int cached)
-+{
-+	int 	i, status;
-+	u_char	ecc_code[8];
-+	int	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
-+	int  	*oob_config = oobsel->eccpos;
-+	int	datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
-+	int	eccbytes = 0;
-+	
-+	/* FIXME: Enable cached programming */
-+	cached = 0;
-+	
-+	/* 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, write all */
-+	case NAND_ECC_NONE:
-+		printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
-+		this->write_buf(mtd, this->data_poi, mtd->oobblock);
-+		break;
-+		
-+	/* Software ecc 3/256, write all */
-+	case NAND_ECC_SOFT:
-+		for (; eccsteps; eccsteps--) {
-+			this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
-+			for (i = 0; i < 3; i++, eccidx++)
-+				oob_buf[oob_config[eccidx]] = ecc_code[i];
-+			datidx += this->eccsize;
-+		}
-+		this->write_buf(mtd, this->data_poi, mtd->oobblock);
-+		break;
-+		
-+	/* Hardware ecc 8 byte / 512 byte data */	
-+	case NAND_ECC_HW8_512:	
-+		eccbytes += 2;
-+	/* Hardware ecc 6 byte / 512 byte data */	
-+	case NAND_ECC_HW6_512:	
-+		eccbytes += 3;
-+	/* Hardware ecc 3 byte / 256 data */	
-+	/* Hardware ecc 3 byte / 512 byte data */	
-+	case NAND_ECC_HW3_256:		
-+	case NAND_ECC_HW3_512:
-+		eccbytes += 3;
-+		for (; eccsteps; eccsteps--) {
-+			/* enable hardware ecc logic for write */
-+			this->enable_hwecc(mtd, NAND_ECC_WRITE);
-+			this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);
-+			this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
-+			for (i = 0; i < eccbytes; i++, eccidx++)
-+				oob_buf[oob_config[eccidx]] = ecc_code[i];
-+			/* If the hardware ecc provides syndromes then
-+			 * the ecc code must be written immidiately after
-+			 * the data bytes (words) */
-+			if (this->options & NAND_HWECC_SYNDROME)
-+				this->write_buf(mtd, ecc_code, eccbytes);
-+
-+			datidx += this->eccsize;
-+		}
-+		break;
-+
-+	default:
-+		printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-+		BUG();	
-+	}
-+										
-+	/* Write out OOB data */
-+	if (this->options & NAND_HWECC_SYNDROME)
-+		this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
-+	else 
-+		this->write_buf(mtd, oob_buf, mtd->oobsize);
-+
-+	/* Send command to actually program the data */
-+	this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);
-+
-+	if (!cached) {
-+		/* 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;
-+		}
-+	} else {
-+		/* FIXME: Implement cached programming ! */
-+		/* wait until cache is ready*/
-+		// status = this->waitfunc (mtd, this, FL_CACHEDRPG);
-+	}
-+	return 0;	
-+}
-+
-+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
-+/**
-+ * nand_verify_pages - [GENERIC] verify the chip contents after a write
-+ * @mtd:	MTD device structure
-+ * @this:	NAND chip structure
-+ * @page: 	startpage inside the chip, must be called with (page & this->pagemask)
-+ * @numpages:	number of pages to verify
-+ * @oob_buf:	out of band data buffer
-+ * @oobsel:	out of band selecttion structre
-+ * @chipnr:	number of the current chip
-+ * @oobmode:	1 = full buffer verify, 0 = ecc only
-+ *
-+ * 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.
-+ */
-+static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 
-+	u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode)
-+{
-+	int 	i, j, datidx = 0, oobofs = 0, res = -EIO;
-+	int	eccsteps = this->eccsteps;
-+	int	hweccbytes; 
-+	u_char 	oobdata[64];
-+
-+	hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;
-+
-+	/* Send command to read back the first page */
-+	this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);
-+
-+	for(;;) {
-+		for (j = 0; j < eccsteps; j++) {
-+			/* Loop through and verify the data */
-+			if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {
-+				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
-+				goto out;
-+			}
-+			datidx += mtd->eccsize;
-+			/* Have we a hw generator layout ? */
-+			if (!hweccbytes)
-+				continue;
-+			if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {
-+				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
-+				goto out;
-+			}
-+			oobofs += hweccbytes;
-+		}
-+
-+		/* check, if we must compare all data or if we just have to
-+		 * compare the ecc bytes
-+		 */
-+		if (oobmode) {
-+			if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {
-+				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
-+				goto out;
-+			}
-+		} else {
-+			/* Read always, else autoincrement fails */
-+			this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
-+
-+			if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
-+				int ecccnt = oobsel->eccbytes;
-+		
-+				for (i = 0; i < ecccnt; i++) {
-+					int idx = oobsel->eccpos[i];
-+					if (oobdata[idx] != oob_buf[oobofs + idx] ) {
-+						DEBUG (MTD_DEBUG_LEVEL0,
-+					       	"%s: Failed ECC write "
-+						"verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);
-+						goto out;
-+					}
-+				}
-+			}	
-+		}
-+		oobofs += mtd->oobsize - hweccbytes * eccsteps;
-+		page++;
-+		numpages--;
-+
-+		/* Apply delay or wait for ready/busy pin 
-+		 * Do this before the AUTOINCR check, so no problems
-+		 * arise if a chip which does auto increment
-+		 * is marked as NOAUTOINCR by the board driver.
-+		 * Do this also before returning, so the chip is
-+		 * ready for the next command.
-+		*/
-+		if (!this->dev_ready) 
-+			udelay (this->chip_delay);
-+		else
-+			while (!this->dev_ready(mtd));	
-+
-+		/* All done, return happy */
-+		if (!numpages)
-+			return 0;
-+		
-+			
-+		/* Check, if the chip supports auto page increment */ 
-+		if (!NAND_CANAUTOINCR(this))
-+			this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
-+	}
-+	/* 
-+	 * Terminate the read command. We come here in case of an error
-+	 * So we must issue a reset command.
-+	 */
-+out:	 
-+	this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1);
-+	return res;
-+}
-+#endif
-+
-+/**
-+ * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
-+ * @mtd:	MTD device structure
-+ * @from:	offset to read from
-+ * @len:	number of bytes to read
-+ * @retlen:	pointer to variable to store the number of read bytes
-+ * @buf:	the databuffer to put data
-+ *
-+ * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
-+*/
-+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_ecc - [MTD Interface] Read data with ECC
-+ * @mtd:	MTD device structure
-+ * @from:	offset to read from
-+ * @len:	number of bytes to read
-+ * @retlen:	pointer to variable to store the number of read bytes
-+ * @buf:	the databuffer to put data
-+ * @oob_buf:	filesystem supplied oob data buffer
-+ * @oobsel:	oob selection structure
-+ *
-+ * 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 i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
-+	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
-+	struct nand_chip *this = mtd->priv;
-+	u_char *data_poi, *oob_data = oob_buf;
-+	u_char ecc_calc[32];
-+	u_char ecc_code[32];
-+        int eccmode, eccsteps;
-+	int	*oob_config, datidx;
-+	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
-+	int	eccbytes = 3;
-+	int	compareecc = 1;
-+	int	oobreadlen;
-+
-+
-+	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);
-+
-+	/* use userspace supplied oobinfo, if zero */
-+	if (oobsel == NULL)
-+		oobsel = &mtd->oobinfo;
-+	
-+	/* Autoplace of oob data ? Use the default placement scheme */
-+	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
-+		oobsel = this->autooob;
-+		
-+	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
-+	oob_config = oobsel->eccpos;
-+
-+	/* Select the NAND device */
-+	chipnr = (int)(from >> this->chip_shift);
-+	this->select_chip(mtd, chipnr);
-+
-+	/* First we calculate the starting page */
-+	realpage = (int) (from >> this->page_shift);
-+	page = realpage & this->pagemask;
-+
-+	/* Get raw starting column */
-+	col = from & (mtd->oobblock - 1);
-+
-+	end = mtd->oobblock;
-+	ecc = this->eccsize;
-+	switch (eccmode) {
-+	case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data  */
-+		eccbytes = 6;
-+		break;						
-+	case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data  */
-+		eccbytes = 8;
-+		break;
-+	case NAND_ECC_NONE:
-+		compareecc = 0;
-+		break;						
-+	}	 
-+
-+	if (this->options & NAND_HWECC_SYNDROME)
-+		compareecc = 0;
-+
-+	oobreadlen = mtd->oobsize;
-+	if (this->options & NAND_HWECC_SYNDROME) 
-+		oobreadlen -= oobsel->eccbytes;
-+
-+	/* Loop until all data read */
-+	while (read < len) {
-+		
-+		int aligned = (!col && (len - read) >= end);
-+		/* 
-+		 * 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 (aligned)
-+			data_poi = &buf[read];
-+		else 
-+			data_poi = this->data_buf;
-+		
-+		/* Check, if we have this page in the buffer 
-+		 *
-+		 * FIXME: Make it work when we must provide oob data too,
-+		 * check the usage of data_buf oob field
-+		 */
-+		if (realpage == this->pagebuf && !oob_buf) {
-+			/* aligned read ? */
-+			if (aligned)
-+				memcpy (data_poi, this->data_buf, end);
-+			goto readdata;
-+		}
-+
-+		/* Check, if we must send the read command */
-+		if (sndcmd) {
-+			this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);
-+			sndcmd = 0;
-+		}	
-+
-+		/* get oob area, if we have no oob buffer from fs-driver */
-+		if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE)
-+			oob_data = &this->data_buf[end];
-+
-+		eccsteps = this->eccsteps;
-+		
-+		switch (eccmode) {
-+		case NAND_ECC_NONE: {	/* No ECC, Read in a page */
-+			static unsigned long lastwhinge = 0;
-+			if ((lastwhinge / HZ) != (jiffies / HZ)) {
-+				printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");
-+				lastwhinge = jiffies;
-+			}
-+			this->read_buf(mtd, data_poi, end);
-+			break;
-+		}
-+			
-+		case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */
-+			this->read_buf(mtd, data_poi, end);
-+			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) 
-+				this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
-+			break;	
-+			
-+		case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data */
-+		case NAND_ECC_HW3_512: /* Hardware ECC 3 byte /512 byte data */	
-+		case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data  */
-+		case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data  */
-+			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {
-+				this->enable_hwecc(mtd, NAND_ECC_READ);	
-+				this->read_buf(mtd, &data_poi[datidx], ecc);
-+
-+				/* HW ecc with syndrome calculation must read the
-+				 * syndrome from flash immidiately after the data */
-+				if (!compareecc) {
-+					/* Some hw ecc generators need to know when the
-+					 * syndrome is read from flash */
-+					this->enable_hwecc(mtd, NAND_ECC_READSYN);
-+					this->read_buf(mtd, &oob_data[i], eccbytes);
-+					/* We calc error correction directly, it checks the hw
-+					 * generator for an error, reads back the syndrome and
-+					 * does the error correction on the fly */
-+					if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
-+						DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 
-+							"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
-+						ecc_failed++;
-+					}
-+				} else {
-+					this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
-+				}	
-+			}
-+			break;						
-+
-+		default:
-+			printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
-+			BUG();	
-+		}
-+
-+		/* read oobdata */
-+		this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
-+
-+		/* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
-+		if (!compareecc)
-+			goto readoob;	
-+		
-+		/* Pick the ECC bytes out of the oob data */
-+		for (j = 0; j < oobsel->eccbytes; j++)
-+			ecc_code[j] = oob_data[oob_config[j]];
-+
-+		/* correct data, if neccecary */
-+		for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
-+			ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
-+			
-+			/* Get next chunk of ecc bytes */
-+			j += eccbytes;
-+			
-+			/* Check, if we have a fs supplied oob-buffer, 
-+			 * This is the legacy mode. Used by YAFFS1
-+			 * Should go away some day
-+			 */
-+			if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { 
-+				int *p = (int *)(&oob_data[mtd->oobsize]);
-+				p[i] = ecc_status;
-+			}
-+			
-+			if (ecc_status == -1) {	
-+				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
-+				ecc_failed++;
-+			}
-+		}		
-+
-+	readoob:
-+		/* check, if we have a fs supplied oob-buffer */
-+		if (oob_buf) {
-+			/* without autoplace. Legacy mode used by YAFFS1 */
-+			switch(oobsel->useecc) {
-+			case MTD_NANDECC_AUTOPLACE:
-+				/* Walk through the autoplace chunks */
-+				for (i = 0, j = 0; j < mtd->oobavail; i++) {
-+					int from = oobsel->oobfree[i][0];
-+					int num = oobsel->oobfree[i][1];
-+					memcpy(&oob_buf[oob], &oob_data[from], num);
-+					j+= num;
-+				}
-+				oob += mtd->oobavail;
-+				break;
-+			case MTD_NANDECC_PLACE:
-+				/* YAFFS1 legacy mode */
-+				oob_data += this->eccsteps * sizeof (int);
-+			default:
-+				oob_data += mtd->oobsize;
-+			}
-+		}
-+	readdata:
-+		/* Partial page read, transfer data into fs buffer */
-+		if (!aligned) { 
-+			for (j = col; j < end && read < len; j++)
-+				buf[read++] = data_poi[j];
-+			this->pagebuf = realpage;	
-+		} else		
-+			read += mtd->oobblock;
-+
-+		/* Apply delay or wait for ready/busy pin 
-+		 * Do this before the AUTOINCR check, so no problems
-+		 * arise if a chip which does auto increment
-+		 * is marked as NOAUTOINCR by the board driver.
-+		*/
-+		if (!this->dev_ready) 
-+			udelay (this->chip_delay);
-+		else
-+			while (!this->dev_ready(mtd));	
-+			
-+		if (read == len)
-+			break;	
-+
-+		/* For subsequent reads align to page boundary. */
-+		col = 0;
-+		/* Increment page address */
-+		realpage++;
-+
-+		page = realpage & this->pagemask;
-+		/* Check, if we cross a chip boundary */
-+		if (!page) {
-+			chipnr++;
-+			this->select_chip(mtd, -1);
-+			this->select_chip(mtd, chipnr);
-+		}
-+		/* Check, if the chip supports auto page increment 
-+		 * or if we have hit a block boundary. 
-+		*/ 
-+		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
-+			sndcmd = 1;				
-+	}
-+
-+	/* Deselect and wake up anyone waiting on the device */
-+	nand_release_chip(mtd);
-+
-+	/*
-+	 * Return success, if no ECC failures, else -EBADMSG
-+	 * fs driver will take care of that, because
-+	 * retlen == desired len and result == -EBADMSG
-+	 */
-+	*retlen = read;
-+	return ecc_failed ? -EBADMSG : 0;
-+}
-+
-+/**
-+ * nand_read_oob - [MTD Interface] NAND read out-of-band
-+ * @mtd:	MTD device structure
-+ * @from:	offset to read from
-+ * @len:	number of bytes to read
-+ * @retlen:	pointer to variable to store the number of read bytes
-+ * @buf:	the databuffer to put data
-+ *
-+ * NAND read out-of-band data from the spare area
-+ */
-+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, chipnr;
-+	struct nand_chip *this = mtd->priv;
-+	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
-+
-+	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);
-+	chipnr = (int)(from >> this->chip_shift);
-+	
-+	/* Mask to get column */
-+	col = from & (mtd->oobsize - 1);
-+
-+	/* 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);
-+
-+	/* Select the NAND device */
-+	this->select_chip(mtd, chipnr);
-+
-+	/* Send the read command */
-+	this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask);
-+	/* 
-+	 * Read the data, if we read more than one page
-+	 * oob data, let the device transfer the data !
-+	 */
-+	i = 0;
-+	while (i < len) {
-+		int thislen = mtd->oobsize - col;
-+		thislen = min_t(int, thislen, len);
-+		this->read_buf(mtd, &buf[i], thislen);
-+		i += thislen;
-+		
-+		/* Apply delay or wait for ready/busy pin 
-+		 * Do this before the AUTOINCR check, so no problems
-+		 * arise if a chip which does auto increment
-+		 * is marked as NOAUTOINCR by the board driver.
-+		*/
-+		if (!this->dev_ready) 
-+			udelay (this->chip_delay);
-+		else
-+			while (!this->dev_ready(mtd));	
-+
-+		/* Read more ? */
-+		if (i < len) {
-+			page++;
-+			col = 0;
-+
-+			/* Check, if we cross a chip boundary */
-+			if (!(page & this->pagemask)) {
-+				chipnr++;
-+				this->select_chip(mtd, -1);
-+				this->select_chip(mtd, chipnr);
-+			}
-+				
-+			/* Check, if the chip supports auto page increment 
-+			 * or if we have hit a block boundary. 
-+			*/ 
-+			if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) {
-+				/* For subsequent page reads set offset to 0 */
-+			        this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask);
-+			}
-+		}
-+	}
-+
-+	/* Deselect and wake up anyone waiting on the device */
-+	nand_release_chip(mtd);
-+
-+	/* Return happy */
-+	*retlen = len;
-+	return 0;
-+}
-+
-+/**
-+ * nand_read_raw - [GENERIC] Read raw data including oob into buffer
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @from:	offset to read from
-+ * @len:	number of bytes to read
-+ * @ooblen:	number of oob data bytes to read
-+ *
-+ * Read raw data including oob into buffer
-+ */
-+int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int page = (int) (from >> this->page_shift);
-+	int chip = (int) (from >> this->chip_shift);
-+	int sndcmd = 1;
-+	int cnt = 0;
-+	int pagesize = mtd->oobblock + mtd->oobsize;
-+	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
-+
-+	/* Do not allow reads past end of device */
-+	if ((from + len) > mtd->size) {
-+		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");
-+		return -EINVAL;
-+	}
-+
-+	/* Grab the lock and see if the device is available */
-+	nand_get_chip (this, mtd , FL_READING);
-+
-+	this->select_chip (mtd, chip);
-+	
-+	/* Add requested oob length */
-+	len += ooblen;
-+	
-+	while (len) {
-+		if (sndcmd)
-+			this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask);
-+		sndcmd = 0;	
-+
-+		this->read_buf (mtd, &buf[cnt], pagesize);
-+
-+		len -= pagesize;
-+		cnt += pagesize;
-+		page++;
-+		
-+		if (!this->dev_ready) 
-+			udelay (this->chip_delay);
-+		else
-+			while (!this->dev_ready(mtd));	
-+			
-+		/* Check, if the chip supports auto page increment */ 
-+		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
-+			sndcmd = 1;
-+	}
-+
-+	/* Deselect and wake up anyone waiting on the device */
-+	nand_release_chip(mtd);
-+	return 0;
-+}
-+
-+
-+/** 
-+ * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer 
-+ * @mtd:	MTD device structure
-+ * @fsbuf:	buffer given by fs driver
-+ * @oobsel:	out of band selection structre
-+ * @autoplace:	1 = place given buffer into the oob bytes
-+ * @numpages:	number of pages to prepare
-+ *
-+ * Return:
-+ * 1. Filesystem buffer available and autoplacement is off,
-+ *    return filesystem buffer
-+ * 2. No filesystem buffer or autoplace is off, return internal
-+ *    buffer
-+ * 3. Filesystem buffer is given and autoplace selected
-+ *    put data from fs buffer into internal buffer and
-+ *    retrun internal buffer
-+ *
-+ * Note: The internal buffer is filled with 0xff. This must
-+ * be done only once, when no autoplacement happens
-+ * Autoplacement sets the buffer dirty flag, which
-+ * forces the 0xff fill before using the buffer again.
-+ *
-+*/
-+static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel,
-+		int autoplace, int numpages)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int i, len, ofs;
-+
-+	/* Zero copy fs supplied buffer */
-+	if (fsbuf && !autoplace) 
-+		return fsbuf;
-+
-+	/* Check, if the buffer must be filled with ff again */
-+	if (this->oobdirty) {	
-+		memset (this->oob_buf, 0xff, 
-+			mtd->oobsize << (this->phys_erase_shift - this->page_shift));
-+		this->oobdirty = 0;
-+	}	
-+	
-+	/* If we have no autoplacement or no fs buffer use the internal one */
-+	if (!autoplace || !fsbuf)
-+		return this->oob_buf;
-+	
-+	/* Walk through the pages and place the data */
-+	this->oobdirty = 1;
-+	ofs = 0;
-+	while (numpages--) {
-+		for (i = 0, len = 0; len < mtd->oobavail; i++) {
-+			int to = ofs + oobsel->oobfree[i][0];
-+			int num = oobsel->oobfree[i][1];
-+			memcpy (&this->oob_buf[to], fsbuf, num);
-+			len += num;
-+			fsbuf += num;
-+		}
-+		ofs += mtd->oobavail;
-+	}
-+	return this->oob_buf;
-+}
-+
-+#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0
-+
-+/**
-+ * nand_write - [MTD Interface] compability function for nand_write_ecc
-+ * @mtd:	MTD device structure
-+ * @to:		offset to write to
-+ * @len:	number of bytes to write
-+ * @retlen:	pointer to variable to store the number of written bytes
-+ * @buf:	the data to write
-+ *
-+ * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL
-+ *
-+*/
-+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_ecc - [MTD Interface] NAND write with ECC
-+ * @mtd:	MTD device structure
-+ * @to:		offset to write to
-+ * @len:	number of bytes to write
-+ * @retlen:	pointer to variable to store the number of written bytes
-+ * @buf:	the data to write
-+ * @eccbuf:	filesystem supplied oob data buffer
-+ * @oobsel:	oob selection structure
-+ *
-+ * 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 startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;
-+	int autoplace = 0, numpages, totalpages;
-+	struct nand_chip *this = mtd->priv;
-+	u_char *oobbuf, *bufstart;
-+	int	ppblock = (1 << (this->phys_erase_shift - this->page_shift));
-+
-+	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);
-+
-+	/* Initialize retlen, in case of early exit */
-+	*retlen = 0;
-+
-+	/* 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;
-+	}
-+
-+	/* Grab the lock and see if the device is available */
-+	nand_get_chip (this, mtd, FL_WRITING);
-+
-+	/* Calculate chipnr */
-+	chipnr = (int)(to >> this->chip_shift);
-+	/* Select the NAND device */
-+	this->select_chip(mtd, chipnr);
-+
-+	/* Check, if it is write protected */
-+	if (nand_check_wp(mtd))
-+		goto out;
-+
-+	/* if oobsel is NULL, use chip defaults */
-+	if (oobsel == NULL) 
-+		oobsel = &mtd->oobinfo;		
-+		
-+	/* Autoplace of oob data ? Use the default placement scheme */
-+	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
-+		oobsel = this->autooob;
-+		autoplace = 1;
-+	}	
-+
-+	/* Setup variables and oob buffer */
-+	totalpages = len >> this->page_shift;
-+	page = (int) (to >> this->page_shift);
-+	/* Invalidate the page cache, if we write to the cached page */
-+	if (page <= this->pagebuf && this->pagebuf < (page + totalpages))  
-+		this->pagebuf = -1;
-+	
-+	/* Set it relative to chip */
-+	page &= this->pagemask;
-+	startpage = page;
-+	/* Calc number of pages we can write in one go */
-+	numpages = min (ppblock - (startpage  & (ppblock - 1)), totalpages);
-+	oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages);
-+	bufstart = (u_char *)buf;
-+
-+	/* Loop until all data is written */
-+	while (written < len) {
-+
-+		this->data_poi = (u_char*) &buf[written];
-+		/* Write one page. If this is the last page to write
-+		 * or the last page in this block, then use the
-+		 * real pageprogram command, else select cached programming
-+		 * if supported by the chip.
-+		 */
-+		ret = nand_write_page (mtd, this, page, &oobbuf[oob], oobsel, (--numpages > 0));
-+		if (ret) {
-+			DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret);
-+			goto out;
-+		}	
-+		/* Next oob page */
-+		oob += mtd->oobsize;
-+		/* Update written bytes count */
-+		written += mtd->oobblock;
-+		if (written == len) 
-+			goto cmp;
-+		
-+		/* Increment page address */
-+		page++;
-+
-+		/* Have we hit a block boundary ? Then we have to verify and
-+		 * if verify is ok, we have to setup the oob buffer for
-+		 * the next pages.
-+		*/
-+		if (!(page & (ppblock - 1))){
-+			int ofs;
-+			this->data_poi = bufstart;
-+			ret = nand_verify_pages (mtd, this, startpage, 
-+				page - startpage,
-+				oobbuf, oobsel, chipnr, (eccbuf != NULL));
-+			if (ret) {
-+				DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
-+				goto out;
-+			}	
-+			*retlen = written;
-+
-+			ofs = autoplace ? mtd->oobavail : mtd->oobsize;
-+			if (eccbuf)
-+				eccbuf += (page - startpage) * ofs;
-+			totalpages -= page - startpage;
-+			numpages = min (totalpages, ppblock);
-+			page &= this->pagemask;
-+			startpage = page;
-+			oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, 
-+					autoplace, numpages);
-+			/* Check, if we cross a chip boundary */
-+			if (!page) {
-+				chipnr++;
-+				this->select_chip(mtd, -1);
-+				this->select_chip(mtd, chipnr);
-+			}
-+		}
-+	}
-+	/* Verify the remaining pages */
-+cmp:
-+	this->data_poi = bufstart;
-+ 	ret = nand_verify_pages (mtd, this, startpage, totalpages,
-+		oobbuf, oobsel, chipnr, (eccbuf != NULL));
-+	if (!ret)
-+		*retlen = written;
-+	else	
-+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret);
-+
-+out:
-+	/* Deselect and wake up anyone waiting on the device */
-+	nand_release_chip(mtd);
-+
-+	return ret;
-+}
-+
-+
-+/**
-+ * nand_write_oob - [MTD Interface] NAND write out-of-band
-+ * @mtd:	MTD device structure
-+ * @to:		offset to write to
-+ * @len:	number of bytes to write
-+ * @retlen:	pointer to variable to store the number of written bytes
-+ * @buf:	the data to write
-+ *
-+ * 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 column, page, status, ret = -EIO, chipnr;
-+	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);
-+	chipnr = (int) (to >> this->chip_shift);
-+
-+	/* Mask to get column */
-+	column = to & (mtd->oobsize - 1);
-+
-+	/* 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);
-+
-+	/* Select the NAND device */
-+	this->select_chip(mtd, chipnr);
-+
-+	/* Reset the chip. Some chips (like the Toshiba TC5832DC found
-+	   in one of my DiskOnChip 2000 test units) will clear the whole
-+	   data page too if we don't do this. I have no clue why, but
-+	   I seem to have 'fixed' it in the doc2000 driver in
-+	   August 1999.  dwmw2. */
-+	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-+
-+	/* Check, if it is write protected */
-+	if (nand_check_wp(mtd))
-+		goto out;
-+	
-+	/* Invalidate the page cache, if we write to the cached page */
-+	if (page == this->pagebuf)
-+		this->pagebuf = -1;
-+
-+	if (NAND_MUST_PAD(this)) {
-+		/* Write out desired data */
-+		this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page & this->pagemask);
-+		/* prepad 0xff for partial programming */
-+		this->write_buf(mtd, ffchars, column);
-+		/* write data */
-+		this->write_buf(mtd, buf, len);
-+		/* postpad 0xff for partial programming */
-+		this->write_buf(mtd, ffchars, mtd->oobsize - (len+column));
-+	} else {
-+		/* Write out desired data */
-+		this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock + column, page & this->pagemask);
-+		/* write data */
-+		this->write_buf(mtd, buf, len);
-+	}
-+	/* 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 & this->pagemask);
-+
-+	if (this->verify_buf(mtd, buf, len)) {
-+		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);
-+		ret = -EIO;
-+		goto out;
-+	}
-+#endif
-+	ret = 0;
-+out:
-+	/* Deselect and wake up anyone waiting on the device */
-+	nand_release_chip(mtd);
-+
-+	return ret;
-+}
-+
-+
-+/**
-+ * nand_writev - [MTD Interface] compabilty function for nand_writev_ecc
-+ * @mtd:	MTD device structure
-+ * @vecs:	the iovectors to write
-+ * @count:	number of vectors
-+ * @to:		offset to write to
-+ * @retlen:	pointer to variable to store the number of written bytes
-+ *
-+ * NAND write with kvec. This just calls the ecc function
-+ */
-+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));	
-+}
-+
-+/**
-+ * nand_writev_ecc - [MTD Interface] write with iovec with ecc
-+ * @mtd:	MTD device structure
-+ * @vecs:	the iovectors to write
-+ * @count:	number of vectors
-+ * @to:		offset to write to
-+ * @retlen:	pointer to variable to store the number of written bytes
-+ * @eccbuf:	filesystem supplied oob data buffer
-+ * @oobsel:	oob selection structure
-+ *
-+ * NAND write with iovec with ecc
-+ */
-+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 = -EIO, written = 0, chipnr;
-+	int oob, numpages, autoplace = 0, startpage;
-+	struct nand_chip *this = mtd->priv;
-+	int	ppblock = (1 << (this->phys_erase_shift - this->page_shift));
-+	u_char *oobbuf, *bufstart;
-+
-+	/* Preset written len for early exit */
-+	*retlen = 0;
-+
-+	/* 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;
-+	}
-+
-+	/* Grab the lock and see if the device is available */
-+	nand_get_chip (this, mtd, FL_WRITING);
-+
-+	/* Get the current chip-nr */
-+	chipnr = (int) (to >> this->chip_shift);
-+	/* Select the NAND device */
-+	this->select_chip(mtd, chipnr);
-+
-+	/* Check, if it is write protected */
-+	if (nand_check_wp(mtd))
-+		goto out;
-+
-+	/* if oobsel is NULL, use chip defaults */
-+	if (oobsel == NULL) 
-+		oobsel = &mtd->oobinfo;		
-+
-+	/* Autoplace of oob data ? Use the default placement scheme */
-+	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {
-+		oobsel = this->autooob;
-+		autoplace = 1;
-+	}	
-+
-+	/* Setup start page */
-+	page = (int) (to >> this->page_shift);
-+	/* Invalidate the page cache, if we write to the cached page */
-+	if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift))  
-+		this->pagebuf = -1;
-+
-+	startpage = page & this->pagemask;
-+
-+	/* Loop until all kvec' data has been written */
-+	len = 0;
-+	while (count) {
-+		/* If the given tuple is >= pagesize then
-+		 * write it out from the iov
-+		 */
-+		if ((vecs->iov_len - len) >= mtd->oobblock) {
-+			/* Calc number of pages we can write
-+			 * out of this iov in one go */
-+			numpages = (vecs->iov_len - len) >> this->page_shift;
-+			/* Do not cross block boundaries */
-+			numpages = min (ppblock - (startpage & (ppblock - 1)), numpages);
-+			oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages);
-+			bufstart = (u_char *)vecs->iov_base;
-+			bufstart += len;
-+			this->data_poi = bufstart;
-+			oob = 0;
-+			for (i = 1; i <= numpages; i++) {
-+				/* Write one page. If this is the last page to write
-+				 * then use the real pageprogram command, else select 
-+				 * cached programming if supported by the chip.
-+				 */
-+				ret = nand_write_page (mtd, this, page & this->pagemask, 
-+					&oobbuf[oob], oobsel, i != numpages);
-+				if (ret)
-+					goto out;
-+				this->data_poi += mtd->oobblock;
-+				len += mtd->oobblock;
-+				oob += mtd->oobsize;
-+				page++;
-+			}
-+			/* Check, if we have to switch to the next tuple */
-+			if (len >= (int) vecs->iov_len) {
-+				vecs++;
-+				len = 0;
-+				count--;
-+			}
-+		} else {
-+			/* We must use the internal buffer, read data out of each 
-+			 * tuple until we have a full page to write
-+			 */
-+			int cnt = 0;
-+			while (cnt < mtd->oobblock) {
-+				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->pagebuf = page;	
-+			this->data_poi = this->data_buf;	
-+			bufstart = this->data_poi;
-+			numpages = 1;		
-+			oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages);
-+			ret = nand_write_page (mtd, this, page & this->pagemask,
-+				oobbuf, oobsel, 0);
-+			if (ret)
-+				goto out;
-+			page++;
-+		}
-+
-+		this->data_poi = bufstart;
-+		ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0);
-+		if (ret)
-+			goto out;
-+			
-+		written += mtd->oobblock * numpages;
-+		/* All done ? */
-+		if (!count)
-+			break;
-+
-+		startpage = page & this->pagemask;
-+		/* Check, if we cross a chip boundary */
-+		if (!startpage) {
-+			chipnr++;
-+			this->select_chip(mtd, -1);
-+			this->select_chip(mtd, chipnr);
-+		}
-+	}
-+	ret = 0;
-+out:
-+	/* Deselect and wake up anyone waiting on the device */
-+	nand_release_chip(mtd);
-+
-+	*retlen = written;
-+	return ret;
-+}
-+
-+/**
-+ * single_erease_cmd - [GENERIC] NAND standard block erase command function
-+ * @mtd:	MTD device structure
-+ * @page:	the page address of the block which will be erased
-+ *
-+ * Standard erase command for NAND chips
-+ */
-+static void single_erase_cmd (struct mtd_info *mtd, int page)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	/* Send commands to erase a block */
-+	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
-+	this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
-+}
-+
-+/**
-+ * multi_erease_cmd - [GENERIC] AND specific block erase command function
-+ * @mtd:	MTD device structure
-+ * @page:	the page address of the block which will be erased
-+ *
-+ * AND multi block erase command function
-+ * Erase 4 consecutive blocks
-+ */
-+static void multi_erase_cmd (struct mtd_info *mtd, int page)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	/* Send commands to erase a block */
-+	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
-+	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
-+	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page++);
-+	this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
-+	this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
-+}
-+
-+/**
-+ * nand_erase - [MTD Interface] erase block(s)
-+ * @mtd:	MTD device structure
-+ * @instr:	erase instruction
-+ *
-+ * Erase one ore more blocks
-+ */
-+static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
-+{
-+	return nand_erase_nand (mtd, instr, 0);
-+}
-+ 
-+/**
-+ * nand_erase_intern - [NAND Interface] erase block(s)
-+ * @mtd:	MTD device structure
-+ * @instr:	erase instruction
-+ * @allowbbt:	allow erasing the bbt area
-+ *
-+ * Erase one ore more blocks
-+ */
-+int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt)
-+{
-+	int page, len, status, pages_per_block, ret, chipnr;
-+	struct nand_chip *this = mtd->priv;
-+
-+	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 & ((1 << this->phys_erase_shift) - 1)) {
-+		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
-+		return -EINVAL;
-+	}
-+
-+	/* Length must align on block boundary */
-+	if (instr->len & ((1 << this->phys_erase_shift) - 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;
-+	}
-+
-+	instr->fail_addr = 0xffffffff;
-+
-+	/* Grab the lock and see if the device is available */
-+	nand_get_chip (this, mtd, FL_ERASING);
-+
-+	/* Shift to get first page */
-+	page = (int) (instr->addr >> this->page_shift);
-+	chipnr = (int) (instr->addr >> this->chip_shift);
-+
-+	/* Calculate pages in each block */
-+	pages_per_block = 1 << (this->phys_erase_shift - this->page_shift);
-+
-+	/* Select the NAND device */
-+	this->select_chip(mtd, chipnr);
-+
-+	/* Check the WP bit */
-+	/* Check, if it is write protected */
-+	if (nand_check_wp(mtd)) {
-+		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 ! */
-+		if (nand_block_checkbad(mtd, ((loff_t) page) << this->page_shift, 0, allowbbt)) {
-+			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;
-+		}
-+		
-+		/* Invalidate the page cache, if we erase the block which contains 
-+		   the current cached page */
-+		if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block))
-+			this->pagebuf = -1;
-+
-+		this->erase_cmd (mtd, page & this->pagemask);
-+		
-+		status = this->waitfunc (mtd, this, FL_ERASING);
-+
-+		/* 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;
-+			instr->fail_addr = (page << this->page_shift);
-+			goto erase_exit;
-+		}
-+		
-+		/* Increment page address and decrement length */
-+		len -= (1 << this->phys_erase_shift);
-+		page += pages_per_block;
-+
-+		/* Check, if we cross a chip boundary */
-+		if (len && !(page & this->pagemask)) {
-+			chipnr++;
-+			this->select_chip(mtd, -1);
-+			this->select_chip(mtd, chipnr);
-+		}
-+	}
-+	instr->state = MTD_ERASE_DONE;
-+
-+erase_exit:
-+
-+	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
-+	/* Do call back function */
-+	if (!ret)
-+		mtd_erase_callback(instr);
-+
-+	/* Deselect and wake up anyone waiting on the device */
-+	nand_release_chip(mtd);
-+
-+	/* Return more or less happy */
-+	return ret;
-+}
-+
-+/**
-+ * nand_sync - [MTD Interface] sync
-+ * @mtd:	MTD device structure
-+ *
-+ * Sync is actually a wait for chip ready function
-+ */
-+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);
-+}
-+
-+
-+/**
-+ * nand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad
-+ * @mtd:	MTD device structure
-+ * @ofs:	offset relative to mtd start
-+ */
-+static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs)
-+{
-+	/* Check for invalid offset */
-+	if (ofs > mtd->size) 
-+		return -EINVAL;
-+	
-+	return nand_block_checkbad (mtd, ofs, 1, 0);
-+}
-+
-+/**
-+ * nand_block_markbad - [MTD Interface] Mark the block at the given offset as bad
-+ * @mtd:	MTD device structure
-+ * @ofs:	offset relative to mtd start
-+ */
-+static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int ret;
-+
-+        if ((ret = nand_block_isbad(mtd, ofs))) {
-+        	/* If it was bad already, return success and do nothing. */
-+		if (ret > 0)
-+			return 0;
-+        	return ret;
-+        }
-+
-+	return this->block_markbad(mtd, ofs);
-+}
-+
-+/**
-+ * nand_scan - [NAND Interface] Scan for the NAND device
-+ * @mtd:	MTD device structure
-+ * @maxchips:	Number of chips to scan for
-+ *
-+ * This fills out all the not initialized function pointers
-+ * with the defaults.
-+ * The flash ID is read and the mtd/chip structures are
-+ * filled with the appropriate values. Buffers are allocated if
-+ * they are not provided by the board driver
-+ *
-+ */
-+int nand_scan (struct mtd_info *mtd, int maxchips)
-+{
-+	int i, j, nand_maf_id, nand_dev_id, busw;
-+	struct nand_chip *this = mtd->priv;
-+
-+	/* Get buswidth to select the correct functions*/
-+	busw = this->options & NAND_BUSWIDTH_16;
-+
-+	/* 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;
-+
-+	if (!this->select_chip)
-+		this->select_chip = nand_select_chip;
-+	if (!this->write_byte)
-+		this->write_byte = busw ? nand_write_byte16 : nand_write_byte;
-+	if (!this->read_byte)
-+		this->read_byte = busw ? nand_read_byte16 : nand_read_byte;
-+	if (!this->write_word)
-+		this->write_word = nand_write_word;
-+	if (!this->read_word)
-+		this->read_word = nand_read_word;
-+	if (!this->block_bad)
-+		this->block_bad = nand_block_bad;
-+	if (!this->block_markbad)
-+		this->block_markbad = nand_default_block_markbad;
-+	if (!this->write_buf)
-+		this->write_buf = busw ? nand_write_buf16 : nand_write_buf;
-+	if (!this->read_buf)
-+		this->read_buf = busw ? nand_read_buf16 : nand_read_buf;
-+	if (!this->verify_buf)
-+		this->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
-+	if (!this->scan_bbt)
-+		this->scan_bbt = nand_default_bbt;
-+
-+	/* Select the device */
-+	this->select_chip(mtd, 0);
-+
-+	/* Send the command for reading device ID */
-+	this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
-+
-+	/* Read manufacturer and device IDs */
-+	nand_maf_id = this->read_byte(mtd);
-+	nand_dev_id = this->read_byte(mtd);
-+
-+	/* 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) 
-+			continue;
-+
-+		if (!mtd->name) mtd->name = nand_flash_ids[i].name;
-+		this->chipsize = nand_flash_ids[i].chipsize << 20;
-+		
-+		/* New devices have all the information in additional id bytes */
-+		if (!nand_flash_ids[i].pagesize) {
-+			int extid;
-+			/* The 3rd id byte contains non relevant data ATM */
-+			extid = this->read_byte(mtd);
-+			/* The 4th id byte is the important one */
-+			extid = this->read_byte(mtd);
-+			/* Calc pagesize */
-+			mtd->oobblock = 1024 << (extid & 0x3);
-+			extid >>= 2;
-+			/* Calc oobsize */
-+			mtd->oobsize = (8 << (extid & 0x03)) * (mtd->oobblock / 512);
-+			extid >>= 2;
-+			/* Calc blocksize. Blocksize is multiples of 64KiB */
-+			mtd->erasesize = (64 * 1024)  << (extid & 0x03);
-+			extid >>= 2;
-+			/* Get buswidth information */
-+			busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
-+		
-+		} else {
-+			/* Old devices have this data hardcoded in the
-+			 * device id table */
-+			mtd->erasesize = nand_flash_ids[i].erasesize;
-+			mtd->oobblock = nand_flash_ids[i].pagesize;
-+			mtd->oobsize = mtd->oobblock / 32;
-+			busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
-+		}
-+
-+		/* Check, if buswidth is correct. Hardware drivers should set
-+		 * this correct ! */
-+		if (busw != (this->options & NAND_BUSWIDTH_16)) {
-+			printk (KERN_INFO "NAND device: Manufacturer ID:"
-+				" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-+				nand_manuf_ids[i].name , mtd->name);
-+			printk (KERN_WARNING 
-+				"NAND bus width %d instead %d bit\n", 
-+					(this->options & NAND_BUSWIDTH_16) ? 16 : 8,
-+					busw ? 16 : 8);
-+			this->select_chip(mtd, -1);
-+			return 1;	
-+		}
-+		
-+		/* Calculate the address shift from the page size */	
-+		this->page_shift = ffs(mtd->oobblock) - 1;
-+		this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1;
-+		this->chip_shift = ffs(this->chipsize) - 1;
-+
-+		/* Set the bad block position */
-+		this->badblockpos = mtd->oobblock > 512 ? 
-+			NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS;
-+
-+		/* Get chip options, preserve non chip based options */
-+		this->options &= ~NAND_CHIPOPTIONS_MSK;
-+		this->options |= nand_flash_ids[i].options & NAND_CHIPOPTIONS_MSK;
-+		/* Set this as a default. Board drivers can override it, if neccecary */
-+		this->options |= NAND_NO_AUTOINCR;
-+		/* Check if this is a not a samsung device. Do not clear the options
-+		 * for chips which are not having an extended id.
-+		 */	
-+		if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize)
-+			this->options &= ~NAND_SAMSUNG_LP_OPTIONS;
-+		
-+		/* Check for AND chips with 4 page planes */
-+		if (this->options & NAND_4PAGE_ARRAY)
-+			this->erase_cmd = multi_erase_cmd;
-+		else
-+			this->erase_cmd = single_erase_cmd;
-+
-+		/* Do not replace user supplied command function ! */
-+		if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
-+			this->cmdfunc = nand_command_lp;
-+				
-+		/* Try to identify manufacturer */
-+		for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
-+			if (nand_manuf_ids[j].id == nand_maf_id)
-+				break;
-+		}
-+		printk (KERN_INFO "NAND device: Manufacturer ID:"
-+			" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, 
-+			nand_manuf_ids[j].name , nand_flash_ids[i].name);
-+		break;
-+	}
-+
-+	if (!nand_flash_ids[i].name) {
-+		printk (KERN_WARNING "No NAND device found!!!\n");
-+		this->select_chip(mtd, -1);
-+		return 1;
-+	}
-+
-+	for (i=1; i < maxchips; i++) {
-+		this->select_chip(mtd, i);
-+
-+		/* Send the command for reading device ID */
-+		this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);
-+
-+		/* Read manufacturer and device IDs */
-+		if (nand_maf_id != this->read_byte(mtd) ||
-+		    nand_dev_id != this->read_byte(mtd))
-+			break;
-+	}
-+	if (i > 1)
-+		printk(KERN_INFO "%d NAND chips detected\n", i);
-+	
-+	/* Allocate buffers, if neccecary */
-+	if (!this->oob_buf) {
-+		size_t len;
-+		len = mtd->oobsize << (this->phys_erase_shift - this->page_shift);
-+		this->oob_buf = kmalloc (len, GFP_KERNEL);
-+		if (!this->oob_buf) {
-+			printk (KERN_ERR "nand_scan(): Cannot allocate oob_buf\n");
-+			return -ENOMEM;
-+		}
-+		this->options |= NAND_OOBBUF_ALLOC;
-+	}
-+	
-+	if (!this->data_buf) {
-+		size_t len;
-+		len = mtd->oobblock + mtd->oobsize;
-+		this->data_buf = kmalloc (len, GFP_KERNEL);
-+		if (!this->data_buf) {
-+			if (this->options & NAND_OOBBUF_ALLOC)
-+				kfree (this->oob_buf);
-+			printk (KERN_ERR "nand_scan(): Cannot allocate data_buf\n");
-+			return -ENOMEM;
-+		}
-+		this->options |= NAND_DATABUF_ALLOC;
-+	}
-+
-+	/* Store the number of chips and calc total size for mtd */
-+	this->numchips = i;
-+	mtd->size = i * this->chipsize;
-+	/* Convert chipsize to number of pages per chip -1. */
-+	this->pagemask = (this->chipsize >> this->page_shift) - 1;
-+	/* Preset the internal oob buffer */
-+	memset(this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift));
-+
-+	/* If no default placement scheme is given, select an
-+	 * appropriate one */
-+	if (!this->autooob) {
-+		/* Select the appropriate default oob placement scheme for
-+		 * placement agnostic filesystems */
-+		switch (mtd->oobsize) { 
-+		case 8:
-+			this->autooob = &nand_oob_8;
-+			break;
-+		case 16:
-+			this->autooob = &nand_oob_16;
-+			break;
-+		case 64:
-+			this->autooob = &nand_oob_64;
-+			break;
-+		default:
-+			printk (KERN_WARNING "No oob scheme defined for oobsize %d\n",
-+				mtd->oobsize);
-+			BUG();
-+		}
-+	}
-+	
-+	/* The number of bytes available for the filesystem to place fs dependend
-+	 * oob data */
-+	if (this->options & NAND_BUSWIDTH_16) {
-+		mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
-+		if (this->autooob->eccbytes & 0x01)
-+			mtd->oobavail--;
-+	} else
-+		mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
-+
-+	/* 
-+	 * 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: 
-+	case NAND_ECC_HW6_512: 
-+	case NAND_ECC_HW8_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();	
-+	}	
-+	
-+	mtd->eccsize = this->eccsize;
-+	
-+	/* Set the number of read / write steps for one page to ensure ECC generation */
-+	switch (this->eccmode) {
-+	case NAND_ECC_HW3_512:
-+	case NAND_ECC_HW6_512:
-+	case NAND_ECC_HW8_512:
-+		this->eccsteps = mtd->oobblock / 512;
-+		break;
-+	case NAND_ECC_HW3_256:
-+	case NAND_ECC_SOFT:	
-+		this->eccsteps = mtd->oobblock / 256;
-+		break;
-+		
-+	case NAND_ECC_NONE: 
-+		this->eccsteps = 1;
-+		break;
-+	}
-+	
-+	/* Initialize state, waitqueue and spinlock */
-+	this->state = FL_READY;
-+	init_waitqueue_head (&this->wq);
-+	spin_lock_init (&this->chip_lock);
-+
-+	/* De-select the device */
-+	this->select_chip(mtd, -1);
-+
-+	/* Invalidate the pagebuffer reference */
-+	this->pagebuf = -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->block_isbad = nand_block_isbad;
-+	mtd->block_markbad = nand_block_markbad;
-+
-+	/* and make the autooob the default one */
-+	memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
-+
-+	mtd->owner = THIS_MODULE;
-+
-+	/* Build bad block table */
-+	return this->scan_bbt (mtd);
-+}
-+
-+/**
-+ * nand_release - [NAND Interface] Free resources held by the NAND device 
-+ * @mtd:	MTD device structure
-+*/
-+void nand_release (struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+	/* Deregister partitions */
-+	del_mtd_partitions (mtd);
-+#endif
-+	/* Deregister the device */
-+	del_mtd_device (mtd);
-+
-+	/* Free bad block table memory, if allocated */
-+	if (this->bbt)
-+		kfree (this->bbt);
-+	/* Buffer allocated by nand_scan ? */
-+	if (this->options & NAND_OOBBUF_ALLOC)
-+		kfree (this->oob_buf);
-+	/* Buffer allocated by nand_scan ? */
-+	if (this->options & NAND_DATABUF_ALLOC)
-+		kfree (this->data_buf);
-+}
-+
-+EXPORT_SYMBOL (nand_scan);
-+EXPORT_SYMBOL (nand_release);
-+
-+MODULE_LICENSE ("GPL");
-+MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
-+MODULE_DESCRIPTION ("Generic NAND flash driver code");
-Index: linux-2.6.5/drivers/mtd/nand/nand_bbt.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/nand_bbt.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/nand_bbt.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,1053 @@
-+/*
-+ *  drivers/mtd/nand_bbt.c
-+ *
-+ *  Overview:
-+ *   Bad block table support for the NAND driver
-+ *   
-+ *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * $Id: nand_bbt.c,v 1.24 2004/06/28 08:25:35 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.
-+ *
-+ * Description:
-+ *
-+ * When nand_scan_bbt is called, then it tries to find the bad block table 
-+ * depending on the options in the bbt descriptor(s). If a bbt is found 
-+ * then the contents are read and the memory based bbt is created. If a 
-+ * mirrored bbt is selected then the mirror is searched too and the
-+ * versions are compared. If the mirror has a greater version number 
-+ * than the mirror bbt is used to build the memory based bbt.
-+ * If the tables are not versioned, then we "or" the bad block information.
-+ * If one of the bbt's is out of date or does not exist it is (re)created. 
-+ * If no bbt exists at all then the device is scanned for factory marked 
-+ * good / bad blocks and the bad block tables are created. 
-+ *
-+ * For manufacturer created bbts like the one found on M-SYS DOC devices 
-+ * the bbt is searched and read but never created
-+ *
-+ * The autogenerated bad block table is located in the last good blocks 
-+ * of the device. The table is mirrored, so it can be updated eventually. 
-+ * The table is marked in the oob area with an ident pattern and a version 
-+ * number which indicates which of both tables is more up to date.
-+ *
-+ * The table uses 2 bits per block
-+ * 11b: 	block is good
-+ * 00b: 	block is factory marked bad
-+ * 01b, 10b: 	block is marked bad due to wear
-+ *
-+ * The memory bad block table uses the following scheme:
-+ * 00b:		block is good
-+ * 01b:		block is marked bad due to wear
-+ * 10b:		block is reserved (to protect the bbt area)
-+ * 11b:		block is factory marked bad
-+ * 
-+ * Multichip devices like DOC store the bad block info per floor.
-+ *
-+ * Following assumptions are made:
-+ * - bbts start at a page boundary, if autolocated on a block boundary
-+ * - the space neccecary for a bbt in FLASH does not exceed a block boundary
-+ * 
-+ */
-+
-+#include <linux/slab.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/bitops.h>
-+#include <linux/delay.h>
-+
-+
-+/** 
-+ * check_pattern - [GENERIC] check if a pattern is in the buffer
-+ * @buf:	the buffer to search
-+ * @len:	the length of buffer to search
-+ * @paglen:	the pagelength
-+ * @td:		search pattern descriptor
-+ *
-+ * Check for a pattern at the given place. Used to search bad block
-+ * tables and good / bad block identifiers.
-+ * If the SCAN_EMPTY option is set then check, if all bytes except the
-+ * pattern area contain 0xff
-+ *
-+*/
-+static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
-+{
-+	int i, end;
-+	uint8_t *p = buf;
-+
-+	end = paglen + td->offs;
-+	if (td->options & NAND_BBT_SCANEMPTY) {
-+		for (i = 0; i < end; i++) {
-+			if (p[i] != 0xff)
-+				return -1;
-+		}
-+	}	
-+	p += end;
-+	
-+	/* Compare the pattern */
-+	for (i = 0; i < td->len; i++) {
-+		if (p[i] != td->pattern[i])
-+			return -1;
-+	}
-+
-+	p += td->len;
-+	end += td->len;
-+	if (td->options & NAND_BBT_SCANEMPTY) {
-+		for (i = end; i < len; i++) {
-+			if (*p++ != 0xff)
-+				return -1;
-+		}
-+	}
-+	return 0;
-+}
-+
-+/**
-+ * read_bbt - [GENERIC] Read the bad block table starting from page
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @page:	the starting page
-+ * @num:	the number of bbt descriptors to read
-+ * @bits:	number of bits per block
-+ * @offs:	offset in the memory table
-+ *
-+ * Read the bad block table starting from page.
-+ *
-+ */
-+static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, 
-+	int bits, int offs, int reserved_block_code)
-+{
-+	int res, i, j, act = 0;
-+	struct nand_chip *this = mtd->priv;
-+	size_t retlen, len, totlen;
-+	loff_t from;
-+	uint8_t msk = (uint8_t) ((1 << bits) - 1);
-+
-+	totlen = (num * bits) >> 3;
-+	from = ((loff_t)page) << this->page_shift;
-+	
-+	while (totlen) {
-+		len = min (totlen, (size_t) (1 << this->bbt_erase_shift));
-+		res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob);
-+		if (res < 0) {
-+			if (retlen != len) {
-+				printk (KERN_INFO "nand_bbt: Error reading bad block table\n");
-+				return res;
-+			}
-+			printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");
-+		}	
-+
-+		/* Analyse data */
-+		for (i = 0; i < len; i++) {
-+			uint8_t dat = buf[i];
-+			for (j = 0; j < 8; j += bits, act += 2) {
-+				uint8_t tmp = (dat >> j) & msk;
-+				if (tmp == msk)
-+					continue;
-+				if (reserved_block_code &&
-+				    (tmp == reserved_block_code)) {
-+					printk (KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",
-+						((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
-+					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
-+					continue;
-+				}
-+				/* Leave it for now, if its matured we can move this
-+				 * message to MTD_DEBUG_LEVEL0 */
-+				printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",
-+					((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
-+				/* Factory marked bad or worn out ? */	
-+				if (tmp == 0)
-+					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
-+				else
-+					this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
-+			}	
-+		}
-+		totlen -= len;
-+		from += len;
-+	}
-+	return 0;
-+}
-+
-+/**
-+ * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @td:		descriptor for the bad block table 
-+ * @chip:	read the table for a specific chip, -1 read all chips.
-+ *		Applies only if NAND_BBT_PERCHIP option is set
-+ *
-+ * Read the bad block table for all chips starting at a given page
-+ * We assume that the bbt bits are in consecutive order.
-+*/
-+static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int res = 0, i;
-+	int bits;
-+
-+	bits = td->options & NAND_BBT_NRBITS_MSK;
-+	if (td->options & NAND_BBT_PERCHIP) {
-+		int offs = 0;
-+		for (i = 0; i < this->numchips; i++) {
-+			if (chip == -1 || chip == i)
-+				res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code);
-+			if (res)
-+				return res;
-+			offs += this->chipsize >> (this->bbt_erase_shift + 2);
-+		}
-+	} else {
-+		res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code);
-+		if (res)
-+			return res;
-+	}
-+	return 0;
-+}
-+
-+/**
-+ * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @td:		descriptor for the bad block table 
-+ * @md:		descriptor for the bad block table mirror
-+ *
-+ * Read the bad block table(s) for all chips starting at a given page
-+ * We assume that the bbt bits are in consecutive order.
-+ *
-+*/
-+static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td,
-+	struct nand_bbt_descr *md)
-+{
-+	struct nand_chip *this = mtd->priv;
-+
-+	/* Read the primary version, if available */	
-+	if (td->options & NAND_BBT_VERSION) {
-+		nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); 
-+		td->version[0] = buf[mtd->oobblock + td->veroffs];
-+		printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]);
-+	}
-+
-+	/* Read the mirror version, if available */	
-+	if (md && (md->options & NAND_BBT_VERSION)) {
-+		nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); 
-+		md->version[0] = buf[mtd->oobblock + md->veroffs];
-+		printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]);
-+	}
-+
-+	return 1;
-+}
-+
-+/**
-+ * create_bbt - [GENERIC] Create a bad block table by scanning the device
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @bd:		descriptor for the good/bad block search pattern
-+ * @chip:	create the table for a specific chip, -1 read all chips.
-+ *		Applies only if NAND_BBT_PERCHIP option is set
-+ *
-+ * Create a bad block table by scanning the device
-+ * for the given good/bad block identify pattern
-+ */
-+static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int i, j, numblocks, len, scanlen;
-+	int startblock;
-+	loff_t from;
-+	size_t readlen, ooblen;
-+
-+	printk (KERN_INFO "Scanning device for bad blocks\n");
-+
-+	if (bd->options & NAND_BBT_SCANALLPAGES)
-+		len = 1 << (this->bbt_erase_shift - this->page_shift);
-+	else {
-+		if (bd->options & NAND_BBT_SCAN2NDPAGE)
-+			len = 2;
-+		else	
-+			len = 1;
-+	}
-+	scanlen	= mtd->oobblock + mtd->oobsize;
-+	readlen = len * mtd->oobblock;
-+	ooblen = len * mtd->oobsize;
-+
-+	if (chip == -1) {
-+		/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
-+		 * makes shifting and masking less painful */
-+		numblocks = mtd->size >> (this->bbt_erase_shift - 1);
-+		startblock = 0;
-+		from = 0;
-+	} else {
-+		if (chip >= this->numchips) {
-+			printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
-+				chip + 1, this->numchips);
-+			return;	
-+		}
-+		numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
-+		startblock = chip * numblocks;
-+		numblocks += startblock;
-+		from = startblock << (this->bbt_erase_shift - 1);
-+	}
-+	
-+	for (i = startblock; i < numblocks;) {
-+		nand_read_raw (mtd, buf, from, readlen, ooblen);
-+		for (j = 0; j < len; j++) {
-+			if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
-+				this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-+				printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", 
-+					i >> 1, (unsigned int) from);
-+				break;
-+			}
-+		}
-+		i += 2;
-+		from += (1 << this->bbt_erase_shift);
-+	}
-+}
-+
-+/**
-+ * search_bbt - [GENERIC] scan the device for a specific bad block table
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @td:		descriptor for the bad block table
-+ *
-+ * Read the bad block table by searching for a given ident pattern.
-+ * Search is preformed either from the beginning up or from the end of 
-+ * the device downwards. The search starts always at the start of a
-+ * block.
-+ * If the option NAND_BBT_PERCHIP is given, each chip is searched 
-+ * for a bbt, which contains the bad block information of this chip.
-+ * This is neccecary to provide support for certain DOC devices.
-+ *
-+ * The bbt ident pattern resides in the oob area of the first page 
-+ * in a block. 
-+ */
-+static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int i, chips;
-+	int bits, startblock, block, dir;
-+	int scanlen = mtd->oobblock + mtd->oobsize;
-+	int bbtblocks;
-+
-+	/* Search direction top -> down ? */
-+	if (td->options & NAND_BBT_LASTBLOCK) {
-+		startblock = (mtd->size >> this->bbt_erase_shift) -1;
-+		dir = -1;
-+	} else {
-+		startblock = 0;	
-+		dir = 1;
-+	}	
-+	
-+	/* Do we have a bbt per chip ? */
-+	if (td->options & NAND_BBT_PERCHIP) {
-+		chips = this->numchips;
-+		bbtblocks = this->chipsize >> this->bbt_erase_shift;
-+		startblock &= bbtblocks - 1;
-+	} else {
-+		chips = 1;
-+		bbtblocks = mtd->size >> this->bbt_erase_shift;
-+	}
-+	
-+	/* Number of bits for each erase block in the bbt */
-+	bits = td->options & NAND_BBT_NRBITS_MSK;
-+	
-+	for (i = 0; i < chips; i++) {
-+		/* Reset version information */
-+		td->version[i] = 0;	
-+		td->pages[i] = -1;
-+		/* Scan the maximum number of blocks */
-+		for (block = 0; block < td->maxblocks; block++) {
-+			int actblock = startblock + dir * block;
-+			/* Read first page */
-+			nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); 
-+			if (!check_pattern(buf, scanlen, mtd->oobblock, td)) {
-+				td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift);
-+				if (td->options & NAND_BBT_VERSION) {
-+					td->version[i] = buf[mtd->oobblock + td->veroffs];
-+				}
-+				break;
-+			}
-+		}
-+		startblock += this->chipsize >> this->bbt_erase_shift;
-+	}
-+	/* Check, if we found a bbt for each requested chip */
-+	for (i = 0; i < chips; i++) {
-+		if (td->pages[i] == -1)
-+			printk (KERN_WARNING "Bad block table not found for chip %d\n", i);
-+		else
-+			printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]);
-+	}
-+	return 0;	
-+}
-+
-+/**
-+ * search_read_bbts - [GENERIC] scan the device for bad block table(s)
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @td:		descriptor for the bad block table 
-+ * @md:		descriptor for the bad block table mirror
-+ *
-+ * Search and read the bad block table(s)
-+*/
-+static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, 
-+	struct nand_bbt_descr *td, struct nand_bbt_descr *md)
-+{
-+	/* Search the primary table */
-+	search_bbt (mtd, buf, td);
-+		
-+	/* Search the mirror table */
-+	if (md)
-+		search_bbt (mtd, buf, md);
-+	
-+	/* Force result check */
-+	return 1;	
-+}
-+	
-+
-+/** 
-+ * write_bbt - [GENERIC] (Re)write the bad block table
-+ *
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @td:		descriptor for the bad block table 
-+ * @md:		descriptor for the bad block table mirror
-+ * @chipsel:	selector for a specific chip, -1 for all
-+ *
-+ * (Re)write the bad block table
-+ *
-+*/
-+static int write_bbt (struct mtd_info *mtd, uint8_t *buf, 
-+	struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	struct nand_oobinfo oobinfo;
-+	struct erase_info einfo;
-+	int i, j, res, chip = 0;
-+	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
-+	int nrchips, bbtoffs, pageoffs;
-+	uint8_t msk[4];
-+	uint8_t rcode = td->reserved_block_code;
-+	size_t retlen, len = 0;
-+	loff_t to;
-+
-+	if (!rcode)
-+		rcode = 0xff;
-+	/* Write bad block table per chip rather than per device ? */
-+	if (td->options & NAND_BBT_PERCHIP) {
-+		numblocks = (int) (this->chipsize >> this->bbt_erase_shift);
-+		/* Full device write or specific chip ? */	
-+		if (chipsel == -1) {
-+			nrchips = this->numchips;
-+		} else {
-+			nrchips = chipsel + 1;
-+			chip = chipsel;
-+		}
-+	} else {
-+		numblocks = (int) (mtd->size >> this->bbt_erase_shift);
-+		nrchips = 1;
-+	}	
-+	
-+	/* Loop through the chips */
-+	for (; chip < nrchips; chip++) {
-+		
-+		/* There was already a version of the table, reuse the page 
-+		 * This applies for absolute placement too, as we have the 
-+		 * page nr. in td->pages.
-+		 */
-+		if (td->pages[chip] != -1) {
-+			page = td->pages[chip];
-+			goto write;
-+		}	
-+
-+		/* Automatic placement of the bad block table */
-+		/* Search direction top -> down ? */
-+		if (td->options & NAND_BBT_LASTBLOCK) {
-+			startblock = numblocks * (chip + 1) - 1;
-+			dir = -1;
-+		} else {
-+			startblock = chip * numblocks;
-+			dir = 1;
-+		}	
-+
-+		for (i = 0; i < td->maxblocks; i++) {
-+			int block = startblock + dir * i;
-+			/* Check, if the block is bad */
-+			switch ((this->bbt[block >> 2] >> (2 * (block & 0x03))) & 0x03) {
-+			case 0x01:
-+			case 0x03:
-+				continue;
-+			}
-+			page = block << (this->bbt_erase_shift - this->page_shift);
-+			/* Check, if the block is used by the mirror table */
-+			if (!md || md->pages[chip] != page)
-+				goto write;
-+		}
-+		printk (KERN_ERR "No space left to write bad block table\n");
-+		return -ENOSPC;
-+write:	
-+
-+		/* Set up shift count and masks for the flash table */
-+		bits = td->options & NAND_BBT_NRBITS_MSK;
-+		switch (bits) {
-+		case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x01; break;
-+		case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; msk[2] = ~rcode; msk[3] = 0x03; break;
-+		case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; msk[2] = ~rcode; msk[3] = 0x0f; break;
-+		case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break;
-+		default: return -EINVAL;
-+		}
-+		
-+		bbtoffs = chip * (numblocks >> 2);
-+		
-+		to = ((loff_t) page) << this->page_shift;
-+
-+		memcpy (&oobinfo, this->autooob, sizeof(oobinfo));
-+		oobinfo.useecc = MTD_NANDECC_PLACEONLY;
-+		
-+		/* Must we save the block contents ? */
-+		if (td->options & NAND_BBT_SAVECONTENT) {
-+			/* Make it block aligned */
-+			to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1));
-+			len = 1 << this->bbt_erase_shift;
-+			res = mtd->read_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
-+			if (res < 0) {
-+				if (retlen != len) {
-+					printk (KERN_INFO "nand_bbt: Error reading block for writing the bad block table\n");
-+					return res;
-+				}
-+				printk (KERN_WARNING "nand_bbt: ECC error while reading block for writing bad block table\n");
-+			}
-+			/* Calc the byte offset in the buffer */
-+			pageoffs = page - (int)(to >> this->page_shift);
-+			offs = pageoffs << this->page_shift;
-+			/* Preset the bbt area with 0xff */
-+			memset (&buf[offs], 0xff, (size_t)(numblocks >> sft));
-+			/* Preset the bbt's oob area with 0xff */
-+			memset (&buf[len + pageoffs * mtd->oobsize], 0xff,
-+				((len >> this->page_shift) - pageoffs) * mtd->oobsize);
-+			if (td->options & NAND_BBT_VERSION) {
-+				buf[len + (pageoffs * mtd->oobsize) + td->veroffs] = td->version[chip];
-+			}
-+		} else {
-+			/* Calc length */
-+			len = (size_t) (numblocks >> sft);
-+			/* Make it page aligned ! */
-+			len = (len + (mtd->oobblock-1)) & ~(mtd->oobblock-1);
-+			/* Preset the buffer with 0xff */
-+			memset (buf, 0xff, len + (len >> this->page_shift) * mtd->oobsize);
-+			offs = 0;
-+			/* Pattern is located in oob area of first page */
-+			memcpy (&buf[len + td->offs], td->pattern, td->len);
-+			if (td->options & NAND_BBT_VERSION) {
-+				buf[len + td->veroffs] = td->version[chip];
-+			}
-+		}
-+	
-+		/* walk through the memory table */
-+		for (i = 0; i < numblocks; ) {
-+			uint8_t dat;
-+			dat = this->bbt[bbtoffs + (i >> 2)];
-+			for (j = 0; j < 4; j++ , i++) {
-+				int sftcnt = (i << (3 - sft)) & sftmsk;
-+				/* Do not store the reserved bbt blocks ! */
-+				buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt);
-+				dat >>= 2;
-+			}
-+		}
-+		
-+		memset (&einfo, 0, sizeof (einfo));
-+		einfo.mtd = mtd;
-+		einfo.addr = (unsigned long) to;
-+		einfo.len = 1 << this->bbt_erase_shift;
-+		res = nand_erase_nand (mtd, &einfo, 1);
-+		if (res < 0) {
-+			printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res);
-+			return res;
-+		}
-+	
-+		res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo);
-+		if (res < 0) {
-+			printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res);
-+			return res;
-+		}
-+		printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", 
-+			(unsigned int) to, td->version[chip]);
-+	
-+		/* Mark it as used */
-+		td->pages[chip] = page;
-+	}	
-+	return 0;
-+}
-+
-+/**
-+ * nand_memory_bbt - [GENERIC] create a memory based bad block table
-+ * @mtd:	MTD device structure
-+ * @bd:		descriptor for the good/bad block search pattern
-+ *
-+ * The function creates a memory based bbt by scanning the device 
-+ * for manufacturer / software marked good / bad blocks
-+*/
-+static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+
-+	/* Ensure that we only scan for the pattern and nothing else */
-+	bd->options = 0;
-+	create_bbt (mtd, this->data_buf, bd, -1);
-+	return 0;
-+}
-+
-+/**
-+ * check_create - [GENERIC] create and write bbt(s) if neccecary
-+ * @mtd:	MTD device structure
-+ * @buf:	temporary buffer
-+ * @bd:		descriptor for the good/bad block search pattern
-+ *
-+ * The function checks the results of the previous call to read_bbt
-+ * and creates / updates the bbt(s) if neccecary
-+ * Creation is neccecary if no bbt was found for the chip/device
-+ * Update is neccecary if one of the tables is missing or the
-+ * version nr. of one table is less than the other
-+*/
-+static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd)
-+{
-+	int i, chips, writeops, chipsel, res;
-+	struct nand_chip *this = mtd->priv;
-+	struct nand_bbt_descr *td = this->bbt_td;
-+	struct nand_bbt_descr *md = this->bbt_md;
-+	struct nand_bbt_descr *rd, *rd2;
-+
-+	/* Do we have a bbt per chip ? */
-+	if (td->options & NAND_BBT_PERCHIP) 
-+		chips = this->numchips;
-+	else 
-+		chips = 1;
-+	
-+	for (i = 0; i < chips; i++) {
-+		writeops = 0;
-+		rd = NULL;
-+		rd2 = NULL;
-+		/* Per chip or per device ? */
-+		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
-+		/* Mirrored table avilable ? */
-+		if (md) {
-+			if (td->pages[i] == -1 && md->pages[i] == -1) {
-+				writeops = 0x03;
-+				goto create;
-+			}
-+
-+			if (td->pages[i] == -1) {
-+				rd = md;				
-+				td->version[i] = md->version[i];
-+				writeops = 1;
-+				goto writecheck;
-+			}
-+
-+			if (md->pages[i] == -1) {
-+				rd = td;
-+				md->version[i] = td->version[i];
-+				writeops = 2;
-+				goto writecheck;
-+			}
-+
-+			if (td->version[i] == md->version[i]) {
-+				rd = td;
-+				if (!(td->options & NAND_BBT_VERSION))
-+					rd2 = md;
-+				goto writecheck;
-+			}	
-+
-+			if (((int8_t) (td->version[i] - md->version[i])) > 0) {
-+				rd = td;
-+				md->version[i] = td->version[i];
-+				writeops = 2;
-+			} else {
-+				rd = md;
-+				td->version[i] = md->version[i];
-+				writeops = 1;
-+			}
-+
-+			goto writecheck;
-+
-+		} else {
-+			if (td->pages[i] == -1) {
-+				writeops = 0x01;
-+				goto create;
-+			}
-+			rd = td;
-+			goto writecheck;
-+		}
-+create:
-+		/* Create the bad block table by scanning the device ? */
-+		if (!(td->options & NAND_BBT_CREATE))
-+			continue;	
-+		
-+		/* Create the table in memory by scanning the chip(s) */
-+		create_bbt (mtd, buf, bd, chipsel);
-+		
-+		td->version[i] = 1;
-+		if (md)
-+			md->version[i] = 1;	
-+writecheck:	
-+		/* read back first ? */
-+		if (rd)
-+			read_abs_bbt (mtd, buf, rd, chipsel);
-+		/* If they weren't versioned, read both. */
-+		if (rd2)
-+			read_abs_bbt (mtd, buf, rd2, chipsel);
-+
-+		/* Write the bad block table to the device ? */
-+		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-+			res = write_bbt (mtd, buf, td, md, chipsel);
-+			if (res < 0)
-+				return res;
-+		}
-+		
-+		/* Write the mirror bad block table to the device ? */
-+		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-+			res = write_bbt (mtd, buf, md, td, chipsel);
-+			if (res < 0)
-+				return res;
-+		}
-+	}
-+	return 0;	
-+}
-+
-+/**
-+ * mark_bbt_regions - [GENERIC] mark the bad block table regions 
-+ * @mtd:	MTD device structure
-+ * @td:		bad block table descriptor
-+ *
-+ * The bad block table regions are marked as "bad" to prevent
-+ * accidental erasures / writes. The regions are identified by
-+ * the mark 0x02.
-+*/
-+static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int i, j, chips, block, nrblocks, update;
-+	uint8_t oldval, newval;
-+
-+	/* Do we have a bbt per chip ? */
-+	if (td->options & NAND_BBT_PERCHIP) {
-+		chips = this->numchips;
-+		nrblocks = (int)(this->chipsize >> this->bbt_erase_shift);
-+	} else {
-+		chips = 1;
-+		nrblocks = (int)(mtd->size >> this->bbt_erase_shift);
-+	}	
-+	
-+	for (i = 0; i < chips; i++) {
-+		if ((td->options & NAND_BBT_ABSPAGE) ||
-+		    !(td->options & NAND_BBT_WRITE)) {
-+		    	if (td->pages[i] == -1) continue;
-+			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
-+			block <<= 1;		
-+			oldval = this->bbt[(block >> 3)];
-+			newval = oldval | (0x2 << (block & 0x06));
-+			this->bbt[(block >> 3)] = newval;
-+			if ((oldval != newval) && td->reserved_block_code)
-+				nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1));
-+			continue;
-+		}
-+		update = 0;
-+		if (td->options & NAND_BBT_LASTBLOCK)
-+			block = ((i + 1) * nrblocks) - td->maxblocks;
-+		else	
-+			block = i * nrblocks;
-+		block <<= 1;	
-+		for (j = 0; j < td->maxblocks; j++) {
-+			oldval = this->bbt[(block >> 3)];
-+			newval = oldval | (0x2 << (block & 0x06));
-+			this->bbt[(block >> 3)] = newval;
-+			if (oldval != newval) update = 1;
-+			block += 2;
-+		}	
-+		/* If we want reserved blocks to be recorded to flash, and some
-+		   new ones have been marked, then we need to update the stored
-+		   bbts.  This should only happen once. */
-+		if (update && td->reserved_block_code)
-+			nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1));
-+	}
-+}
-+
-+/**
-+ * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
-+ * @mtd:	MTD device structure
-+ * @bd:		descriptor for the good/bad block search pattern
-+ *
-+ * The function checks, if a bad block table(s) is/are already 
-+ * available. If not it scans the device for manufacturer
-+ * marked good / bad blocks and writes the bad block table(s) to
-+ * the selected place.
-+ *
-+ * The bad block table memory is allocated here. It must be freed
-+ * by calling the nand_free_bbt function.
-+ *
-+*/
-+int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int len, res = 0;
-+	uint8_t *buf;
-+	struct nand_bbt_descr *td = this->bbt_td;
-+	struct nand_bbt_descr *md = this->bbt_md;
-+
-+	len = mtd->size >> (this->bbt_erase_shift + 2);
-+	/* Allocate memory (2bit per block) */
-+	this->bbt = (uint8_t *) kmalloc (len, GFP_KERNEL);
-+	if (!this->bbt) {
-+		printk (KERN_ERR "nand_scan_bbt: Out of memory\n");
-+		return -ENOMEM;
-+	}
-+	/* Clear the memory bad block table */
-+	memset (this->bbt, 0x00, len);
-+
-+	/* If no primary table decriptor is given, scan the device
-+	 * to build a memory based bad block table
-+	 */
-+	if (!td)
-+		return nand_memory_bbt(mtd, bd);
-+
-+	/* Allocate a temporary buffer for one eraseblock incl. oob */
-+	len = (1 << this->bbt_erase_shift);
-+	len += (len >> this->page_shift) * mtd->oobsize;
-+	buf = kmalloc (len, GFP_KERNEL);
-+	if (!buf) {
-+		printk (KERN_ERR "nand_bbt: Out of memory\n");
-+		kfree (this->bbt);
-+		this->bbt = NULL;
-+		return -ENOMEM;
-+	}
-+	
-+	/* Is the bbt at a given page ? */
-+	if (td->options & NAND_BBT_ABSPAGE) {
-+		res = read_abs_bbts (mtd, buf, td, md);
-+	} else {	
-+		/* Search the bad block table using a pattern in oob */
-+		res = search_read_bbts (mtd, buf, td, md);
-+	}	
-+
-+	if (res) 
-+		res = check_create (mtd, buf, bd);
-+	
-+	/* Prevent the bbt regions from erasing / writing */
-+	mark_bbt_region (mtd, td);
-+	if (md)
-+		mark_bbt_region (mtd, md);
-+	
-+	kfree (buf);
-+	return res;
-+}
-+
-+
-+/**
-+ * nand_update_bbt - [NAND Interface] update bad block table(s) 
-+ * @mtd:	MTD device structure
-+ * @offs:	the offset of the newly marked block
-+ *
-+ * The function updates the bad block table(s)
-+*/
-+int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int len, res = 0, writeops = 0;
-+	int chip, chipsel;
-+	uint8_t *buf;
-+	struct nand_bbt_descr *td = this->bbt_td;
-+	struct nand_bbt_descr *md = this->bbt_md;
-+
-+	if (!this->bbt || !td)
-+		return -EINVAL;
-+
-+	len = mtd->size >> (this->bbt_erase_shift + 2);
-+	/* Allocate a temporary buffer for one eraseblock incl. oob */
-+	len = (1 << this->bbt_erase_shift);
-+	len += (len >> this->page_shift) * mtd->oobsize;
-+	buf = kmalloc (len, GFP_KERNEL);
-+	if (!buf) {
-+		printk (KERN_ERR "nand_update_bbt: Out of memory\n");
-+		return -ENOMEM;
-+	}
-+	
-+	writeops = md != NULL ? 0x03 : 0x01;
-+
-+	/* Do we have a bbt per chip ? */
-+	if (td->options & NAND_BBT_PERCHIP) {
-+		chip = (int) (offs >> this->chip_shift);
-+		chipsel = chip;
-+	} else {
-+		chip = 0;
-+		chipsel = -1;
-+	}
-+
-+	td->version[chip]++;
-+	if (md)
-+		md->version[chip]++;	
-+
-+	/* Write the bad block table to the device ? */
-+	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
-+		res = write_bbt (mtd, buf, td, md, chipsel);
-+		if (res < 0)
-+			goto out;
-+	}
-+	/* Write the mirror bad block table to the device ? */
-+	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
-+		res = write_bbt (mtd, buf, md, td, chipsel);
-+	}
-+
-+out:	
-+	kfree (buf);
-+	return res;
-+}
-+
-+/* Define some generic bad / good block scan pattern which are used 
-+ * while scanning a device for factory marked good / bad blocks
-+ * 
-+ * The memory based patterns just 
-+ */
-+static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
-+
-+static struct nand_bbt_descr smallpage_memorybased = {
-+	.options = 0,
-+	.offs = 5,
-+	.len = 1,
-+	.pattern = scan_ff_pattern
-+};
-+
-+static struct nand_bbt_descr largepage_memorybased = {
-+	.options = 0,
-+	.offs = 0,
-+	.len = 2,
-+	.pattern = scan_ff_pattern
-+};
-+
-+static struct nand_bbt_descr smallpage_flashbased = {
-+	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
-+	.offs = 5,
-+	.len = 1,
-+	.pattern = scan_ff_pattern
-+};
-+
-+static struct nand_bbt_descr largepage_flashbased = {
-+	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
-+	.offs = 0,
-+	.len = 2,
-+	.pattern = scan_ff_pattern
-+};
-+
-+static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };
-+
-+static struct nand_bbt_descr agand_flashbased = {
-+	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
-+	.offs = 0x20,
-+	.len = 6,
-+	.pattern = scan_agand_pattern
-+};
-+
-+/* Generic flash bbt decriptors
-+*/
-+static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-+static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
-+
-+static struct nand_bbt_descr bbt_main_descr = {
-+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 
-+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-+	.offs =	8,
-+	.len = 4,
-+	.veroffs = 12,
-+	.maxblocks = 4,
-+	.pattern = bbt_pattern
-+};
-+
-+static struct nand_bbt_descr bbt_mirror_descr = {
-+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE 
-+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-+	.offs =	8,
-+	.len = 4,
-+	.veroffs = 12,
-+	.maxblocks = 4,
-+	.pattern = mirror_pattern
-+};
-+
-+/**
-+ * nand_default_bbt - [NAND Interface] Select a default bad block table for the device 
-+ * @mtd:	MTD device structure
-+ *
-+ * This function selects the default bad block table
-+ * support for the device and calls the nand_scan_bbt function
-+ *
-+*/
-+int nand_default_bbt (struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	
-+	/* Default for AG-AND. We must use a flash based 
-+	 * bad block table as the devices have factory marked
-+	 * _good_ blocks. Erasing those blocks leads to loss
-+	 * of the good / bad information, so we _must_ store
-+	 * this information in a good / bad table during 
-+	 * startup
-+	*/
-+	if (this->options & NAND_IS_AND) {
-+		/* Use the default pattern descriptors */
-+		if (!this->bbt_td) {	
-+			this->bbt_td = &bbt_main_descr;
-+			this->bbt_md = &bbt_mirror_descr;
-+		}	
-+		this->options |= NAND_USE_FLASH_BBT;
-+		return nand_scan_bbt (mtd, &agand_flashbased);
-+	}
-+	
-+	/* Is a flash based bad block table requested ? */
-+	if (this->options & NAND_USE_FLASH_BBT) {
-+		/* Use the default pattern descriptors */	
-+		if (!this->bbt_td) {	
-+			this->bbt_td = &bbt_main_descr;
-+			this->bbt_md = &bbt_mirror_descr;
-+		}	
-+		if (mtd->oobblock > 512)
-+			return nand_scan_bbt (mtd, &largepage_flashbased);
-+		else	
-+			return nand_scan_bbt (mtd, &smallpage_flashbased);			
-+	} else {
-+		this->bbt_td = NULL;
-+		this->bbt_md = NULL;
-+		if (mtd->oobblock > 512)
-+			return nand_scan_bbt (mtd, &largepage_memorybased);
-+		else
-+			return nand_scan_bbt (mtd, &smallpage_memorybased);
-+	}
-+}
-+
-+/**
-+ * nand_isbad_bbt - [NAND Interface] Check if a block is bad 
-+ * @mtd:	MTD device structure
-+ * @offs:	offset in the device
-+ * @allowbbt:	allow access to bad block table region
-+ *
-+*/
-+int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	int block;
-+	uint8_t	res;
-+	
-+	/* Get block number * 2 */
-+	block = (int) (offs >> (this->bbt_erase_shift - 1));
-+	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
-+
-+	DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", 
-+		(unsigned int)offs, res, block >> 1);
-+
-+	switch ((int)res) {
-+	case 0x00:	return 0;
-+	case 0x01:	return 1;
-+	case 0x02:	return allowbbt ? 0 : 1;
-+	}
-+	return 1;
-+}
-+
-+EXPORT_SYMBOL (nand_scan_bbt);
-+EXPORT_SYMBOL (nand_default_bbt);
-Index: linux-2.6.5/drivers/mtd/nand/nand_ecc.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/nand_ecc.c	2004-04-03 22:36:54.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/nand_ecc.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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 @@
- };
- 
- 
--/*
-+/**
-+ * 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 @@
- 	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 @@
- 	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: linux-2.6.5/drivers/mtd/nand/nand_ids.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/nand_ids.c	2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/nand_ids.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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
-@@ -13,26 +12,99 @@
-  */
- #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 @@
- 	{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: linux-2.6.5/drivers/mtd/nand/ppchameleonevb.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/ppchameleonevb.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/ppchameleonevb.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,419 @@
-+/*
-+ *  drivers/mtd/nand/ppchameleonevb.c
-+ *
-+ *  Copyright (C) 2003 DAVE Srl (info@wawnet.biz)
-+ *
-+ *  Derived from drivers/mtd/nand/edb7312.c
-+ *
-+ *
-+ * $Id: ppchameleonevb.c,v 1.3 2004/09/16 23:27:14 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.
-+ *
-+ *  Overview:
-+ *   This is a device driver for the NAND flash devices found on the
-+ *   PPChameleon/PPChameleonEVB system.
-+ *   PPChameleon options (autodetected):
-+ *   - BA model: no NAND
-+ *   - ME model: 32MB (Samsung K9F5608U0B)
-+ *   - HI model: 128MB (Samsung K9F1G08UOM)
-+ *   PPChameleonEVB options:
-+ *   - 32MB (Samsung K9F5608U0B)
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <platforms/PPChameleonEVB.h>
-+
-+#undef USE_READY_BUSY_PIN
-+#define USE_READY_BUSY_PIN
-+/* see datasheets (tR) */
-+#define NAND_BIG_DELAY_US		25
-+#define NAND_SMALL_DELAY_US		10
-+
-+/* handy sizes */
-+#define SZ_4M                           0x00400000
-+#define NAND_SMALL_SIZE                 0x02000000
-+#define NAND_MTD_NAME		"ppchameleon-nand"
-+#define NAND_EVB_MTD_NAME	"ppchameleonevb-nand"
-+
-+/* GPIO pins used to drive NAND chip mounted on processor module */
-+#define NAND_nCE_GPIO_PIN 		(0x80000000 >> 1)
-+#define NAND_CLE_GPIO_PIN 		(0x80000000 >> 2)
-+#define NAND_ALE_GPIO_PIN 		(0x80000000 >> 3)
-+#define NAND_RB_GPIO_PIN 		(0x80000000 >> 4)
-+/* GPIO pins used to drive NAND chip mounted on EVB */
-+#define NAND_EVB_nCE_GPIO_PIN 	(0x80000000 >> 14)
-+#define NAND_EVB_CLE_GPIO_PIN 	(0x80000000 >> 15)
-+#define NAND_EVB_ALE_GPIO_PIN 	(0x80000000 >> 16)
-+#define NAND_EVB_RB_GPIO_PIN 	(0x80000000 >> 31)
-+
-+/*
-+ * MTD structure for PPChameleonEVB board
-+ */
-+static struct mtd_info *ppchameleon_mtd 	= NULL;
-+static struct mtd_info *ppchameleonevb_mtd = NULL;
-+
-+/*
-+ * Module stuff
-+ */
-+static int ppchameleon_fio_pbase 	= CFG_NAND0_PADDR;
-+static int ppchameleonevb_fio_pbase = CFG_NAND1_PADDR;
-+
-+#ifdef MODULE
-+MODULE_PARM(ppchameleon_fio_pbase, "i");
-+__setup("ppchameleon_fio_pbase=",ppchameleon_fio_pbase);
-+MODULE_PARM(ppchameleonevb_fio_pbase, "i");
-+__setup("ppchameleonevb_fio_pbase=",ppchameleonevb_fio_pbase);
-+#endif
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+/*
-+ * Define static partitions for flash devices
-+ */
-+static struct mtd_partition partition_info_hi[] = {
-+	{ name: "PPChameleon HI Nand Flash",
-+		  offset: 0,
-+		  size: 128*1024*1024 }
-+};
-+
-+static struct mtd_partition partition_info_me[] = {
-+	{ name: "PPChameleon ME Nand Flash",
-+		  offset: 0,
-+		  size: 32*1024*1024 }
-+};
-+
-+static struct mtd_partition partition_info_evb[] = {
-+	{ name: "PPChameleonEVB Nand Flash",
-+		  offset: 0,
-+		  size: 32*1024*1024 }
-+};
-+
-+#define NUM_PARTITIONS 1
-+
-+extern int parse_cmdline_partitions(struct mtd_info *master,
-+				    struct mtd_partition **pparts,
-+				    const char *mtd_id);
-+#endif
-+
-+
-+/*
-+ *	hardware specific access to control-lines
-+ */
-+static void ppchameleon_hwcontrol(struct mtd_info *mtdinfo, int cmd)
-+{
-+	switch(cmd) {
-+
-+	case NAND_CTL_SETCLE:
-+        	MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND0_PADDR);
-+		break;
-+	case NAND_CTL_CLRCLE:
-+        	MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND0_PADDR);
-+		break;
-+	case NAND_CTL_SETALE:
-+        	MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND0_PADDR);
-+		break;
-+	case NAND_CTL_CLRALE:
-+        	MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND0_PADDR);
-+		break;
-+	case NAND_CTL_SETNCE:
-+			MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND0_PADDR);
-+		break;
-+	case NAND_CTL_CLRNCE:
-+			MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND0_PADDR);
-+		break;
-+	}
-+}
-+
-+static void ppchameleonevb_hwcontrol(struct mtd_info *mtdinfo, int cmd)
-+{
-+	switch(cmd) {
-+
-+	case NAND_CTL_SETCLE:
-+        	MACRO_NAND_CTL_SETCLE((unsigned long)CFG_NAND1_PADDR);
-+		break;
-+	case NAND_CTL_CLRCLE:
-+        	MACRO_NAND_CTL_CLRCLE((unsigned long)CFG_NAND1_PADDR);
-+		break;
-+	case NAND_CTL_SETALE:
-+        	MACRO_NAND_CTL_SETALE((unsigned long)CFG_NAND1_PADDR);
-+		break;
-+	case NAND_CTL_CLRALE:
-+        	MACRO_NAND_CTL_CLRALE((unsigned long)CFG_NAND1_PADDR);
-+		break;
-+	case NAND_CTL_SETNCE:
-+        	MACRO_NAND_ENABLE_CE((unsigned long)CFG_NAND1_PADDR);
-+		break;
-+	case NAND_CTL_CLRNCE:
-+        	MACRO_NAND_DISABLE_CE((unsigned long)CFG_NAND1_PADDR);
-+		break;
-+	}
-+}
-+
-+#ifdef USE_READY_BUSY_PIN
-+/*
-+ *	read device ready pin
-+ */
-+static int ppchameleon_device_ready(struct mtd_info *minfo)
-+{
-+	if (in_be32((volatile unsigned*)GPIO0_IR) & NAND_RB_GPIO_PIN)
-+		return 1;
-+	return 0;
-+}
-+
-+static int ppchameleonevb_device_ready(struct mtd_info *minfo)
-+{
-+	if (in_be32((volatile unsigned*)GPIO0_IR) & NAND_EVB_RB_GPIO_PIN)
-+	return 1;
-+	return 0;
-+}
-+#endif
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+const char *part_probes[] = { "cmdlinepart", NULL };
-+const char *part_probes_evb[] = { "cmdlinepart", NULL };
-+#endif
-+
-+/*
-+ * Main initialization routine
-+ */
-+static int __init ppchameleonevb_init (void)
-+{
-+	struct nand_chip *this;
-+	const char *part_type = 0;
-+	int mtd_parts_nb = 0;
-+	struct mtd_partition *mtd_parts = 0;
-+	void __iomem *ppchameleon_fio_base;
-+	void __iomem *ppchameleonevb_fio_base;
-+
-+
-+	/*********************************
-+	* Processor module NAND (if any) *
-+	*********************************/
-+	/* Allocate memory for MTD device structure and private data */
-+	ppchameleon_mtd = (struct mtd_info *) kmalloc(sizeof(struct mtd_info) +
-+						      sizeof(struct nand_chip), GFP_KERNEL);
-+	if (!ppchameleon_mtd) {
-+		printk("Unable to allocate PPChameleon NAND MTD device structure.\n");
-+		return -ENOMEM;
-+	}
-+
-+	/* map physical address */
-+	ppchameleon_fio_base = (void __iomem *) ioremap(ppchameleon_fio_pbase, SZ_4M);
-+	if(!ppchameleon_fio_base) {
-+		printk("ioremap PPChameleon NAND flash failed\n");
-+		kfree(ppchameleon_mtd);
-+		return -EIO;
-+	}
-+
-+	/* Get pointer to private data */
-+	this = (struct nand_chip *) (&ppchameleon_mtd[1]);
-+
-+	/* Initialize structures */
-+	memset((char *) ppchameleon_mtd, 0, sizeof(struct mtd_info));
-+	memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+	/* Link the private data with the MTD structure */
-+	ppchameleon_mtd->priv = this;
-+
-+        /* Initialize GPIOs */
-+	/* Pin mapping for NAND chip */
-+	/*
-+		CE	GPIO_01
-+		CLE	GPIO_02
-+		ALE	GPIO_03
-+		R/B	GPIO_04
-+	*/
-+	/* output select */
-+	out_be32((volatile unsigned*)GPIO0_OSRH, in_be32((volatile unsigned*)GPIO0_OSRH) & 0xC0FFFFFF);
-+	/* three-state select */
-+	out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xC0FFFFFF);
-+	/* enable output driver */
-+	out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_nCE_GPIO_PIN | NAND_CLE_GPIO_PIN | NAND_ALE_GPIO_PIN);
-+#ifdef USE_READY_BUSY_PIN
-+	/* three-state select */
-+	out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFF3FFFFF);
-+	/* high-impedecence */
-+	out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) & (~NAND_RB_GPIO_PIN));
-+	/* input select */
-+	out_be32((volatile unsigned*)GPIO0_ISR1H, (in_be32((volatile unsigned*)GPIO0_ISR1H) & 0xFF3FFFFF) | 0x00400000);
-+#endif
-+
-+	/* insert callbacks */
-+	this->IO_ADDR_R = ppchameleon_fio_base;
-+	this->IO_ADDR_W = ppchameleon_fio_base;
-+	this->hwcontrol = ppchameleon_hwcontrol;
-+#ifdef USE_READY_BUSY_PIN
-+	this->dev_ready = ppchameleon_device_ready;
-+#endif
-+	this->chip_delay = NAND_BIG_DELAY_US;
-+	/* ECC mode */
-+	this->eccmode = NAND_ECC_SOFT;
-+
-+	/* Scan to find existence of the device (it could not be mounted) */
-+	if (nand_scan (ppchameleon_mtd, 1)) {
-+		iounmap((void *)ppchameleon_fio_base);
-+		kfree (ppchameleon_mtd);
-+		goto nand_evb_init;
-+	}
-+
-+#ifndef USE_READY_BUSY_PIN
-+	/* Adjust delay if necessary */
-+	if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
-+		this->chip_delay = NAND_SMALL_DELAY_US;
-+#endif
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+	ppchameleon_mtd->name = "ppchameleon-nand";
-+	mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, part_probes, &mtd_parts, 0);
-+	if (mtd_parts_nb > 0)
-+	  part_type = "command line";
-+	else
-+	  mtd_parts_nb = 0;
-+#endif
-+	if (mtd_parts_nb == 0)
-+	{
-+		if (ppchameleon_mtd->size == NAND_SMALL_SIZE)
-+			mtd_parts = partition_info_me;
-+		else
-+			mtd_parts = partition_info_hi;
-+		mtd_parts_nb = NUM_PARTITIONS;
-+		part_type = "static";
-+	}
-+
-+	/* Register the partitions */
-+	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-+	add_mtd_partitions(ppchameleon_mtd, mtd_parts, mtd_parts_nb);
-+
-+nand_evb_init:
-+	/****************************
-+	* EVB NAND (always present) *
-+	****************************/
-+	/* Allocate memory for MTD device structure and private data */
-+	ppchameleonevb_mtd = (struct mtd_info *) kmalloc(sizeof(struct mtd_info) +
-+							 sizeof(struct nand_chip), GFP_KERNEL);
-+	if (!ppchameleonevb_mtd) {
-+		printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
-+		return -ENOMEM;
-+	}
-+
-+	/* map physical address */
-+	ppchameleonevb_fio_base = (void __iomem *)ioremap(ppchameleonevb_fio_pbase, SZ_4M);
-+	if(!ppchameleonevb_fio_base) {
-+		printk("ioremap PPChameleonEVB NAND flash failed\n");
-+		kfree(ppchameleonevb_mtd);
-+		return -EIO;
-+	}
-+
-+	/* Get pointer to private data */
-+	this = (struct nand_chip *) (&ppchameleonevb_mtd[1]);
-+
-+	/* Initialize structures */
-+	memset((char *) ppchameleonevb_mtd, 0, sizeof(struct mtd_info));
-+	memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+	/* Link the private data with the MTD structure */
-+	ppchameleonevb_mtd->priv = this;
-+
-+        /* Initialize GPIOs */
-+	/* Pin mapping for NAND chip */
-+	/*
-+		CE	GPIO_14
-+		CLE	GPIO_15
-+		ALE	GPIO_16
-+		R/B	GPIO_31
-+	*/
-+	/* output select */
-+	out_be32((volatile unsigned*)GPIO0_OSRH, in_be32((volatile unsigned*)GPIO0_OSRH) & 0xFFFFFFF0);
-+	out_be32((volatile unsigned*)GPIO0_OSRL, in_be32((volatile unsigned*)GPIO0_OSRL) & 0x3FFFFFFF);
-+	/* three-state select */
-+	out_be32((volatile unsigned*)GPIO0_TSRH, in_be32((volatile unsigned*)GPIO0_TSRH) & 0xFFFFFFF0);
-+	out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0x3FFFFFFF);
-+	/* enable output driver */
-+	out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) | NAND_EVB_nCE_GPIO_PIN | 
-+		 NAND_EVB_CLE_GPIO_PIN | NAND_EVB_ALE_GPIO_PIN);
-+#ifdef USE_READY_BUSY_PIN
-+	/* three-state select */
-+	out_be32((volatile unsigned*)GPIO0_TSRL, in_be32((volatile unsigned*)GPIO0_TSRL) & 0xFFFFFFFC);
-+	/* high-impedecence */
-+	out_be32((volatile unsigned*)GPIO0_TCR, in_be32((volatile unsigned*)GPIO0_TCR) & (~NAND_EVB_RB_GPIO_PIN));
-+	/* input select */
-+	out_be32((volatile unsigned*)GPIO0_ISR1L, (in_be32((volatile unsigned*)GPIO0_ISR1L) & 0xFFFFFFFC) | 0x00000001);
-+#endif
-+
-+	/* insert callbacks */
-+	this->IO_ADDR_R = ppchameleonevb_fio_base;
-+	this->IO_ADDR_W = ppchameleonevb_fio_base;
-+	this->hwcontrol = ppchameleonevb_hwcontrol;
-+#ifdef USE_READY_BUSY_PIN
-+	this->dev_ready = ppchameleonevb_device_ready;
-+#endif
-+	this->chip_delay = NAND_SMALL_DELAY_US;
-+
-+	/* ECC mode */
-+	this->eccmode = NAND_ECC_SOFT;
-+
-+	/* Scan to find existence of the device */
-+	if (nand_scan (ppchameleonevb_mtd, 1)) {
-+		iounmap((void *)ppchameleonevb_fio_base);
-+		kfree (ppchameleonevb_mtd);
-+		return -ENXIO;
-+	}
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+	ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME;
-+	mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &mtd_parts, 0);
-+	if (mtd_parts_nb > 0)
-+	  part_type = "command line";
-+	else
-+	  mtd_parts_nb = 0;
-+#endif
-+	if (mtd_parts_nb == 0)
-+	{
-+		mtd_parts = partition_info_evb;
-+		mtd_parts_nb = NUM_PARTITIONS;
-+		part_type = "static";
-+	}
-+
-+	/* Register the partitions */
-+	printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-+	add_mtd_partitions(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb);
-+
-+	/* Return happy */
-+	return 0;
-+}
-+module_init(ppchameleonevb_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit ppchameleonevb_cleanup (void)
-+{
-+	struct nand_chip *this;
-+
-+	/* Release resources, unregister device(s) */
-+	nand_release (ppchameleon_mtd);
-+	nand_release (ppchameleonevb_mtd);
-+	
-+	/* Release iomaps */
-+	this = (struct nand_chip *) &ppchameleon_mtd[1];
-+	iounmap((void *) this->IO_ADDR_R;
-+	this = (struct nand_chip *) &ppchameleonevb_mtd[1];
-+	iounmap((void *) this->IO_ADDR_R;
-+
-+	/* Free the MTD device structure */
-+	kfree (ppchameleon_mtd);
-+	kfree (ppchameleonevb_mtd);
-+}
-+module_exit(ppchameleonevb_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("DAVE Srl <support-ppchameleon@dave-tech.it>");
-+MODULE_DESCRIPTION("MTD map driver for DAVE Srl PPChameleonEVB board");
-Index: linux-2.6.5/drivers/mtd/nand/rtc_from4.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/rtc_from4.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/rtc_from4.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,500 @@
-+/*
-+ *  drivers/mtd/nand/rtc_from4.c
-+ *
-+ *  Copyright (C) 2004  Red Hat, Inc.
-+ * 
-+ *  Derived from drivers/mtd/nand/spia.c
-+ *       Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
-+ *
-+ * $Id: rtc_from4.c,v 1.1 2004/09/16 23:23:42 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.
-+ *
-+ * Overview:
-+ *   This is a device driver for the AG-AND flash device found on the
-+ *   Renesas Technology Corp. Flash ROM 4-slot interface board (FROM_BOARD4), 
-+ *   which utilizes the Renesas HN29V1G91T-30 part. 
-+ *   This chip is a 1 GBibit (128MiB x 8 bits) AG-AND flash device.
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/rslib.h>
-+#include <linux/module.h>
-+#include <linux/mtd/compatmac.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+
-+/*
-+ * MTD structure for Renesas board
-+ */
-+static struct mtd_info *rtc_from4_mtd = NULL;
-+
-+#define RTC_FROM4_MAX_CHIPS	2
-+
-+/* HS77x9 processor register defines */
-+#define SH77X9_BCR1	((volatile unsigned short *)(0xFFFFFF60))
-+#define SH77X9_BCR2	((volatile unsigned short *)(0xFFFFFF62))
-+#define SH77X9_WCR1	((volatile unsigned short *)(0xFFFFFF64))
-+#define SH77X9_WCR2	((volatile unsigned short *)(0xFFFFFF66))
-+#define SH77X9_MCR	((volatile unsigned short *)(0xFFFFFF68))
-+#define SH77X9_PCR	((volatile unsigned short *)(0xFFFFFF6C))
-+#define SH77X9_FRQCR	((volatile unsigned short *)(0xFFFFFF80))
-+
-+/*
-+ * Values specific to the Renesas Technology Corp. FROM_BOARD4 (used with HS77x9 processor)
-+ */
-+/* Address where flash is mapped */
-+#define RTC_FROM4_FIO_BASE	0x14000000
-+
-+/* CLE and ALE are tied to address lines 5 & 4, respectively */
-+#define RTC_FROM4_CLE		(1 << 5)
-+#define RTC_FROM4_ALE		(1 << 4)
-+
-+/* address lines A24-A22 used for chip selection */
-+#define RTC_FROM4_NAND_ADDR_SLOT3	(0x00800000)
-+#define RTC_FROM4_NAND_ADDR_SLOT4	(0x00C00000)
-+#define RTC_FROM4_NAND_ADDR_FPGA	(0x01000000)
-+/* mask address lines A24-A22 used for chip selection */
-+#define RTC_FROM4_NAND_ADDR_MASK	(RTC_FROM4_NAND_ADDR_SLOT3 | RTC_FROM4_NAND_ADDR_SLOT4 | RTC_FROM4_NAND_ADDR_FPGA)
-+
-+/* FPGA status register for checking device ready (bit zero) */
-+#define RTC_FROM4_FPGA_SR		(RTC_FROM4_NAND_ADDR_FPGA | 0x00000002)
-+#define RTC_FROM4_DEVICE_READY		0x0001
-+
-+/* FPGA Reed-Solomon ECC Control register */
-+
-+#define RTC_FROM4_RS_ECC_CTL		(RTC_FROM4_NAND_ADDR_FPGA | 0x00000050)
-+#define RTC_FROM4_RS_ECC_CTL_CLR	(1 << 7)
-+#define RTC_FROM4_RS_ECC_CTL_GEN	(1 << 6)
-+#define RTC_FROM4_RS_ECC_CTL_FD_E	(1 << 5)
-+
-+/* FPGA Reed-Solomon ECC code base */
-+#define RTC_FROM4_RS_ECC		(RTC_FROM4_NAND_ADDR_FPGA | 0x00000060)
-+#define RTC_FROM4_RS_ECCN		(RTC_FROM4_NAND_ADDR_FPGA | 0x00000080)
-+
-+/* FPGA Reed-Solomon ECC check register */
-+#define RTC_FROM4_RS_ECC_CHK		(RTC_FROM4_NAND_ADDR_FPGA | 0x00000070)
-+#define RTC_FROM4_RS_ECC_CHK_ERROR	(1 << 7)
-+
-+/* Undefine for software ECC */
-+#define RTC_FROM4_HWECC	1
-+
-+/*
-+ * Module stuff
-+ */
-+static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE);
-+
-+MODULE_PARM(rtc_from4_fio_base, "i");
-+
-+const static struct mtd_partition partition_info[] = {
-+        {
-+                .name   = "Renesas flash partition 1",
-+                .offset = 0,
-+                .size   = MTDPART_SIZ_FULL
-+        },
-+};
-+#define NUM_PARTITIONS 1
-+
-+/* 
-+ *	hardware specific flash bbt decriptors
-+ *	Note: this is to allow debugging by disabling 
-+ *		NAND_BBT_CREATE and/or NAND_BBT_WRITE
-+ *
-+ */
-+static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
-+static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
-+
-+static struct nand_bbt_descr rtc_from4_bbt_main_descr = {
-+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-+	.offs = 40,
-+	.len = 4,
-+	.veroffs = 44,
-+	.maxblocks = 4,
-+	.pattern = bbt_pattern
-+};
-+
-+static struct nand_bbt_descr rtc_from4_bbt_mirror_descr = {
-+	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
-+		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
-+	.offs = 40,
-+	.len = 4,
-+	.veroffs = 44,
-+	.maxblocks = 4,
-+	.pattern = mirror_pattern
-+};
-+
-+
-+
-+#ifdef RTC_FROM4_HWECC
-+
-+/* the Reed Solomon control structure */
-+static struct rs_control *rs_decoder;
-+
-+/* 
-+ *      hardware specific Out Of Band information
-+ */
-+static struct nand_oobinfo rtc_from4_nand_oobinfo = {
-+	.useecc = MTD_NANDECC_AUTOPLACE,
-+	.eccbytes = 32,
-+	.eccpos = {
-+		 0,  1,  2,  3,  4,  5,  6,  7,
-+		 8,  9, 10, 11, 12, 13, 14, 15,
-+		16, 17, 18, 19, 20, 21, 22, 23,
-+		24, 25, 26, 27, 28, 29, 30, 31},
-+	.oobfree = { {32, 32} }
-+};
-+#endif
-+
-+
-+
-+/* 
-+ * rtc_from4_hwcontrol - hardware specific access to control-lines
-+ * @mtd:	MTD device structure
-+ * @cmd:	hardware control command
-+ *
-+ * Address lines (A5 and A4) are used to control Command and Address Latch 
-+ * Enable on this board, so set the read/write address appropriately.
-+ *
-+ * Chip Enable is also controlled by the Chip Select (CS5) and 
-+ * Address lines (A24-A22), so no action is required here.
-+ *
-+ */
-+static void rtc_from4_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+	struct nand_chip* this = (struct nand_chip *) (mtd->priv);
-+	
-+	switch(cmd) {
-+		
-+	case NAND_CTL_SETCLE: 
-+		this->IO_ADDR_W |= RTC_FROM4_CLE;
-+		break;
-+	case NAND_CTL_CLRCLE: 
-+		this->IO_ADDR_W &= ~RTC_FROM4_CLE;
-+		break;
-+		
-+	case NAND_CTL_SETALE:
-+		this->IO_ADDR_W |= RTC_FROM4_ALE;
-+		break;
-+	case NAND_CTL_CLRALE:
-+		this->IO_ADDR_W &= ~RTC_FROM4_ALE;
-+		break;
-+		
-+	case NAND_CTL_SETNCE:
-+		break;
-+	case NAND_CTL_CLRNCE:
-+		break;
-+
-+	}
-+}
-+
-+
-+/*
-+ * rtc_from4_nand_select_chip - hardware specific chip select
-+ * @mtd:	MTD device structure
-+ * @chip:	Chip to select (0 == slot 3, 1 == slot 4)
-+ *
-+ * The chip select is based on address lines A24-A22.
-+ * This driver uses flash slots 3 and 4 (A23-A22).
-+ *
-+ */
-+static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip)
-+{
-+        struct nand_chip *this = mtd->priv;
-+
-+	this->IO_ADDR_R &= ~RTC_FROM4_NAND_ADDR_MASK;
-+	this->IO_ADDR_W &= ~RTC_FROM4_NAND_ADDR_MASK;
-+
-+        switch(chip) {
-+
-+        case 0:		/* select slot 3 chip */
-+		this->IO_ADDR_R |= RTC_FROM4_NAND_ADDR_SLOT3;
-+		this->IO_ADDR_W |= RTC_FROM4_NAND_ADDR_SLOT3;
-+                break;
-+        case 1:		/* select slot 4 chip */
-+		this->IO_ADDR_R |= RTC_FROM4_NAND_ADDR_SLOT4;
-+		this->IO_ADDR_W |= RTC_FROM4_NAND_ADDR_SLOT4;
-+                break;
-+
-+        }
-+}
-+
-+
-+
-+/*
-+ * rtc_from4_nand_device_ready - hardware specific ready/busy check
-+ * @mtd:	MTD device structure
-+ *
-+ * This board provides the Ready/Busy state in the status register
-+ * of the FPGA.  Bit zero indicates the RDY(1)/BSY(0) signal.
-+ *
-+ */
-+static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
-+{
-+	unsigned short status;
-+
-+	status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_FPGA_SR));
-+
-+	return (status & RTC_FROM4_DEVICE_READY);
-+
-+}
-+
-+#ifdef RTC_FROM4_HWECC
-+/*
-+ * rtc_from4_enable_hwecc - hardware specific hardware ECC enable function
-+ * @mtd:	MTD device structure
-+ * @mode:	I/O mode; read or write
-+ *
-+ * enable hardware ECC for data read or write 
-+ *
-+ */
-+static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+	volatile unsigned short * rs_ecc_ctl = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CTL);
-+	unsigned short status;
-+
-+	switch (mode) {
-+	    case NAND_ECC_READ :
-+		status =  RTC_FROM4_RS_ECC_CTL_CLR 
-+			| RTC_FROM4_RS_ECC_CTL_FD_E;
-+
-+		*rs_ecc_ctl = status;
-+		break;
-+
-+	    case NAND_ECC_READSYN :
-+		status =  0x00;
-+
-+		*rs_ecc_ctl = status;
-+		break;
-+
-+	    case NAND_ECC_WRITE :
-+		status =  RTC_FROM4_RS_ECC_CTL_CLR 
-+			| RTC_FROM4_RS_ECC_CTL_GEN 
-+			| RTC_FROM4_RS_ECC_CTL_FD_E;
-+
-+		*rs_ecc_ctl = status;
-+		break;
-+
-+	    default:
-+		BUG();
-+		break;
-+	}
-+
-+}
-+
-+/*
-+ * rtc_from4_calculate_ecc - hardware specific code to read ECC code
-+ * @mtd:	MTD device structure
-+ * @dat:	buffer containing the data to generate ECC codes
-+ * @ecc_code	ECC codes calculated
-+ *
-+ * The ECC code is calculated by the FPGA.  All we have to do is read the values
-+ * from the FPGA registers.
-+ *
-+ * Note: We read from the inverted registers, since data is inverted before
-+ * the code is calculated. So all 0xff data (blank page) results in all 0xff rs code
-+ *
-+ */
-+static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
-+{
-+	volatile unsigned short * rs_eccn = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECCN);
-+	unsigned short value;
-+	int i;
-+
-+	for (i = 0; i < 8; i++) {
-+		value = *rs_eccn;
-+		ecc_code[i] = (unsigned char)value;
-+		rs_eccn++;
-+	}
-+	ecc_code[7] |= 0x0f;	/* set the last four bits (not used) */
-+}
-+
-+
-+/*
-+ * rtc_from4_correct_data - hardware specific code to correct data using ECC code
-+ * @mtd:	MTD device structure
-+ * @buf:	buffer containing the data to generate ECC codes
-+ * @ecc1	ECC codes read
-+ * @ecc2	ECC codes calculated
-+ *
-+ * The FPGA tells us fast, if there's an error or not. If no, we go back happy
-+ * else we read the ecc results from the fpga and call the rs library to decode
-+ * and hopefully correct the error
-+ *
-+ * For now I use the code, which we read from the FLASH to use the RS lib,
-+ * as the syndrom conversion has a unresolved issue.
-+ */
-+static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
-+{
-+	int i, res;
-+	unsigned short status; 
-+	uint16_t rpar[6];
-+
-+	status = *((volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC_CHK));
-+
-+	if (!(status & RTC_FROM4_RS_ECC_CHK_ERROR))
-+		return 0;
-+
-+	/* convert into 6 10bit parity fields */
-+	rpar[0] = ((uint16_t)ecc1[7] >> 4) | (((uint16_t)ecc1[6] << 4) & 0x3f0);
-+	rpar[1] = ((uint16_t)ecc1[6] >> 6) | (((uint16_t)ecc1[5] << 2) & 0x3f3);
-+	rpar[2] = ((uint16_t)ecc1[4] >> 0) | (((uint16_t)ecc1[3] << 8) & 0x300);
-+	rpar[3] = ((uint16_t)ecc1[3] >> 2) | (((uint16_t)ecc1[2] << 6) & 0x3c0);
-+	rpar[4] = ((uint16_t)ecc1[2] >> 4) | (((uint16_t)ecc1[1] << 4) & 0x3f0);
-+	rpar[5] = ((uint16_t)ecc1[1] >> 6) | (((uint16_t)ecc1[0] << 2) & 0x3f3);
-+
-+	/* Invert the codes */
-+	for (i = 0; i < 6; i++)
-+		rpar[i] ^= 0x3ff;
-+
-+	/* Let the library code do its magic. 
-+	 * Set the data inversion mask to 0xff, as the FPGA inverts data on read
-+	 * except for the virtual bits 9 /10 which are tied low
-+	*/
-+	res = decode_rs8 (rs_decoder, buf, rpar, 512, NULL, 0, NULL, 0xff);
-+	if (res > 0)
-+		DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " 
-+			"ECC corrected %d errors on read\n", res);
-+
-+	return res;
-+}
-+#endif
-+
-+/*
-+ * Main initialization routine
-+ */
-+int __init rtc_from4_init (void)
-+{
-+	struct nand_chip *this;
-+	unsigned short bcr1, bcr2, wcr2;
-+
-+	/* Allocate memory for MTD device structure and private data */
-+	rtc_from4_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+				GFP_KERNEL);
-+	if (!rtc_from4_mtd) {
-+		printk ("Unable to allocate Renesas NAND MTD device structure.\n");
-+		return -ENOMEM;
-+	}
-+
-+	/* Get pointer to private data */
-+	this = (struct nand_chip *) (&rtc_from4_mtd[1]);
-+
-+	/* Initialize structures */
-+	memset((char *) rtc_from4_mtd, 0, sizeof(struct mtd_info));
-+	memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+	/* Link the private data with the MTD structure */
-+	rtc_from4_mtd->priv = this;
-+
-+	/* set area 5 as PCMCIA mode to clear the spec of tDH(Data hold time;9ns min) */
-+	bcr1 = *SH77X9_BCR1 & ~0x0002;
-+	bcr1 |= 0x0002;
-+	*SH77X9_BCR1 = bcr1;
-+
-+	/* set */
-+	bcr2 = *SH77X9_BCR2 & ~0x0c00;
-+	bcr2 |= 0x0800;
-+	*SH77X9_BCR2 = bcr2;
-+
-+	/* set area 5 wait states */
-+	wcr2 = *SH77X9_WCR2 & ~0x1c00;
-+	wcr2 |= 0x1c00;
-+	*SH77X9_WCR2 = wcr2;
-+
-+	/* Set address of NAND IO lines */
-+	this->IO_ADDR_R = rtc_from4_fio_base;
-+	this->IO_ADDR_W = rtc_from4_fio_base;
-+	/* Set address of hardware control function */
-+	this->hwcontrol = rtc_from4_hwcontrol;
-+	/* Set address of chip select function */
-+        this->select_chip = rtc_from4_nand_select_chip;
-+	/* command delay time (in us) */
-+	this->chip_delay = 100;
-+	/* return the status of the Ready/Busy line */
-+	this->dev_ready = rtc_from4_nand_device_ready;
-+
-+#ifdef RTC_FROM4_HWECC
-+	printk(KERN_INFO "rtc_from4_init: using hardware ECC detection.\n");
-+
-+        this->eccmode = NAND_ECC_HW8_512;
-+	this->options |= NAND_HWECC_SYNDROME;
-+	/* set the nand_oobinfo to support FPGA H/W error detection */
-+	this->autooob = &rtc_from4_nand_oobinfo;
-+	this->enable_hwecc = rtc_from4_enable_hwecc;
-+	this->calculate_ecc = rtc_from4_calculate_ecc;
-+	this->correct_data = rtc_from4_correct_data;
-+#else
-+	printk(KERN_INFO "rtc_from4_init: using software ECC detection.\n");
-+
-+	this->eccmode = NAND_ECC_SOFT;
-+#endif
-+
-+	/* set the bad block tables to support debugging */
-+	this->bbt_td = &rtc_from4_bbt_main_descr;
-+	this->bbt_md = &rtc_from4_bbt_mirror_descr;
-+
-+	/* Scan to find existence of the device */
-+	if (nand_scan (rtc_from4_mtd, RTC_FROM4_MAX_CHIPS)) {
-+		kfree (rtc_from4_mtd);
-+		return -ENXIO;
-+	}
-+
-+	/* Register the partitions */
-+	add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
-+
-+#ifdef RTC_FROM4_HWECC
-+	/* We could create the decoder on demand, if memory is a concern.
-+	 * This way we have it handy, if an error happens 
-+	 *
-+	 * Symbolsize is 10 (bits)
-+	 * Primitve polynomial is x^10+x^3+1
-+	 * first consecutive root is 0
-+	 * primitve element to generate roots = 1
-+	 * generator polinomial degree = 6
-+	 */
-+	rs_decoder = init_rs (10, 0x409, 0, 1, 6);
-+	if (!rs_decoder) {
-+		printk (KERN_ERROR "Could not create a RS decoder\n");
-+		nand_release(rtc_from4_mtd);
-+		kfree (rtc_from4_mtd);
-+		return -ENOMEM;
-+	}
-+#endif
-+	/* Return happy */
-+	return 0;
-+}
-+module_init(rtc_from4_init);
-+
-+
-+/*
-+ * Clean up routine
-+ */
-+#ifdef MODULE
-+static void __exit rtc_from4_cleanup (void)
-+{
-+	/* Release resource, unregister partitions */
-+	nand_release(rtc_from4_mtd);
-+
-+	/* Free the MTD device structure */
-+	kfree (rtc_from4_mtd);
-+
-+#ifdef RTC_FROM4_HWECC
-+	/* Free the reed solomon resources */
-+	if (rs_decoder)
-+		free_rs(rs_decoder);
-+#endif
-+}
-+module_exit(rtc_from4_cleanup);
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("d.marlin <dmarlin@redhat.com");
-+MODULE_DESCRIPTION("Board-specific glue layer for AG-AND flash on Renesas FROM_BOARD4");
-+
-Index: linux-2.6.5/drivers/mtd/nand/spia.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/spia.c	2004-04-03 22:37:23.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/spia.c	2005-02-01 17:11:17.000000000 -0500
-@@ -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.22 2004/09/16 23:27:14 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
-@@ -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 @@
- /*
-  * 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_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 @@
- /* 
-  *	hardware specific access to control-lines
- */
--void spia_hwcontrol(int cmd){
-+static void spia_hwcontrol(struct mtd_info *mtd, int cmd){
- 
-     switch(cmd){
- 
-@@ -111,7 +108,7 @@
- 	struct nand_chip *this;
- 
- 	/* Allocate memory for MTD device structure and private data */
--	spia_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+	spia_mtd = (struct mtd_info *) kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
- 				GFP_KERNEL);
- 	if (!spia_mtd) {
- 		printk ("Unable to allocate SPIA NAND MTD device structure.\n");
-@@ -135,27 +132,19 @@
- 	(*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07;
- 
- 	/* Set address of NAND IO lines */
--	this->IO_ADDR_R = spia_fio_base;
--	this->IO_ADDR_W = spia_fio_base;
-+	this->IO_ADDR_R = (void __iomem *) spia_fio_base;
-+	this->IO_ADDR_W = (void __iomem *) spia_fio_base;
- 	/* Set address of hardware control function */
- 	this->hwcontrol = spia_hwcontrol;
- 	/* 15 us command delay time */
- 	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;
- 	}
- 
--	/* Allocate memory for internal data buffer */
--	this->data_buf = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL);
--	if (!this->data_buf) {
--		printk ("Unable to allocate NAND data buffer for SPIA.\n");
--		kfree (spia_mtd);
--		return -ENOMEM;
--	}
--
- 	/* Register the partitions */
- 	add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS);
- 
-@@ -170,13 +159,8 @@
- #ifdef MODULE
- static void __exit spia_cleanup (void)
- {
--	struct nand_chip *this = (struct nand_chip *) &spia_mtd[1];
--
--	/* Unregister the device */
--	del_mtd_device (spia_mtd);
--
--	/* Free internal data buffer */
--	kfree (this->data_buf);
-+	/* Release resources, unregister device */
-+	nand_release (spia_mtd);
- 
- 	/* Free the MTD device structure */
- 	kfree (spia_mtd);
-Index: linux-2.6.5/drivers/mtd/nand/toto.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/toto.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/toto.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,205 @@
-+/*
-+ *  drivers/mtd/nand/toto.c
-+ *
-+ *  Copyright (c) 2003 Texas Instruments
-+ *
-+ *  Derived from drivers/mtd/autcpu12.c
-+ *
-+ *  Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
-+ *
-+ * 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.
-+ *
-+ *  Overview:
-+ *   This is a device driver for the NAND flash device found on the
-+ *   TI fido board. It supports 32MiB and 64MiB cards
-+ *
-+ * $Id: toto.c,v 1.3 2004/09/16 23:27:15 gleixner Exp $
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/delay.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/arch/hardware.h>
-+#include <asm/sizes.h>
-+#include <asm/arch/toto.h>
-+#include <asm/arch-omap1510/hardware.h>
-+#include <asm/arch/gpio.h>
-+
-+/*
-+ * MTD structure for TOTO board
-+ */
-+static struct mtd_info *toto_mtd = NULL;
-+
-+static unsigned long toto_io_base = OMAP_FLASH_1_BASE;
-+
-+#define CONFIG_NAND_WORKAROUND 1
-+
-+#define NAND_NCE 0x4000
-+#define NAND_CLE 0x1000
-+#define NAND_ALE 0x0002
-+#define NAND_MASK (NAND_CLE | NAND_ALE | NAND_NCE)
-+
-+#define T_NAND_CTL_CLRALE(iob)  gpiosetout(NAND_ALE, 0)
-+#define T_NAND_CTL_SETALE(iob)  gpiosetout(NAND_ALE, NAND_ALE)
-+#ifdef CONFIG_NAND_WORKAROUND     /* "some" dev boards busted, blue wired to rts2 :( */
-+#define T_NAND_CTL_CLRCLE(iob)  gpiosetout(NAND_CLE, 0); rts2setout(2, 2)
-+#define T_NAND_CTL_SETCLE(iob)  gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0)
-+#else
-+#define T_NAND_CTL_CLRCLE(iob)  gpiosetout(NAND_CLE, 0)
-+#define T_NAND_CTL_SETCLE(iob)  gpiosetout(NAND_CLE, NAND_CLE)
-+#endif
-+#define T_NAND_CTL_SETNCE(iob)  gpiosetout(NAND_NCE, 0)
-+#define T_NAND_CTL_CLRNCE(iob)  gpiosetout(NAND_NCE, NAND_NCE)
-+                
-+/*
-+ * Define partitions for flash devices
-+ */
-+
-+static struct mtd_partition partition_info64M[] = {
-+	{ .name =	"toto kernel partition 1",
-+	  .offset =	0,
-+	  .size	=	2 * SZ_1M },
-+	{ .name =	"toto file sys partition 2",
-+	  .offset =	2 * SZ_1M,
-+	  .size =	14 * SZ_1M },
-+	{ .name =	"toto user partition 3",
-+	  .offset =	16 * SZ_1M,
-+	  .size =	16 * SZ_1M },
-+	{ .name =	"toto devboard extra partition 4",
-+	  .offset =	32 * SZ_1M,
-+	  .size =	32 * SZ_1M },
-+};
-+
-+static struct mtd_partition partition_info32M[] = {
-+	{ .name =	"toto kernel partition 1",
-+	  .offset =	0,
-+	  .size =	2 * SZ_1M },
-+	{ .name =	"toto file sys partition 2",
-+	  .offset =	2 * SZ_1M,
-+	  .size =	14 * SZ_1M },
-+	{ .name =	"toto user partition 3",
-+	  .offset =	16 * SZ_1M,
-+	  .size =	16 * SZ_1M },
-+};
-+
-+#define NUM_PARTITIONS32M 3
-+#define NUM_PARTITIONS64M 4
-+/* 
-+ *	hardware specific access to control-lines
-+*/
-+
-+static void toto_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+
-+	udelay(1); /* hopefully enough time for tc make proceding write to clear */
-+	switch(cmd){
-+
-+		case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break;
-+		case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break;
-+
-+		case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break;
-+		case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break;
-+
-+		case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break;
-+		case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break;
-+	}
-+	udelay(1); /* allow time to ensure gpio state to over take memory write */
-+}
-+
-+/*
-+ * Main initialization routine
-+ */
-+int __init toto_init (void)
-+{
-+	struct nand_chip *this;
-+	int err = 0;
-+
-+	/* Allocate memory for MTD device structure and private data */
-+	toto_mtd = (struct mtd_info *) kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+				GFP_KERNEL);
-+	if (!toto_mtd) {
-+		printk (KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n");
-+		err = -ENOMEM;
-+		goto out;
-+	}
-+
-+	/* Get pointer to private data */
-+	this = (struct nand_chip *) (&toto_mtd[1]);
-+
-+	/* Initialize structures */
-+	memset((char *) toto_mtd, 0, sizeof(struct mtd_info));
-+	memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+	/* Link the private data with the MTD structure */
-+	toto_mtd->priv = this;
-+
-+	/* Set address of NAND IO lines */
-+	this->IO_ADDR_R = toto_io_base;
-+	this->IO_ADDR_W = toto_io_base;
-+	this->hwcontrol = toto_hwcontrol;
-+	this->dev_ready = NULL;
-+	/* 25 us command delay time */
-+	this->chip_delay = 30;		
-+	this->eccmode = NAND_ECC_SOFT;
-+
-+        /* Scan to find existance of the device */
-+	if (nand_scan (toto_mtd, 1)) {
-+		err = -ENXIO;
-+		goto out_mtd;
-+	}
-+
-+	/* Register the partitions */
-+	switch(toto_mtd->size){
-+		case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; 
-+		case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; 
-+		default: {
-+			printk (KERN_WARNING "Unsupported Nand device\n"); 
-+			err = -ENXIO;
-+			goto out_buf;
-+		}
-+	}
-+
-+    	gpioreserve(NAND_MASK);  /* claim our gpios */
-+    	archflashwp(0,0);	 /* open up flash for writing */
-+
-+	goto out;
-+    
-+out_buf:
-+	kfree (this->data_buf);    
-+out_mtd:
-+	kfree (toto_mtd);
-+out:
-+	return err;
-+}
-+
-+module_init(toto_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit toto_cleanup (void)
-+{
-+	/* Release resources, unregister device */
-+	nand_release (toto_mtd);
-+
-+	/* Free the MTD device structure */
-+	kfree (toto_mtd);
-+
-+	/* stop flash writes */
-+	 archflashwp(0,1);
-+	
-+	/* release gpios to system */
-+	 gpiorelease(NAND_MASK);
-+}
-+module_exit(toto_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Richard Woodruff <r-woodruff2@ti.com>");
-+MODULE_DESCRIPTION("Glue layer for NAND flash on toto board");
-Index: linux-2.6.5/drivers/mtd/nand/tx4925ndfmc.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/tx4925ndfmc.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/tx4925ndfmc.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,416 @@
-+/*
-+ *  drivers/mtd/tx4925ndfmc.c
-+ *
-+ *  Overview:
-+ *   This is a device driver for the NAND flash device found on the
-+ *   Toshiba RBTX4925 reference board, which is a SmartMediaCard. It supports 
-+ *   16MiB, 32MiB and 64MiB cards.
-+ *
-+ * Author: MontaVista Software, Inc.  source@mvista.com
-+ *
-+ * Derived from drivers/mtd/autcpu12.c
-+ *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
-+ *
-+ * $Id: tx4925ndfmc.c,v 1.4 2004/09/16 23:27:15 gleixner Exp $
-+ *
-+ * Copyright (C) 2001 Toshiba Corporation 
-+ * 
-+ * 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.
-+ *
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/delay.h>
-+#include <asm/io.h>
-+#include <asm/tx4925/tx4925_nand.h>
-+
-+extern struct nand_oobinfo jffs2_oobinfo;
-+
-+/*
-+ * MTD structure for RBTX4925 board
-+ */
-+static struct mtd_info *tx4925ndfmc_mtd = NULL;
-+
-+/*
-+ * Define partitions for flash devices
-+ */
-+
-+static struct mtd_partition partition_info16k[] = {
-+	{ .name = "RBTX4925 flash partition 1",
-+	  .offset =  0,
-+	  .size =    8 * 0x00100000 },
-+	{ .name = "RBTX4925 flash partition 2",
-+	  .offset =  8 * 0x00100000,
-+	  .size =    8 * 0x00100000 },
-+};
-+
-+static struct mtd_partition partition_info32k[] = {
-+	{ .name = "RBTX4925 flash partition 1",
-+	  .offset =  0,
-+	  .size =    8 * 0x00100000 },
-+	{ .name = "RBTX4925 flash partition 2",
-+	  .offset = 8 * 0x00100000,
-+	  .size =  24 * 0x00100000 },
-+};
-+
-+static struct mtd_partition partition_info64k[] = {
-+	{ .name = "User FS",
-+	  .offset =  0,
-+	  .size =   16 * 0x00100000 },
-+	{ .name = "RBTX4925 flash partition 2",
-+	  .offset = 16 * 0x00100000,
-+	  .size =   48 * 0x00100000},
-+};
-+
-+static struct mtd_partition partition_info128k[] = {
-+	{ .name = "Skip bad section",
-+	  .offset =  0,
-+	  .size =   16 * 0x00100000 },
-+	{ .name = "User FS",
-+	  .offset = 16 * 0x00100000,
-+	  .size =   112 * 0x00100000 },
-+};
-+#define NUM_PARTITIONS16K  2
-+#define NUM_PARTITIONS32K  2
-+#define NUM_PARTITIONS64K  2
-+#define NUM_PARTITIONS128K 2
-+
-+/* 
-+ *	hardware specific access to control-lines
-+*/
-+static void tx4925ndfmc_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+
-+	switch(cmd){
-+
-+		case NAND_CTL_SETCLE: 
-+			tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CLE;
-+			break;
-+		case NAND_CTL_CLRCLE:
-+			tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CLE;
-+			break;
-+		case NAND_CTL_SETALE:
-+			tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ALE;
-+			break;
-+		case NAND_CTL_CLRALE: 
-+			tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ALE;
-+			break;
-+		case NAND_CTL_SETNCE:
-+			tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CE;
-+			break;
-+		case NAND_CTL_CLRNCE:
-+			tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CE;
-+			break;
-+		case NAND_CTL_SETWP:
-+			tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_WE;
-+			break;
-+		case NAND_CTL_CLRWP:
-+			tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_WE;
-+			break;
-+	}
-+}
-+
-+/*
-+*	read device ready pin
-+*/
-+static int tx4925ndfmc_device_ready(struct mtd_info *mtd)
-+{
-+	int ready;
-+	ready = (tx4925_ndfmcptr->sr & TX4925_NDSFR_BUSY) ? 0 : 1;
-+	return ready;
-+}
-+void tx4925ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+	/* reset first */
-+	tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_MASK;
-+	tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
-+	tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_ENAB;
-+}
-+static void tx4925ndfmc_disable_ecc(void)
-+{
-+	tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
-+}
-+static void tx4925ndfmc_enable_read_ecc(void)
-+{
-+	tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
-+	tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_READ;
-+}
-+void tx4925ndfmc_readecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){
-+	int i;
-+	u_char *ecc = ecc_code;
-+        tx4925ndfmc_enable_read_ecc();
-+	for (i = 0;i < 6;i++,ecc++)
-+		*ecc = tx4925_read_nfmc(&(tx4925_ndfmcptr->dtr));
-+        tx4925ndfmc_disable_ecc();
-+}
-+void tx4925ndfmc_device_setup(void)
-+{
-+
-+	*(unsigned char *)0xbb005000 &= ~0x08;
-+
-+        /* reset NDFMC */
-+        tx4925_ndfmcptr->rstr |= TX4925_NDFRSTR_RST;
-+	while (tx4925_ndfmcptr->rstr & TX4925_NDFRSTR_RST);       
-+
-+	/* setup BusSeparete, Hold Time, Strobe Pulse Width */
-+	tx4925_ndfmcptr->mcr = TX4925_BSPRT ? TX4925_NDFMCR_BSPRT : 0;
-+	tx4925_ndfmcptr->spr = TX4925_HOLD << 4 | TX4925_SPW;             
-+}
-+static u_char tx4925ndfmc_nand_read_byte(struct mtd_info *mtd)
-+{
-+        struct nand_chip *this = mtd->priv;
-+        return tx4925_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static void tx4925ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+        struct nand_chip *this = mtd->priv;
-+        tx4925_write_nfmc(byte, this->IO_ADDR_W);
-+}
-+
-+static void tx4925ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		tx4925_write_nfmc(buf[i], this->IO_ADDR_W);
-+}
-+
-+static void tx4925ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		buf[i] = tx4925_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static int tx4925ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		if (buf[i] != tx4925_read_nfmc(this->IO_ADDR_R))
-+			return -EFAULT;
-+
-+	return 0;
-+}
-+
-+/*
-+ * Send command to NAND device
-+ */
-+static void tx4925ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-+{
-+	register struct nand_chip *this = mtd->priv;
-+
-+	/* Begin command latch cycle */
-+	this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+	/*
-+	 * Write out the command to the device.
-+	 */
-+	if (command == NAND_CMD_SEQIN) {
-+		int readcmd;
-+
-+		if (column >= mtd->oobblock) {
-+			/* OOB area */
-+			column -= mtd->oobblock;
-+			readcmd = NAND_CMD_READOOB;
-+		} else if (column < 256) {
-+			/* First 256 bytes --> READ0 */
-+			readcmd = NAND_CMD_READ0;
-+		} else {
-+			column -= 256;
-+			readcmd = NAND_CMD_READ1;
-+		}
-+		this->write_byte(mtd, readcmd);
-+	}
-+	this->write_byte(mtd, command);
-+
-+	/* Set ALE and clear CLE to start address cycle */
-+	this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+
-+	if (column != -1 || page_addr != -1) {
-+		this->hwcontrol(mtd, NAND_CTL_SETALE);
-+
-+		/* Serially input address */
-+		if (column != -1)
-+			this->write_byte(mtd, column);
-+		if (page_addr != -1) {
-+			this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
-+			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
-+			/* One more address cycle for higher density devices */
-+			if (mtd->size & 0x0c000000) 
-+				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
-+		}
-+		/* Latch in address */
-+		this->hwcontrol(mtd, NAND_CTL_CLRALE);
-+	}
-+	
-+	/* 
-+	 * program and erase have their own busy handlers 
-+	 * status and sequential in needs no delay
-+	*/
-+	switch (command) {
-+			
-+	case NAND_CMD_PAGEPROG:
-+		/* Turn off WE */
-+		this->hwcontrol (mtd, NAND_CTL_CLRWP);
-+                return;
-+
-+	case NAND_CMD_SEQIN:
-+		/* Turn on WE */
-+		this->hwcontrol (mtd, NAND_CTL_SETWP);
-+                return;
-+
-+	case NAND_CMD_ERASE1:
-+	case NAND_CMD_ERASE2:
-+	case NAND_CMD_STATUS:
-+		return;
-+
-+	case NAND_CMD_RESET:
-+		if (this->dev_ready)	
-+			break;
-+		this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+		this->write_byte(mtd, NAND_CMD_STATUS);
-+		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+		while ( !(this->read_byte(mtd) & 0x40));
-+		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(mtd));
-+}
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio
-+n **pparts, char *);
-+#endif
-+
-+/*
-+ * Main initialization routine
-+ */
-+extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-+int __init tx4925ndfmc_init (void)
-+{
-+	struct nand_chip *this;
-+	int err = 0;
-+
-+	/* Allocate memory for MTD device structure and private data */
-+	tx4925ndfmc_mtd = (struct mtd_info *) kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+				GFP_KERNEL);
-+	if (!tx4925ndfmc_mtd) {
-+		printk ("Unable to allocate RBTX4925 NAND MTD device structure.\n");
-+		err = -ENOMEM;
-+		goto out;
-+	}
-+
-+        tx4925ndfmc_device_setup();
-+
-+	/* io is indirect via a register so don't need to ioremap address */
-+
-+	/* Get pointer to private data */
-+	this = (struct nand_chip *) (&tx4925ndfmc_mtd[1]);
-+
-+	/* Initialize structures */
-+	memset((char *) tx4925ndfmc_mtd, 0, sizeof(struct mtd_info));
-+	memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+	/* Link the private data with the MTD structure */
-+	tx4925ndfmc_mtd->priv = this;
-+
-+	/* Set address of NAND IO lines */
-+	this->IO_ADDR_R = (void __iomem *)&(tx4925_ndfmcptr->dtr);
-+	this->IO_ADDR_W = (void __iomem *)&(tx4925_ndfmcptr->dtr);
-+	this->hwcontrol = tx4925ndfmc_hwcontrol;
-+	this->enable_hwecc = tx4925ndfmc_enable_hwecc;
-+	this->calculate_ecc = tx4925ndfmc_readecc;
-+	this->correct_data = nand_correct_data;
-+	this->eccmode = NAND_ECC_HW6_512;	
-+	this->dev_ready = tx4925ndfmc_device_ready;
-+	/* 20 us command delay time */
-+	this->chip_delay = 20;		
-+        this->read_byte = tx4925ndfmc_nand_read_byte;
-+        this->write_byte = tx4925ndfmc_nand_write_byte;
-+	this->cmdfunc = tx4925ndfmc_nand_command;
-+	this->write_buf = tx4925ndfmc_nand_write_buf;
-+	this->read_buf = tx4925ndfmc_nand_read_buf;
-+	this->verify_buf = tx4925ndfmc_nand_verify_buf;
-+
-+	/* Scan to find existance of the device */
-+	if (nand_scan (tx4925ndfmc_mtd, 1)) {
-+		err = -ENXIO;
-+		goto out_ior;
-+	}
-+
-+	/* Register the partitions */
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+        {
-+                int mtd_parts_nb = 0;
-+                struct mtd_partition *mtd_parts = 0;
-+                mtd_parts_nb = parse_cmdline_partitions(tx4925ndfmc_mtd, &mtd_parts, "tx4925ndfmc");
-+                if (mtd_parts_nb > 0)
-+                        add_mtd_partitions(tx4925ndfmc_mtd, mtd_parts, mtd_parts_nb);
-+                else
-+                        add_mtd_device(tx4925ndfmc_mtd);
-+        }
-+#else /* ifdef CONFIG_MTD_CMDLINE_PARTS */
-+	switch(tx4925ndfmc_mtd->size){
-+		case 0x01000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info16k, NUM_PARTITIONS16K); break;
-+		case 0x02000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info32k, NUM_PARTITIONS32K); break;
-+		case 0x04000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info64k, NUM_PARTITIONS64K); break; 
-+		case 0x08000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info128k, NUM_PARTITIONS128K); break; 
-+		default: {
-+			printk ("Unsupported SmartMedia device\n"); 
-+			err = -ENXIO;
-+			goto out_ior;
-+		}
-+	}
-+#endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */
-+	goto out;
-+
-+out_ior:
-+out:
-+	return err;
-+}
-+
-+module_init(tx4925ndfmc_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+#ifdef MODULE
-+static void __exit tx4925ndfmc_cleanup (void)
-+{
-+	/* Release resources, unregister device */
-+	nand_release (tx4925ndfmc_mtd);
-+
-+	/* Free the MTD device structure */
-+	kfree (tx4925ndfmc_mtd);
-+}
-+module_exit(tx4925ndfmc_cleanup);
-+#endif
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBTX4925");
-Index: linux-2.6.5/drivers/mtd/nand/tx4938ndfmc.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nand/tx4938ndfmc.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nand/tx4938ndfmc.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,406 @@
-+/*
-+ * drivers/mtd/nand/tx4938ndfmc.c
-+ *
-+ *  Overview:
-+ *   This is a device driver for the NAND flash device connected to
-+ *   TX4938 internal NAND Memory Controller.
-+ *   TX4938 NDFMC is almost same as TX4925 NDFMC, but register size are 64 bit.
-+ *
-+ * Author: source@mvista.com
-+ *
-+ * Based on spia.c by Steven J. Hill
-+ *
-+ * $Id: tx4938ndfmc.c,v 1.3 2004/09/16 23:27:15 gleixner Exp $
-+ *
-+ * Copyright (C) 2000-2001 Toshiba Corporation 
-+ *
-+ * 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.
-+ */
-+#include <linux/config.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/nand_ecc.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/bootinfo.h>
-+#include <linux/delay.h>
-+#include <asm/tx4938/rbtx4938.h>
-+
-+extern struct nand_oobinfo jffs2_oobinfo;
-+
-+/*
-+ * MTD structure for TX4938 NDFMC
-+ */
-+static struct mtd_info *tx4938ndfmc_mtd;
-+
-+/*
-+ * Define partitions for flash device
-+ */
-+#define flush_wb()	(void)tx4938_ndfmcptr->mcr;
-+
-+#define NUM_PARTITIONS  	3
-+#define NUMBER_OF_CIS_BLOCKS	24
-+#define SIZE_OF_BLOCK		0x00004000
-+#define NUMBER_OF_BLOCK_PER_ZONE 1024
-+#define SIZE_OF_ZONE		(NUMBER_OF_BLOCK_PER_ZONE * SIZE_OF_BLOCK)
-+#ifndef CONFIG_MTD_CMDLINE_PARTS
-+/*
-+ * You can use the following sample of MTD partitions 
-+ * on the NAND Flash Memory 32MB or more.
-+ *
-+ * The following figure shows the image of the sample partition on
-+ * the 32MB NAND Flash Memory. 
-+ *
-+ *   Block No.
-+ *    0 +-----------------------------+ ------
-+ *      |             CIS             |   ^
-+ *   24 +-----------------------------+   |
-+ *      |         kernel image        |   | Zone 0
-+ *      |                             |   |
-+ *      +-----------------------------+   |
-+ * 1023 |         unused area         |   v
-+ *      +-----------------------------+ ------
-+ * 1024 |            JFFS2            |   ^
-+ *      |                             |   |
-+ *      |                             |   | Zone 1
-+ *      |                             |   |
-+ *      |                             |   |
-+ *      |                             |   v
-+ * 2047 +-----------------------------+ ------
-+ *
-+ */
-+static struct mtd_partition partition_info[NUM_PARTITIONS] = {
-+	{
-+		.name = "RBTX4938 CIS Area",
-+ 		.offset =  0,
-+ 		.size =    (NUMBER_OF_CIS_BLOCKS * SIZE_OF_BLOCK),
-+ 		.mask_flags  = MTD_WRITEABLE	/* This partition is NOT writable */
-+ 	},
-+ 	{
-+ 		.name = "RBTX4938 kernel image",
-+ 		.offset =  MTDPART_OFS_APPEND,
-+ 		.size =    8 * 0x00100000,	/* 8MB (Depends on size of kernel image) */
-+ 		.mask_flags  = MTD_WRITEABLE	/* This partition is NOT writable */
-+ 	},
-+ 	{
-+ 		.name = "Root FS (JFFS2)",
-+ 		.offset =  (0 + SIZE_OF_ZONE),    /* start address of next zone */
-+ 		.size =    MTDPART_SIZ_FULL
-+ 	},
-+};
-+#endif
-+
-+static void tx4938ndfmc_hwcontrol(struct mtd_info *mtd, int cmd)
-+{
-+	switch (cmd) {
-+		case NAND_CTL_SETCLE:
-+			tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CLE;
-+			break;
-+		case NAND_CTL_CLRCLE:
-+			tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CLE;
-+			break;
-+		case NAND_CTL_SETALE:
-+			tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_ALE;
-+			break;
-+		case NAND_CTL_CLRALE:
-+			tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_ALE;
-+			break;
-+		/* TX4938_NDFMCR_CE bit is 0:high 1:low */
-+		case NAND_CTL_SETNCE:
-+			tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CE;
-+			break;
-+		case NAND_CTL_CLRNCE:
-+			tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CE;
-+			break;
-+		case NAND_CTL_SETWP:
-+			tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_WE;
-+			break;
-+		case NAND_CTL_CLRWP:
-+			tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_WE;
-+			break;
-+	}
-+}
-+static int tx4938ndfmc_dev_ready(struct mtd_info *mtd)
-+{
-+	flush_wb();
-+	return !(tx4938_ndfmcptr->sr & TX4938_NDFSR_BUSY);
-+}
-+static void tx4938ndfmc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
-+{
-+	u32 mcr = tx4938_ndfmcptr->mcr;
-+	mcr &= ~TX4938_NDFMCR_ECC_ALL;
-+	tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+	tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_READ;
-+	ecc_code[1] = tx4938_ndfmcptr->dtr;
-+	ecc_code[0] = tx4938_ndfmcptr->dtr;
-+	ecc_code[2] = tx4938_ndfmcptr->dtr;
-+	tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+}
-+static void tx4938ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
-+{
-+	u32 mcr = tx4938_ndfmcptr->mcr;
-+	mcr &= ~TX4938_NDFMCR_ECC_ALL;
-+	tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_RESET;
-+	tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-+	tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_ON;
-+}
-+
-+static u_char tx4938ndfmc_nand_read_byte(struct mtd_info *mtd)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	return tx4938_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static void tx4938ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte)
-+{
-+	struct nand_chip *this = mtd->priv;
-+	tx4938_write_nfmc(byte, this->IO_ADDR_W);
-+}
-+
-+static void tx4938ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		tx4938_write_nfmc(buf[i], this->IO_ADDR_W);
-+}
-+
-+static void tx4938ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		buf[i] = tx4938_read_nfmc(this->IO_ADDR_R);
-+}
-+
-+static int tx4938ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-+{
-+	int i;
-+	struct nand_chip *this = mtd->priv;
-+
-+	for (i=0; i<len; i++)
-+		if (buf[i] != tx4938_read_nfmc(this->IO_ADDR_R))
-+			return -EFAULT;
-+
-+	return 0;
-+}
-+
-+/*
-+ * Send command to NAND device
-+ */
-+static void tx4938ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-+{
-+	register struct nand_chip *this = mtd->priv;
-+
-+	/* Begin command latch cycle */
-+	this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+	/*
-+	 * Write out the command to the device.
-+	 */
-+	if (command == NAND_CMD_SEQIN) {
-+		int readcmd;
-+
-+		if (column >= mtd->oobblock) {
-+			/* OOB area */
-+			column -= mtd->oobblock;
-+			readcmd = NAND_CMD_READOOB;
-+		} else if (column < 256) {
-+			/* First 256 bytes --> READ0 */
-+			readcmd = NAND_CMD_READ0;
-+		} else {
-+			column -= 256;
-+			readcmd = NAND_CMD_READ1;
-+		}
-+		this->write_byte(mtd, readcmd);
-+	}
-+	this->write_byte(mtd, command);
-+
-+	/* Set ALE and clear CLE to start address cycle */
-+	this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+
-+	if (column != -1 || page_addr != -1) {
-+		this->hwcontrol(mtd, NAND_CTL_SETALE);
-+
-+		/* Serially input address */
-+		if (column != -1)
-+			this->write_byte(mtd, column);
-+		if (page_addr != -1) {
-+			this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
-+			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
-+			/* One more address cycle for higher density devices */
-+			if (mtd->size & 0x0c000000) 
-+				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
-+		}
-+		/* Latch in address */
-+		this->hwcontrol(mtd, NAND_CTL_CLRALE);
-+	}
-+	
-+	/* 
-+	 * program and erase have their own busy handlers 
-+	 * status and sequential in needs no delay
-+	*/
-+	switch (command) {
-+			
-+	case NAND_CMD_PAGEPROG:
-+		/* Turn off WE */
-+		this->hwcontrol (mtd, NAND_CTL_CLRWP);
-+                return;
-+
-+	case NAND_CMD_SEQIN:
-+		/* Turn on WE */
-+		this->hwcontrol (mtd, NAND_CTL_SETWP);
-+                return;
-+
-+	case NAND_CMD_ERASE1:
-+	case NAND_CMD_ERASE2:
-+	case NAND_CMD_STATUS:
-+		return;
-+
-+	case NAND_CMD_RESET:
-+		if (this->dev_ready)	
-+			break;
-+		this->hwcontrol(mtd, NAND_CTL_SETCLE);
-+		this->write_byte(mtd, NAND_CMD_STATUS);
-+		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-+		while ( !(this->read_byte(mtd) & 0x40));
-+		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(mtd));
-+}
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
-+#endif
-+/*
-+ * Main initialization routine
-+ */
-+int __init tx4938ndfmc_init (void)
-+{
-+	struct nand_chip *this;
-+	int bsprt = 0, hold = 0xf, spw = 0xf;
-+	int protected = 0;
-+
-+	if ((*rbtx4938_piosel_ptr & 0x0c) != 0x08) {
-+		printk("TX4938 NDFMC: disabled by IOC PIOSEL\n");
-+		return -ENODEV;
-+	}
-+	bsprt = 1;
-+	hold = 2;
-+	spw = 9 - 1;	/* 8 GBUSCLK = 80ns (@ GBUSCLK 100MHz) */
-+
-+	if ((tx4938_ccfgptr->pcfg &
-+	     (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL))
-+	    != TX4938_PCFG_NDF_SEL) {
-+		printk("TX4938 NDFMC: disabled by PCFG.\n");
-+		return -ENODEV;
-+	}
-+
-+	/* reset NDFMC */
-+	tx4938_ndfmcptr->rstr |= TX4938_NDFRSTR_RST;
-+	while (tx4938_ndfmcptr->rstr & TX4938_NDFRSTR_RST)
-+		;
-+	/* setup BusSeparete, Hold Time, Strobe Pulse Width */
-+	tx4938_ndfmcptr->mcr = bsprt ? TX4938_NDFMCR_BSPRT : 0;
-+	tx4938_ndfmcptr->spr = hold << 4 | spw;
-+
-+	/* Allocate memory for MTD device structure and private data */
-+	tx4938ndfmc_mtd = (struct mtd_info *) kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
-+				      GFP_KERNEL);
-+	if (!tx4938ndfmc_mtd) {
-+		printk ("Unable to allocate TX4938 NDFMC MTD device structure.\n");
-+		return -ENOMEM;
-+	}
-+
-+	/* Get pointer to private data */
-+	this = (struct nand_chip *) (&tx4938ndfmc_mtd[1]);
-+
-+	/* Initialize structures */
-+	memset((char *) tx4938ndfmc_mtd, 0, sizeof(struct mtd_info));
-+	memset((char *) this, 0, sizeof(struct nand_chip));
-+
-+	/* Link the private data with the MTD structure */
-+	tx4938ndfmc_mtd->priv = this;
-+
-+	/* Set address of NAND IO lines */
-+	this->IO_ADDR_R = (unsigned long)&tx4938_ndfmcptr->dtr;
-+	this->IO_ADDR_W = (unsigned long)&tx4938_ndfmcptr->dtr;
-+	this->hwcontrol = tx4938ndfmc_hwcontrol;
-+	this->dev_ready = tx4938ndfmc_dev_ready;
-+	this->calculate_ecc = tx4938ndfmc_calculate_ecc;
-+	this->correct_data = nand_correct_data;
-+	this->enable_hwecc = tx4938ndfmc_enable_hwecc;
-+	this->eccmode = NAND_ECC_HW3_256;
-+	this->chip_delay = 100;
-+	this->read_byte = tx4938ndfmc_nand_read_byte;
-+	this->write_byte = tx4938ndfmc_nand_write_byte;
-+	this->cmdfunc = tx4938ndfmc_nand_command;
-+	this->write_buf = tx4938ndfmc_nand_write_buf;
-+	this->read_buf = tx4938ndfmc_nand_read_buf;
-+	this->verify_buf = tx4938ndfmc_nand_verify_buf;
-+
-+	/* Scan to find existance of the device */
-+	if (nand_scan (tx4938ndfmc_mtd, 1)) {
-+		kfree (tx4938ndfmc_mtd);
-+		return -ENXIO;
-+	}
-+
-+	if (protected) {
-+		printk(KERN_INFO "TX4938 NDFMC: write protected.\n");
-+		tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE);
-+	}
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+	{
-+		int mtd_parts_nb = 0;
-+		struct mtd_partition *mtd_parts = 0;
-+		mtd_parts_nb = parse_cmdline_partitions(tx4938ndfmc_mtd, &mtd_parts, "tx4938ndfmc");
-+		if (mtd_parts_nb > 0)
-+			add_mtd_partitions(tx4938ndfmc_mtd, mtd_parts, mtd_parts_nb);
-+		else
-+			add_mtd_device(tx4938ndfmc_mtd);
-+	}
-+#else
-+	add_mtd_partitions(tx4938ndfmc_mtd, partition_info, NUM_PARTITIONS );
-+#endif
-+
-+	return 0;
-+}
-+module_init(tx4938ndfmc_init);
-+
-+/*
-+ * Clean up routine
-+ */
-+static void __exit tx4938ndfmc_cleanup (void)
-+{
-+	/* Release resources, unregister device */
-+	nand_release (tx4938ndfmc_mtd);
-+
-+	/* Free the MTD device structure */
-+	kfree (tx4938ndfmc_mtd);
-+}
-+module_exit(tx4938ndfmc_cleanup);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on TX4938 NDFMC");
-Index: linux-2.6.5/drivers/mtd/nftlcore.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nftlcore.c	2004-04-03 22:36:15.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nftlcore.c	2005-02-01 17:11:29.000000000 -0500
-@@ -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 @@
- 	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 @@
- 	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 @@
-                 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 @@
- 
-                 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 @@
- 	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 @@
- 		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 @@
- 	} 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 @@
- 
- 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: linux-2.6.5/drivers/mtd/nftlmount.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/nftlmount.c	2004-04-03 22:37:36.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/nftlmount.c	2005-02-01 17:11:29.000000000 -0500
-@@ -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.37 2004/09/16 23:32:37 gleixner Exp $
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -31,7 +31,7 @@
- 
- #define SECTORSIZE 512
- 
--char nftlmountrev[]="$Revision: 1.34 $";
-+char nftlmountrev[]="$Revision: 1.37 $";
- 
- /* 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
-@@ -41,7 +41,6 @@
- static int find_boot_record(struct NFTLrecord *nftl)
- {
- 	struct nftl_uci1 h1;
--	struct nftl_oob oob;
- 	unsigned int block, boot_record_count = 0;
- 	size_t retlen;
- 	u8 buf[SECTORSIZE];
-@@ -50,6 +49,10 @@
- 
-         /* 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 +65,10 @@
- 
- 		/* 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 +110,7 @@
- 
- 		/* 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 +155,10 @@
- 		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 +171,7 @@
- 			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 +224,13 @@
- 
- 		/* 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 +241,9 @@
- 			/* 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 +269,16 @@
- 			      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 +293,6 @@
-  * 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 +322,10 @@
- 	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 +338,18 @@
- 		 * 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 +454,7 @@
- 
- 		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: linux-2.6.5/drivers/mtd/redboot.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/redboot.c	2004-04-03 22:37:23.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/redboot.c	2005-02-01 17:11:17.000000000 -0500
-@@ -1,5 +1,5 @@
- /*
-- * $Id: redboot.c,v 1.11 2003/05/21 10:39:26 dwmw2 Exp $
-+ * $Id: redboot.c,v 1.15 2004/08/10 07:55:16 dwmw2 Exp $
-  *
-  * Parse RedBoot-style Flash Image System (FIS) tables and
-  * produce a Linux partition array to match.
-@@ -8,6 +8,7 @@
- #include <linux/kernel.h>
- #include <linux/slab.h>
- #include <linux/init.h>
-+#include <linux/vmalloc.h>
- 
- #include <linux/mtd/mtd.h>
- #include <linux/mtd/partitions.h>
-@@ -48,21 +49,24 @@
- 	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 = vmalloc(master->erasesize);
- 
- 	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 +84,7 @@
- 		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 +116,69 @@
- 
- 		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);
-@@ -166,7 +191,7 @@
- 		fl = fl->next;
- 		kfree(old);
- 	}
--	kfree(buf);
-+	vfree(buf);
- 	return ret;
- }
- 
-Index: linux-2.6.5/drivers/mtd/ssfdc.c
-===================================================================
---- linux-2.6.5.orig/drivers/mtd/ssfdc.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/drivers/mtd/ssfdc.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,1132 @@
-+/*
-+ *  drivers/mtd/ssfdc.c
-+ *
-+ *  Copyright (C) 2003 Simon Haynes (simon@baydel.con)
-+ *                     Baydel Ltd
-+ *
-+ * 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.
-+ *
-+ * This module provides a translation layer, via mtd, for smart
-+ * media card access. It essentially enables the possibility 
-+ * of using cards on a hardware which does not have a hardware translation
-+ * layer and interchanging them with hardware that does ie: PC card readers
-+ *
-+ * I had to write this module for a specific task and in a short timeframe
-+ * for this reason I have imposed some restricions to make the job easier.
-+ *
-+ * To build an compile the driver I added the following lines
-+ * to mtd/Config.in
-+ *
-+ *  dep_tristate '  SSFDC support' CONFIG_SSFDC $CONFIG_MTD
-+ *
-+ * to /mtd/Makefile
-+ *
-+ * obj-$(CONFIG_SSFDC)             += ssfdc.o
-+ *
-+ * and compiled the kernel via the usual methods.
-+ *
-+ * I am sure that there are many problems I don't know about but here are
-+ * some that I know of
-+ *
-+ * Currently the driver uses MAJOR number 44 which I think is FTL or NFTL
-+ * I did this because I wanted a static number and I didn't know
-+ * how to go about getting a new one. This needs addressing
-+ * The dev nodes required are like standard. I only use minor 0
-+ * (/dev/ssfdca), and minor 1 (/dev/ssfdca1).
-+ * You should be able to run fdisk on /dev/ssfdca and the first partition
-+ * is /dev/ssfdca1. There is no working code in the module for changing the
-+ * SMC and rebuilding the maps so the card should not be changed once the
-+ * module is loaded. At present I only look for 1 partition. But this is a
-+ * small commented hack.
-+ *
-+ * There is no support cards which do not have a 512 byte page size with 16
-+ * bytes of oob and an erase size of 16K.
-+ * There are no checks for this at present. In addition the MTD reported size
-+ * must be 16M or a multiple.
-+ *
-+ * Code to handle multiple partitions or multiple cards is incomplete
-+ * Need to allocate data buffer and oob buffer on a per partition basis.
-+ * As I am only concerned with one partition I will do this if I ever need to.
-+ * The cached physical address variable also needs this attention.
-+ *
-+ * Recently I have started to work on media changes. Some of this is specific
-+ * to my hardware and you will see references to pt_ssfdc_smc and smc_status.
-+ * This code is incomplete and does not work. I have commented it for the moment
-+ * but it should give an indication of what I think is required. Maybe there is
-+ * something it mtd that can help
-+ *
-+ * 17th August 2004 MHB
-+ *
-+ * Following updating CVS I noticed some single bit data corruption. I believe
-+ * that this was down to the fact that I was using mtd->read instead of mtd->read_ecc
-+ * and that mtd->read was applying it's own error corretion from the wrong ecc bytes
-+ * I have now corrected this.
-+ *
-+ * During this time I noticed that while in allocate new I only seem to look for blocks
-+ * in 1 zone. So this limits the partition size to 16MB with all the other SMC size
-+ * restrictions
-+
-+
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/fs.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/blktrans.h>
-+#include <linux/mtd/nand_ecc.h>
-+#include <linux/sched.h>
-+#include <linux/ptrace.h>
-+#include <linux/string.h>
-+#include <linux/timer.h>
-+#include <linux/major.h>
-+#include <linux/ioctl.h>
-+#include <linux/hdreg.h>
-+#include <linux/list.h>
-+#include <asm/semaphore.h>
-+#include <asm/uaccess.h>
-+
-+
-+#if (LINUX_VERSION_CODE >= 0x20100)
-+#include <linux/vmalloc.h>
-+#endif
-+#if (LINUX_VERSION_CODE >= 0x20303)
-+#include <linux/blkpg.h>
-+#endif
-+
-+#include <asm/semaphore.h>
-+
-+#define SSFDC_FORMAT 1
-+
-+#define PDEBUG(fmt, args...)
-+
-+#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
-+#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
-+
-+#if (LINUX_VERSION_CODE < 0x20320)
-+#define BLK_DEFAULT_QUEUE(n)    blk_dev[n].request_fn
-+#define blk_init_queue(q, req)  q = (req)
-+#define blk_cleanup_queue(q)    q = NULL
-+#define request_arg_t           void
-+#else
-+#define request_arg_t           request_queue_t *q
-+#endif
-+
-+#define TRUE 1
-+#define FALSE 0
-+
-+#define SSFDC_MAJOR	44
-+
-+#define MAJOR_NR		SSFDC_MAJOR
-+#define DEVICE_NAME		"ssfdc"
-+#define DEVICE_REQUEST		do_ssfdc_request
-+#define DEVICE_ON(device)
-+#define DEVICE_OFF(device)
-+
-+#include <linux/blk.h>
-+
-+#include "/home/simon/ebony/dbwhatu/dbwhatu/smccontrol.h"
-+
-+
-+
-+#define ZONE_SIZE 		(16 * 1024 * 1024)
-+#define SMC_BLOCK_SIZE 		(16 * 1024)
-+#define SECTOR_SIZE 		512
-+#define SECTORS_PER_ZONE  	(ZONE_SIZE / SECTOR_SIZE)
-+#define BLOCKS_PER_ZONE	    	(ZONE_SIZE / SMC_BLOCK_SIZE)
-+#define SECTORS_PER_BLOCK	(SMC_BLOCK_SIZE / SECTOR_SIZE)
-+#define OOB_SIZE		16
-+
-+
-+#define MAX_DEVICES 	4
-+#define MAX_PARTITIONS 	8
-+#define PARTITION_BITS 	3
-+#define MAX_ZONES 	8
-+
-+
-+int ssfdc_major = SSFDC_MAJOR;
-+unsigned int ssfdc_cached = 0xFFFFFFFF;
-+static unsigned char ssfdc_scratch[16384];
-+static unsigned char ssfdc_buffer[16];
-+static unsigned char ssfdc_ffoob_buf[OOB_SIZE * SECTORS_PER_BLOCK];
-+static unsigned char ssfdc_oob_buf[OOB_SIZE * SECTORS_PER_BLOCK];
-+
-+
-+static struct nand_oobinfo ssfdc_ffoob_info = {
-+	.useecc = 0,
-+};
-+
-+
-+typedef struct minor_t {
-+	atomic_t open;
-+	int cached;
-+	unsigned char * pt_data;
-+	unsigned char * pt_oob;
-+} minor_t;
-+
-+
-+
-+typedef struct partition_t {
-+	int type;
-+    	struct mtd_info	*mtd;
-+    	int count;
-+	unsigned int *zone;
-+	unsigned int zoneCount;
-+	minor_t minor[MAX_PARTITIONS];
-+	unsigned int last_written[MAX_ZONES];
-+} partition_t;
-+
-+partition_t SMCParts[MAX_DEVICES];
-+
-+
-+static unsigned char ssfdc_ecc[] = {14, 13, 15, 9, 8, 10};
-+
-+static struct hd_struct ssfdc_hd[MAX_DEVICES * MAX_PARTITIONS];
-+static int ssfdc_sizes[MAX_DEVICES * MAX_PARTITIONS];
-+static int ssfdc_blocksizes[MAX_DEVICES * MAX_PARTITIONS];
-+smc_control * pt_ssfdc_smc;
-+
-+
-+static struct gendisk ssfdc_gendisk = {
-+    major:		SSFDC_MAJOR,
-+    major_name:		"ssfdc",
-+    minor_shift:	PARTITION_BITS,
-+    max_p:		MAX_PARTITIONS,
-+    part:		ssfdc_hd,
-+    sizes:		ssfdc_sizes,
-+};
-+
-+
-+static int	ssfdc_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg);
-+static int 	ssfdc_open(struct inode *inode, struct file *file);
-+static int 	ssfdc_close(struct inode *inode, struct file *file);
-+static int 	ssfdc_write(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks);
-+static int 	ssfdc_read(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks);
-+static int 	ssfdc_physical(partition_t * pt_smcpart, int zone, int block);
-+static int 	ssfdc_erase(partition_t *pt_smcpart, unsigned int offset);
-+static int 	ssfdc_read_partitions(partition_t * pt_smcpart);
-+static void 	ssfdc_notify_add(struct mtd_info *mtd);
-+static void 	ssfdc_notify_remove(struct mtd_info *mtd);
-+static void 	ssfdc_tables(partition_t * pt_smcpart);
-+static int 	ssfdc_sector_blank(partition_t * pt_smcpart, int sc);
-+static int  	ssfdc_allocate_new(partition_t * pt_smcpart, int zone);
-+int 		ssfdc_parity(int number);
-+static void 	ssfdc_erase_callback(struct erase_info *erase);
-+
-+
-+
-+static DECLARE_WAIT_QUEUE_HEAD(ssfdc_wq);
-+
-+
-+static struct mtd_notifier ssfdc_notifier = {
-+	add:		ssfdc_notify_add,
-+	remove:		ssfdc_notify_remove,
-+};
-+
-+
-+
-+static struct block_device_operations ssfdc_fops = {
-+    open:	ssfdc_open,
-+    release:	ssfdc_close,
-+    ioctl:	ssfdc_ioctl,
-+};
-+                                               
-+static struct semaphore ssfdc_semaphore;
-+
-+static void ssfdc_notify_add(struct mtd_info *mtd) {
-+
-+
-+
-+	
-+	if(mtd->index >= 1) return;   // Hack to limit SSFDC to 1 partition
-+
-+	if( ((mtd->size % ZONE_SIZE) != 0) && (mtd->size < (ZONE_SIZE * MAX_ZONES)) ){
-+		PDEBUG("ssfdc_notify_add : mtd partition %d is not modulus 16M, not SSFDC\n", mtd->index);	
-+	}
-+	else {
-+		memset((void *)&SMCParts[mtd->index].type, 0, sizeof(partition_t));	
-+		SMCParts[mtd->index].mtd = mtd;
-+		SMCParts[mtd->index].count = mtd->index;
-+		SMCParts[mtd->index].type = 1;
-+		SMCParts[mtd->index].zoneCount = mtd->size / ZONE_SIZE;
-+		SMCParts[mtd->index].zone = kmalloc(SMCParts[mtd->index].zoneCount * 8192, GFP_KERNEL);
-+		
-+
-+		if(!SMCParts[mtd->index].zone) {
-+			printk(KERN_NOTICE "ssfdc_notify_add : mtd partition %d, failed to allocate mapping table\n", mtd->index);
-+			SMCParts[mtd->index].type = 0;
-+		}
-+		else {
-+			memset((void *)SMCParts[mtd->index].zone, 0xFF, SMCParts[mtd->index].zoneCount * 8192);
-+		}
-+	
-+		ssfdc_read_partitions((partition_t *)&SMCParts[mtd->index].type);
-+	}
-+	return;
-+
-+}
-+static int ssfdc_read_partitions(partition_t * pt_smcpart) {
-+
-+	int whole, i, j, size;
-+
-+//=printk("ssfdc_read_partitions : start\n");
-+
-+	for(i=0; i<MAX_PARTITIONS; i++)
-+	   	if ((atomic_read(&pt_smcpart->minor[i].open) > 1)) {
-+//=printk("ssfdc_read_partitions : part %d busy\n", i);
-+
-+    		return -EBUSY;
-+   		}
-+
-+
-+//=printk("ssfdc_read_partitions : tables start\n");
-+	ssfdc_tables(pt_smcpart);
-+//=printk("ssfdc_read_partitions : tables end\n");
-+
-+   	whole = pt_smcpart->count << PARTITION_BITS;         		
-+
-+
-+   	j = MAX_PARTITIONS - 1;
-+   	while (j-- > 0) {
-+		if (ssfdc_hd[whole+j].nr_sects > 0) {
-+    			kdev_t rdev = MKDEV(SSFDC_MAJOR, whole+j);
-+    			invalidate_device(rdev, 1);
-+		}
-+		ssfdc_hd[whole+j].start_sect = 0;
-+		ssfdc_hd[whole+j].nr_sects = 0;
-+   	}
-+
-+
-+	size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;
-+	size /= (0x8 * 0x20);
-+	size = size * (0x8 * 0x20);
-+
-+//=printk("ssfdc_read_partitions : register start\n");
-+
-+    register_disk(&ssfdc_gendisk, whole >> PARTITION_BITS, MAX_PARTITIONS,
-+		  &ssfdc_fops, size);
-+
-+//=printk("ssfdc_read_partitions : register end\n");
-+
-+
-+    	return 0;
-+}
-+
-+
-+static void ssfdc_notify_remove(struct mtd_info *mtd) {
-+int i, j, whole;
-+
-+	i=mtd->index;
-+	whole = i << PARTITION_BITS;
-+   	if(SMCParts[i].mtd == mtd) {
-+       		if(SMCParts[i].zone)kfree(SMCParts[i].zone);
-+		memset((void *)&SMCParts[i].type, 0, sizeof(partition_t));
-+    		for (j = 0; j < MAX_PARTITIONS; j++) {
-+			if (ssfdc_hd[whole+j].nr_sects > 0) {
-+		   		ssfdc_hd[whole+j].start_sect = 0;
-+	   			ssfdc_hd[whole+j].nr_sects=0;
-+			}
-+    		}
-+		return;
-+	}
-+	return;
-+}
-+
-+
-+
-+static int ssfdc_ioctl(struct inode *inode, struct file *file,
-+		u_int cmd, u_long arg) {
-+
-+    int minor = MINOR(inode->i_rdev);
-+    int ret = -EINVAL;
-+    partition_t * pt_smcpart = (partition_t *)&SMCParts[(minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS].type;
-+    struct hd_geometry geo;
-+    int size;
-+/*
-+	unsigned char smc_status;
-+
-+  	smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);
-+  	if(!(smc_status & SMC_PRESENT)) {
-+		printk("ssfdc : media not present\n");
-+		ret = 1;
-+		goto ssfdc_ioctl_error;
-+	}
-+
-+  	if(smc_status & SMC_CHANGED) {
-+   		out_8((void *)&pt_ssfdc_smc->smc_status, smc_status);
-+		if(minor & ((1<< PARTITION_BITS) - 1)) return -ENOTTY;
-+			ssfdc_read_partitions(pt_smcpart);
-+		printk("ssfdc : media change\n");
-+  	}
-+*/
-+	switch(cmd) {
-+
-+	    case HDIO_GETGEO:
-+		   	memset(&geo, 0, sizeof(geo));
-+			size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;
-+			size /= (0x8 * 0x20);
-+			geo.heads = 0x8;
-+			geo.sectors = 0x20;
-+			geo.cylinders = size;
-+			geo.start = ssfdc_hd[minor].start_sect;
-+//			printk(KERN_WARNING "ssfdc : HDIO_GETGEO heads %d, sectors %d, cylinders %d, start %lu\n",
-+//				geo.heads, geo.sectors, geo.cylinders, geo.start);
-+			copy_to_user((void *)arg, &geo, sizeof(geo));
-+			ret = 0;
-+		break;
-+
-+	    case BLKGETSIZE64:
-+   	 	case BLKGETSIZE:
-+			size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;
-+			//=printk(KERN_WARNING "ssfdc : BLKGETSIZE %d, minor %d\n", size, minor);
-+			ret = copy_to_user((unsigned long *)arg, &size, sizeof(size));
-+		break;
-+		case BLKSSZGET:
-+			size = 512;
-+			ret = copy_to_user((unsigned long *)arg, &size, sizeof(size));
-+		break;
-+		break;
-+
-+    	case BLKRRPART:
-+				if(minor & ((1<< PARTITION_BITS) - 1)) return -ENOTTY;
-+				ssfdc_read_partitions(pt_smcpart);
-+				ret=0;
-+		break;
-+   		case BLKFLSBUF:
-+			printk(KERN_WARNING "ssfdc : block ioctl 0x%x\n", cmd);
-+		break;
-+
-+   		default:
-+			printk(KERN_WARNING "ssfdc: unknown ioctl 0x%x\n", cmd);
-+    }
-+
-+//ssfdc_ioctl_error:
-+    return(ret);
-+
-+}
-+static int ssfdc_open(struct inode *inode, struct file *file)
-+{
-+    int minor = MINOR(inode->i_rdev);
-+    partition_t *pt_smcpart;
-+	int index;
-+
-+    if (minor >= MAX_MTD_DEVICES)
-+	return -ENODEV;
-+
-+    index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;
-+
-+
-+    if(SMCParts[index].type != SSFDC_FORMAT)
-+	return -ENXIO;
-+
-+	pt_smcpart = &SMCParts[index];
-+
-+
-+	if(!pt_smcpart->zone)
-+	return -ENXIO;
-+ 
-+
-+    BLK_INC_USE_COUNT;
-+
-+    if (!get_mtd_device(pt_smcpart->mtd, -1)) {
-+	    BLK_DEC_USE_COUNT;
-+	    return -ENXIO;
-+    }
-+
-+    if ((file->f_mode & 2) && !(pt_smcpart->mtd->flags & MTD_CLEAR_BITS) ) {
-+	    put_mtd_device(pt_smcpart->mtd);
-+	    BLK_DEC_USE_COUNT;
-+            return -EROFS;
-+    }
-+
-+
-+    atomic_inc(&pt_smcpart->minor[minor & ~(MAX_PARTITIONS -1)].open);
-+
-+	PDEBUG("ssfdc_open : device %d\n", minor);
-+
-+	return(0);
-+}
-+
-+static void ssfdc_tables(partition_t * pt_smcpart) {
-+
-+	int * logical, * physical;
-+	int offset = 0;
-+	int zone, block;
-+	int i, retlen;
-+	int block_address, parity;
-+	int h, l;
-+
-+	for(zone=0; zone<pt_smcpart->zoneCount; zone++) {	
-+		logical  =  pt_smcpart->zone + (2048 * zone);
-+		memset((void *)logical, 0xFF, 1024 * sizeof(int));
-+		physical =  pt_smcpart->zone + (2048 * zone) + 1024;
-+		memset((void *)physical, 0xFF, 1024 * sizeof(int));
-+
-+		for(block=0; block < 1024; block++) {
-+			offset = (zone * ZONE_SIZE) + (block * SMC_BLOCK_SIZE);
-+	    		pt_smcpart->mtd->read_oob(pt_smcpart->mtd, offset, sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);
-+			if(retlen != sizeof(ssfdc_buffer)) {
-+				printk(KERN_WARNING "ssfdc_tables : failed to read OOB\n");
-+				pt_smcpart->type = 0;
-+				return;
-+			}
-+
-+			l = (ssfdc_buffer[7] & 0xFF);
-+			h = (ssfdc_buffer[6] & 0xFF);
-+            		block_address = l + (h << 8L);
-+
-+			if((block_address & ~0x7FF) != 0x1000) {
-+					continue;
-+			}
-+
-+			parity = block_address & 0x01;
-+			
-+			block_address &= 0x7FF;
-+			block_address >>= 1;
-+
-+
-+			if(ssfdc_parity(block_address) != parity) {
-+ 				printk(KERN_WARNING "ssfdc_tables : parity error offset 0x%x, block 0x%x, parity 0x%x\nOOB : "
-+						, offset, block_address, parity);
-+			    	for(i=0; i<16; i++) {
-+                 			printk("0x%02x ", (unsigned char)ssfdc_buffer[i]);
-+			    	}
-+				printk("\n");
-+				pt_smcpart->type = 0;
-+				return;          		
-+			}
-+
-+
-+            		/* Ok we have a valid block number so insert it */
-+            		*(logical + block_address) = (offset/SMC_BLOCK_SIZE);
-+			PDEBUG("ssfdc_tables : logical 0x%x + 0x%x = 0x%x\n", 
-+					(unsigned int)logical, block_address, (offset/SMC_BLOCK_SIZE));
-+			*(physical + block) = block_address;
-+			PDEBUG("ssfdc_tables : physical 0x%x + 0x%x = 0x%x\n", (unsigned int)physical, block, block_address);
-+			
-+
-+    		}
-+    	}
-+    	return;
-+}
-+int ssfdc_parity(int number) {
-+ 	int i;
-+	int parity = 1; // the 0x1000 bit
-+
-+	for(i=0; i<10; i++) {
-+      		parity += ((number >> i) & 1);
-+	}
-+	PDEBUG("ssfdc_parity : number 0x%x, parity 0x%x\n", number, parity);
-+	return(parity % 2);
-+}
-+static int ssfdc_physical(partition_t * pt_smcpart, int zone, int block) {
-+
-+	unsigned int * logical;
-+
-+	logical = pt_smcpart->zone + (zone * 2048);
-+
-+	logical += block;
-+
-+	if(*logical == 0xFFFFFFFF) {
-+		PDEBUG("ssfdc_physical : physical for zone %d, block %d invalid\n", zone, block);
-+		return(-1);
-+	}
-+
-+	PDEBUG("ssfdc_physical : physical for zone %d, block %d, 0x%x\n", zone, block, (*logical * SMC_BLOCK_SIZE));
-+	return(*logical * SMC_BLOCK_SIZE);
-+}
-+
-+static int ssfdc_close(struct inode *inode, struct file *file)
-+{                       
-+    int minor = MINOR(inode->i_rdev);
-+    partition_t *pt_smcpart;
-+	int index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;
-+
-+    if (minor >= MAX_MTD_DEVICES)
-+	return -ENODEV;
-+
-+    if(SMCParts[index].type != SSFDC_FORMAT)
-+	return -ENXIO;
-+
-+    pt_smcpart = &SMCParts[index];
-+    atomic_dec(&pt_smcpart->minor[minor & ~(MAX_PARTITIONS -1)].open);
-+    put_mtd_device(pt_smcpart->mtd);
-+    BLK_DEC_USE_COUNT;
-+
-+    return(0);
-+} 
-+
-+
-+static void do_ssfdc_request(request_arg_t)
-+{
-+    int ret, minor;
-+    partition_t *pt_smcpart;
-+	int index;
-+    do {
-+
-+	INIT_REQUEST;
-+
-+
-+
-+	minor = MINOR(CURRENT->rq_dev);
-+	index = (minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS;
-+
-+	pt_smcpart = &SMCParts[index];
-+	if (pt_smcpart->type == SSFDC_FORMAT) {
-+ 		ret = 0;
-+		switch (CURRENT->cmd) {
-+			case READ:
-+	  			ret = ssfdc_read(pt_smcpart, CURRENT->buffer,
-+					CURRENT->sector + ssfdc_hd[minor].start_sect,
-+					CURRENT->current_nr_sectors);
-+		    break;
-+
-+		  	case WRITE:
-+		    	ret = ssfdc_write(pt_smcpart, CURRENT->buffer,
-+				    CURRENT->sector	+ ssfdc_hd[minor].start_sect,
-+				    CURRENT->current_nr_sectors);
-+		    break;
-+
-+		  default:
-+		    panic("do_ssfdc_request : unknown block command!\n");
-+		  }
-+	
-+	} else {
-+	  ret = 1;
-+	  PDEBUG("not ssfdc partition type\n");
-+	}
-+
-+	if (!ret) {
-+	  CURRENT->sector += CURRENT->current_nr_sectors;
-+	}
-+
-+	end_request((ret == 0) ? 1 : 0);
-+    } while (1);
-+}
-+
-+static int ssfdc_write(partition_t *pt_smcpart, caddr_t buffer,
-+		     u_long sector, u_long nblocks)
-+{
-+	int zone, block, offset;
-+	int sectors_written = 0;
-+    	int physical;
-+	int * pt_logical;
-+	int * pt_physical;
-+	int new = -1;
-+	int size;
-+	int retlen;
-+	int i;
-+	int sc;
-+	int ptr_done = 0;
-+	unsigned char * ptr = (unsigned char *)buffer;
-+	unsigned char ecc_code[6], ecc_calc[6];
-+	int do_erase;
-+//	unsigned char smc_status;
-+
-+
-+
-+	offset = (sector % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;
-+
-+    	PDEBUG("write device %d, sector %d, count %d\n",
-+			pt_smcpart->count, sector, nblocks);
-+/*
-+  	smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);
-+	if(!(smc_status & SMC_PRESENT)) {
-+		printk("ssfdc : media not present\n");
-+		return -ENXIO;
-+	}
-+
-+    if(smc_status & SMC_CHANGED) {
-+   		out_8((void *)&pt_ssfdc_smc->smc_status, smc_status);
-+		ssfdc_read_partitions(pt_smcpart);
-+		printk("ssfdc : media change\n");
-+	}
-+*/
-+	while(sectors_written < nblocks) {
-+
-+		new = -1;
-+		do_erase = FALSE;
-+    
-+		zone = (sector + sectors_written) / SECTORS_PER_ZONE;
-+		block = ((sector + sectors_written) % SECTORS_PER_ZONE) / SECTORS_PER_BLOCK ;
-+		offset = ((sector + sectors_written) % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;
-+
-+		pt_logical = pt_smcpart->zone + (zone * 2048);
-+		pt_physical = pt_smcpart->zone + (zone * 2048) + 1024;
-+
-+		size = ((SECTORS_PER_BLOCK - offset) < (nblocks - sectors_written)) ?
-+				(SECTORS_PER_BLOCK - offset) : (nblocks - sectors_written);
-+		size *= SECTOR_SIZE;
-+
-+		PDEBUG("write device %d, sector %d, count %d, zone %d, block %d, offset %d, done %d, size %d, address 0x%x\n",
-+				pt_smcpart->count, sector, nblocks, zone, block, offset, sectors_written, size, (unsigned int)ptr);
-+
-+		physical = ssfdc_physical(pt_smcpart, zone, block);
-+
-+
-+		if(physical >= 0) {
-+			if(ssfdc_cached != physical) {
-+	   			pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, physical, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch,
-+					 ssfdc_oob_buf, &ssfdc_ffoob_info);
-+				if(retlen != SMC_BLOCK_SIZE) {
-+					printk(KERN_WARNING "ssfdc_write : failed to read physical\n");
-+					return -ENXIO;
-+				}
-+
-+				for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {
-+	   				pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);
-+					if(retlen != sizeof(ssfdc_buffer)) {
-+						printk(KERN_WARNING "ssfdc_write : failed to read physical oob\n");
-+						return -ENXIO;
-+					}
-+
-+					nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);
-+					nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);
-+					for(i=0; i<6; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];
-+					nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_code[0], &ecc_calc[0]);
-+					nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_code[3], &ecc_calc[3]);
-+				}
-+
-+			}
-+			
-+			for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {
-+				if(offset > sc) {
-+					PDEBUG("offset %d, sector %d\n", offset, sc);
-+					continue;
-+				}
-+   				pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);
-+				if(retlen != sizeof(ssfdc_buffer)) {
-+					printk(KERN_WARNING "ssfdc_write : failed to read physical oob\n");
-+					return -ENXIO;
-+				}
-+
-+				nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);
-+				nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);
-+				for(i=0; i<6; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];
-+				nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_code[0], &ecc_calc[0]);
-+				nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_code[3], &ecc_calc[3]);
-+				
-+				/* find out if the block is being used */
-+
-+
-+				if(ssfdc_sector_blank(pt_smcpart, sc)) {
-+					PDEBUG("ssfdc_write : zone %d, block %d, sector %d, lbn %d, blank, physical 0x%x\n",
-+						zone, block, sc, sector, physical);
-+					memcpy(&ssfdc_scratch[(sc * SECTOR_SIZE)], ptr+ptr_done, SECTOR_SIZE);
-+					nand_calculate_ecc (pt_smcpart->mtd, (ptr + ptr_done), &ecc_calc[0]);
-+					nand_calculate_ecc (pt_smcpart->mtd, (ptr + ptr_done + 256), &ecc_calc[3]);
-+					for(i=0; i<6; i++) ssfdc_buffer[ssfdc_ecc[i]] = ecc_calc[i];
-+					i = (block << 1) | 0x1000;
-+					i |= ssfdc_parity(block);
-+       				        ssfdc_buffer[7] = ssfdc_buffer[12] = i & 0xFF;
-+                    			ssfdc_buffer[6] = ssfdc_buffer[11] = (i & 0xFF00) >> 0x08;
-+
-+                    pt_smcpart->mtd->write_ecc(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), SECTOR_SIZE, &retlen,
-+								ptr + ptr_done, ssfdc_buffer, &ssfdc_ffoob_info);
-+					if(retlen != SECTOR_SIZE) {
-+						printk(KERN_WARNING "ssfdc_write : failed to write physical 0x%x, sector 0x%x, blank, retlen %d\n"
-+								, physical, sc, retlen);
-+						return -ENXIO;
-+					}
-+
-+                    ptr_done += SECTOR_SIZE;
-+					if(ptr_done >= size) break;
-+				}
-+				else {
-+					new = ssfdc_allocate_new(pt_smcpart, zone);
-+					/* erase the old block */
-+		            *(pt_physical + ((physical % ZONE_SIZE) / SMC_BLOCK_SIZE)) = 0xFFFFFFFF;
-+
-+					PDEBUG("ssfdc_write : physical 0x%x + 0x%x = 0x%x\n",
-+						(unsigned int)pt_physical, ((physical % ZONE_SIZE) / SMC_BLOCK_SIZE), 0xFFFFFFFF);
-+					do_erase = TRUE;
-+					PDEBUG("ssfdc_write : zone %d, block %d, sector %d, lbn %d, written, physical 0x%x, new 0x%x\n",
-+						zone, block, sc, sector, physical, new);
-+					break;
-+				}
-+			}
-+		}
-+		else {
-+			ssfdc_cached = 0xFFFFFFFF;
-+			memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));
-+			new = ssfdc_allocate_new(pt_smcpart, zone);
-+			PDEBUG("ssfdc_write : zone %d, block %d, lbn %d, physical 0x%x, unallocated, new 0x%x\n",
-+				zone, block, sector, physical, new);
-+		}
-+
-+
-+
-+		if(new != -1) {
-+
-+
-+			memcpy(&ssfdc_scratch[(offset * SECTOR_SIZE)], ptr, size);
-+			PDEBUG("ssfdc_write : new 0x%x, offset 0x%x, size 0x%x, block 0x%x\n", new, offset, size, block);
-+       		for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {
-+				memset(ssfdc_buffer, 0xFF, OOB_SIZE);
-+				nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);
-+				nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);
-+				for(i=0; i<6; i++) ssfdc_buffer[ssfdc_ecc[i]] = ecc_calc[i];
-+				i = (block << 1) | 0x1000;
-+				i |= ssfdc_parity(block);
-+                		ssfdc_buffer[7] = ssfdc_buffer[12] = i & 0xFF;
-+                		ssfdc_buffer[6] = ssfdc_buffer[11] = (i & 0xFF00) >> 0x08;
-+                memcpy(&ssfdc_oob_buf[sc * OOB_SIZE], ssfdc_buffer, OOB_SIZE);
-+			}
-+
-+
-+	   		pt_smcpart->mtd->write_ecc(pt_smcpart->mtd, new, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch,
-+                        ssfdc_oob_buf, &ssfdc_ffoob_info);
-+			if(retlen != SMC_BLOCK_SIZE) {
-+				printk(KERN_WARNING "ssfdc_write : failed to write block, physical 0x%x, returned 0x%x\n", new, retlen);
-+				return -ENXIO;
-+			}
-+			/* change the mapping table to reflect the new block placement */
-+
-+			*(pt_logical + block) = (new % ZONE_SIZE) / SMC_BLOCK_SIZE;
-+			PDEBUG("ssfdc_write : logical 0x%x + 0x%x = 0x%x\n",
-+						(unsigned int)pt_logical, block, (new % ZONE_SIZE) / SMC_BLOCK_SIZE);
-+
-+            		*(pt_physical + ((new % ZONE_SIZE) / SMC_BLOCK_SIZE)) = block;
-+			PDEBUG("ssfdc_write : physical 0x%x + 0x%x = 0x%x\n",
-+				(unsigned int)pt_physical, ((new % ZONE_SIZE) / SMC_BLOCK_SIZE), block);
-+
-+
-+			ssfdc_cached = new;
-+   	    }
-+
-+
-+		ptr += size;
-+		ptr_done = 0;
-+		sectors_written += (size / SECTOR_SIZE);
-+		if(do_erase) ssfdc_erase(pt_smcpart, physical);
-+
-+	}
-+
-+
-+
-+
-+	return(0);
-+}
-+static int ssfdc_sector_blank(partition_t * pt_smcpart, int sc) {
-+int b;
-+
-+	for(b=0; b<SECTOR_SIZE; b++) {
-+		if(ssfdc_scratch[b + (sc * SECTOR_SIZE)] != 0xFF) return(0);
-+	}
-+	for(b=0; b<OOB_SIZE; b++) {
-+		if((b==6) || (b==7) || (b==11) || (b==12)) continue;   // Block address fields
-+		if(ssfdc_buffer[b] != 0xFF) return(0);
-+	}
-+    return(1);
-+}
-+static int ssfdc_allocate_new(partition_t * pt_smcpart, int zone) {
-+
-+	int new = pt_smcpart->last_written[zone] + 1;
-+	int * pt_physical;
-+	int physical;
-+    	int block;
-+	int retlen;
-+	unsigned char oob[16];
-+	
-+
-+	if(new >= BLOCKS_PER_ZONE) new = 0;
-+
-+
-+	while (new != pt_smcpart->last_written[zone]) {
-+       	block = new % BLOCKS_PER_ZONE;
-+		pt_physical = pt_smcpart->zone + (zone * 2048) + 1024 + block;
-+		physical = (zone * ZONE_SIZE) + (block * SMC_BLOCK_SIZE);
-+
-+	  	PDEBUG("ssfdc_allocate_new : zone %d, block %d, address 0x%08x, data 0x%08x\n",
-+			zone, block, (unsigned int)pt_physical, *pt_physical);
-+     		if(*pt_physical == 0xFFFFFFFF) {
-+			PDEBUG("ssfdc_allocate_new : physical 0x%x = 0x%x\n", (unsigned int)pt_physical, *pt_physical);
-+			memset(oob, 0, OOB_SIZE);
-+			pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical, OOB_SIZE, &retlen, oob);
-+			if((oob[5] == 0xFF) && (retlen == OOB_SIZE)) {   // If not a bad block
-+				pt_smcpart->last_written[zone] = new;
-+				return((new * SMC_BLOCK_SIZE) + (zone * ZONE_SIZE));
-+			}
-+			else {
-+             			PDEBUG("ssfdc_allocate_new : new 0x%x, physical 0x%x, block status 0x%x, oob length 0x%x\n", new, physical, oob[5], retlen);
-+			}
-+		}
-+		new++;
-+		if(new >= BLOCKS_PER_ZONE) new = 0;
-+	}
-+
-+   	panic("ssfdc_allocate_new : cant find free block\n");
-+
-+}
-+	
-+
-+
-+static int ssfdc_read(partition_t *pt_smcpart, caddr_t buffer,
-+		    u_long sector, u_long nblocks)
-+{
-+	int zone, block, offset;
-+	int sectors_read = 0;
-+    int physical;
-+	int size;
-+	int retlen;
-+	int i;
-+	int sc;
-+	unsigned char * ptr = (unsigned char *)buffer;
-+	unsigned char ecc_code[6], ecc_calc[6];
-+/*
-+    unsigned char smc_status;
-+
-+  	smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);
-+	if(!(smc_status & SMC_PRESENT)) {
-+		printk("ssfdc : media not present\n");
-+		return -ENXIO;
-+	}
-+
-+
-+
-+    if(smc_status & SMC_CHANGED) {
-+   		out_8((void *)&pt_ssfdc_smc->smc_status, smc_status);
-+		ssfdc_read_partitions(pt_smcpart);
-+		printk("ssfdc : media change\n");
-+	}
-+*/
-+	while(sectors_read < nblocks) {
-+
-+		zone = (sector + sectors_read) / SECTORS_PER_ZONE;
-+		block = ((sector + sectors_read) % SECTORS_PER_ZONE) / SECTORS_PER_BLOCK ;
-+		offset = ((sector + sectors_read) % SECTORS_PER_ZONE) % SECTORS_PER_BLOCK ;
-+
-+
-+		if(offset) {
-+			size = ((SECTORS_PER_BLOCK - offset) < (nblocks - sectors_read)) ?
-+					(SECTORS_PER_BLOCK - offset) : (nblocks - sectors_read);
-+		}
-+		else {
-+			size = (SECTORS_PER_BLOCK < (nblocks - sectors_read)) ? SECTORS_PER_BLOCK : nblocks - sectors_read;
-+		}
-+		size *= SECTOR_SIZE;
-+
-+	    PDEBUG("ssfdc_read :  device %d, sector %d, count %d, zone %d, block %d, offset %d, done %d, size %d, address 0x%x\n",
-+			pt_smcpart->count, sector, nblocks, zone, block, offset, sectors_read, size, (unsigned int)ptr);
-+
-+			
-+		physical = ssfdc_physical(pt_smcpart, zone, block);
-+		if(physical >=  0) {
-+			if(ssfdc_cached != physical) {
-+           		pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, physical, SMC_BLOCK_SIZE, &retlen, ssfdc_scratch,
-+													 ssfdc_oob_buf, &ssfdc_ffoob_info);
-+				if(retlen != SMC_BLOCK_SIZE) {
-+					printk(KERN_WARNING "ssfdc_read : failed to read physical\n");
-+					return -ENXIO;
-+				}
-+				for(sc=0; sc<SECTORS_PER_BLOCK; sc++) {
-+	    			pt_smcpart->mtd->read_oob(pt_smcpart->mtd, physical + (sc * SECTOR_SIZE), sizeof(ssfdc_buffer), &retlen, ssfdc_buffer);
-+					if(retlen != sizeof(ssfdc_buffer)) {
-+						printk(KERN_WARNING "ssfdc_read : failed to read physical oob\n");
-+						return -ENXIO;
-+					}
-+					nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_calc[0]);
-+					nand_calculate_ecc (pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_calc[3]);
-+					for(i=0; i<3; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];
-+					for(i=3; i<6; i++) ecc_code[i] = ssfdc_buffer[ssfdc_ecc[i]];
-+					nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[sc * SECTOR_SIZE], &ecc_code[0], &ecc_calc[0]);
-+					nand_correct_data(pt_smcpart->mtd, &ssfdc_scratch[(sc * SECTOR_SIZE) + 256], &ecc_code[3], &ecc_calc[3]);
-+				}
-+
-+				/* Get the ecc bytes and check that they are ok */
-+
-+
-+			}
-+			ssfdc_cached = physical;
-+			
-+			
-+		}
-+		else {
-+			memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));
-+			ssfdc_cached = 0xFFFFFFFF;
-+		}
-+			
-+
-+		memcpy(ptr, &ssfdc_scratch[(offset * SECTOR_SIZE)], size);
-+		ptr += size;
-+		sectors_read += (size / SECTOR_SIZE);	
-+	}
-+
-+
-+	                                                    
-+	return(0);
-+}
-+
-+static void ssfdc_erase_callback(struct erase_info *erase) {
-+
-+	PDEBUG("ssfdc_erase_callback : wake erase\n");
-+    	up(&ssfdc_semaphore);
-+	PDEBUG("ssfdc_erase_callback : woken erase\n");
-+}
-+
-+static int ssfdc_erase(partition_t *pt_smcpart, unsigned int offset)
-+{
-+	int ret = 0;
-+    	struct erase_info *erase;
-+	unsigned char * junk;
-+	unsigned char * oob;
-+	int retlen;
-+	int b, sc;
-+
-+
-+	PDEBUG("ssfdc_erase : offset 0x%08x\n", offset);
-+
-+	erase=kmalloc(sizeof(struct erase_info), GFP_KERNEL);
-+    	junk=kmalloc(pt_smcpart->mtd->erasesize + 16, GFP_KERNEL);
-+    	oob = junk + pt_smcpart->mtd->erasesize;
-+
-+    	if (!erase)
-+        	 return -ENOMEM;
-+    	if (!junk)
-+        	 return -ENOMEM;
-+
-+    	erase->addr = offset;
-+    	erase->len = pt_smcpart->mtd->erasesize;
-+	erase->callback = ssfdc_erase_callback;
-+    	ret = pt_smcpart->mtd->erase(pt_smcpart->mtd, erase);
-+	if(ret) {
-+     		printk(KERN_WARNING "ssfdc_erase : failed status 0x%x\n", ret);
-+		goto end;
-+
-+	}
-+
-+	down(&ssfdc_semaphore);
-+
-+	pt_smcpart->mtd->read_ecc(pt_smcpart->mtd, offset, SMC_BLOCK_SIZE, &retlen, junk,
-+							 ssfdc_oob_buf, &ssfdc_ffoob_info);
-+	if(retlen != SMC_BLOCK_SIZE) {
-+           	printk(KERN_WARNING "ssfdc_erase : offset 0x%x, read returned length %d\n", offset, retlen);
-+		goto end;
-+	}
-+
-+
-+	for(sc=0; sc < SECTORS_PER_BLOCK; sc++) {
-+		for(b=0; b<SECTOR_SIZE; b++) {
-+			if(*(junk + (b + (sc * SECTOR_SIZE))) != 0xFF) {
-+             			printk(KERN_WARNING "ssfdc_erase : offset 0x%x, sector 0x%x, byte 0x%x, data 0x%02x, expected 0xff\n"
-+						, offset, sc, b, *(junk + (b + (sc * SECTOR_SIZE))));
-+				goto end;
-+			}
-+		}
-+		pt_smcpart->mtd->read_oob(pt_smcpart->mtd, offset + (sc * SECTOR_SIZE), OOB_SIZE, &retlen, oob);
-+		if(retlen != OOB_SIZE) {
-+           		printk(KERN_WARNING "ssfdc_erase : offset 0x%x, read oob returned length %d\n", offset, retlen);
-+			goto end;
-+		}
-+		for(b=0; b<OOB_SIZE; b++) {
-+			if(*(oob+b) != 0xFF) {
-+             			printk(KERN_WARNING "ssfdc_erase : offset 0x%x, byte 0x%x, oob got 0x%02x, expected 0xff\n", 
-+						offset, b, *(oob+b));
-+				goto end;
-+			}
-+		}
-+	}
-+
-+end:
-+	
-+    kfree(erase);
-+	kfree(junk);
-+
-+    return ret;
-+} /* erase_xfer */
-+
-+
-+
-+
-+
-+int init_ssfdc(void)
-+{
-+	int result, i;
-+
-+//	unsigned char smc_status;
-+//	#define B01159_FIO_PBASE 0x0000000148000000  /* Physical Base address of SMC control chip  */
-+
-+	printk(KERN_INFO "SSFDC block device translation layer V1.0\n");
-+/*
-+	pt_ssfdc_smc = ioremap64(B01159_FIO_PBASE, 1024);
-+	if(!pt_ssfdc_smc){
-+     	printk("ssfdc : failed to map SMC control device\n");
-+        return(-EFAULT);
-+	}
-+	
-+  	smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);
-+*/	
-+    memset(ssfdc_ffoob_buf, 0xFF, sizeof(ssfdc_ffoob_buf));
-+    
-+	for (i = 0; i < MAX_DEVICES*MAX_PARTITIONS; i++) {
-+		ssfdc_hd[i].nr_sects = 0;
-+		ssfdc_hd[i].start_sect = 0;
-+		ssfdc_blocksizes[i] = 4096;
-+    	}
-+   	blksize_size[SSFDC_MAJOR] = ssfdc_blocksizes;
-+   	ssfdc_gendisk.major = SSFDC_MAJOR;
-+
-+
-+	memset(ssfdc_scratch, 0xFF, sizeof(ssfdc_scratch));
-+
-+	result = register_blkdev(ssfdc_major, "ssfdc", &ssfdc_fops);
-+	if(result != 0) {
-+		printk(KERN_WARNING "ssfdc : failed to get a major number\n");
-+		return(result);
-+	}
-+//	if(ssfdc_major == 0) ssfdc_major = result;
-+	
-+    	blk_init_queue(BLK_DEFAULT_QUEUE(ssfdc_major), &do_ssfdc_request);
-+
-+    	add_gendisk(&ssfdc_gendisk);
-+
-+
-+
-+    	register_mtd_user(&ssfdc_notifier);
-+
-+
-+	init_MUTEX_LOCKED(&ssfdc_semaphore);
-+
-+
-+
-+    	return 0;
-+}
-+
-+static void __exit cleanup_ssfdc(void)
-+{
-+	int i;
-+
-+	for(i=0; i<MAX_DEVICES; i++) {
-+       		if(SMCParts[i].zone)kfree(SMCParts[i].zone);
-+	}
-+
-+
-+    	unregister_mtd_user(&ssfdc_notifier);
-+    	unregister_blkdev(ssfdc_major, "ssfdc");
-+    	blk_cleanup_queue(BLK_DEFAULT_QUEUE(ssfdc_major));
-+
-+
-+
-+    	blksize_size[SSFDC_MAJOR] = NULL;
-+    	del_gendisk(&ssfdc_gendisk);
-+
-+}
-+
-+module_init(init_ssfdc);
-+module_exit(cleanup_ssfdc);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Simon Haynes <simon@baydel.com>");
-+MODULE_DESCRIPTION("SSFDC translation layer support for MTD");
-+
-+
-+
-+
-Index: linux-2.6.5/include/linux/mtd/cfi.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/cfi.h	2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/cfi.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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.46 2004/08/12 07:49:04 eric Exp $
-  */
- 
- #ifndef __MTD_CFI_H__
-@@ -13,200 +13,74 @@
- #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 @@
- 
- /* 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 @@
- #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 @@
- #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 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,48 +293,47 @@
-  * 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]);
- 	}
- }
- 
- static inline void cfi_udelay(int us)
- {
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- 	unsigned long t = us * HZ / 1000000;
- 	if (t) {
- 		set_current_state(TASK_UNINTERRUPTIBLE);
- 		schedule_timeout(t);
- 		return;
- 	}
--#endif
- 	udelay(us);
- 	cond_resched();
- }
-@@ -480,4 +348,28 @@
- 	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 mtd_info *mtd, void* param);
-+	void* param;
-+};
-+
-+#define CFI_MFR_ANY 0xffff
-+#define CFI_ID_ANY  0xffff
-+
-+#define CFI_MFR_AMD 0x0001
-+#define CFI_MFR_ST  0x0020 	/* STMicroelectronics */
-+
-+void cfi_fixup(struct mtd_info *mtd, struct cfi_fixup* fixups);
-+
-+typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip,
-+			      unsigned long adr, int len, void *thunk);
-+
-+int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
-+	loff_t ofs, size_t len, void *thunk);
-+
-+
- #endif /* __MTD_CFI_H__ */
-Index: linux-2.6.5/include/linux/mtd/compatmac.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/compatmac.h	2004-04-03 22:38:00.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/compatmac.h	2005-02-01 17:11:17.000000000 -0500
-@@ -1,10 +1,210 @@
-+/*
-+ * $Id: compatmac.h,v 1.68 2004/09/17 22:00:30 eric Exp $
-+ *
-+ * Extensions and omissions from the normal 'linux/compatmac.h'
-+ * files. hopefully this will end up empty as the 'real' one 
-+ * becomes fully-featured.
-+ */
- 
- #ifndef __LINUX_MTD_COMPATMAC_H__
- #define __LINUX_MTD_COMPATMAC_H__
- 
--/* Nothing to see here. We write 2.5-compatible code and this
--   file makes it all OK in older kernels, but it's empty in _current_
--   kernels. Include guard just to make GCC ignore it in future inclusions
--   anyway... */
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
-+#error "This kernel is too old: not supported by this file"
-+#endif
-+
-+	/* O(1) scheduler stuff. */
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) && !defined(__rh_config_h__)
-+#include <linux/sched.h>
-+static inline void __recalc_sigpending(void)
-+{
-+	recalc_sigpending(current);
-+}
-+#undef recalc_sigpending
-+#define recalc_sigpending() __recalc_sigpending ()
-+
-+#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0)
-+#endif
-+
-+
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20)
-+
-+#ifndef yield
-+#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0)
-+#endif
-+
-+#ifndef minor
-+#define major(d) (MAJOR(to_kdev_t(d)))
-+#define minor(d) (MINOR(to_kdev_t(d)))
-+#endif
-+
-+#ifndef mk_kdev
-+#define mk_kdev(ma,mi) MKDEV(ma,mi)
-+#define kdev_t_to_nr(x)	(x)
-+#endif
-+
-+#define need_resched() (current->need_resched)
-+#define cond_resched() do { if need_resched() { yield(); } } while(0)
-+
-+#endif /* < 2.4.20 */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
-+#define iminor(i) minor((i)->i_rdev)
-+#define imajor(i) major((i)->i_rdev)
-+#define old_encode_dev(d) ( (major(d)<<8) | minor(d) )
-+#define old_decode_dev(rdev)  (kdev_t_to_nr(mk_kdev((rdev)>>8, (rdev)&0xff)))
-+#define old_valid_dev(d) (1)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61)
-+
-+#include <linux/sched.h>
-+
-+#ifdef __rh_config_h__
-+#define sigmask_lock sighand->siglock
-+#define sig sighand
-+#endif
-+
-+static inline void __daemonize_modvers(void)
-+{
-+	daemonize();
-+
-+	spin_lock_irq(&current->sigmask_lock);
-+	sigfillset(&current->blocked);
-+	recalc_sigpending();
-+	spin_unlock_irq(&current->sigmask_lock);
-+}
-+#undef daemonize
-+#define daemonize(fmt, ...) do {						\
-+	snprintf(current->comm, sizeof(current->comm), fmt ,##__VA_ARGS__);	\
-+	__daemonize_modvers();							\
-+	} while(0)
-+
-+static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
-+{
-+	unsigned long flags;
-+	unsigned long ret;
-+
-+	spin_lock_irqsave(&current->sigmask_lock, flags);
-+	ret = dequeue_signal(mask, info);
-+	spin_unlock_irqrestore(&current->sigmask_lock, flags);
-+
-+	return ret;
-+}
-+
-+static inline int allow_signal(int sig)
-+{
-+	if (sig < 1 || sig > _NSIG)
-+		return -EINVAL;
-+
-+        spin_lock_irq(&current->sigmask_lock);
-+	sigdelset(&current->blocked, sig);
-+	recalc_sigpending();
-+	/* Make sure the kernel neither eats it now converts to SIGKILL */
-+	current->sig->action[sig-1].sa.sa_handler = (void *)2;
-+	spin_unlock_irq(&current->sigmask_lock);
-+	return 0;
-+}
-+static inline int disallow_signal(int sig)
-+{
-+	if (sig < 1 || sig > _NSIG)
-+		return -EINVAL;
-+
-+	spin_lock_irq(&current->sigmask_lock);
-+	sigaddset(&current->blocked, sig);
-+	recalc_sigpending();
-+
-+	current->sig->action[sig-1].sa.sa_handler = SIG_DFL;
-+	spin_unlock_irq(&current->sigmask_lock);
-+	return 0;
-+}
-+
-+#define PF_FREEZE 0
-+#define refrigerator(x) do { ; } while(0)
-+#endif
-+
-+	/* Module bits */
-+
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
-+#define try_module_get(m) try_inc_mod_count(m)
-+#define __module_get(m) do { if (!try_inc_mod_count(m)) BUG(); } while(0)
-+#define module_put(m) do { if (m) __MOD_DEC_USE_COUNT((struct module *)(m)); } while(0)
-+#define set_module_owner(x) do { x->owner = THIS_MODULE; } while(0)
-+#endif
-+
-+
-+	/* Random filesystem stuff, only for JFFS2 really */
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
-+#define parent_ino(d) ((d)->d_parent->d_inode->i_ino)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12)
-+#define PageUptodate(x) Page_Uptodate(x)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
-+#define get_seconds() CURRENT_TIME
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,53)
-+#define generic_file_readonly_mmap generic_file_mmap
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70)
-+
-+#include <linux/kmod.h>
-+#include <linux/string.h>
-+
-+static inline char *strlcpy(char *dest, const char *src, int len)
-+{
-+	dest[len-1] = 0;
-+	return strncpy(dest, src, len-1);
-+}
-+
-+static inline int do_old_request_module(const char *mod)
-+{
-+	return request_module(mod);
-+}
-+#undef request_module
-+#define request_module(fmt, ...) \
-+ ({ char modname[32]; snprintf(modname, 31, fmt ,##__VA_ARGS__); do_old_request_module(modname); })
-+
-+#endif /* 2.5.70 */
-+
-+#ifndef container_of
-+#define container_of(ptr, type, member) ({		     \
-+	const typeof( ((type *)0)->member ) *__mptr = (ptr); \
-+	(type *)( (char *)__mptr - offsetof(type,member) );})
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)
-+#define kvec iovec
-+#define __user 
-+#endif
-+
-+#ifndef __iomem
-+#define __iomem
-+#endif
-+
-+#ifndef list_for_each_entry_safe
-+/**
-+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
-+ * @pos:	the type * to use as a loop counter.
-+ * @n:		another type * to use as temporary storage
-+ * @head:	the head for your list.
-+ * @member:	the name of the list_struct within the struct.
-+ */
-+#define list_for_each_entry_safe(pos, n, head, member)			\
-+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
-+		n = list_entry(pos->member.next, typeof(*pos), member);	\
-+	     &pos->member != (head); 					\
-+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
-+
-+#endif
- 
- #endif /* __LINUX_MTD_COMPATMAC_H__ */
-Index: linux-2.6.5/include/linux/mtd/doc2000.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/doc2000.h	2004-04-03 22:37:07.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/doc2000.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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.23 2004/09/16 23:26:08 gleixner 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
-@@ -73,16 +81,16 @@
-  * 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 WriteDOC_(d, adr, reg)  writeb(d, ((unsigned long)adr) + (reg))
-+#define ReadDOC_(adr, reg)      readb((void __iomem *)(((unsigned long)adr) + (reg)))
-+#define WriteDOC_(d, adr, reg)  writeb(d, (void __iomem *)(((unsigned long)adr) + (reg)))
- #define DOC_IOREMAP_LEN 0x2000
- 
- #endif
-@@ -106,6 +114,7 @@
- #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 @@
- #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
-@@ -159,9 +168,9 @@
- 
- struct DiskOnChip {
- 	unsigned long physadr;
--	unsigned long virtadr;
-+	void __iomem *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: linux-2.6.5/include/linux/mtd/flashchip.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/flashchip.h	2004-04-03 22:38:13.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/flashchip.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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 @@
- 
- 
- /* 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 @@
- 
- 	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 @@
- 	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: linux-2.6.5/include/linux/mtd/ftl.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/ftl.h	2004-04-03 22:37:37.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/ftl.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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: linux-2.6.5/include/linux/mtd/gen_probe.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/gen_probe.h	2004-04-03 22:37:25.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/gen_probe.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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__
-@@ -10,12 +10,12 @@
- #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: linux-2.6.5/include/linux/mtd/inftl.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/inftl.h	2004-04-03 22:38:14.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/inftl.h	2005-02-01 17:11:17.000000000 -0500
-@@ -3,105 +3,32 @@
-  *
-  *	(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 @@
-         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: linux-2.6.5/include/linux/mtd/map.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/map.h	2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/map.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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.44 2004/09/16 23:26:08 gleixner Exp $ */
- 
- #ifndef __LINUX_MTD_MAP_H__
- #define __LINUX_MTD_MAP_H__
-@@ -8,17 +8,164 @@
- #include <linux/config.h>
- #include <linux/types.h>
- #include <linux/list.h>
-+#include <linux/mtd/compatmac.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 
-@@ -33,31 +180,32 @@
- 	unsigned long phys;
- #define NO_XIP (-1UL)
- 
--	unsigned long virt;
-+	void __iomem *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 +233,173 @@
- #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: linux-2.6.5/include/linux/mtd/mtd.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/mtd.h	2005-02-01 16:55:50.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/mtd.h	2005-02-01 17:11:17.000000000 -0500
-@@ -1,10 +1,17 @@
--
--/* $Id: mtd.h,v 1.45 2003/05/20 21:56:40 dwmw2 Exp $ */
-+/* 
-+ * $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin 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>
-@@ -12,115 +19,27 @@
- #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 *ptr;
--};
-+#include <linux/mtd/compatmac.h>
-+#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 +69,7 @@
- 
- 	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;
- 	
-@@ -200,16 +120,16 @@
- 	/* This function is not yet implemented */
- 	int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
- 
--	/* iovec-based read/write methods. We need these especially for NAND flash,
-+	/* kvec-based read/write methods. We need these especially for NAND flash,
- 	   with its limited number of write cycles per erase.
- 	   NB: The 'count' parameter is the number of _vectors_, each of 
- 	   which contains an (ofs, len) tuple.
- 	*/
--	int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
--	int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, 
-+	int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen);
-+	int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, 
- 		size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel);
--	int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
--	int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, 
-+	int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen);
-+	int (*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);
- 
- 	/* Sync */
-@@ -222,9 +142,10 @@
- 	/* Power Management functions */
- 	int (*suspend) (struct mtd_info *mtd);
- 	void (*resume) (struct mtd_info *mtd);
--	
--	/* Semaphore */
--	struct semaphore mutex;
-+
-+	/* 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;
- 
-@@ -253,10 +174,10 @@
- extern void register_mtd_user (struct mtd_notifier *new);
- extern int unregister_mtd_user (struct mtd_notifier *old);
- 
--int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs,
-+int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
- 		       unsigned long count, loff_t to, size_t *retlen);
- 
--int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs,
-+int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
- 		      unsigned long count, loff_t from, size_t *retlen);
- 
- #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args)
-@@ -272,6 +193,17 @@
- #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args)
- #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd);  } while (0) 
- 
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+void mtd_erase_callback(struct erase_info *instr);
-+#else
-+static inline void mtd_erase_callback(struct erase_info *instr)
-+{
-+	if (instr->callback)
-+		instr->callback(instr);
-+}
-+#endif
-+
- /*
-  * Debugging macro and defines
-  */
-@@ -291,6 +223,4 @@
- 
- #endif /* CONFIG_MTD_DEBUG */
- 
--#endif /* __KERNEL__ */
--
- #endif /* __MTD_MTD_H__ */
-Index: linux-2.6.5/include/linux/mtd/nand.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/nand.h	2004-04-03 22:38:14.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/nand.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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.64 2004/09/16 23:26:08 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
-@@ -44,6 +44,10 @@
-  *			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
-@@ -51,22 +55,46 @@
- #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 @@
- #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 @@
- 	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);
-+	void  __iomem	*IO_ADDR_R;
-+	void  __iomem 	*IO_ADDR_W;
-+	
-+	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 @@
- #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:
-+/**
-+ * struct nand_flash_dev - NAND Flash Device ID Structure
-  *
-- *  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.
-+ * @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 @@
- 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: linux-2.6.5/include/linux/mtd/nand_ecc.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/nand_ecc.h	2004-04-03 22:37:07.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/nand_ecc.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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
-@@ -12,17 +12,19 @@
-  * 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: linux-2.6.5/include/linux/mtd/nftl.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/nftl.h	2004-04-03 22:37:43.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/nftl.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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>
-  */
-@@ -10,71 +10,7 @@
- #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 @@
-         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 @@
- #define MAX_SECTORS_PER_UNIT 64
- #define NFTL_PARTN_BITS 4
- 
--#endif /* __KERNEL__ */
--
- #endif /* __MTD_NFTL_H__ */
-Index: linux-2.6.5/include/linux/mtd/partitions.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/partitions.h	2004-04-03 22:38:16.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/partitions.h	2005-02-01 17:11:17.000000000 -0500
-@@ -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 @@
- #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: linux-2.6.5/include/linux/mtd/physmap.h
-===================================================================
---- linux-2.6.5.orig/include/linux/mtd/physmap.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/include/linux/mtd/physmap.h	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,61 @@
-+/*
-+ * For boards with physically mapped flash and using 
-+ * drivers/mtd/maps/physmap.c mapping driver.
-+ *
-+ * $Id: physmap.h,v 1.3 2004/07/21 00:16:15 jwboyer Exp $
-+ *
-+ * Copyright (C) 2003 MontaVista Software Inc.
-+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
-+ *
-+ * 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.
-+ *
-+ */
-+
-+#ifndef __LINUX_MTD_PHYSMAP__
-+
-+#include <linux/config.h>
-+
-+#if defined(CONFIG_MTD_PHYSMAP) 
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+
-+/*
-+ * The map_info for physmap.  Board can override size, buswidth, phys,
-+ * (*set_vpp)(), etc in their initial setup routine.
-+ */
-+extern struct map_info physmap_map;
-+
-+/*
-+ * Board needs to specify the exact mapping during their setup time.
-+ */
-+static inline void physmap_configure(unsigned long addr, unsigned long size, int bankwidth, void (*set_vpp)(struct map_info *, int) )
-+{
-+	physmap_map.phys = addr;
-+	physmap_map.size = size;
-+	physmap_map.bankwidth = bankwidth;
-+	physmap_map.set_vpp = set_vpp;
-+}
-+
-+#if defined(CONFIG_MTD_PARTITIONS)
-+
-+/*
-+ * Machines that wish to do flash partition may want to call this function in 
-+ * their setup routine.  
-+ *
-+ *	physmap_set_partitions(mypartitions, num_parts);
-+ *
-+ * Note that one can always override this hard-coded partition with 
-+ * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS).
-+ */
-+void physmap_set_partitions(struct mtd_partition *parts, int num_parts);
-+
-+#endif /* defined(CONFIG_MTD_PARTITIONS) */
-+#endif /* defined(CONFIG_MTD) */
-+
-+#endif /* __LINUX_MTD_PHYSMAP__ */
-+
-Index: linux-2.6.5/include/linux/rslib.h
-===================================================================
---- linux-2.6.5.orig/include/linux/rslib.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/include/linux/rslib.h	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,99 @@
-+/* 
-+ * include/linux/rslib.h
-+ *
-+ * Overview:
-+ *   Generic Reed Solomon encoder / decoder library
-+ *   
-+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * RS code lifted from reed solomon library written by Phil Karn
-+ * Copyright 2002 Phil Karn, KA9Q
-+ *
-+ * $Id: rslib.h,v 1.1 2004/09/16 23:58:55 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.
-+ */
-+
-+#ifndef _RSLIB_H_
-+#define _RSLIB_H_
-+
-+#include <linux/list.h>
-+
-+/** 
-+ * struct rs_contol - rs control structure
-+ * 
-+ * @mm:		Bits per symbol
-+ * @nn:		Symbols per block (= (1<<mm)-1)
-+ * @alpha_to:	log lookup table
-+ * @index_of:	Antilog lookup table
-+ * @genpoly:	Generator polynomial 
-+ * @nroots:	Number of generator roots = number of parity symbols
-+ * @fcr:	First consecutive root, index form
-+ * @prim:	Primitive element, index form 
-+ * @iprim:	prim-th root of 1, index form 
-+ * @gfpoly:	The primitive generator polynominal 
-+ * @users:	Users of this structure 
-+ * @list:	List entry for the rs control list
-+*/
-+struct rs_control {
-+	int 		mm;
-+	int 		nn;
-+	uint16_t	*alpha_to;
-+	uint16_t	*index_of;
-+	uint16_t	*genpoly;
-+	int 		nroots;
-+	int 		fcr;
-+	int 		prim;
-+	int 		iprim;
-+	int		gfpoly;
-+	int		users;
-+	struct list_head list;
-+};
-+
-+/* General purpose RS codec, 8-bit data width, symbol width 1-15 bit  */
-+int encode_rs8 (struct rs_control *rs, uint8_t *data, int len, uint16_t *par, uint16_t invmsk);
-+int decode_rs8 (struct rs_control *rs, uint8_t *data, uint16_t *par, 
-+			int len, uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk);
-+
-+/* General purpose RS codec, 16-bit data width, symbol width 1-15 bit  */
-+int encode_rs16 (struct rs_control *rs, uint16_t *data, int len, uint16_t *par, uint16_t invmsk);
-+int decode_rs16 (struct rs_control *rs, uint16_t *data, uint16_t *par, 
-+			int len, uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk);
-+
-+/* General purpose RS codec, 32-bit data width, symbol width 1-15 bit  */
-+int encode_rs32 (struct rs_control *rs, uint32_t *data, int len, uint16_t *par, uint16_t invmsk);
-+int decode_rs32 (struct rs_control *rs, uint32_t *data, uint16_t *par, 
-+			int len, uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk);
-+
-+/* Create or get a matching rs control structure */
-+struct rs_control *init_rs (int symsize, int gfpoly, int fcr, int prim, int nroots);
-+
-+/* Release a rs control structure */
-+void free_rs (struct rs_control *rs);
-+
-+/* Internal usage only */
-+static inline int modnn (struct rs_control *rs, int x)
-+{
-+	while (x >= rs->nn) {
-+		x -= rs->nn;
-+		x = (x >> rs->mm) + (x & rs->nn);
-+	}
-+	return x;
-+}
-+
-+#define MODNN(x) modnn(rs,x)
-+#define MM (rs->mm)
-+#define NN (rs->nn)
-+#define ALPHA_TO (rs->alpha_to) 
-+#define INDEX_OF (rs->index_of)
-+#define GENPOLY (rs->genpoly)
-+#define NROOTS (rs->nroots)
-+#define FCR (rs->fcr)
-+#define PRIM (rs->prim)
-+#define IPRIM (rs->iprim)
-+#define A0 (NN)
-+
-+#endif
-+
-Index: linux-2.6.5/include/mtd/inftl-user.h
-===================================================================
---- linux-2.6.5.orig/include/mtd/inftl-user.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/include/mtd/inftl-user.h	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,91 @@
-+/*
-+ * $Id: inftl-user.h,v 1.1 2004/05/05 15:17:00 dwmw2 Exp $
-+ *
-+ * Parts of INFTL headers shared with userspace 
-+ *
-+ */
-+
-+#ifndef __MTD_INFTL_USER_H__
-+#define __MTD_INFTL_USER_H__
-+
-+#define	OSAK_VERSION	0x5120
-+#define	PERCENTUSED	98
-+
-+#define	SECTORSIZE	512
-+
-+/* Block Control Information */
-+
-+struct inftl_bci {
-+	uint8_t ECCsig[6];
-+	uint8_t Status;
-+	uint8_t Status1;
-+} __attribute__((packed));
-+
-+struct inftl_unithead1 {
-+	uint16_t virtualUnitNo;
-+	uint16_t prevUnitNo;
-+	uint8_t ANAC;
-+	uint8_t NACs;
-+	uint8_t parityPerField;
-+	uint8_t discarded;
-+} __attribute__((packed));
-+
-+struct inftl_unithead2 {
-+	uint8_t parityPerField;
-+	uint8_t ANAC;
-+	uint16_t prevUnitNo;
-+	uint16_t virtualUnitNo;
-+	uint8_t NACs;
-+	uint8_t discarded;
-+} __attribute__((packed));
-+
-+struct inftl_unittail {
-+	uint8_t Reserved[4];
-+	uint16_t EraseMark;
-+	uint16_t 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
-+
-+#endif /* __MTD_INFTL_USER_H__ */
-+
-+
-Index: linux-2.6.5/include/mtd/jffs2-user.h
-===================================================================
---- linux-2.6.5.orig/include/mtd/jffs2-user.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/include/mtd/jffs2-user.h	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,35 @@
-+/*
-+ * $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
-+ *
-+ * JFFS2 definitions for use in user space only
-+ */
-+
-+#ifndef __JFFS2_USER_H__
-+#define __JFFS2_USER_H__
-+
-+/* This file is blessed for inclusion by userspace */
-+#include <linux/jffs2.h>
-+#include <endian.h>
-+#include <byteswap.h>
-+
-+#undef cpu_to_je16
-+#undef cpu_to_je32
-+#undef cpu_to_jemode
-+#undef je16_to_cpu
-+#undef je32_to_cpu
-+#undef jemode_to_cpu
-+
-+extern int target_endian;
-+
-+#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
-+#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
-+
-+#define cpu_to_je16(x) ((jint16_t){t16(x)})
-+#define cpu_to_je32(x) ((jint32_t){t32(x)})
-+#define cpu_to_jemode(x) ((jmode_t){t32(x)})
-+
-+#define je16_to_cpu(x) (t16((x).v16))
-+#define je32_to_cpu(x) (t32((x).v32))
-+#define jemode_to_cpu(x) (t32((x).m))
-+
-+#endif /* __JFFS2_USER_H__ */
-Index: linux-2.6.5/include/mtd/mtd-abi.h
-===================================================================
---- linux-2.6.5.orig/include/mtd/mtd-abi.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/include/mtd/mtd-abi.h	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,102 @@
-+/*
-+ * $Id: mtd-abi.h,v 1.6 2004/08/09 13:38:30 dwmw2 Exp $
-+ *
-+ * Portions of MTD ABI definition which are shared by kernel and user space 
-+ */
-+
-+#ifndef __MTD_ABI_H__
-+#define __MTD_ABI_H__
-+
-+#ifndef __KERNEL__ /* Urgh. The whole point of splitting this out into
-+		    separate files was to avoid #ifdef __KERNEL__ */
-+#define __user
-+#endif
-+
-+struct erase_info_user {
-+	uint32_t start;
-+	uint32_t length;
-+};
-+
-+struct mtd_oob_buf {
-+	uint32_t start;
-+	uint32_t length;
-+	unsigned char __user *ptr;
-+};
-+
-+#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
-+
-+/* ECC byte placement */
-+#define MTD_NANDECC_OFF		0	// Switch off ECC (Not recommended)
-+#define MTD_NANDECC_PLACE	1	// Use the given placement in the structure (YAFFS1 legacy mode)
-+#define MTD_NANDECC_AUTOPLACE	2	// Use the default placement scheme
-+#define MTD_NANDECC_PLACEONLY	3	// Use the given placement in the structure (Do not store ecc result on read)
-+
-+struct mtd_info_user {
-+	uint8_t type;
-+	uint32_t flags;
-+	uint32_t size;	 // Total size of the MTD
-+	uint32_t erasesize;
-+	uint32_t oobblock;  // Size of OOB blocks (e.g. 512)
-+	uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)
-+	uint32_t ecctype;
-+	uint32_t eccsize;
-+};
-+
-+struct region_info_user {
-+	uint32_t offset;		/* At which this region starts, 
-+					 * from the beginning of the MTD */
-+	uint32_t erasesize;		/* For this region */
-+	uint32_t numblocks;		/* Number of blocks in this region */
-+	uint32_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)
-+#define MEMGETOOBSEL		_IOR('M', 10, struct nand_oobinfo)
-+#define MEMGETBADBLOCK		_IOW('M', 11, loff_t)
-+#define MEMSETBADBLOCK		_IOW('M', 12, loff_t)
-+
-+struct nand_oobinfo {
-+	uint32_t useecc;
-+	uint32_t eccbytes;
-+	uint32_t oobfree[8][2];
-+	uint32_t eccpos[32];
-+};
-+
-+#endif /* __MTD_ABI_H__ */
-Index: linux-2.6.5/include/mtd/mtd-user.h
-===================================================================
---- linux-2.6.5.orig/include/mtd/mtd-user.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/include/mtd/mtd-user.h	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,20 @@
-+/*
-+ * $Id: mtd-user.h,v 1.2 2004/05/05 14:44:57 dwmw2 Exp $
-+ *
-+ * MTD ABI header for use by user space only.
-+ */
-+
-+#ifndef __MTD_USER_H__
-+#define __MTD_USER_H__
-+
-+#include <stdint.h>
-+
-+/* This file is blessed for inclusion by userspace */
-+#include <mtd/mtd-abi.h>
-+
-+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;
-+
-+#endif /* __MTD_USER_H__ */
-Index: linux-2.6.5/include/mtd/nftl-user.h
-===================================================================
---- linux-2.6.5.orig/include/mtd/nftl-user.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/include/mtd/nftl-user.h	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,76 @@
-+/*
-+ * $Id: nftl-user.h,v 1.1 2004/05/05 14:44:57 dwmw2 Exp $
-+ *
-+ * Parts of NFTL headers shared with userspace 
-+ *
-+ */
-+
-+#ifndef __MTD_NFTL_USER_H__
-+#define __MTD_NFTL_USER_H__
-+
-+/* Block Control Information */
-+
-+struct nftl_bci {
-+	unsigned char ECCSig[6];
-+	uint8_t Status;
-+	uint8_t Status1;
-+}__attribute__((packed));
-+
-+/* Unit Control Information */
-+
-+struct nftl_uci0 {
-+	uint16_t VirtUnitNum;
-+	uint16_t ReplUnitNum;
-+	uint16_t SpareVirtUnitNum;
-+	uint16_t SpareReplUnitNum;
-+} __attribute__((packed));
-+
-+struct nftl_uci1 {
-+	uint32_t WearInfo;
-+	uint16_t EraseMark;
-+	uint16_t EraseMark1;
-+} __attribute__((packed));
-+
-+struct nftl_uci2 {
-+        uint16_t FoldMark;
-+        uint16_t FoldMark1;
-+	uint32_t 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];
-+	uint16_t NumEraseUnits;
-+	uint16_t FirstPhysicalEUN;
-+	uint32_t 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
-+
-+
-+#endif /* __MTD_NFTL_USER_H__ */
-Index: linux-2.6.5/lib/Kconfig
-===================================================================
---- linux-2.6.5.orig/lib/Kconfig	2005-02-01 16:55:08.000000000 -0500
-+++ linux-2.6.5/lib/Kconfig	2005-02-01 17:11:17.000000000 -0500
-@@ -24,5 +24,11 @@
- config ZLIB_DEFLATE
- 	tristate
- 
-+#
-+# reed solomon support is select'ed if needed
-+#
-+config REED_SOLOMON
-+	tristate
-+
- endmenu
- 
-Index: linux-2.6.5/lib/Kconfig.orig
-===================================================================
---- linux-2.6.5.orig/lib/Kconfig.orig	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/lib/Kconfig.orig	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,28 @@
-+#
-+# Library configuration
-+#
-+
-+menu "Library routines"
-+
-+config CRC32
-+	tristate "CRC32 functions"
-+	help
-+	  This option is provided for the case where no in-kernel-tree
-+	  modules require CRC32 functions, but a module built outside the
-+	  kernel tree does. Such modules that use library CRC32 functions
-+	  require M here.
-+
-+config QSORT
-+	bool "Quick Sort"
-+
-+#
-+# compression support is select'ed if needed
-+#
-+config ZLIB_INFLATE
-+	tristate
-+
-+config ZLIB_DEFLATE
-+	tristate
-+
-+endmenu
-+
-Index: linux-2.6.5/lib/Makefile
-===================================================================
---- linux-2.6.5.orig/lib/Makefile	2005-02-01 16:55:56.000000000 -0500
-+++ linux-2.6.5/lib/Makefile	2005-02-01 17:11:17.000000000 -0500
-@@ -23,6 +23,7 @@
- 
- obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
- obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
-+obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
- 
- host-progs	:= gen_crc32table
- clean-files	:= crc32table.h
-Index: linux-2.6.5/lib/reed_solomon/Makefile
-===================================================================
---- linux-2.6.5.orig/lib/reed_solomon/Makefile	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/lib/reed_solomon/Makefile	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,6 @@
-+#
-+# This is a modified version of reed solomon lib, 
-+#
-+
-+obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o
-+
-Index: linux-2.6.5/lib/reed_solomon/decode_rs.c
-===================================================================
---- linux-2.6.5.orig/lib/reed_solomon/decode_rs.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/lib/reed_solomon/decode_rs.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,225 @@
-+/* 
-+ * lib/reed_solomon/decode_rs.c
-+ *
-+ * Overview:
-+ *   Generic Reed Solomon encoder / decoder library
-+ *   
-+ * Copyright 2002, Phil Karn, KA9Q
-+ * May be used under the terms of the GNU General Public License (GPL)
-+ *
-+ * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * $Id: decode_rs.c,v 1.1 2004/09/16 23:58:56 gleixner Exp $
-+ *
-+ */
-+
-+/* Generic data witdh independend code which is included by the 
-+ * wrappers.
-+ */
-+{ 
-+	int deg_lambda, el, deg_omega;
-+	int i, j, r, k, PAD;
-+	uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
-+	/* Err+Eras Locator poly and syndrome poly */
-+	uint16_t lambda[NROOTS + 1], syn[NROOTS];	
-+	uint16_t b[NROOTS + 1], t[NROOTS + 1], omega[NROOTS + 1];
-+	uint16_t root[NROOTS], reg[NROOTS + 1], loc[NROOTS];
-+	int count = 0;
-+	uint16_t msk = (uint16_t) rs->nn;
-+
-+	/* Check length parameter for validity */
-+	PAD = NN - NROOTS - len;
-+	if (PAD < 0 || PAD >= NN)
-+		return -ERANGE;
-+		
-+	/* The caller does not provide the syndrome */
-+	if (s == NULL) {
-+		/* form the syndromes; i.e., evaluate data(x) at roots of g(x) */
-+		for (i = 0; i < NROOTS; i++)
-+			syn[i] = (((uint16_t) data[0]) ^ invmsk) & msk;
-+
-+		for (j = 1; j < len; j++) {
-+			for (i = 0; i < NROOTS; i++) {
-+				if (syn[i] == 0) {
-+					syn[i] = (((uint16_t) data[j]) ^ invmsk) & msk;
-+				} else {
-+					syn[i] = ((((uint16_t) data[j]) ^ invmsk) & msk) ^ ALPHA_TO[MODNN(INDEX_OF[syn[i]] + (FCR+i)*PRIM)];
-+				}
-+			}
-+		}
-+
-+		for (j = 0; j < NROOTS; j++) {
-+			for (i = 0; i < NROOTS; i++) {
-+				if (syn[i] == 0) {
-+					syn[i] = ((uint16_t) par[j]) & msk;
-+				} else {
-+					syn[i] = (((uint16_t) par[j]) & msk) ^ ALPHA_TO[MODNN(INDEX_OF[syn[i]] + (FCR+i)*PRIM)];
-+				}
-+			}
-+		}
-+		s = syn;
-+	}
-+
-+	/* Convert syndromes to index form, checking for nonzero condition */
-+	syn_error = 0;
-+	for (i = 0; i < NROOTS; i++) {
-+		syn_error |= s[i];
-+		s[i] = INDEX_OF[s[i]];
-+	}
-+
-+	if (!syn_error) {
-+		/* if syndrome is zero, data[] is a codeword and there are no
-+		 * errors to correct. So return data[] unmodified
-+		 */
-+		count = 0;
-+		goto finish;
-+	}
-+	memset (&lambda[1], 0, NROOTS * sizeof (lambda[0]));
-+	lambda[0] = 1;
-+
-+	if (no_eras > 0) {
-+		/* Init lambda to be the erasure locator polynomial */
-+		lambda[1] = ALPHA_TO[MODNN (PRIM * (NN - 1 - eras_pos[0]))];
-+		for (i = 1; i < no_eras; i++) {
-+			u = MODNN (PRIM * (NN - 1 - eras_pos[i]));
-+			for (j = i + 1; j > 0; j--) {
-+				tmp = INDEX_OF[lambda[j - 1]];
-+				if (tmp != A0)
-+					lambda[j] ^= ALPHA_TO[MODNN (u + tmp)];
-+			}
-+		}
-+	}
-+
-+	for (i = 0; i < NROOTS + 1; i++)
-+		b[i] = INDEX_OF[lambda[i]];
-+
-+	/*
-+	 * Begin Berlekamp-Massey algorithm to determine error+erasure
-+	 * locator polynomial
-+	 */
-+	r = no_eras;
-+	el = no_eras;
-+	while (++r <= NROOTS) {	/* r is the step number */
-+		/* Compute discrepancy at the r-th step in poly-form */
-+		discr_r = 0;
-+		for (i = 0; i < r; i++) {
-+			if ((lambda[i] != 0) && (s[r - i - 1] != A0)) {
-+				discr_r ^= ALPHA_TO[MODNN (INDEX_OF[lambda[i]] + s[r - i - 1])];
-+			}
-+		}
-+		discr_r = INDEX_OF[discr_r];	/* Index form */
-+		if (discr_r == A0) {
-+			/* 2 lines below: B(x) <-- x*B(x) */
-+			memmove (&b[1], b, NROOTS * sizeof (b[0]));
-+			b[0] = A0;
-+		} else {
-+			/* 7 lines below: T(x) <-- lambda(x) - discr_r*x*b(x) */
-+			t[0] = lambda[0];
-+			for (i = 0; i < NROOTS; i++) {
-+				if (b[i] != A0)
-+					t[i + 1] = lambda[i + 1] ^ ALPHA_TO[MODNN (discr_r + b[i])];
-+				else
-+					t[i + 1] = lambda[i + 1];
-+			}
-+			if (2 * el <= r + no_eras - 1) {
-+				el = r + no_eras - el;
-+				/*
-+				 * 2 lines below: B(x) <-- inv(discr_r) *
-+				 * lambda(x)
-+				 */
-+				for (i = 0; i <= NROOTS; i++)
-+					b[i] = (lambda[i] == 0) ? A0 : MODNN (INDEX_OF[lambda[i]] - discr_r + NN);
-+			} else {
-+				/* 2 lines below: B(x) <-- x*B(x) */
-+				memmove (&b[1], b, NROOTS * sizeof (b[0]));
-+				b[0] = A0;
-+			}
-+			memcpy (lambda, t, (NROOTS + 1) * sizeof (t[0]));
-+		}
-+	}
-+
-+	/* Convert lambda to index form and compute deg(lambda(x)) */
-+	deg_lambda = 0;
-+	for (i = 0; i < NROOTS + 1; i++) {
-+		lambda[i] = INDEX_OF[lambda[i]];
-+		if (lambda[i] != A0)
-+			deg_lambda = i;
-+	}
-+	/* Find roots of the error+erasure locator polynomial by Chien search */
-+	memcpy (&reg[1], &lambda[1], NROOTS * sizeof (reg[0]));
-+	count = 0;		/* Number of roots of lambda(x) */
-+	for (i = 1, k = IPRIM - 1; i <= NN; i++, k = MODNN (k + IPRIM)) {
-+		q = 1;		/* lambda[0] is always 0 */
-+		for (j = deg_lambda; j > 0; j--) {
-+			if (reg[j] != A0) {
-+				reg[j] = MODNN (reg[j] + j);
-+				q ^= ALPHA_TO[reg[j]];
-+			}
-+		}
-+		if (q != 0)
-+			continue;	/* Not a root */
-+		/* store root (index-form) and error location number */
-+		root[count] = i;
-+		loc[count] = k;
-+		/* If we've already found max possible roots,
-+		 * abort the search to save time
-+		 */
-+		if (++count == deg_lambda)
-+			break;
-+	}
-+	if (deg_lambda != count) {
-+		/*
-+		 * deg(lambda) unequal to number of roots => uncorrectable
-+		 * error detected
-+		 */
-+		count = -1;
-+		goto finish;
-+	}
-+	/*
-+	 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
-+	 * x**NROOTS). in index form. Also find deg(omega).
-+	 */
-+	deg_omega = deg_lambda - 1;
-+	for (i = 0; i <= deg_omega; i++) {
-+		tmp = 0;
-+		for (j = i; j >= 0; j--) {
-+			if ((s[i - j] != A0) && (lambda[j] != A0))
-+				tmp ^=
-+				    ALPHA_TO[MODNN (s[i - j] + lambda[j])];
-+		}
-+		omega[i] = INDEX_OF[tmp];
-+	}
-+
-+	/*
-+	 * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
-+	 * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form
-+	 */
-+	for (j = count - 1; j >= 0; j--) {
-+		num1 = 0;
-+		for (i = deg_omega; i >= 0; i--) {
-+			if (omega[i] != A0)
-+				num1 ^= ALPHA_TO[MODNN (omega[i] + i * root[j])];
-+		}
-+		num2 = ALPHA_TO[MODNN (root[j] * (FCR - 1) + NN)];
-+		den = 0;
-+
-+		/* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
-+		for (i = min (deg_lambda, NROOTS - 1) & ~1; i >= 0; i -= 2) {
-+			if (lambda[i + 1] != A0)
-+				den ^= ALPHA_TO[MODNN (lambda[i + 1] + i * root[j])];
-+		}
-+		/* Apply error to data */
-+		if (num1 != 0 && loc[j] >= PAD) {
-+			uint16_t cor = ALPHA_TO[MODNN (INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])];
-+			data[loc[j] - PAD] ^= cor ^ invmsk;
-+		}
-+	}
-+
-+finish:
-+	if (eras_pos != NULL) {
-+		for (i = 0; i < count; i++)
-+			eras_pos[i] = loc[i] - PAD;
-+	}
-+	return count;
-+
-+}
-Index: linux-2.6.5/lib/reed_solomon/encode_rs.c
-===================================================================
---- linux-2.6.5.orig/lib/reed_solomon/encode_rs.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/lib/reed_solomon/encode_rs.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,47 @@
-+/* 
-+ * lib/reed_solomon/encode_rs.c
-+ *
-+ * Overview:
-+ *   Generic Reed Solomon encoder / decoder library
-+ *   
-+ * Copyright 2002, Phil Karn, KA9Q
-+ * May be used under the terms of the GNU General Public License (GPL)
-+ *
-+ * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * $Id: encode_rs.c,v 1.1 2004/09/16 23:58:56 gleixner Exp $
-+ *
-+ */
-+
-+/* Generic data witdh independend code which is included by the 
-+ * wrappers.
-+ * int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par)
-+ */
-+{
-+	int i, j, pad;
-+	uint16_t feedback;
-+	uint16_t msk = (uint16_t) NN;
-+
-+	/* Check length parameter for validity */
-+	pad = NN - NROOTS - len;
-+	if (pad < 0 || pad >= NN)
-+		return -ERANGE;
-+
-+	memset (par, 0, NROOTS * sizeof (uint16_t));
-+
-+	for (i = 0; i < len; i++) {
-+		feedback = INDEX_OF[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]];
-+		/* feedback term is non-zero */
-+		if (feedback != A0) {	
-+			for (j = 1; j < NROOTS; j++)
-+				par[j] ^= ALPHA_TO[MODNN (feedback + GENPOLY[NROOTS - j])];
-+		}
-+		/* Shift */
-+		memmove (&par[0], &par[1], sizeof (uint16_t) * (NROOTS - 1));
-+		if (feedback != A0)
-+			par[NROOTS - 1] = ALPHA_TO[MODNN (feedback + GENPOLY[0])];
-+		else
-+			par[NROOTS - 1] = 0;
-+	}
-+	return 0;
-+}
-Index: linux-2.6.5/lib/reed_solomon/rslib.c
-===================================================================
---- linux-2.6.5.orig/lib/reed_solomon/rslib.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5/lib/reed_solomon/rslib.c	2005-02-01 17:11:17.000000000 -0500
-@@ -0,0 +1,366 @@
-+/* 
-+ * lib/reed_solomon/lib_rs.c
-+ *
-+ * Overview:
-+ *   Generic Reed Solomon encoder / decoder library
-+ *   
-+ * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
-+ *
-+ * Reed Solomon code lifted from reed solomon library written by Phil Karn
-+ * Copyright 2002 Phil Karn, KA9Q
-+ *
-+ * $Id: rslib.c,v 1.1 2004/09/16 23:58:56 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.
-+ *
-+ * Description:
-+ *	
-+ * The generic Reed Solomon library provides runtime configurable
-+ * encoding / decoding of RS codes.
-+ * Each user must call init_rs to get a pointer to a rs_control
-+ * structure for the given rs parameters. This structure is either
-+ * generated or a already available matching control structure is used.
-+ * If a structure is generated then the polynominal arrays for
-+ * fast encoding / decoding are built. This can take some time so
-+ * make sure not to call this function from a timecritical path.
-+ * Usually a module / driver should initialize the neccecary 
-+ * rs_control structure on module / driver init and release it
-+ * on exit.
-+ * The encoding puts the calculated syndrome into a given syndrom 
-+ * buffer. 
-+ * The decoding is a two step process. The first step calculates
-+ * the syndrome over the received (data + syndrom) and calls the
-+ * second stage, which does the decoding / error correction itself.
-+ * Many hw encoders provide a syndrom calculation over the received
-+ * data + syndrom and can call the second stage directly.
-+ *
-+ */
-+
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/rslib.h>
-+#include <linux/slab.h>
-+#include <asm/semaphore.h>
-+
-+/* This list holds all currently allocated rs control structures */
-+static LIST_HEAD (rslist);
-+/* Protection for the list */
-+static DECLARE_MUTEX(rslistlock);
-+
-+/** 
-+ * rs_init - Initialize a Reed-Solomon codec
-+ *
-+ * @symsize:	symbol size, bits (1-8)
-+ * @gfpoly:	Field generator polynomial coefficients
-+ * @fcr:	first root of RS code generator polynomial, index form
-+ * @prim:	primitive element to generate polynomial roots
-+ * @nroots:	RS code generator polynomial degree (number of roots)
-+ *
-+ * Allocate a control structure and the polynom arrays for faster
-+ * en/decoding. Fill the arrays according to the given parameters
-+ */
-+static struct rs_control *rs_init (int symsize, int gfpoly, int fcr, int prim, int nroots)
-+{
-+	struct rs_control *rs;
-+	int i, j, sr, root, iprim;
-+
-+	/* Allocate the control structure */
-+	rs = (struct rs_control *) kmalloc (sizeof (struct rs_control), GFP_KERNEL);
-+	if (rs == NULL)
-+		return NULL;
-+
-+	INIT_LIST_HEAD(&rs->list);
-+
-+	rs->mm = symsize;
-+	rs->nn = (1 << symsize) - 1;
-+	rs->fcr = fcr;
-+	rs->prim = prim;
-+	rs->nroots = nroots;
-+	rs->gfpoly = gfpoly;
-+
-+	/* Allocate the arrays */
-+	rs->alpha_to = (uint16_t *) kmalloc (sizeof (uint16_t) * (rs->nn + 1), GFP_KERNEL);
-+	if (rs->alpha_to == NULL)
-+		goto errrs;
-+
-+	rs->index_of = (uint16_t *) kmalloc (sizeof (uint16_t) * (rs->nn + 1), GFP_KERNEL);
-+	if (rs->index_of == NULL)
-+		goto erralp;
-+
-+	rs->genpoly = (uint16_t *) kmalloc (sizeof (uint16_t) * (rs->nroots + 1), GFP_KERNEL);
-+	if (rs->genpoly == NULL)
-+		goto erridx;
-+
-+	/* Generate Galois field lookup tables */
-+	rs->index_of[0] = rs->nn;	/* log(zero) = -inf */
-+	rs->alpha_to[rs->nn] = 0;	/* alpha**-inf = 0 */
-+	sr = 1;
-+	for (i = 0; i < rs->nn; i++) {
-+		rs->index_of[sr] = i;
-+		rs->alpha_to[i] = sr;
-+		sr <<= 1;
-+		if (sr & (1 << symsize))
-+			sr ^= gfpoly;
-+		sr &= rs->nn;
-+	}
-+	/* If it's not primitive, exit */
-+	if (sr != 1)
-+		goto errpol;
-+
-+	/* Find prim-th root of 1, used in decoding */
-+	for (iprim = 1; (iprim % prim) != 0; iprim += rs->nn);
-+	/* prim-th root of 1, index form */
-+	rs->iprim = iprim / prim;
-+
-+	/* Form RS code generator polynomial from its roots */
-+	rs->genpoly[0] = 1;
-+	for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) {
-+		rs->genpoly[i + 1] = 1;
-+
-+		/* Multiply rs->genpoly[] by  @**(root + x) */
-+		for (j = i; j > 0; j--) {
-+			if (rs->genpoly[j] != 0)
-+				rs->genpoly[j] = rs->genpoly[j -1] ^ rs->alpha_to[(rs->index_of[rs->genpoly[j]] + root) % rs->nn];
-+			else
-+				rs->genpoly[j] = rs->genpoly[j - 1];
-+		}
-+		/* rs->genpoly[0] can never be zero */
-+		rs->genpoly[0] = rs->alpha_to[(rs->index_of[rs->genpoly[0]] + root) % rs->nn];
-+	}
-+	/* convert rs->genpoly[] to index form for quicker encoding */
-+	for (i = 0; i <= nroots; i++)
-+		rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
-+	return rs;
-+
-+	/* Error exit */
-+errpol:
-+	kfree (rs->genpoly);
-+erridx:
-+	kfree (rs->index_of);
-+erralp:
-+	kfree (rs->alpha_to);
-+errrs:
-+	kfree (rs);
-+	return NULL;
-+}
-+
-+
-+/** 
-+ *  free_rs - Free the rs control structure, if its not longer used
-+ *
-+ *  @rs:	the control structure which is not longer used by the
-+ *		caller
-+ */
-+void free_rs (struct rs_control *rs)
-+{
-+	down (&rslistlock);
-+	rs->users--;
-+	if (!rs->users) {
-+		list_del (&rs->list);
-+		kfree (rs->alpha_to);
-+		kfree (rs->index_of);
-+		kfree (rs->genpoly);
-+		kfree (rs);
-+	}
-+	up (&rslistlock);
-+}
-+
-+/** 
-+ * init_rs - Find a matching or allocate a new rs control structure
-+ *
-+ *  @symsize:	the symbol size (number of bits)
-+ *  @gfpoly:	the extended Galois field generator polynomial coefficients,
-+ *		with the 0th coefficient in the low order bit. The polynomial
-+ *		must be primitive;
-+ *  @fcr:  	the first consecutive root of the rs code generator polynomial 
-+ *		in index form
-+ *  @prim:	primitive element to generate polynomial roots
-+ *  @nroots:	RS code generator polynomial degree (number of roots)
-+ */
-+struct rs_control *init_rs (int symsize, int gfpoly, int fcr, int prim, int nroots)
-+{
-+	struct list_head	*tmp;
-+	struct rs_control	*rs;
-+
-+	/* Sanity checks */
-+	if (symsize < 1)
-+		return NULL;
-+	if (fcr < 0 || fcr >= (1<<symsize))
-+    		return NULL;
-+	if (prim <= 0 || prim >= (1<<symsize))
-+    		return NULL;
-+	if (nroots < 0 || nroots >= (1<<symsize))
-+		return NULL;
-+	
-+	down (&rslistlock);
-+
-+#ifdef __KERNEL__	
-+	/* Walk through the list and look for a matching entry */
-+	list_for_each (tmp, &rslist) {
-+		rs = list_entry (tmp, struct rs_control, list);
-+		if (symsize != rs->mm)
-+			continue;
-+		if (gfpoly != rs->gfpoly)
-+			continue;
-+		if (fcr != rs->fcr)
-+			continue;	
-+		if (prim != rs->prim)
-+			continue;	
-+		if (nroots != rs->nroots)
-+			continue;
-+		/* We have a matching one already */
-+		rs->users++;
-+		goto out;
-+	}
-+#endif
-+
-+	/* Create a new one */
-+	rs = rs_init (symsize, gfpoly, fcr, prim, nroots);
-+	if (rs) {
-+		rs->users = 1;
-+		list_add (&rs->list, &rslist);
-+	}
-+out:	
-+	up (&rslistlock);
-+	return rs;
-+}
-+
-+/** 
-+ *  encode_rs8 - Calculate the parity for data values (8bit data width)
-+ *
-+ *  @rs:	the rs control structure
-+ *  @data:	data field of a given type
-+ *  @len:	data length 
-+ *  @par:	parity data field
-+ *  @invmsk:	invert data mask
-+ *
-+ *  The parity uses a uint16_t data type to enable
-+ *  symbol size > 8. The calling code must take care of encoding of the
-+ *  syndrome result for storage itself.
-+ */
-+int encode_rs8 (struct rs_control *rs, uint8_t *data, int len, uint16_t *par, uint16_t invmsk)
-+{
-+#define RSINVMSK 0xFF
-+#include "encode_rs.c"
-+}
-+
-+/** 
-+ *  decode_rs8 - Decode codeword (8bit data width)
-+ *
-+ *  @rs:	the rs control structure
-+ *  @data:	data field of a given type
-+ *  @par:	received parity data field
-+ *  @len:	data length
-+ *  @s:		syndrome data field (if NULL, syndrome must be calculated)
-+ *  @no_eras:	number of erasures
-+ *  @eras_pos:	position of erasures, can be NULL
-+ *  @invmsk:	invert data mask
-+ *
-+ *  The syndrome and parity uses a uint16_t data type to enable
-+ *  symbol size > 8. The calling code must take care of decoding of the
-+ *  syndrome result and the received parity before calling this code.
-+ */
-+int decode_rs8 (struct rs_control *rs, uint8_t *data, uint16_t *par, 
-+			int len, uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk)
-+{
-+#include "decode_rs.c"
-+}
-+
-+/**
-+ *  encode_rs16 - Calculate the parity for data values (16bit data width)
-+ *
-+ *  @rs:	the rs control structure
-+ *  @data:	data field of a given type
-+ *  @len:	data length 
-+ *  @par:	parity data field
-+ *  @invmsk:	invert data mask
-+ *
-+ *  Each field in the data array contains up to symbol size bits of valid data.
-+ */
-+int encode_rs16 (struct rs_control *rs, uint16_t *data, int len, uint16_t *par, uint16_t invmsk)
-+{
-+#undef RSINVMSK
-+#define RSINVMSK 0xFFFF
-+#include "encode_rs.c"
-+}
-+
-+/** 
-+ *  decode_rs16 - Decode codeword (16bit data width)
-+ *
-+ *  @rs:	the rs control structure
-+ *  @data:	data field of a given type
-+ *  @par:	received parity data field
-+ *  @len:	data length
-+ *  @s:		syndrome data field (if NULL, syndrome must be calculated)
-+ *  @no_eras:	number of erasures
-+ *  @eras_pos:	position of erasures, can be NULL
-+ *  @invmsk:	invert data mask
-+ *
-+ *  Each field in the data array contains up to symbol size bits of valid data.
-+ */
-+int decode_rs16 (struct rs_control *rs, uint16_t *data, uint16_t *par, 
-+			int len, uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk)
-+{
-+#include "decode_rs.c"
-+}
-+
-+/** 
-+ *  encode_rs32 - Calculate the parity for data values (32bit data width)
-+ *
-+ *  @rs:	the rs control structure
-+ *  @data:	data field of a given type
-+ *  @len:	data length 
-+ *  @par:	parity data field
-+ *  @invmsk:	invert data mask
-+ *
-+ *  The parity uses a uint16_t data type due to the fact that
-+ *  we can't handle symbol size >= 16 bit as the polynominal arrays would 
-+ *  be to large and the computation would be extreme slow.
-+ *  Each field in the data array contains up to symbol size bits of data.
-+ */
-+int encode_rs32 (struct rs_control *rs, uint32_t *data, int len, uint16_t *par, uint16_t invmsk)
-+{
-+#include "encode_rs.c"
-+}
-+
-+/** 
-+ *  decode_rs32 - Decode codeword (32bit data width)
-+ *
-+ *  @rs:	the rs control structure
-+ *  @data:	data field of a given type
-+ *  @par:	received parity data field
-+ *  @len:	data length
-+ *  @s:		syndrome data field (if NULL, syndrome must be calculated)
-+ *  @no_eras:	number of erasures
-+ *  @eras_pos:	position of erasures, can be NULL
-+ *  @invmsk:	invert data mask
-+ *
-+ *  The syndrome and parity use a uint16_t data type due to the fact that
-+ *  we can't handle symbol size > 16 as the polynominal arrays would be to 
-+ *  large and the computation would be extreme slow. The calling code must 
-+ *  take care of decoding of the syndrome result and the received parity 
-+ *  before calling this code.
-+ *  Each field in the data array contains up to symbol size bits of data.
-+ */
-+int decode_rs32 (struct rs_control *rs, uint32_t *data, uint16_t *par, 
-+			int len, uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk)
-+{
-+#include "decode_rs.c"
-+}
-+
-+EXPORT_SYMBOL(encode_rs8);
-+EXPORT_SYMBOL(encode_rs16);
-+EXPORT_SYMBOL(encode_rs32);
-+EXPORT_SYMBOL(decode_rs8);
-+EXPORT_SYMBOL(decode_rs16);
-+EXPORT_SYMBOL(decode_rs32);
-+EXPORT_SYMBOL(init_rs);
-+EXPORT_SYMBOL(free_rs);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Reed Solomon encoder/decoder");
-+MODULE_AUTHOR("Phil Karn, Thomas Gleixner");
diff --git a/lustre/kernel_patches/patches/nfs-cifs-intent-2.6-rhel4.patch b/lustre/kernel_patches/patches/nfs-cifs-intent-2.6-rhel4.patch
deleted file mode 100644
index 4707842f3a..0000000000
--- a/lustre/kernel_patches/patches/nfs-cifs-intent-2.6-rhel4.patch
+++ /dev/null
@@ -1,123 +0,0 @@
-diff -urp a/fs/cifs/dir.c b/fs/cifs/dir.c
---- a/fs/cifs/dir.c	2006-03-10 18:50:15.000000000 -0800
-+++ b/fs/cifs/dir.c	2006-03-10 18:50:44.000000000 -0800
-@@ -146,23 +146,23 @@ cifs_create(struct inode *inode, struct 
- 	}
- 
- 	if(nd) {
--		if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
-+		if ((nd->intent.it_flags & O_ACCMODE) == O_RDONLY)
- 			desiredAccess = GENERIC_READ;
--		else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY) {
-+		else if ((nd->intent.it_flags & O_ACCMODE) == O_WRONLY) {
- 			desiredAccess = GENERIC_WRITE;
- 			write_only = TRUE;
--		} else if ((nd->intent.open.flags & O_ACCMODE) == O_RDWR) {
-+		} else if ((nd->intent.it_flags & O_ACCMODE) == O_RDWR) {
- 			/* GENERIC_ALL is too much permission to request */
- 			/* can cause unnecessary access denied on create */
- 			/* desiredAccess = GENERIC_ALL; */
- 			desiredAccess = GENERIC_READ | GENERIC_WRITE;
- 		}
- 
--		if((nd->intent.open.flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
-+		if((nd->intent.it_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
- 			disposition = FILE_CREATE;
--		else if((nd->intent.open.flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
-+		else if((nd->intent.it_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
- 			disposition = FILE_OVERWRITE_IF;
--		else if((nd->intent.open.flags & O_CREAT) == O_CREAT)
-+		else if((nd->intent.it_flags & O_CREAT) == O_CREAT)
- 			disposition = FILE_OPEN_IF;
- 		else {
- 			cFYI(1,("Create flag not set in create function"));
-diff -urp a/fs/nfs/dir.c b/fs/nfs/dir.c
---- a/fs/nfs/dir.c	2006-03-10 19:07:50.000000000 -0800
-+++ b/fs/nfs/dir.c	2006-03-10 17:27:15.000000000 -0800
-@@ -752,7 +752,7 @@ int nfs_is_exclusive_create(struct inode
- 		return 0;
- 	if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE))
- 		return 0;
--	return (nd->intent.open.flags & O_EXCL) != 0;
-+	return (nd->intent.it_flags & O_EXCL) != 0;
- }
- 
- static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
-@@ -827,7 +827,7 @@ static int is_atomic_open(struct inode *
- 	if (nd->flags & LOOKUP_DIRECTORY)
- 		return 0;
- 	/* Are we trying to write to a read only partition? */
--	if (IS_RDONLY(dir) && (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))
-+	if (IS_RDONLY(dir) && (nd->intent.it_flags & (O_CREAT|O_TRUNC|FMODE_WRITE)))
- 		return 0;
- 	return 1;
- }
-@@ -848,7 +848,7 @@ static struct dentry *nfs_atomic_lookup(
- 	dentry->d_op = NFS_PROTO(dir)->dentry_ops;
- 
- 	/* Let vfs_create() deal with O_EXCL */
--	if (nd->intent.open.flags & O_EXCL)
-+	if (nd->intent.it_flags & O_EXCL)
- 		goto no_entry;
- 
- 	/* Open the file on the server */
-@@ -860,7 +860,7 @@ static struct dentry *nfs_atomic_lookup(
- 		goto out;
- 	}
- 
--	if (nd->intent.open.flags & O_CREAT) {
-+	if (nd->intent.it_flags & O_CREAT) {
- 		nfs_begin_data_update(dir);
- 		inode = nfs4_atomic_open(dir, dentry, nd);
- 		nfs_end_data_update(dir);
-@@ -876,7 +876,7 @@ static struct dentry *nfs_atomic_lookup(
- 				break;
- 			/* This turned out not to be a regular file */
- 			case -ELOOP:
--				if (!(nd->intent.open.flags & O_NOFOLLOW))
-+				if (!(nd->intent.it_flags & O_NOFOLLOW))
- 					goto no_open;
- 			/* case -EISDIR: */
- 			/* case -EINVAL: */
-@@ -915,7 +915,7 @@ static int nfs_open_revalidate(struct de
- 	/* NFS only supports OPEN on regular files */
- 	if (!S_ISREG(inode->i_mode))
- 		goto no_open;
--	openflags = nd->intent.open.flags;
-+	openflags = nd->intent.it_flags;
- 	/* We cannot do exclusive creation on a positive dentry */
- 	if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
- 		goto no_open;
-@@ -1080,7 +1080,7 @@ static int nfs_create(struct inode *dir,
- 	attr.ia_valid = ATTR_MODE;
- 
- 	if (nd && (nd->flags & LOOKUP_CREATE))
--		open_flags = nd->intent.open.flags;
-+		open_flags = nd->intent.it_flags;
- 
- 	/*
- 	 * The 0 argument passed into the create function should one day
-diff -urp a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
---- a/fs/nfs/nfs4proc.c	2006-03-10 17:19:45.000000000 -0800
-+++ b/fs/nfs/nfs4proc.c	2006-03-10 17:19:58.000000000 -0800
-@@ -776,17 +776,17 @@ nfs4_atomic_open(struct inode *dir, stru
- 	struct nfs4_state *state;
- 
- 	if (nd->flags & LOOKUP_CREATE) {
--		attr.ia_mode = nd->intent.open.create_mode;
-+		attr.ia_mode = nd->intent.it_create_mode;
- 		attr.ia_valid = ATTR_MODE;
- 		if (!IS_POSIXACL(dir))
- 			attr.ia_mode &= ~current->fs->umask;
- 	} else {
- 		attr.ia_valid = 0;
--		BUG_ON(nd->intent.open.flags & O_CREAT);
-+		BUG_ON(nd->intent.it_flags & O_CREAT);
- 	}
- 
- 	cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
--	state = nfs4_do_open(dir, &dentry->d_name, nd->intent.open.flags, &attr, cred);
-+	state = nfs4_do_open(dir, &dentry->d_name, nd->intent.it_flags, &attr, cred);
- 	put_rpccred(cred);
- 	if (IS_ERR(state))
- 		return (struct inode *)state;
diff --git a/lustre/kernel_patches/patches/perfctr-2.6-suse-lnxi.patch b/lustre/kernel_patches/patches/perfctr-2.6-suse-lnxi.patch
deleted file mode 100644
index 0224205855..0000000000
--- a/lustre/kernel_patches/patches/perfctr-2.6-suse-lnxi.patch
+++ /dev/null
@@ -1,10070 +0,0 @@
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/CREDITS
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/CREDITS	2004-11-11 10:28:48.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/CREDITS	2004-11-18 20:59:11.000000000 -0500
-@@ -2522,6 +2522,7 @@
- E: mikpe@csd.uu.se
- W: http://www.csd.uu.se/~mikpe/
- D: Miscellaneous fixes
-+D: Performance-monitoring counters driver
- 
- N: Reed H. Petty
- E: rhp@draper.net
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/Documentation/ioctl-number.txt
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/Documentation/ioctl-number.txt	2004-04-03 22:38:18.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/Documentation/ioctl-number.txt	2004-11-18 20:59:11.000000000 -0500
-@@ -187,5 +187,7 @@
- 0xB1	00-1F	PPPoX			<mailto:mostrows@styx.uwaterloo.ca>
- 0xCB	00-1F	CBM serial IEC bus	in development:
- 					<mailto:michael.klein@puffin.lb.shuttle.de>
-+0xD0	all	performance counters	see drivers/perfctr/
-+					<mailto:mikpe@csd.uu.se>
- 0xDD	00-3F	ZFCP device driver	see drivers/s390/scsi/
- 					<mailto:aherrman@de.ibm.com>
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/MAINTAINERS
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/MAINTAINERS	2004-11-11 10:28:39.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/MAINTAINERS	2004-11-18 20:59:11.000000000 -0500
-@@ -1608,6 +1608,12 @@
- L:	linux-net@vger.kernel.org
- S:	Supported
- 
-+PERFORMANCE-MONITORING COUNTERS DRIVER
-+P:	Mikael Pettersson
-+M:	mikpe@csd.uu.se
-+W:	http://www.csd.uu.se/~mikpe/linux/perfctr/
-+S:	Maintained
-+
- PNP SUPPORT
- P:	Adam Belay
- M:	ambx1@neo.rr.com
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/i386/Kconfig
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/i386/Kconfig	2004-11-11 10:28:16.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/i386/Kconfig	2004-11-18 20:59:11.000000000 -0500
-@@ -857,6 +857,8 @@
- 	generate incorrect output with certain kernel constructs when
- 	-mregparm=3 is used.
- 
-+source "drivers/perfctr/Kconfig"
-+
- endmenu
- 
- menu "Special options"
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/i386/kernel/entry.S
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/i386/kernel/entry.S	2004-11-11 10:28:47.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/i386/kernel/entry.S	2004-11-18 20:59:11.000000000 -0500
-@@ -444,6 +444,16 @@
- /* The include is where all of the SMP etc. interrupts come from */
- #include "entry_arch.h"
- 
-+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_KPERFCTR)
-+ENTRY(perfctr_interrupt)
-+	pushl $LOCAL_PERFCTR_VECTOR-256
-+	SAVE_ALL
-+	pushl %esp
-+	call smp_perfctr_interrupt
-+	addl $4, %esp
-+	jmp ret_from_intr
-+#endif
-+
- ENTRY(divide_error)
- 	pushl $0			# no error code
- 	pushl $do_divide_error
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/i386/kernel/i8259.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/i386/kernel/i8259.c	2004-11-11 10:27:12.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/i386/kernel/i8259.c	2004-11-18 20:59:11.000000000 -0500
-@@ -23,6 +23,7 @@
- #include <asm/apic.h>
- #include <asm/arch_hooks.h>
- #include <asm/i8259.h>
-+#include <asm/perfctr.h>
- 
- #include <linux/irq.h>
- 
-@@ -436,6 +437,8 @@
- 	 */
- 	intr_init_hook();
- 
-+	perfctr_vector_init();
-+
- 	/*
- 	 * Set the clock to HZ Hz, we already have a valid
- 	 * vector now:
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/i386/kernel/process.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/i386/kernel/process.c	2004-11-11 10:28:16.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/i386/kernel/process.c	2004-11-18 20:59:11.000000000 -0500
-@@ -32,6 +32,7 @@
- #include <linux/delay.h>
- #include <linux/reboot.h>
- #include <linux/init.h>
-+#include <linux/perfctr.h>
- #include <linux/mc146818rtc.h>
- #include <linux/module.h>
- #include <linux/kallsyms.h>
-@@ -305,6 +306,7 @@
- 		tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
- 		put_cpu();
- 	}
-+	perfctr_exit_thread(&tsk->thread);
- 	if (tsk->thread.debugreg[7])
- 		dr_dec_use_count(tsk->thread.debugreg[7]);
- }
-@@ -371,6 +373,8 @@
- 	savesegment(fs,p->thread.fs);
- 	savesegment(gs,p->thread.gs);
- 
-+	perfctr_copy_thread(&p->thread);
-+
- 	tsk = current;
- 	if (unlikely(NULL != tsk->thread.io_bitmap_ptr)) {
- 		p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
-@@ -519,6 +523,8 @@
- 
- 	/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
- 
-+	perfctr_suspend_thread(prev);
-+
- 	__unlazy_fpu(prev_p);
- 
- 	/*
-@@ -599,6 +605,9 @@
- 			 */
- 			tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
- 	}
-+
-+	perfctr_resume_thread(next);
-+
- 	return prev_p;
- }
- 
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/ppc/Kconfig
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/ppc/Kconfig	2004-11-11 10:28:15.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/ppc/Kconfig	2004-11-18 20:59:11.000000000 -0500
-@@ -214,6 +214,8 @@
- 	depends on 4xx || 8xx
- 	default y
- 
-+source "drivers/perfctr/Kconfig"
-+
- endmenu
- 
- menu "Platform options"
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/ppc/kernel/process.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/ppc/kernel/process.c	2004-11-11 10:28:48.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/ppc/kernel/process.c	2004-11-18 20:59:11.000000000 -0500
-@@ -37,6 +37,7 @@
- #include <linux/module.h>
- #include <linux/kallsyms.h>
- #include <linux/mqueue.h>
-+#include <linux/perfctr.h>
- 
- #include <asm/pgtable.h>
- #include <asm/uaccess.h>
-@@ -255,7 +256,9 @@
- 		new->thread.regs->msr |= MSR_VEC;
- 	new_thread = &new->thread;
- 	old_thread = &current->thread;
-+	perfctr_suspend_thread(&prev->thread);
- 	last = _switch(old_thread, new_thread);
-+	perfctr_resume_thread(&current->thread);
- 	local_irq_restore(s);
- 	return last;
- }
-@@ -314,6 +317,7 @@
- 		last_task_used_math = NULL;
- 	if (last_task_used_altivec == current)
- 		last_task_used_altivec = NULL;
-+	perfctr_exit_thread(&current->thread);
- }
- 
- void flush_thread(void)
-@@ -400,6 +404,8 @@
- 
- 	p->thread.last_syscall = -1;
- 
-+	perfctr_copy_thread(&p->thread);
-+
- 	return 0;
- }
- 
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/Kconfig
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/Kconfig	2004-11-11 10:28:39.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/Kconfig	2004-11-18 20:59:11.000000000 -0500
-@@ -319,6 +319,8 @@
- 	bool
- 	default y
- 
-+source "drivers/perfctr/Kconfig"
-+
- endmenu
- 
- 
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/entry.S
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/entry.S	2004-04-03 22:36:56.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/entry.S	2004-11-18 20:59:11.000000000 -0500
-@@ -556,6 +556,11 @@
- 	apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
- #endif
- 				
-+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_KPERFCTR)
-+ENTRY(perfctr_interrupt)
-+	apicinterrupt LOCAL_PERFCTR_VECTOR,smp_perfctr_interrupt
-+#endif
-+ 		
- /*
-  * Exception entry points.
-  */ 		
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/i8259.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/i8259.c	2004-04-03 22:36:25.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/i8259.c	2004-11-18 20:59:11.000000000 -0500
-@@ -23,6 +23,7 @@
- #include <asm/delay.h>
- #include <asm/desc.h>
- #include <asm/apic.h>
-+#include <asm/perfctr.h>
- 
- #include <linux/irq.h>
- 
-@@ -484,6 +485,8 @@
- 	set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
- #endif
- 
-+	perfctr_vector_init();
-+
- 	/*
- 	 * Set the clock to HZ Hz, we already have a valid
- 	 * vector now:
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/process.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/arch/x86_64/kernel/process.c	2004-11-11 10:27:51.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/arch/x86_64/kernel/process.c	2004-11-18 20:59:11.000000000 -0500
-@@ -32,6 +32,7 @@
- #include <linux/delay.h>
- #include <linux/irq.h>
- #include <linux/ptrace.h>
-+#include <linux/perfctr.h>
- #include <linux/version.h>
- 
- #include <asm/uaccess.h>
-@@ -258,6 +259,7 @@
- 		(init_tss + smp_processor_id())->io_bitmap_base = 
- 			INVALID_IO_BITMAP_OFFSET;
- 	}
-+	perfctr_exit_thread(&me->thread);
- }
- 
- void flush_thread(void)
-@@ -361,6 +363,8 @@
- 	asm("movl %%es,%0" : "=m" (p->thread.es));
- 	asm("movl %%ds,%0" : "=m" (p->thread.ds));
- 
-+	perfctr_copy_thread(&p->thread);
-+
- 	if (unlikely(me->thread.io_bitmap_ptr != NULL)) { 
- 		p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
- 		if (!p->thread.io_bitmap_ptr) 
-@@ -407,6 +411,8 @@
- 	int cpu = smp_processor_id();  
- 	struct tss_struct *tss = init_tss + cpu;
- 
-+	perfctr_suspend_thread(prev);
-+
- 	unlazy_fpu(prev_p);
- 
- 	/*
-@@ -510,6 +516,8 @@
- 		}
- 	}
- 
-+	perfctr_resume_thread(next);
-+
- 	return prev_p;
- }
- 
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Makefile
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/Makefile	2004-11-18 20:59:08.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/Makefile	2004-11-18 20:59:11.000000000 -0500
-@@ -51,6 +51,7 @@
- obj-$(CONFIG_MCA)		+= mca/
- obj-$(CONFIG_EISA)		+= eisa/
- obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
-+obj-$(CONFIG_KPERFCTR)		+= perfctr/
- obj-$(CONFIG_INFINIBAND)	+= infiniband/
- obj-y				+= firmware/
- obj-$(CONFIG_CRASH_DUMP)	+= dump/
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64_compat.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_64_compat.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64_compat.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,25 @@
-+/* $Id: x86_64_compat.h,v 1.1 2003/05/14 21:51:57 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * x86_64-specific compatibility definitions for 2.4/2.5 kernels.
-+ *
-+ * Copyright (C) 2003  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-+
-+/* irq_enter() and irq_exit() take two parameters in 2.4. However,
-+   we only use them to disable preemption in the interrupt handler,
-+   which isn't needed in non-preemptive 2.4 kernels. */
-+#ifdef CONFIG_PREEMPT
-+#error "not yet ported to 2.4+PREEMPT"
-+#endif
-+#undef irq_enter
-+#undef irq_exit
-+#define irq_enter()	do{}while(0)
-+#define irq_exit()	do{}while(0)
-+
-+#endif
-+
-+extern unsigned int perfctr_cpu_khz(void);
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/Makefile
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/Makefile	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/Makefile	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,46 @@
-+# $Id: Makefile,v 1.20.2.2 2004/08/02 22:24:58 mikpe Exp $
-+# Makefile for the Performance-monitoring counters driver.
-+
-+ifeq ($(VERSION)$(PATCHLEVEL),24)
-+include Makefile24
-+else
-+
-+# We need -fno-unit-at-a-time with gcc-3.4 on x86 to avoid stack overflow.
-+# Kernels >= 2.6.6 do that automatically but older ones do not, so we
-+# unconditionally add that option here just in case.
-+my_check_gcc = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
-+EXTRA_CFLAGS_$(CONFIG_X86) := $(call my_check_gcc,-fno-unit-at-a-time,)
-+EXTRA_CFLAGS_$(CONFIG_X86_64) :=
-+EXTRA_CFLAGS_$(CONFIG_PPC32) :=
-+EXTRA_CFLAGS := $(EXTRA_CFLAGS_y)
-+
-+# construct various object file lists:
-+# kernel-objs-y		kernel objects
-+# m-objs-m		perfctr.o if driver is module, empty otherwise
-+# driver-objs-y		objects for perfctr.o module, or empty
-+
-+# This also covers x86_64.
-+driver-objs-$(CONFIG_X86) := x86.o
-+tests-objs-$(CONFIG_X86) := x86_tests.o
-+kernel-objs-$(CONFIG_X86) := x86_setup.o
-+
-+driver-objs-$(CONFIG_PPC32) := ppc.o
-+tests-objs-$(CONFIG_PPC32) := ppc_tests.o
-+kernel-objs-$(CONFIG_PPC32) := ppc_setup.o
-+
-+driver-objs-y += init.o marshal.o
-+driver-objs-$(CONFIG_PERFCTR_INIT_TESTS) += $(tests-objs-y)
-+driver-objs-$(CONFIG_PERFCTR_VIRTUAL) += virtual.o
-+stub-objs-$(CONFIG_PERFCTR)-$(CONFIG_PERFCTR_VIRTUAL) := virtual_stub.o
-+driver-objs-$(CONFIG_PERFCTR_GLOBAL) += global.o
-+m-objs-$(CONFIG_PERFCTR) := perfctr.o
-+kernel-objs-$(CONFIG_PERFCTR) += $(driver-objs-y)
-+kernel-objs-y += $(stub-objs-m-y)
-+
-+perfctr-objs		:= $(driver-objs-y)
-+obj-m			+= $(m-objs-m)
-+
-+obj-$(CONFIG_KPERFCTR)	+= kperfctr.o
-+kperfctr-objs		:= $(kernel-objs-y)
-+
-+endif	# ifeq 24
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/RELEASE-NOTES
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/RELEASE-NOTES	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/RELEASE-NOTES	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,1357 @@
-+$Id: RELEASE-NOTES,v 1.234.2.28 2004/10/19 16:22:47 mikpe Exp $
-+
-+RELEASE NOTES
-+=============
-+
-+Version 2.6.10.2, 2004-10-19
-+- virtual.c: replace nrctrs_lock with a mutex. Avoids illegal
-+  may-sleep-while-holding-lock, caused by mutex operations in
-+  perfctr_cpu_{reserve,release}().
-+  Backport from perfctr-2.7.6.
-+- PPC32: Correct MMCR0 handling for FCECE/TRIGGER. Read
-+  MMCR0 at suspend and then freeze the counters. Move
-+  this code from read_counters() to suspend(). At resume,
-+  reload MMCR0 to unfreeze the counters. Clean up the
-+  cstatus checks controlling this behaviour.
-+  Backport from perfctr-2.7.6.
-+
-+Version 2.6.10, 2004-09-14
-+- Fixed p4_clear_counters() to not access IQ_ESCR{0,1}
-+  on P4 models >= 3.
-+
-+Version 2.6.10-pre1, 2004-08-03
-+- Changed x86-64 to use the x86 include file and driver.
-+  Intel's 64-bit P4 should now work in the x86-64 kernel.
-+- Replaced PERFCTR_INTERRUPT_SUPPORT and NMI_LOCAL_APIC
-+  #if:s in x86 code by #ifdef:s on CONFIG_X86_LOCAL_APIC.
-+- Use macros to clean up x86 per-cpu cache accesses.
-+- Recognize model 13 Pentium-Ms.
-+- Changed isuspend_cpu on x86 to be like x86-64's: it
-+  now stores a CPU number instead of a cache pointer.
-+- x86: make perfctr_cpu_name more approximate.
-+- The x86 driver records a simplified CPU type for x86_tests,
-+  but this only occurs if PERFCTR_INIT_TESTS is configured.
-+  perfctr_info.cpu_type is now unused.
-+- Changed P4 driver to set up and check an explicit flag
-+  for EXTENDED_CASCADE availability. perfctr_info.cpu_type
-+  is now unused except for perfctr_x86_init_tests().
-+- x86: Reformatted "if( x )" to "if (x)" and similarly for while
-+  and switch statements. Deleted #if 0 blocks.
-+
-+Version 2.6.9, 2004-07-27
-+- Fix ppc_check_control() to allow 7400/7410 processors to
-+  specify MMCR2[THRESHMULT].
-+- PPC32 cleanups: make get_cpu_cache() return pointer not lvalue,
-+  eliminate duplicated initialisation/cleanup code.
-+- Makefile: enforce -fno-unit-at-a-time with gcc-3.4 on x86,
-+  to prevent stack overflow in 2.6 kernels < 2.6.6.
-+- Do sync_core() before rdtsc() in x86_tests, to avoid bogus
-+  benchmarking data on K8. Add sync_core() implementation for
-+  the 32-bit kernel. Add sync_core() benchmark.
-+- Added __perfctr_mk_cstatus() to allow x86.c:finalise_backpatching()
-+  to create a cstatus with i-mode counters marked as present, but
-+  with zero actual counters. This prevents perfctr_cpu_isuspend()
-+  from clearing the control register for counter #0 at init-time,
-+  when the hardware doesn't belong to this driver. On AMD and P6
-+  this would accidentally disable the NMI watchdog.
-+- x86: Marked initial targets of backpatchable calls
-+  'noinline' to prevent gcc from inlining them, which
-+  completely breaks the backpatching mechanism.
-+- x86_tests: fix CONFIG_X86_LOCAL_APIC=n linkage error.
-+- 2.6.8-rc1 no longer makes cpu_online_map a #define on UP,
-+  breaking modules. Reintroduce the macro.
-+- 2.6.8-rc1 changed cpus_complement() calling convention.
-+  Replace cpus_complement();cpus_and() with cpus_andnot(),
-+  and provide cpus_andnot() compat macro.
-+- PPC32: support generic CPUs using only the TB.
-+- PPC32: query OF for CPU/TB frequencies, drop /proc/cpuinfo
-+  parsing code.
-+- PPC32: avoid CPU re-detection in tests code.
-+- PPC32: clean up and sync with current perfctr-2.7 code.
-+
-+Version 2.6.8, 2004-05-29
-+- Added recognition of PowerPC 750GX.
-+- Changes for the {reserve,release}_lapic_nmi() API added in
-+  kernel 2.6.6 backported from perfctr-2.7.1:
-+  * Starting with kernel 2.6.6 we no longer need access to
-+    nmi_perfctr_msr, so removed EXPORT_SYMBOL() and <asm/apic.h>
-+    patches related to this variable (except for older kernels).
-+  * Updated x86.c to use the new API. Added simulation (without
-+    the non-conflict guarantees) for older kernels.
-+  * Moved hardware reservation to x86.c's "reserve" procedure.
-+    The init code now only does read-only hardware detection.
-+  * Added a mutex to the reserve/release procedures, eliminating
-+  * a long-standing race possibility.
-+  * Changed x86.c to reserve and release the hardware around its
-+    call to perfctr_x86_init_tests().
-+  * Similarly updated x86_64.c for the new API.
-+
-+Version 2.6.7, 2004-05-04
-+- Replaced x86_64_tests.{c,h} with x86_tests.{c,h}.
-+- sys_device_{,un}register() was renamed as sysdev_{,un}register()
-+  in 2.6.4-rc2. Updated x86.c and x86_64.c accordingly, and
-+  added a compatibility definition in compat.h.
-+- Removed unnecessary '#include "compat.h"' from x86_tests.c.
-+- Replaced x86_64_setup.c with x86_setup.c.
-+- Replaced x86_64_compat.h with x86_compat.h.
-+- Moved perfctr_interrupt entry point from x86_setup.c to patch kit,
-+  for kernels older than 2.4.21. Cleanup to facilitate future merge
-+  of x86_setup.c and x86_64_setup.c.
-+
-+Version 2.6.6, 2004-02-21
-+- Fixed a bug in x86-64's perfctr interrupt entry code in 2.4 kernels,
-+  causing it to pass the wrong value for "struct pt_regs*". This
-+  was harmless since the retrieved "rip" was unused, but still wrong.
-+  Renamed do_perfctr_interrupt to smp_perfctr_interrupt to allow
-+  using the 2.4 kernel's standard BUILD_SMP_INTERRUPT macro.
-+- Unmask LVTPC after interrupt on Pentium-M. An oprofile user
-+  reports that P-M auto-masks LVTPC just like P4. Preliminary
-+  measurements indicate a 40 to 60 cycle cost for the apic write
-+  on P4s and P6s, so the unmask is not done unconditionally.
-+- Measure LVTPC write overhead in x86{,_64}_tests.c.
-+- Add Pentium 4 Model 3 detection.
-+- The 2.4.21-193 SuSE kernel does EXPORT_SYMBOL(mmu_cr4_features).
-+  Add compat24.h workaround for this.
-+
-+Version 2.6.5, 2004-01-26
-+- Added perfctr_info.cpu_type constants to <asm-ppc/perfctr.h>.
-+- Init filp->f_mapping in virtual.c for 2.6.2-rc1+ kernels.
-+- Updated p4_check_control():
-+  * Allow ESCR.CPL_T1 to be non-zero when using global-mode
-+    counters on HT processors.
-+  * Don't require ESCR.CPL_T0 to be non-zero. CPL_T0==0b00
-+    is safe and potentially useful (global counters on HT).
-+  * Require CCCR.ACTIVE_THREAD==0b11 on non-HT processors, as
-+    documented in the IA32 Volume 3 manual. Old non-HT P4s
-+    seem to work Ok for all four values (see perfctr-2.6.0-pre3
-+    notes), but this is neither guaranteed nor useful.
-+- x86.c now detects & records P4 HT-ness also in UP kernels.
-+- Added 'is_global' parameter to perfctr_cpu_update_control().
-+  This flag is ignored on everything except P4 (sigh).
-+
-+Version 2.6.4, 2004-01-12
-+- Added 'tsc_to_cpu_mult' field to struct perfctr_info, replacing
-+  '_reserved1'. This is needed on PowerPC to map time-base ticks
-+  to actual time. On x86/AMD64, tsc_to_cpu_mult == 1.
-+- Added support for PowerPC 604/7xx/74xx processors. Overflow
-+  interrupts are currently not allowed due to the PMI/DECR erratum.
-+- Replaced perfctr_cpus_mask() with cpus_addr(). Updated cpumask.h
-+  to define cpus_addr() for kernels older than 2.6.1.
-+
-+Version 2.6.3-pl1, 2004-01-01
-+- Moved the x86 interrupt handler definition from x86_setup.c to
-+  the patch kit for 2.4.21 and later 2.4 kernels, like it already
-+  is done for 2.6 kernels. This change is needed due to extensive
-+  interrupt handler changes in RedHat's 2.4.21-6.EL kernel.
-+- Simplified <asm-i386/perfctr.h>: now that early 2.4 kernels no
-+  longer are supported, LOCAL_PERFCTR_VECTOR is known to be defined,
-+  so CONFIG_X86_LOCAL_APIC implies PERFCTR_INTERRUPT_SUPPORT.
-+
-+Version 2.6.3, 2003-12-21
-+- Removed gperfctr_cpu_state_only_cpu_sdesc's total_sizeof
-+  optimisation. The ABI change in 2.6.2 broke it, leading to
-+  the new fields not being cleared and later causing EOVERFLOW.
-+- The perfctr_ioctl32_handler() workaround is now only applied
-+  to kernels older than 2.4.23, since 2.4.23 added the "NULL
-+  handler == sys_ioctl" logic.
-+
-+Version 2.6.2, 2003-11-23
-+- Added 16 bytes (four fields) of reserved data to perfctr_info,
-+  perfctr_cpu_control, vperfctr_control, gperfctr_cpu_control,
-+  and gperfctr_cpu_state. Renumbered marshalling tags for
-+  generic structures. Bumped ABI versions.
-+- Only allow use of IQ_ESCR{0,1} on P4 models <= 2. These ESCRs
-+  were removed from later models, according to a recent Intel
-+  documentation update (252046-006).
-+- Fixes for Fedora Core 1's 2.4.22-1.2115.nptl kernel:
-+  * Work around their incomplete and broken cpumask_t backport.
-+  * Avoid name conflict due to their on_each_cpu() backport.
-+  * Handle their preempt_disable()/enable() macros.
-+- Added new perfctr_cpu_is_forbidden() macro to fix a
-+  compilation error affecting AMD64 in SMP 2.6 kernels.
-+  SMP cpu_isset() requires that mask is an lvalue, but
-+  for AMD64 the mask is a constant.
-+
-+Version 2.6.1, 2003-10-05
-+- Kernel 2.6.0-test6 changed /proc/self and the /proc/<pid>/
-+  namespace to refer to "processes" (groups of CLONE tasks)
-+  instead of actual kernel tasks. This forced the planned
-+  transition of the vperfctr API from /proc/<pid>/perfctr
-+  to /dev/perfctr to occur immediately. Changes:
-+  * Moved /dev/perfctr implementation from global.c to init.c.
-+  * Implemented VPERFCTR_{CREAT,OPEN}, vperfctr_attach(), and
-+    the vperfctrfs pseudo-fs needed to support the magic files.
-+    The fs code was ported from perfctr-1.6/3.1, but updated
-+    for 2.6 and fixed to permit module unloading in 2.4.
-+  * Fixed VPERFCTR_OPEN to accept tsk->thread.perfctr == NULL.
-+    (Needed to info querying commands.)
-+  * Removed /proc/<pid>/perfctr code. Simplified vperfctr_stub code.
-+  * Updated vperfctr_attach() to mimic the old /proc vperfctr_open().
-+    This fixes some synchronisation issues.
-+- Cleanups:
-+  * Removed #if checks and code for kernels older than 2.4.16.
-+  * Eliminated compat macros that are identical in 2.6 and 2.4.
-+  * Moved ptrace_check_attach EXPORT_SYMBOL from x86{,_64}_setup.c
-+    to virtual_stub.c.
-+  * get_task_by_proc_pid_inode() is now trivial. Eliminated it.
-+  * p4_ht_finalise() is now trivial. Eliminated it.
-+- Added MODULE_ALIAS() declaration, eliminating the need for
-+  an alias in /etc/modprobe.conf with 2.6 kernels. Added
-+  MODULE_ALIAS() compatibility #define in compat24.h.
-+- Added detection of AMD K8 Revision C processors.
-+- Updated K8C detection for Revision C Athlon64s.
-+
-+Version 2.6.0, 2003-09-08
-+- Handle set_cpus_allowed() when PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED:
-+  * Add bad_cpus_allowed flag to struct vperfctr.
-+  * Check bad_cpus_allowed in __vperfctr_resume: if resuming
-+    with PMCs on forbidden CPU, kill counters and SIGILL current.
-+  * __vperfctr_set_cpus_allowed() callback: set bad_cpus_allowed
-+    and print warning if mask allows forbidden CPUs.
-+  * Use task_lock/unlock instead of preempt_disable/enable to
-+    synchronise task_struct accesses.
-+  * Ensure sampling_timer and bad_cpus_allowed share cache line.
-+  * #include <linux/compiler.h> explicitly for 2.4.18 and older
-+    kernels; newer kernels include it from <linux/kernel.h>.
-+  * Hook in virtual_stub.c.
-+  * Hook and cpumask_t typedef in <linux/perfctr.h>.
-+- Simplify #if test for set_cpus_allowed() emulation code.
-+  Also don't define it if CONFIG_PERFCTR_VIRTUAL isn't set.
-+- cpumask.h only typedefs cpumask_t if <linux/perfctr.h> hasn't.
-+- Don't hide #include <linux/kernel.h> in compat24.h.
-+- Fixed compat24.h to test for MODULE not CONFIG_MODULES at the
-+  __module_get/module_put macros.
-+
-+Version 2.6.0-pre5, 2003-08-31
-+- printk() is not allowed in switch_to(). Disabled debug code
-+  which could violate that rule. Changed virtual_stub.c to BUG()
-+  instead of printk() if the driver is invoked when not loaded.
-+- Renamed vperfctr_exit2() to vperfctr_unlink() for clarity.
-+- gcc-3.3.1 issued several "dereferencing type-punned pointer will
-+  break strict-aliasing rules" warnings for marshal.c. Used explicit
-+  unions to fix the warnings and clean up the code.
-+- Removed compat22.h.
-+- cpumask_t was included in standard 2.6.0-test4; replace #ifndef
-+  test in cpumask.h with normal kernel version test.
-+- x86-64 fix: sys_ioctl() isn't exported to modules, so call
-+  filp->f_op->ioctl() instead in perfctr_ioctl32_handler().
-+- x86-64 fix: init.c must include <asm/ioctl32.h> not <linux/ioctl32.h>
-+  for compatibility with 2.4 kernels.
-+
-+Version 2.6.0-pre4, 2003-08-19
-+- Fix x86-64 register_ioctl32_conversion() usage for 2.4 kernels:
-+  * Supply dummy handler since a NULL handler oopses the kernel.
-+  * Test CONFIG_IA32_EMULATION since CONFIG_COMPAT is post-2.4.
-+- Fixed and merged the new API struct marshalling code:
-+  * New files marshal.c and marshal.h contain the marshalling code
-+    and high-level helper functions (source shared with the library).
-+  * User-space structs are struct perfctr_struct_buf and accessed using
-+    perfctr_copy_{from,to}_user() with ptr to appropriate descriptor.
-+    The cpumask stuff isn't changed.
-+  * All ioctls registered as trivially 32-bit compatible on x86-64.
-+  * Changed perfctr_info cpu_type/cpu_features from short to int:
-+    this avoids the need for UINT16 marshalling support, and cpumask_t
-+    caused perfctr_info to change binary representation anyway.
-+- Declared VPERFCTR_{CREAT,OPEN} ioctls, but left them unimplemented.
-+- Fixed vperfctr_open() preemption bug. The O_CREAT check+install
-+  code could be preempted, leading to remote-control races.
-+- Fixed perfctr_exit_thread() preemption bug. It detached the vperfctr
-+  before calling __vperfctr_exit(). If current was preempted before
-+  __vperfctr_exit() called vperfctr_suspend(), perfctr_suspend_thread()
-+  would fail to suspend the counters. The suspend+detach is now done
-+  atomically within __vperfctr_exit().
-+- Changes to handle 2.6 kernels with the cpumask_t patch (-mm, -osdl):
-+  * Convert perfctr_cpus_forbidden_mask accesses to cpumask_t API.
-+    Based in part on a patch for the -osdl kernel by Stephen Hemminger.
-+  * Remove cpus and cpus_forbidden from struct perfctr_info,
-+    since their sizes depend on the kernel configuration.
-+  * Add struct perfctr_cpu_mask to export cpumask_t objects
-+    sanely (i.e., using ints not longs) to user-space.
-+  * Add CPUS and CPUS_FORBIDDEN commands to retrieve these sets.
-+  * Add cpumask.h to emulate cpumask_t API in cpumask_t-free kernels.
-+  * Move perfctr_cpus_forbidden_mask declaration/#define from
-+    <asm/perfctr.h> to cpumask.h -- necessary since <asm/perfctr.h>
-+    doesn't have access to the driver's compatibility definitions.
-+- Cleaned up perfctr_cpu_ireload().
-+- Removed struct field offset check from init.c.
-+- 2.4.22-rc1 does EXPORT_SYMBOL(mmu_cr4_features). Added
-+  new compat #define to handle this.
-+- Rename x86.c's rdmsrl() to rdmsr_low() to work around msr.h
-+  changes in 2.6.0-test3. Also rename rdpmcl() to rdpmc_low().
-+- Replaced __attribute__((__aligned__(SMP_CACHE_BYTES))) usage
-+  with the official ____cacheline_aligned macro.
-+- Detect cpuid 0x69x VIA C3s (Antaur/Nehemiah).
-+
-+Version 2.6.0-pre3, 2003-08-03
-+- Changed perfctr_info.cpus and cpus_forbidden to be int instead of
-+  long, to make x86-32 and x86-64 compatible. This is a temporary
-+  solution, as there are patches for >32 CPUs on x86-32. The real
-+  solution is to make these sets variable-sized, and have user-space
-+  retrieve them with a new command.
-+- Simplified GPERFCTR_CONTROL to update a single CPU instead of
-+  a set of CPUs. Moved cstatus clearing to release_hardware().
-+- Moved gperfctr start to new GPERFCTR_START command.
-+- Simplified GPERFCTR_READ to access a single CPU instead of a
-+  set of CPUs.
-+- Removed the requirement that CCCR.ACTIVE_THREAD == 3 on P4.
-+  HT processors define behaviour for all four possible values,
-+  and non-HT processors behave sanely for all four values.
-+- Moved struct perfctr_low_ctrs definition from <asm/perfctr.h> to
-+  the corresponding low-level driver, since it's only used there.
-+- Changed perfctr_info.cpu_khz and vperfctr_control.preserve to be
-+  int instead of long. This corrects x86-64 and makes it compatible
-+  with x86-32.
-+- Updated x86.c to permit extended cascading on P4M2.
-+- Fixed a bug where the perfctr module's refcount could be zero with
-+  code still running in the module (pending returns to exit_thread()).
-+  This could race with rmmod in preemptive kernels, and in theory
-+  also in SMP kernels.
-+  * module owner field added to vperfctr_stub
-+  * _vperfctr_exit() in the modular case is now a function in
-+    vperfctr_stub.c, which brackets the vperfctr_stub.exit() call
-+    with __module_get() and module_put() on vperfctr_stub.owner
-+  * updated 2.4 and 2.2 compat definitions of __module_get() and
-+    module_put() to work for modules != THIS_MODULE  
-+- Replaced uses of (void)try_module_get() with __module_get() as the
-+  latter is more appropriate for 2.6 kernels. Updated compat stuff.
-+
-+Version 2.6.0-pre2, 2003-07-13
-+- vperfctr API fixes:
-+  * The new VPERFCTR_READ_CONTROL command retrieves a vperfctr's
-+    control data.
-+  * Renamed VPERFCTR_SAMPLE to VPERFCTR_READ_SUM, and made it
-+    write the sums to a perfctr_sum_ctrs user-space buffer.
-+  * Non-write commands are now always permitted on unlinked perfctrs.
-+  The first change was needed since the control data no longer is
-+  accessible via the mmap()ed state. The other changes clean up and
-+  simplify perfex and the library's slow-path read_ctrs() operation.
-+- sys_vperfctr_ functions now mark the tsk parameter as "const" if
-+  they don't need write access to it. Typically they only need to
-+  compare it with current to detect self-access cases.
-+- perfctr_cpu_state no longer makes the perfctr_cpu_control part
-+  accessible to user-space (via mmap() of vperfctrs).
-+- Simplified {set,is}_isuspend_cpu() in x86_64.c by having callers
-+  pass the CPU number instead of the cache pointer (which was only
-+  used to derive the CPU number).
-+- Eliminated NMI_LOCAL_APIC #ifs from x86-64 code since x86-64
-+  always defines it.
-+- x86.c cleanups: the non-PERFCTR_INTERRUPT_SUPPORT case now uses
-+  dummy stub functions, eliminated six #ifdefs.
-+- x86_64_setup.c needs <asm/fixmap.h>.
-+- Protected cpu_has_mmx and cpu_has_ht #defines in x86_compat.h
-+  with #ifndef since 2.4.22-pre3 added those #defines.
-+- Eliminated PERFCTR_INTERRUPT_SUPPORT #ifs from x86-64 code
-+  since x86-64 always defines CONFIG_X86_LOCAL_APIC.
-+- Removed the P4-specific versions of isuspend() and iresume().
-+  P4 now uses p6_like_{isuspend,iresume}(), just like P6/K7/K8.
-+- Long overdue cleanup in x86.c/x86_64.c: renamed per_cpu_cache
-+  pointer variables from 'cpu' to 'cache'.
-+- Added inline functions in virtual.c for registering the overflow
-+  handler and for clearing iresume_cstatus. Cleaned out several
-+  #if PERFCTR_INTERRUPT_SUPPORT occurrences from the main code.
-+  (Partial backport from the abandoned perfctr-3.1 branch.)
-+- Inlined now useless 'struct vperfctr_state' in 'struct vperfctr'.
-+
-+Version 2.6.0-pre1, 2003-07-02
-+- Rearranged 'struct perfctr_cpu_state' to reduce the number of
-+  cache lines needed to be touched by key operations (suspend,
-+  resume, sample). Switched from struct-of-arrays to array-of-struct
-+  for perfctr counts, and copied pmc_map into the PMC data array.
-+  The old representation touched at least 3 cache lines at key
-+  operations, the new one only needs one cache line in most cases.
-+  The user-space mmap() view of the new representation is binary
-+  compatible between x86 and x86-64.
-+- Changed 'isuspend_cpu' in perfctr_cpu_state on x86-64 to be a
-+  32-bit CPU number, to maintain binary compatibility with x86.
-+- Removed the union of p5_cesr and id; use id throughout.
-+- Removed _filler and si_signo from 'struct vperfctr_state', making
-+  the user-space view of it identical to 'struct perfctr_cpu_state'.
-+
-+Version 2.5.5, 2003-06-15
-+- Updated x86 driver for 2.5.71 local APIC driver model changes.
-+- Updated x86-64 driver for 2.5.71 NMI watchdog enable/disable API.
-+- x86-64 is broken in 2.5.71 since x86-64 updated to driver model
-+  for local APIC and NMI watchdog, at the same time as x86 moved
-+  to a newer version of the "system device" driver model. Updated
-+  the x86-64 driver for the new model, which is expected to be in
-+  x86-64 by 2.5.72 (patch exists for 2.5.71).
-+
-+Version 2.5.4, 2003-06-01
-+- The generic-x86-with-TSC driver now uses rdpmc_read_counters
-+  and p6_write_control instead of its own procedures.
-+- K8 docs are now available. Updated comment in x86.c accordingly.
-+- P4 OVF_PMI+FORCE_OVF counters didn't work at all, resulting in
-+  BUG messages from the driver since identify_overflow failed to
-+  detect which counters had overflowed, and vperfctr_ihandler
-+  left the vperfctr in an inconsistent state. This works now.
-+  However, hardware quirks makes this configuration only useful
-+  for one-shot counters, since resuming generates a new interrupt
-+  and the faulting instruction again doesn't complete. The same
-+  problem can occur with regular OVF_PMI counters if ireset is
-+  a small-magnitude value, like -5.
-+  This is a user-space problem; the driver survives.
-+- On P4, OVF_PMI+FORCE_OVF counters must have an ireset value of -1.
-+  This allows the regular overflow check to also handle FORCE_OVF
-+  counters. Not having this restriction would lead to MAJOR
-+  complications in the driver's "detect overflow counters" code.
-+  There is no loss of functionality since the ireset value doesn't
-+  affect the counter's PMI rate for FORCE_OVF counters.
-+- Moved P4 APIC_LVTPC reinit from p4_isuspend() to identify_overflow().
-+  Reduces context-switch overheads when i-mode counters are active.
-+- Corrected vperfctr_suspend()'s precondition.
-+- Corrected comment in <asm/perfctr.h> to state that ireset[]
-+  values must be negative rather than non-positive.
-+- Made 'perfctr_cpu_name' __initdata, like its predecessor.
-+
-+Version 2.5.3.1, 2003-05-21
-+- Replaced 'char *perfctr_cpu_name[]' by 'char *perfctr_cpu_name'.
-+  This is needed for x86-64 and other non-x86 architectures.
-+- Changed <asm-x86_64/perfctr.h> to use 'long long' for 64-bit sums.
-+  This doesn't change the ABI, but improves user-space source code
-+  compatibility with 32-bit x86.
-+- Removed the !defined(set_cpus_allowed) check added to compat24.h
-+  in 2.5.3. It's wrong for SMP builds with modules and MODVERSIONS,
-+  since the set_cpus_allowed() emulation function becomes a #define
-+  from include/linux/modules/x86_setup.ver. Instead add the already
-+  used HAVE_SET_CPUS_ALLOWED #define to include/linux/config.h in
-+  the kernel patch, but make it conditional on CONFIG_X86_64.
-+
-+Version 2.5.3, 2003-05-16
-+- Added detection code for Pentium M. MISC_ENABLE_PERF_AVAIL is
-+  now checked on both P4 and Pentium M.
-+- Added x86_64 driver code. Both x86_64.c and asm-x86_64/perfctr.h
-+  are basically simplified versions of corresponding x86 files,
-+  with P5 and P4 support removed, 2.2 kernel support removed, and
-+  'long long' for sums replaced by 'long'. The last change is
-+  painful for user-space and may be reverted.
-+- compat24.h: don't define set_cpus_allowed() if already #defined,
-+  workaround for RawHide's 2.4.20-9.2 x86_64 kernel.
-+- Removed list of supported CPUs from Kconfig. That information
-+  belongs elsewhere (and it's a pain to maintain for 2.2/2.4).
-+
-+Version 2.5.2, 2003-04-13
-+- Minor cleanup: use PROC_I() unconditionally in virtual.c,
-+  implement trivial compat macro in compat24.h.
-+- Updated power management code for the local APIC and NMI
-+  watchdog driver model changes in kernel 2.5.67.
-+  The suspend/resume procedures are still no-ops, however.
-+  This revealed a bug in the lapic_nmi_watchdog resume code:
-+  it resumes the lapic_nmi_watchdog even when it was disabled
-+  before suspend. Perfctr's 2.5.67 kernel patch includes a fix.
-+- perfctr_sample_thread() is now used also on UP. Anton Ertl's
-+  2.26GHz UP P4 managed to execute a process for more than 2^32
-+  cycles before suspending it, causing TSC inaccuracies.
-+- RH9's 2.4.20-8 kernel changed cpu_online(), put_task_struct() and
-+  remap_page_range() to be more like in 2.5 kernels, and moved the
-+  declaration of ptrace_check_attach() from mm.h to ptrace.h, also
-+  like in 2.5 kernels, requiring fixes to compat24.h and x86_setup.c.
-+- Added note in x86.c about the new Pentium M processor.
-+
-+Version 2.5.1, 2003-03-23
-+- Fix P4 HT initialisation. I've seen several boot logs from
-+  people running MP P4 Xeons with HT disabled: this produces
-+  an ugly "restricting access for CPUs 0x0" message, and would
-+  cause P4 HT init to unnecessarily return error in older kernels
-+  lacking set_cpus_allowed(). Now only print the message or
-+  signal error if non-zero siblings actually are found.
-+- The set_cpus_allowed() emulation doesn't compile in 2.4
-+  kernels older than 2.4.15 due to the p->cpus_running field.
-+  Updated version checks to skip it in 2.4.x when x<15.
-+- Fix set_cpus_allowed() emulation compile error on BUG_ON()
-+  in 2.4 kernels older than 2.4.19.
-+- Added Nehemiah note/reminder in x86.c:centaur_init().
-+
-+Version 2.5.0, 2003-03-10
-+- Reverted the 2.5.0-pre2 change that replaced the PERFCTR_INFO
-+  ioctl by read(): it made the API look too weird.
-+  Added a PERFCTR_ABI ioctl which only retrieves 'abi_version'.
-+- Cleaned up struct perfctr_info: renamed abi_magic to abi_version,
-+  and version to driver_version. Renamed PERFCTR_*_MAGIC too.
-+- Cleaned up struct perfctr_cpu_control: moved evntsel_aux[]
-+  into the p4 sub-struct and renamed it as escr[]. Only P4 needs
-+  it anyway, and the new name clarifies its purpose.
-+- Renumbered the vperfctr ioctls to the 8-15 range (8-11 are used)
-+  and reserved 0-7 (0-1 are used) for generic ioctls.
-+- Added 'use_nmi' field to struct gperfctr_control, reserved for
-+  future use if/when support for i-mode gperfctrs is implemented.
-+- Replaced some preempt/smp_call_function combinations with 2.5.64's
-+  new on_each_cpu() construct. Added compatibility definitions to
-+  compat24.h and compat22.h.
-+
-+Version 2.5.0-pre2, 2003-03-03
-+- Added ABI version to perfctr_info. Replaced PERFCTR_INFO ioctl
-+  by read() on the fd, since that allows reading the ABI version
-+  even in the case of a version mismatch. Removed binary layout
-+  magic number from vperfctr_state. Rearranged perfctr_info to
-+  make the 'long' fields 8-byte aligned.
-+- Added #ifdef CONFIG_KPERFCTR to <linux/perfctr.h> to ensure
-+  that <asm/perfctr.h> isn't included unless CONFIG_KPERFCTR=y.
-+  This allows the patched kernel source to compile cleanly also
-+  in archs not yet supported by perfctr.
-+- Removed PERFCTR_PROC_PID_MODE #define and replaced it with
-+  /*notype*/S_IRUSR in the patch files.
-+- Added perfctr_vector_init() to <asm-i386/perfctr.h>. Cleaned
-+  up arch/i386/kernel/i8259.c patch.
-+- Removed apic_lvtpc_irqs[] array. Removed irq.c patch.
-+- Updated CONFIG_PERFCTR_INIT_TESTS help text to match reality.
-+- Kernel 2.4.21-pre5 added set_cpus_allowed(), which required
-+  fixing compat24.h and x86_setup.c.
-+- Fixed init.c for kernel 2.5.63 removing EXPORT_NO_SYMBOLS.
-+- Cleaned up compat.h by moving 2.2/2.4 stuff to separate files.
-+
-+Version 2.5.0-pre1, 2003-02-19
-+- Repair global perfctr API: the target CPUs are now explicit
-+  in the calls to write control and read state. Global perfctrs
-+  now work on 2.5 SMP kernels (which no longer have smp_num_cpus
-+  or cpu_logical_map()), and HT P4s (asymmetric MPs).
-+- struct perfctr_info has new bitmask fields for the set of CPUs
-+  (cpu_online_map) and forbidden CPUs; dropped the nrcpus field.
-+- add cpu_online() compat macro to compat.h
-+- VPERFCTR_STOP is subsumed by VPERFCTR_CONTROL. Removed it.
-+- Detect K8 as K8 not K7. They are not identical.
-+- Makefile cleanup: moved 2.4/2.2 kernel stuff to Makefile24.
-+- Makefile fix: removed export-objs for 2.5 kernels.
-+- Kconfig fix: don't mention obsolete .o module suffix.
-+
-+Version 2.4.5, 2003-02-09
-+- Fixed two minor compile warnings in x86_tests.c for 2.5 kernels.
-+
-+Version 2.4.4, 2003-01-18
-+- Fixed a bug in iresume() where an interrupt-mode counter could
-+  increment unexpectedly, and also miss the overflow interrupt.
-+  The following setup would cause the problem:
-+      P1 has EVNTSELn in non-interrupt mode, counting some high-
-+  frequency event (e.g. INST_RETIRED) in kernel-mode. P2 has
-+  EVNTSELn in interrupt-mode, counting some low-frequency event
-+  (e.g. MMX_ASSIST) in user-mode. P1 suspends. Since EVNTSELn is
-+  in non-interrupt mode, it is not disabled. P2 resumes. First
-+  iresume() finds that the CPU cache ID is not P2's, so it reloads
-+  PERFCTRn with P2's restart value. Then write_control() reloads
-+  EVNTSELn with P2's EVNTSEL. At this point, P2's PERFCTRn has been
-+  counting with P1's EVNTSELn since iresume(), so it will no longer
-+  equal P2's restart value. And if PERFCTRn overflowed, the overflow
-+  will go undetected since P1's EVNTSELn was in non-interrupt mode.
-+      To avoid this problem, iresume() now ensures that a counter's
-+  control register is disabled before reloading the counter.
-+- Fixed some ugly log messages from the new HT P4 init code:
-+  * forbidden_mask would be printed as "0X<mask>" (capital X)
-+  * finalise_backpatching() could trigger a BUG! printk from
-+    p4_write_control() if the CPU the init code runs on was
-+    in the forbidden set. At init-time this is not an error.
-+    Avoided this by temporarily resetting the forbidden_mask.
-+- Added preliminary support for AMD K8 processors with the
-+  regular 32-bit x86 kernel. The K8 performance counters appear
-+  to be identical or very similar to the K7 performance counters.
-+
-+Version 2.4.3, 2002-12-11
-+- Added x86.c:perfctr_cpus_forbidden_mask. This bitmask describes
-+  the set of CPUs that must not access the perfctrs. On HT P4 MPs,
-+  only logical CPU #0 in each package is allowed access -- this
-+  avoids the resource conflict that would occur if both logical
-+  processors were to access the perfctrs. In other cases (UP or
-+  non-HT-P4 MPs) the mask is zero.
-+- vperfctr_control() now calls set_cpus_allowed() to ensure that
-+  the task stays away from CPUs in perfctr_cpus_forbidden_mask.
-+  This is racy with sys_sched_setaffinity(), and possibly some
-+  of the kernel's internal set_cpus_allowed() calls, but the race
-+  is unlikely to occur in current 2.4 kernels.
-+- Cleaned up the parameter passing protocol between vperfctr_ioctl()
-+  and the individual vperfctr "system call" procedures.
-+- Added safety check in global.c to disallow global-mode perfctrs
-+  on asymmetric MPs until the API has been fixed.
-+- Added set_cpus_allowed() implementation for 2.4 kernels, except
-+  those that already have it as indicated by HAVE_SET_CPUS_ALLOWED:
-+  this symbol is added to <linux/config.h> by the kernel patch.
-+- 2.2 kernels can't enforce CPU affinity masks, so x86.c warns if
-+  a HT P4 MP runs a 2.2 kernel, and falls back to generic x86 mode.
-+  Added dummy set_cpus_allowed() macro for 2.2 kernels.
-+- x86_compat.h now implements cpuid_ebx() and cpu_has_ht for old kernels.
-+- Makefile cleanup: Rules.make is obsolete in 2.5.
-+- Compile fixes in x86.c and virtual_stub.c: <linux/fs.h> needs to
-+  be included explicitly for the 2.5.50 kernel.
-+
-+Version 2.4.2, 2002-11-25
-+- Fixed virtual.c:inc_nrctrs() to handle the -EBUSY case correctly.
-+  If the HW was busy (e.g. global running), then the first attempt
-+  to open a vperfctr would fail but further attempts would succeed.
-+  Updated error propagation to distinguish -EBUSY from -ENOMEM.
-+- Updated global.c for preempt-safety.
-+- Made the driver safe for preemptible kernels. This required a lot
-+  of analysis, but resulted in relatively few actual code changes.
-+  (Backport from the perfctr-3.1 branch.)
-+- Ported to 2.5.48: Replaced MOD_INC_USE_COUNT by try_module_get()
-+  and MOD_DEC_USE_COUNT by module_put(). Updated compat.h.
-+- Ported to 2.5.45: added Kconfig, removed Config.help.
-+
-+Version 2.4.1, 2002-10-12
-+- RedHat 8.0's 2.4.18-14 kernel does EXPORT_SYMBOL(cpu_khz) while
-+  the vanilla 2.4.18 does not. This clashes with x86_setup.c's
-+  EXPORT_SYMBOL(cpu_khz). I've found no easy way to distinguish
-+  between these kernels at C preprocessing time, so I changed
-+  x86_setup.c to define a trivial perfctr_cpu_khz() function and
-+  EXPORT_SYMBOL that one instead.
-+
-+Version 2.4.0, 2002-09-26
-+- Config.help updated to state that Pentium 4 is supported.
-+- 2.5.32 moved ptrace_check_attach() declaration to <linux/ptrace.h>.
-+- Removed redundant /proc/<pid>/perfctr access control check
-+  from vperfctr_stub_open(). Since 2.4.0-pre1 this check didn't
-+  match the real one, which prevented remote opens when the
-+  driver was built as a module.
-+
-+Version 2.4.0-pre2, 2002-08-27
-+- vperfctr_control() now allows the user to specify that some PMC
-+  sums are not to be cleared when updating the control.
-+  There is a new bitmap field `preserve' in struct vperfctr_control:
-+  if bit i is set then PMC(i)'s sum is not cleared.
-+  `preserve' is a simple `unsigned long' for now, since this type
-+  fits all currently known CPU types.
-+  This change breaks binary compatibility, but user-space code which
-+  clears the entire control record before filling in relevant fields
-+  will continue to work as before after a recompile.
-+  This feature removes a limitation which some people felt was a
-+  problem for some usage scenarios.
-+
-+Version 2.4.0-pre1, 2002-08-12
-+- Initial implementation of a new remote-control API for virtual
-+  per-process perfctrs. A monitor process may access a target
-+  process' perfctrs via /proc/pid/perfctr and operations on that
-+  file, if the monitor holds the target under ptrace ATTACH control.
-+  Updated virtual.c to allow remote access.
-+  Updated x86.c:perfctr_cpu_ireload() to work also in the remote
-+  control case on SMP machines.
-+
-+Version 2.3.12, 2002-08-12
-+- Trivial comment fixes in compat.h and x86_compat.h.
-+- Removed __vperfctr_sample(), vperfctr_stub.sample, and bug_sample()
-+  from UP builds, since they are needed only on SMP.
-+
-+Version 2.3.11, 2002-07-21
-+- Accumulated sums are now maintained for interrupt-mode perfctrs.
-+  User-space can use the standard syscall-less algorithm for computing
-+  these counters' current sums, should that be needed.
-+
-+Version 2.3.10, 2002-07-19
-+- Added PERFCTR_X86_INTEL_P4M2 CPU type for Model 2 P4s, since
-+  they have ESCR Event Mask changes in a few events.
-+- The driver now supports replay tagging events on P4, using the
-+  pebs_enable and pebs_matrix_vert control fields added in 2.3.8.
-+- Some Pentium MMX and Pentium Pro processors have an erratum
-+  (Pentium erratum #74, Pentium Pro erratum 26) which causes SMM
-+  to shut down if CR4.PCE is set. intel_init() now clears the
-+  RDPMC feature on the affected steppings, to avoid the problem.
-+- perfctr_cpu_release() now clears the hardware registers and
-+  invalidates the per-cpu cache. This should allow the counter
-+  hardware to power down when not used, especially on P4.
-+- Callers of update_control() have no active i-mode counters.
-+  Documented this as a precondition, and changed update_control()
-+  to not call isuspend(). update_control() no longer needs hardware
-+  access, which should ease a port to CONFIG_PREEMPT=y.
-+
-+Version 2.3.9, 2002-06-27
-+- Updated p4_escr_addr() in x86.c to match the latest revision of
-+  Intel's IA32 Volume 3 manual, #245472-007. An error in previous
-+  revisions of this document caused the driver to program the wrong
-+  ESCR in some cases. (CCCRs 12/13/16 with ESCR_SELECT(2) were mapped
-+  to SSU_ESCR0 instead of RAT_ESCR0, affecting the uop_type event.)
-+
-+Version 2.3.8, 2002-06-26
-+- Added counter overflow interrupt support for Intel P4.
-+- 2.5.23 dropped smp_num_cpus and cpu_logical_map(). Added
-+  temporary workarounds to x86.c and global.c to allow compilation
-+  and testing under 2.5. May have to change the API (esp. global's)
-+  to be based on the sparse cpu_online_map instead.
-+- RedHat's 2.4.9-34 defines cpu_relax(). Updated compat.h.
-+- Added pebs_enable and pebs_matrix_vert fields (currently unused)
-+  to perfctr_cpu_control to support replay tagging events on P4.
-+  Updated the perfctr_cpu_state binary layout magic number.
-+- Silenced redefinition warnings for MSR_P6_PERFCTR0 and cpu_has_mmx.
-+- Updated Makefile for the 2.5.19 kernel's Makefile changes.
-+- Merged the P6 and K7 isuspend/iresume/write_control driver code.
-+- Added a VC3 specific clear_counters() procedure.
-+- Removed pointless code from perfctr_cpu_identify_overflow().
-+- Removed _vperfctr_get/set_thread() wrappers and thread->perfctr
-+  clobber checks from the DEBUG code. Removed unused "ibuf" and
-+  obsolete si_code fields from vperfctr state and control objects.
-+  Updated the vperfctr state magic number.
-+- Fixed the CONFIG_PREEMPT anti-dependency check in Config.in.
-+- vperfctr_control() now preserves the TSC sum on STOP;CONTROL
-+  transitions. The failure to do this caused problems for the
-+  PAPI P4 support being developed.
-+
-+Version 2.3.7, 2002-04-14
-+- Kernel 2.5.8-pre3 changed the way APIC/SMP interrupt entries
-+  are defined. Defining these with asm() in C is no longer
-+  practical, so the kernel patch for 2.5.8-pre3 now defines
-+  the perfctr interrupt entry in arch/i386/kernel/entry.S.
-+- Permit use of cascading counters on P4: in the slave counter
-+  one sets the CASCADE flag instead of the ENABLE flag.
-+- Added P4 hyperthreading bit field definitions.
-+- Preliminary infrastructure to support a new remote-control
-+  interface via ptrace(). Updates to compat.h, virtual.c,
-+  virtual_stub.c, and x86_setup.c. ptrace_check_attach()
-+  emulation for older kernels is in x86_setup.c since
-+  virtual_stub.c isn't compiled if the driver isn't a module.
-+
-+Version 2.3.6, 2002-03-21
-+- Rewrote sys_vperfctr_control() to do a proper suspend before
-+  updating the control, and to skip trying to preserve the TSC
-+  start value around the resume. This cleaned up the code and
-+  eliminated the bogus "BUG! resuming non-suspended perfctr"
-+  warnings that control calls to active perfctrs caused.
-+- Rewrote sys_vperfctr_iresume() to not preserve the TSC start
-+  value around the resume. Since we had just done a suspend(),
-+  this would cause double-accounting of the TSC.
-+
-+Version 2.3.5, 2002-03-17
-+- Added detection of the VIA C3 Ezra-T processor.
-+- CPU detection now uses current_cpu_data instead of boot_cpu_data,
-+  to avoid the boot_cpu_data.x86_vendor bug which is present is
-+  all current 2.2/2.4/2.5 kernels. The bug caused the x86_vendor
-+  field to be cleared on SMP machines, which in turn tricked the
-+  driver to identify MP AMD K7 machines as MP Intel P6, with
-+  disastrous results when the wrong MSRs were programmed.
-+- Updated compat.h for /proc/<pid>/ inode change in 2.5.4.
-+- Added a check to prevent building on preemptible 2.4/2.5 kernels,
-+  since the driver isn't yet safe for those.
-+- Put perfctr's configuration help text in Config.help in this
-+  directory: kernel 2.5.3-pre5 changed from a having a common
-+  Configure.help file to having local Config.help files.
-+
-+Version 2.3.4, 2002-01-23
-+- Updated virtual.c for remap_page_range() change in 2.5.3-pre1.
-+  Added emulation for older kernels to compat.h.
-+- Permit use of tagging on P4 for at-retirement counting. This may
-+  not yet work as expected, since up-stream (tag producing) counters
-+  aren't disabled at context switches: a process may therefore see
-+  more tagged uops than expected.
-+- Fixed uses of __FUNCTION__ to comply with changes in GCC 3.0.3.
-+
-+Version 2.3.3, 2001-12-31
-+- Minor x86.c cleanup: reordered function definitions so that
-+  write_control comes after isuspend/iresume: this makes it easier
-+  to follow the runtime control flow.
-+- Fixed isuspend()/iresume()'s broken cache checking protocol. The
-+  old protocol didn't handle process migration across CPUs in SMP
-+  machines correctly, as illustrated by the following scenario:
-+      P1 runs on CPU1 and suspends. P1 and CPU1 now have the same
-+  cache id (->k1.id). P1 is resumed and suspended on CPU2: the state
-+  in CPU1 is now stale. Then P1 is resumed on CPU1, and no other
-+  process has been using CPU1's performance counters since P1's last
-+  suspend on CPU1. The old protocol would see matching cache ids and
-+  that P1's i-mode EVNTSELs are stopped, so it would accept the cache
-+  and resume P1 with CPU1's stale PERFCTRS values.
-+      In the new protocol isuspend() records the active CPU in the
-+  state object, and iresume() checks if both the CPU and the control
-+  id match. The new protocol is also simpler since iresume() no longer
-+  checks if the i-mode EVNTSELs are cleared or not.
-+- P6 nasty i-mode to a-mode context switch bug fixed: p6_isuspend()
-+  used to simply clear EVNTSEL0's Enable flag in order to stop all
-+  i-mode counters. Unfortunately, that was insufficient as shown by
-+  the following case (which actually happened).
-+      P1 has EVNTSEL0 in a-mode and EVNTSEL1 in i-mode. P1 suspends:
-+  PERFCTR1 is stopped but EVNTSEL1 is still in i-mode. P2 has EVNTSEL0
-+  in a-mode and no EVNTSEL1. P2 resumes and updates EVNTSEL0. This
-+  activates not only P2's PERFCTR0 but also the dormant PERFCTR1. If
-+  PERFCTR1 overflows, then P2 will receive an unexpected interrupt. If
-+  PERFCTR1 doesn't overflow, but P2 suspends and P1 resumes, then P1
-+  will find that PERFCTR1 has a larger than expected value.
-+      p6_isuspend() and p6_iresume() were changed to ignore the global
-+  Enable flag and to disable/enable each i-mode EVNTSEL individually,
-+  just like how it's done on the K7.
-+- x86.c cleanups: P5MMX, MII, C6, VC3, P6, K7, and P4 now all
-+  use the same rdpmc_read_counters() method. VIA C3 now uses
-+  p6_write_control() instead of its own method.
-+- Removed "pmc_map[] must be identity" restriction from P6 and K7.
-+  The API uses the virtual counter index to distinguish a-mode
-+  and i-mode counters, but P6 events aren't entirely symmetric:
-+  this lead to some strange cases with the old pmc_map[] rule.
-+      P6 and K7 isuspend() now need access to the control, so
-+  update_control() and its callers had to be changed to allow it
-+  to isuspend() _before_ the new control is installed.
-+- P4 write_control fixes: changed the ESCR cache to be indexed by
-+  MSR offset from 0x3A0, and changed P4 write_control to index the
-+  CCCR/ESCR cache with physical instead of virtual indices. Added
-+  call to debug_evntsel_cache(), after updating it for pmc_map[].
-+- Added P4 and Generic support to x86_tests.c, and some cleanups.
-+
-+Version 2.3.2, 2001-11-19
-+- P4 fix: the mapping from CCCR 17 to its associated ESCRs was
-+  wrong due to an off-by-one error in x86.c:p4_escr_addr().
-+- P4 fix: also clear the PEBS MSRs when initialising the driver.
-+- Minor cleanup in x86.c: replaced the "clear MSRs" loops with
-+  calls to a helper procedure.
-+
-+Version 2.3.1, 2001-11-06
-+- Microscopic P4 cleanups. Testing on my new P4 box has confirmed
-+  that the PMAVAIL flag in MSR_IA32_MISC_ENABLE is read-only.
-+
-+Version 2.3, 2001-10-24
-+- Added support for multiple interrupt-mode virtual perfctrs
-+  with automatic restart. Added an identify_overflow() method
-+  to x86.c to identify and reset the overflowed counters.
-+  Added checks to ensure that the user-specified restart values
-+  for interrupt-mode counters are negative.
-+  Updated virtual.c's signal delivery interface to pass a
-+  bitmask describing which counters overflowed; the siginfo
-+  si_code is now fixed as SI_PMC_OVF (fault-class).
-+- Fixed some typos in x86.c. Added a note about the C3 Ezra.
-+- Added EXPORT_NO_SYMBOLS to init.c, for compatibility with
-+  announced changes in modutils 2.5.
-+
-+Version 2.2, 2001-10-09
-+- Added preliminary support for the Pentium 4. Only basic stuff
-+  for now: no cascading counters, overflow interrupts, tagged
-+  micro-ops, or use of DS/PEBS. The code compiles but hasn't been
-+  tested on an actual Pentium 4.
-+
-+Version 2.1.4, 2001-09-30
-+- No driver-level changes.
-+
-+Version 2.1.3, 2001-09-13
-+- Fixed a compilation problem where virtual_stub couldn't be compiled
-+  in modular kernels older than 2.2.20pre10 if KMOD was disabled, due
-+  to an incompatible stub definition of request_module().
-+- Replaced most occurrences of "VIA Cyrix III / C3" with "VIA C3".
-+
-+Version 2.1.2, 2001-09-05
-+- Added MODULE_LICENSE() tag, for compatibility with the tainted/
-+  non-tainted kernel stuff being put into 2.4.9-ac and modutils.
-+- VIA C3 support is not "preliminary" any more. Testing has revealed
-+  that the reserved bits in the C3's EVNTSEL1 have no function and
-+  need not be preserved. The driver now fills these bits with zeroes.
-+  (Thanks to Dave Jones @ SuSE for running these tests.)
-+- Minor bug fix in the perfctr interrupt assembly code.
-+  (Inherited from the 2.4 kernel. Fixed in 2.4.9-ac4.)
-+
-+Version 2.1.1, 2001-08-28
-+- Preliminary recognition of Pentium 4 processors, including
-+  checking the IA32_MISC_ENABLE MSR.
-+- Moved %cr4 access functions from <asm-i386/perfctr.h> to
-+  x86_compat.h, to work around changes in 2.4.9-ac3.
-+- More %cr4 cleanups possible since the removal of dodgy_tsc()
-+  in Version 2.1: moved {set,clear}_in_cr4_local() into x86.c,
-+  and eliminated the set_in_cr4() compat macro.
-+- Fixed a bug in x86.c:finalise_backpatching(): the fake cstatus
-+  mustn't include i-mode counters unless we have PCINT support.
-+  Failure to check this cased fatal init-time oopses in some
-+  configs (CONFIG_X86_UP_APIC set but no local APIC in the CPU).
-+- Minor comment updates in x86.c due to AMD #22007 Revision J.
-+- Removed '%' before 'cr4' in printouts from x86_tests.c, to
-+  avoid the '%' being mutated by log-reading user-space code.
-+
-+Version 2.1, 2001-08-19
-+- Fixed a call backpatching bug, caused by an incompatibility
-+  between the 2.4 and 2.2 kernels' xchg() macros. The 2.2 version
-+  lacks a "volatile" causing gcc to remove the entire statement
-+  if xchg() is used for side-effect only. Reverted to a plain
-+  assignment, which is safe since the 2.0.1 backpatching changes.
-+- Fixed a bug where an attempt to use /proc/<pid>/perfctr on an
-+  unsupported processor would cause a (well-behaved) kernel oops,
-+  due to calling a NULL function pointer in x86.c, vperfctr_open()
-+  now returns -ENODEV if virtual.c hasn't been initialised.
-+- Removed the WinChip configuration option, the dodgy_tsc() callback,
-+  and the clr_cap_tsc() x86_compat macro. WinChip users should configure
-+  for generic 586 or less and use the kernel's "notsc" boot parameter.
-+  This cleans up the driver and the 2.4 kernel patches, at the expense
-+  of more code in the 2.2 kernel patches to implement "notsc" support.
-+- Minor cleanup: moved version number definition from init.c to
-+  a separate file, version.h.
-+
-+Version 2.0.1, 2001-08-14
-+- The unsynchronised backpatching in x86.c didn't work on SMP,
-+  due to Pentium III erratum E49, and similar errata for other
-+  P6 processors. (The change in 2.0-pre6 was insufficient.)
-+  x86.c now finalises the backpatching at driver init time,
-+  by "priming" the relevant code paths. To make this feasible,
-+  the isuspend() and iresume() methods are now merged into
-+  the other high-level methods; virtual.c became a bit cleaner.
-+- Removed obsolete "WinChip pmc_map[] must be identity" check.
-+
-+Version 2.0, 2001-08-08
-+- Resurrected partial support for interrupt-mode virtual perfctrs.
-+  virtual.c permits a single i-mode perfctr, in addition to TSC
-+  and a number of a-mode perfctrs. BUG: The i-mode PMC must be last,
-+  which constrains CPUs like the P6 where we currently restrict
-+  the pmc_map[] to be the identity mapping. (Not a problem for
-+  K7 since it is symmetric, or P4 since it is expected to use a
-+  non-identity pmc_map[].)
-+  New perfctr_cpu_ireload() procedure to force reload of i-mode
-+  PMCs from their start values before resuming. Currently, this
-+  just invalidates the CPU cache, which forces the following
-+  iresume() and resume() to do the right thing.
-+  perfctr_cpu_update_control() now calls setup_imode_start_values()
-+  to "prime" i-mode PMCs from the control.ireset[] array.
-+- Bug fix in perfctr_cpu_update_control(): start by clearing cstatus.
-+  Prevents a failed attempt to update the control from leaving the
-+  object in a state with old cstatus != 0 but new control.
-+
-+Version 2.0-pre7, 2001-08-07
-+- Cleaned up the driver's debugging code (virtual, x86).
-+- Internal driver rearrangements. The low-level driver (x86) now handles
-+  sampling/suspending/resuming counters. Merged counter state (sums and
-+  start values) and CPU control data to a single "CPU state" object.
-+  This simplifies the high-level drivers, and permits some optimisations
-+  in the low-level driver by avoiding the need to buffer tsc/pmc samples
-+  in memory before updating the accumulated sums (not yet implemented).
-+- Removed the read_counters, write_control, disable_rdpmc, and enable_rdpmc
-+  methods from <asm/perfctr.h>, since they have been obsoleted by the
-+  new suspend/resume/sample methods.
-+- Rearranged the 'cstatus' encoding slightly by putting 'nractrs' in
-+  the low 7 bits; this was done because 'nractrs' is retrieved more
-+  often than 'nrctrs'.
-+- Removed the obsolete 'status' field from vperfctr_state. Exported
-+  'cstatus' and its access methods to user-space. (Remove the
-+  control.tsc_on/nractrs/nrictrs fields entirely?)
-+- Removed WinChip "fake TSC" support. The user-space library can now
-+  sample with slightly less overhead on sane processors.
-+- WinChip and VIA C3 now use p5mmx_read_counters() instead of their
-+  own versions.
-+
-+Version 2.0-pre6, 2001-07-27
-+- New patches for kernels 2.4.6, 2.4.7, and 2.4.7-ac1.
-+- Sampling bug fix for SMP. Normally processes are suspended and
-+  resumed many times per second, but on SMP machines it is possible
-+  for a process to run for a long time without being suspended.
-+  Since sampling is performed at the suspend and resume actions,
-+  a performance counter may wrap around more than once between
-+  sampling points. When this occurs, the accumulated counts will
-+  be highly variable and much lower than expected.
-+  A software timer is now used to ensure that sampling deadlines
-+  aren't missed on SMP machines. (The timer is run by the same code
-+  which runs the ITIMER_VIRTUAL interval timer.)
-+- Bug fix in the x86 "redirect call" backpatching routine. To be
-+  SMP safe, a bus-locked write to the code must be used.
-+- Bug fix in the internal debugging code (CONFIG_PERFCTR_DEBUG).
-+  The "shadow" data structure used to detect if a process' perfctr
-+  pointer has been clobbered could cause lockups with SMP kernels.
-+  Rewrote the code to be simpler and more robust.
-+- Minor performance tweak for the P5/P5MMX read counters procedures,
-+  to work around the P5's cache which doesn't allocate a cache line
-+  on a write miss.
-+- To avoid undetected data layout mismatches, the user-space library
-+  now checks the data layout version field in a virtual perfctr when
-+  it is being mmap:ed into the user's address space.
-+- A few minor cleanups.  
-+
-+Version 2.0-pre5, 2001-06-11
-+- Internally use a single 'cstatus' field instead of the three
-+  tsc_on/nractrs/nrictrs fields. Should reduce overhead slightly.
-+- Reorder the fields in cpu_control so that 'cstatus' and other
-+  frequently used fields get small offsets -- avoids some disp32
-+  addressing modes in timing-critical code.
-+- Fixed a bug in p6_iresume where it forgot to invalidate the
-+  EVNTSEL cache, causing p6_write_control to fail to reload the
-+  MSRs. (K7 had a similar bug.) Since i-mode support is disabled
-+  at the moment, no-one was actually bitten by this.
-+- Fixed another iresume/write_control cache invalidation bug where a
-+  switch to an "uninitialised" CPU would fail to initialise the MSRs.
-+- Added a CONFIG_PERFCTR_DEBUG option to enable internal consistency
-+  checks. Currently, this checks that a task's vperfctr pointer
-+  isn't clobbered behind our backs, that resume and suspend for
-+  a vperfctr are performed on the same CPU, and that the EVNTSEL
-+  cache is semi-consistent when reloading is optimised away.
-+  ("semi" because it only checks that the cache agrees with the
-+  user's control data, and not that the cache agrees with the MSRs.)
-+- Minor cleanups.
-+
-+Version 2.0-pre4, 2001-04-30
-+- Cleanups in x86.c. #defines introduced for magic constants.
-+  More sharing of procedures between different CPU drivers.
-+  Fixed a bug where k7_iresume() could cause k7_write_control()
-+  to fail to reload the correct EVNTSELs.
-+  The WinChip C6/2/3 driver now "fakes" an incrementing TSC.
-+- General cleanups: s/__inline__/inline/ following Linux kernel
-+  coding standards, and renamed the low-level control objects to
-+  cpu_control to distinguish them from {v,g}perfctr_control objects.
-+- O_CREAT is now interpreted when /proc/self/perfctr is opened:
-+  if the vperfctr does not exist, then it is created; if the
-+  vperfctr does exist, then EEXIST is returned (unfortunately
-+  O_EXCL doesn't work, since it's intercepted by the VFS layer).
-+  "perfex -i" uses this to avoid having to create a vperfctr when
-+  only an INFO command is to be issued.
-+  libperfctr.c:vperfctr_open() uses this to decide whether to
-+  UNLINK the newly opened vperfctr in case of errors or not.
-+- Cleaned up virtual.c's 2.4/2.2 VFS interface code a little,
-+  and eliminated the OWNER_THIS_MODULE compat macro.
-+- Added MOD_{INC,DEC}_USE_COUNTs to virtual.c's file_operations
-+  open and release procedures for 2.2 kernels. This should
-+  simulate 2.4's fops_get/put at >open() and >release().
-+
-+Version 2.0-pre3, 2001-04-17
-+- Interrupt-mode virtual perfctrs are temporarily disabled since
-+  x86.c doesn't yet detect which PMC overflowed. The old API
-+  could be made to work, but it was broken anyway.
-+- Integrated the new P4-ready data structures and APIs.
-+  The driver compiles but the user-space stuff hasn't been
-+  updated yet, so there may be some remaining bugs.
-+
-+  I have not yet committed to all details of this API. Some
-+  things, like accumulating counters in virtual.c and global.c,
-+  are uglier now, and going from a single "status == nrctrs"
-+  field to three separate fields (tsc_on, nrctrs, nrictrs)
-+  cannot be good for performance.
-+
-+  In the new API the control information is split in separate
-+  arrays depending on their use, i.e. a struct-of-arrays layout
-+  instead of an array-of-struct layout. The advantage of the
-+  struct-of-arrays layout is that it should cause fewer cache
-+  lines to be touched at the performance-critical operations.
-+  The disadvantage is that the layout changes whenever the
-+  number of array elements has to be increased -- as is the
-+  case for the future Pentium 4 support (18 counters).
-+
-+Version 2.0-pre2, 2001-04-07
-+- Removed automatic inheritance of per-process virtual perfctrs
-+  across fork(). Unless wait4() is modified, it's difficult to
-+  communicate the final values back to the parent: the now
-+  abandoned code did this in a way which made it impossible
-+  to distinguish one child's final counts from another's.
-+  Inheritance can be implemented in user-space anyway, so the
-+  loss is not great. The interface between the driver and the rest
-+  of the kernel is now smaller and simpler than before.
-+- Simulating cpu_khz by a macro in very old kernels broke since
-+  there's also a struct field with that name :-( Instead of
-+  putting the ugly workaround back in, I decided to drop support
-+  for kernels older than 2.2.16.
-+- Preliminary support for the VIA C3 processor -- the C3 is
-+  apparently a faster version of the VIA Cyrix III.
-+- Added rdtsc cost deduction to the init tests code, and changed
-+  it to output per-instruction costs as well.
-+- More cleanups, making 2.2 compatibility crud less visible.
-+
-+Version 2.0-pre1, 2001-03-25
-+- First round of API and coding changes/cleanups for version 2.0:
-+  made perfctr_info.version a string, moved some perfctr_info inits
-+  to x86.c and eliminated some redundant variables, removed dead VFS
-+  code from virtual.c, removed obsolete K7 tests from x86_tests.c,
-+  removed mmu_cr4_features wrappers from x86_compat.h, minor cleanup
-+  in virtual_stub.c.
-+- Fixed an include file problem which made some C compilers (not gcc)
-+  fail when compiling user-space applications using the driver.
-+- Added missing EXPORT_SYMBOL declarations needed by the UP-APIC PM
-+  code when the driver is built as a module.
-+- Preliminary changes in x86.c to deal with UP-APIC power management
-+  issues in 2.4-ac kernels. The PM callback is only a stub for now.
-+
-+Version 1.9, 2001-02-13
-+- Fixed compilation problems for 2.2 and SMP kernels.
-+- Found updated documentation on "VIA Cyrix III". Apparently, there
-+  are two distinct chips: the older Joshua (a Cyrix design) and the
-+  newer Samuel (a Centaur design). Our current code supported Joshua,
-+  but mistook Samuel for Joshua. Corrected the identification of Samuel
-+  and added explicit support for it. Samuel's EVNTSEL1 is not well-
-+  documented, so there are some new Samuel-specific tests in x86_tests.c.
-+- Added preliminary interrupt-mode support for AMD K7.
-+- Small tweaks to virtual.c's interrupt handling.
-+
-+Version 1.8, 2001-01-23
-+- Added preliminary interrupt-mode support to virtual perfctrs.
-+  Currently for P6 only, and the local APIC must have been enabled.
-+  Tested on 2.4.0-ac10 with CONFIG_X86_UP_APIC=y.
-+  When an i-mode vperfctr interrupts on overflow, the counters are
-+  suspended and a user-specified signal is sent to the process. The
-+  user's signal handler can read the trap pc from the mmap:ed vperfctr,
-+  and should then issue an IRESUME ioctl to restart the counters.
-+  The next version will support buffering and automatic restart.
-+- Some cleanups in the x86.c init and exit code. Removed the implicit
-+  smp_call_function() calls from x86_compat.h.
-+
-+Version 1.7, 2001-01-01
-+- Updated Makefile for 2.4.0-test13-pre3 Rules.make changes.
-+- Removed PERFCTR_ATTACH ioctl from /dev/perfctr, making the
-+  vperfctrs only accessible via /proc/self/perfctr. Removed
-+  the "attach" code from virtual.c, and temporarily commented
-+  out the "vperfctr fs" code. Moved /dev/perfctr initialisation
-+  and implementation from init.c to global.c.
-+- Eliminated CONFIG_VPERFCTR_PROC, making /proc/pid/perfctr
-+  mandatory if CONFIG_PERFCTR_VIRTUAL is set.
-+- Some 2.2/2.4 compatibility cleanups.
-+- VIA Cyrix III detection bug fix. Contrary to VIA's documentation,
-+  the Cyrix III vendor field is Centaur, not Cyrix.
-+
-+Version 1.6, 2000-11-21
-+- Preliminary implementation of /proc/pid/perfctr. Seems to work,
-+  but virtual.c and virtual_stub.c is again filled with
-+  #if LINUX_VERSION_CODE crap which will need to be cleaned up.
-+  The INFO ioctl is now implemented by vperfctrs too, to avoid the
-+  need for opening /dev/perfctr.
-+- virtual.c now puts the perfctr pointer in filp->private_data
-+  instead of inode->u.generic_ip. The main reason for this change
-+  is that proc-fs places a dentry pointer in inode->u.generic_ip.
-+- sys_vperfctr_control() no longer resets the virtual TSC
-+  if it already is active. The virtual TSC therefore runs
-+  continuously from its first activation until the process
-+  stops or unlinks its vperfctrs.
-+- Updates for 2.4.0-test11pre6. Use 2.4-style cpu_has_XXX
-+  feature testing macros. Updated x86_compat.h to implement
-+  missing cpu_has_mmx and cpu_has_msr, and compatibility
-+  macros for 2.2. Changed vperfctr_fs_read_super() to use
-+  new_inode(sb) instead of get_empty_inode() + some init code.
-+- Updates for 2.4.0-test9. Fixed x86_compat.h for cpu_khz change.
-+  Since drivers/Makefile was converted to the new list style,
-+  it became more difficult to handle CONFIG_PERFCTR=m. Changed
-+  Config.in to set CONFIG_KPERFCTR=y when CONFIG_PERFCTR != n,
-+  resulting in a much cleaner kernel patch for 2.4.0-test9.
-+- Removed d_alloc_root wrapper since 2.2 doesn't need it any more.
-+- When building for 2.2.18pre, use some of its 2.4 compatibility
-+  features (module_init, module_exit and DECLARE_MUTEX).
-+- Updates for 2.4.0-test8: repaired kernel patch for new parameter
-+  in do_fork, and fixed CLONE_PERFCTR conflict with CLONE_THREAD.
-+
-+Version 1.5, 2000-09-03
-+- Dropped support for intermediate 2.3 and early 2.4.0-test kernels.
-+  The code now supports kernels 2.2.xx and 2.4.0-test7 or later only.
-+  Cleanups in compat.h and virtual.c.
-+- Rewrote the Makefile to use object file lists instead of conditionals.
-+  This gets slightly hairy since kernel extensions are needed even
-+  when the driver proper is built as a module.
-+- Removed the definition of CONFIG_PERFCTR_X86 from Config.in.
-+  Use the 2.4 standard CONFIG_X86 instead. The 2.2.xx kernel
-+  patches now define CONFIG_X86 in arch/i386/config.in.
-+- Cleaned up the vperfctr inheritance filter. Instead of setting
-+  a disable flag (CLONE_KTHREAD) when kernel-internal threads are
-+  created, I now set CLONE_PERFCTR in sys_fork and sys_vfork.
-+- /dev/perfctr no longer accepts the SAMPLE and UNLINK ioctls.
-+  All operations pertaining to a process' virtual perfctrs must
-+  be applied to the fd returned from the ATTACH ioctl.
-+- Removed the remote-control features from the virtual perfctrs.
-+  Significant simplifications in virtual.c. Removed some now
-+  unused stuff from compat.h and virtual_stub.c.
-+
-+Version 1.4, 2000-08-11
-+- Fixed a memory leak bug in virtual.c. An extraneous dget() in
-+  get_vperfctr_filp() prevented reclaiming the dentry and inode
-+  allocated for a vperfctr file.
-+- Major changes to the VFS interface in virtual.c. Starting with
-+  2.4.0-test6, inode->i_sb == NULL no longer works. Added code to
-+  register a "vperfctr" fs and define a superblock and a mount point.
-+  Completely rewrote the dentry init code. Most of the new code is
-+  adapted from fs/pipe.c, with simplifications and macros to continue
-+  supporting 2.2.x kernels. `ls -l /proc/*/fd/' now prints recognizable
-+  names for vperfctr files.
-+- Cleaned up virtual.c slightly. Removed "#if 1" tests around the
-+  vperfctr inheritance code. Rewrote vperfctr_alloc and vperfctr_free
-+  to use the virt_to_page and {Set,Clear}PageReserved macros;
-+  also updated compat.h to provide these for older kernels.
-+- Updated for 2.4.0-test3: a dummy `open' file operation is no longer
-+  required by drivers/char/misc.c.
-+- Updated for `owner' field in file_operations added in 2.4.0-test2.
-+  Removed MOD_{INC,DEC}_USE_COUNT from init.c (except when compiling
-+  for 2.2.x) and virtual.c. Added MOD_{INC,DEC}_USE_COUNT to the
-+  reserve/release functions in x86.c -- needed because the driver
-+  may be active even if no open file refers to it. Using can_unload
-+  in the module struct instead is possible but not as tidy.
-+
-+Version 1.3, 2000-06-29
-+- Implemented inheritance for virtual perfctrs: fork() copies the
-+  evntsel data to the child, exit() stops the child's counters but
-+  does not detach the vperfctr object, and wait() adds the child's
-+  counters to the parent's `children' counters.
-+  Added a CLONE_KTHREAD flag to prevent inheritance to threads
-+  created implicitly by request_module() and kernel_thread().
-+- Fixed a half-broken printk() in x86_tests.c.
-+- Added checks to virtual.c to prevent the remote-control interface
-+  from trying to activate dead vperfctrs.
-+- Updated vperfctr_attach() for changes in 2.3.99-pre7 and 2.4.0-test2.
-+- Fixed a problem introduced in 1.2 which caused linker errors if
-+  CONFIG_PERFCTR=m and CONFIG_PERFCTR_INIT_TESTS=y.
-+- Export CPU kHz via a new field in PERFCTR_INFO ioctl, to enable
-+  user-space to map accumulated TSC counts to actual time.
-+
-+Version 1.2, 2000-05-24
-+- Added support for generic x86 processors with a time-stamp counter
-+  but no performance-monitoring counters. By using the driver to
-+  virtualise the TSC, accurate cycle-count measurements are now
-+  possible on PMC-less processors like the AMD K6.
-+- Removed some of the special-casing of the x86 time-stamp counter.
-+  It's now "just another counter", except that no evntsel is
-+  needed to enable it.
-+- WinChip bug fix: the "fake TSC" code would increment an
-+  uninitialised counter.
-+- Reorganised the x86 driver. Moved the optional init-time testing
-+  code to a separate source file.
-+- Miscellaneous code cleanups and naming convention changes.
-+
-+Version 1.1, 2000-05-13
-+- vperfctr_attach() now accepts pid 0 as an alias for the current
-+  process. This reduces the number of getpid() calls needed in
-+  the user-space library. (Suggested by Ulrich Drepper.)
-+- Added support for the VIA Cyrix III processor.
-+- Tuned the x86 driver interface. Replaced function pointers
-+  with stubs which rewrite callers to invoke the correct callees.
-+- Added ARRAY_SIZE definition to compat.h for 2.2.x builds.
-+- Updated for 2.3.48 inode changes.
-+- Moved code closer to 2.3.x coding standards. Removed init_module
-+  and cleanup_module, added __exit, module_init, and module_exit,
-+  and extended "compat.h" accordingly. Cleaned up <linux/perfctr.h>
-+  and <asm-i386/perfctr.h> a little.
-+
-+Version 1.0, 2000-01-31
-+- Prepared the driver to cope with non-x86 architectures:
-+  - Moved generic parts of <asm-i386/perfctr.h> to <linux/perfctr.h>.
-+  - Merged driver's private "x86.h" into <asm-i386/perfctr.h>.
-+  - Config.in now defines CONFIG_PERFCTR_${ARCH}, and Makefile uses
-+    it to select appropriate arch-dependent object files
-+- The driver now reads the low 32 bits of the counters,
-+  instead of 40 or 48 bits zero-extended to 64 bits.
-+  Sums are still 64 bits. This was done to reduce the number
-+  of cache lines needed for certain data structures, to
-+  simplify and improve the performance of the sampling
-+  procedures, and to change 64+(64-64) arithmetic to 64+(32-32)
-+  for the benefit of gcc on x86. This change doesn't reduce
-+  precision, as long as no event occurs more than 2^32 times
-+  between two sampling points.
-+- PERFCTR_GLOBAL_READ now forces all CPUs to be sampled, if the
-+  sampling timer isn't running.
-+
-+Version 0.11, 2000-01-30
-+- Added a missing EXPORT_SYMBOL which prevented the driver
-+  from being built as a module in SMP kernels.
-+- Support for the CPU sampling instructions (i.e. RDPMC and
-+  RDTSC on x86) is now announced explicitly by PERFCTR_INFO.
-+- The x86 hardware driver now keeps CR4.PCE globally enabled.
-+  There are two reasons for this. First, the cost of toggling
-+  this flag at process suspend/resume is high. Second, changes
-+  in kernel 2.3.40 imply that any processor's %cr4 may be updated
-+  asynchronously from the global variable mmu_cr4_features.
-+
-+Version 0.10, 2000-01-23
-+- Added support for global-mode perfctrs (global.c).
-+- There is now a config option controlling whether to
-+  perform init-time hardware tests or not.
-+- Added a hardware reserve/release mechanism so that multiple
-+  high-level services don't simultaneously use the hardware.
-+- The driver is now officially device <char,major 10,minor 182>.
-+- Tuned the 64-bit tsc/msr/pmc read operations in x86.c.
-+- Support for virtual perfctrs can now be enabled or disabled
-+  via CONFIG_PERFCTR_VIRTUAL.
-+- Added support for the WinChip 3 processor.
-+- Split the code into several files: x86.c (x86 drivers),
-+  virtual.c (virtualised perfctrs), setup.c (boot-time actions),
-+  init.c (driver top-level and init code).
-+
-+Version 0.9, 2000-01-02
-+- The driver can now be built as a module.
-+- Dropped sys_perfctr() system call and went back to using a
-+  /dev/perfctr character device. Generic operations are now
-+  ioctl commands on /dev/perfctr, and control operations on
-+  virtual perfctrs are ioctl commands on their file descriptors.
-+  Initially this change was done because new system calls in 2.3.x
-+  made maintenance and binary compatibility with 2.2.x hard, but
-+  the new API is actually cleaner than the previous system call.
-+- Moved this code from arch/i386/kernel/ to drivers/perfctr/.
-+
-+Version 0.8, 1999-11-14
-+- Made the process management callback functions inline to
-+  reduce scheduling overhead for processes not using perfctrs.
-+- Changed the 'status' field to contain the number of active
-+  counters. Changed read_counters, write_control, and accumulate
-+  to use this information to avoid unnecessary work.
-+- Fixed a bug in k7_check_control() which caused it to
-+  require all four counters to be enabled.
-+- Fixed sys_perfctr() to return -ENODEV instead of -ENOSYS
-+  if the processor doesn't support perfctrs.
-+- Some code cleanups.
-+- Evntsel MSRs are updated lazily, and counters are not written to.
-+
-+  The following table lists the costs (in cycles) of various
-+  instructions which access the counter or evntsel registers.
-+  The table was derived from data collected by init-time tests
-+  run by previous versions of this driver.
-+
-+  Processor		P5	P5MMX	PII	PIII	K7
-+  Clock freq. (MHz)	133	233	266	450	500
-+
-+  RDPMC			n/a	14	31	36	13
-+  RDMSR (counter)	29	28	81	80	52
-+  WRMSR (counter)	35	37	97	115	80
-+  WRMSR (evntsel)	33	37	88	105	232
-+
-+  Several things are apparent from this table:
-+
-+  1. It's much cheaper to use RDPMC than RDMSR to read the counters.
-+  2. It's much more expensive to reset a counter than to read it.
-+  3. It's expensive to write to an evntsel register.
-+
-+  As of version 0.8, this driver uses the following strategies:
-+  * The evntsel registers are updated lazily. A per_cpu_control[]
-+    array caches the contents of each CPU's evntsel registers,
-+    and only when a process requires a different setup are the
-+    evntsel registers written to. In most cases, this eliminates the
-+    need to reprogram the evntsel registers when switching processes.
-+    The older drivers would write to the evntsel registers both at
-+    process suspend and resume.
-+  * The counter registers are read both at process resume and suspend,
-+    and the difference is added to the process' accumulated counters.
-+    The older drivers would reset the counters at resume, read them
-+    at suspend, and add the values read to the accumulated counters.
-+  * Only those registers enabled by the user's control information
-+    are manipulated, instead of blindly manipulating all of them.
-+
-+Version 0.7 1999-10-25
-+- The init-time checks in version 0.6 of this driver showed that
-+  RDMSR is a lot slower than RDPMC for reading the PMCs. The driver
-+  now uses RDPMC instead of RDMSR whenever possible.
-+- Added an mmap() operation to perfctr files. This allows any client
-+  to read the accumulated counter state without making a system call.
-+  The old "sync to user-provided buffer" method has been removed,
-+  as it entailed additional copy operations and only worked for the
-+  "active" process. The PERFCTR_READ operation has been replaced
-+  by a simpler PERFCTR_SAMPLE operation, for the benefit of pre-MMX
-+  Intel P5 processors which cannot sample counters in user-mode.
-+  This rewrite actually simplified the code.
-+- The AMD K7 should now be supported correctly. The init-time checks
-+  in version 0.6 of this driver revealed that each K7 counter has
-+  its own ENable bit. (Thanks to Nathan Slingerland for running the
-+  test and reporting the results to me.)
-+- Plugged a potential memory leak in perfctr_attach_task().
-+- No longer piggyback on prctl(); sys_perfctr() is a real system call.
-+- Some code cleanups.
-+
-+Version 0.6 1999-09-08
-+- Temporarily added some init-time code that checks the
-+  costs of RDPMC/RDMSR/WRMSR operations applied to perfctr MSRs,
-+  the semantics of the ENable bit on the Athlon, and gets
-+  the boot-time value of the WinChip CESR register.
-+  This code can be turned off by #defining INIT_DEBUG to 0.
-+- Preliminary support for the AMD K7 Athlon processor.
-+- The code will now build in both 2.3.x and 2.2.x kernels.
-+
-+Version 0.5 1999-08-29
-+- The user-space buffer is updated whenever state.status changes,
-+  even when a remote command triggers the change.
-+- Reworked and simplified the high-level code. All accesses
-+  now require an attached file in order to implement proper
-+  accounting and syncronisation. The only exception is UNLINK:
-+  a process may always UNLINK its own PMCs.
-+- Fixed counting bug in sys_perfctr_read().
-+- Improved support for the Intel Pentium III.
-+- Another WinChip fix: fake TSC update at process resume.
-+- The code should now be safe for 'gcc -fstrict-aliasing'.
-+
-+Version 0.4 1999-07-31
-+- Implemented PERFCTR_ATTACH and PERFCTR_{READ,CONTROL,STOP,UNLINK}
-+  on attached perfctrs. An attached perfctr is represented as a file.
-+- Fixed an error in the WinChip-specific code.
-+- Perfctrs now survive exec().
-+
-+Version 0.3 1999-07-22
-+- Interface now via sys_prctl() instead of /dev/perfctr.
-+- Added NYI stubs for accessing other processes' perfctrs.
-+- Moved to dynamic allocation of a task's perfctr state.
-+- Minor code cleanups.
-+
-+Version 0.2 1999-06-07
-+- Added support for WinChip CPUs.
-+- Restart counters from zero, not their previous values. This
-+  corrected a problem for Intel P6 (WRMSR writes 32 bits to a PERFCTR
-+  MSR and then sign-extends to 40 bits), and also simplified the code.
-+- Added support for syncing the kernel's counter values to a user-
-+  provided buffer each time a process is resumed. This feature, and
-+  the fact that the driver enables RDPMC in processes using PMCs,
-+  allows user-level computation of a process' accumulated counter
-+  values without incurring the overhead of making a system call.
-+
-+Version 0.1 1999-05-30
-+- First public release.
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/compat24.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/compat24.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/compat24.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,97 @@
-+/* $Id: compat24.h,v 1.22.2.1 2004/07/26 14:05:49 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Compatibility definitions for 2.4 kernels.
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+#include <linux/mm.h>	/* for remap_page_range() [redefined here] */
-+
-+#include "cpumask.h"
-+
-+/* 2.4.18-redhat had BUG_ON() before 2.4.19 */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) && !defined(BUG_ON)
-+#define BUG_ON(condition)	do { if ((condition) != 0) BUG(); } while(0)
-+#endif
-+
-+/* 2.4.18-redhat had set_cpus_allowed() before 2.4.21-pre5 */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) && !defined(HAVE_SET_CPUS_ALLOWED)
-+#if defined(CONFIG_SMP)
-+extern void set_cpus_allowed(struct task_struct*, unsigned long);
-+#else
-+#define set_cpus_allowed(tsk, mask)	do{}while(0)
-+#endif
-+#endif
-+
-+/* 2.4.20-8-redhat added cpu_online() */
-+#if !defined(cpu_online)
-+#define cpu_online(cpu)		(cpu_online_map & (1UL << (cpu)))
-+#endif
-+
-+/* 2.4.20-8-redhat added put_task_struct() */
-+#if defined(put_task_struct)	/* RH 2.4.20-8 */
-+#define EXPORT_SYMBOL___put_task_struct	EXPORT_SYMBOL(__put_task_struct)
-+#else				/* standard 2.4 */
-+#define put_task_struct(tsk)	free_task_struct((tsk))
-+#define EXPORT_SYMBOL___put_task_struct	/*empty*/
-+#endif
-+
-+/* remap_page_range() changed in 2.5.3-pre1 and 2.4.20-8-redhat */
-+#if !defined(HAVE_5ARG_REMAP_PAGE_RANGE)
-+static inline int perfctr_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_t prot)
-+{
-+	return remap_page_range(from, to, size, prot);
-+}
-+#undef remap_page_range
-+#define remap_page_range(vma,from,to,size,prot) perfctr_remap_page_range((vma),(from),(to),(size),(prot))
-+#endif
-+
-+/* 2.4.22-rc1 added EXPORT_SYMBOL(mmu_cr4_features) */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,22) || defined(HAVE_EXPORT_mmu_cr4_features)
-+#define EXPORT_SYMBOL_mmu_cr4_features	/*empty*/
-+#else
-+#define EXPORT_SYMBOL_mmu_cr4_features	EXPORT_SYMBOL(mmu_cr4_features)
-+#endif
-+
-+/* not in 2.4 proper, but some people use 2.4 with preemption patches */
-+#ifdef CONFIG_PREEMPT
-+#error "not yet ported to 2.4+PREEMPT"
-+#endif
-+#ifndef preempt_disable
-+#define preempt_disable()	do{}while(0)
-+#define preempt_enable()	do{}while(0)
-+#endif
-+
-+#ifdef MODULE
-+#define __module_get(module)	do { if ((module)) __MOD_INC_USE_COUNT((module)); } while(0)
-+#define module_put(module)	do { if ((module)) __MOD_DEC_USE_COUNT((module)); } while(0)
-+#else
-+#define __module_get(module)	do{}while(0)
-+#define module_put(module)	do{}while(0)
-+#endif
-+
-+#define MODULE_ALIAS(alias)	/*empty*/
-+
-+/* introduced in 2.5.64; backported to 2.4.22-1.2115.nptl (FC1) */
-+static inline int
-+perfctr_on_each_cpu(void (*func) (void *info), void *info,
-+		    int retry, int wait)
-+{
-+        int ret = 0;
-+
-+        preempt_disable();
-+        ret = smp_call_function(func, info, retry, wait);
-+        func(info);
-+        preempt_enable();
-+        return ret;
-+}
-+#undef on_each_cpu
-+#define on_each_cpu(f,i,r,w)	perfctr_on_each_cpu((f),(i),(r),(w))
-+
-+/* 2.6.4 added 'noinline' */
-+#if !defined(noinline)
-+#if __GNUC__ == 3 && __GNUC_MINOR__ >= 1
-+#define noinline	__attribute__((noinline))
-+#else
-+#define noinline	/* unimplemented */
-+#endif
-+#endif
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/init.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/init.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/init.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,216 @@
-+/* $Id: init.c,v 1.68 2004/01/11 22:12:09 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Top-level initialisation code.
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/fs.h>
-+#include <linux/init.h>
-+#include <linux/miscdevice.h>
-+#include <linux/sched.h>
-+#include <linux/perfctr.h>
-+
-+#include <asm/uaccess.h>
-+
-+#include "compat.h"
-+#include "virtual.h"
-+#include "global.h"
-+#include "version.h"
-+#include "marshal.h"
-+
-+MODULE_AUTHOR("Mikael Pettersson <mikpe@csd.uu.se>");
-+MODULE_DESCRIPTION("Performance-monitoring counters driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("char-major-10-182");
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,63)
-+EXPORT_NO_SYMBOLS;
-+#endif
-+
-+#ifdef CONFIG_PERFCTR_DEBUG
-+#define VERSION_DEBUG " DEBUG"
-+#else
-+#define VERSION_DEBUG
-+#endif
-+
-+struct perfctr_info perfctr_info = {
-+	.abi_version = PERFCTR_ABI_VERSION,
-+	.driver_version = VERSION VERSION_DEBUG,
-+};
-+
-+char *perfctr_cpu_name __initdata;
-+
-+int sys_perfctr_abi(unsigned int *argp)
-+{
-+	if( put_user(PERFCTR_ABI_VERSION, argp) )
-+		return -EFAULT;
-+	return 0;
-+}
-+
-+int sys_perfctr_info(struct perfctr_struct_buf *argp)
-+{
-+	return perfctr_copy_to_user(argp, &perfctr_info, &perfctr_info_sdesc);
-+}
-+
-+static int cpus_copy_to_user(const cpumask_t *cpus, struct perfctr_cpu_mask *argp)
-+{
-+	const unsigned int k_nrwords = PERFCTR_CPUMASK_NRLONGS*(sizeof(long)/sizeof(int));
-+	unsigned int u_nrwords;
-+	unsigned int ui, ki, j;
-+
-+	if( get_user(u_nrwords, &argp->nrwords) )
-+		return -EFAULT;
-+	if( put_user(k_nrwords, &argp->nrwords) )
-+		return -EFAULT;
-+	if( u_nrwords < k_nrwords )
-+		return -EOVERFLOW;
-+	for(ui = 0, ki = 0; ki < PERFCTR_CPUMASK_NRLONGS; ++ki) {
-+		unsigned long mask = cpus_addr(*cpus)[ki];
-+		for(j = 0; j < sizeof(long)/sizeof(int); ++j) {
-+			if( put_user((unsigned int)mask, &argp->mask[ui]) )
-+				return -EFAULT;
-+			++ui;
-+			mask = (mask >> (8*sizeof(int)-1)) >> 1;
-+		}
-+	}
-+	return 0;
-+}
-+
-+int sys_perfctr_cpus(struct perfctr_cpu_mask *argp)
-+{
-+	cpumask_t cpus = cpu_online_map;
-+	return cpus_copy_to_user(&cpus, argp);
-+}
-+
-+int sys_perfctr_cpus_forbidden(struct perfctr_cpu_mask *argp)
-+{
-+	cpumask_t cpus = perfctr_cpus_forbidden_mask;
-+	return cpus_copy_to_user(&cpus, argp);
-+}
-+
-+#ifdef CONFIG_IA32_EMULATION
-+#include <asm/ioctl32.h>
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23)
-+static int perfctr_ioctl32_handler(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
-+{
-+	/* filp->f_op->ioctl is known to exist; see sys32_ioctl() */
-+	return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
-+}
-+#else
-+#define perfctr_ioctl32_handler	0
-+#endif
-+
-+static void __init perfctr_register_ioctl32_conversions(void)
-+{
-+	int err;
-+
-+	err  = register_ioctl32_conversion(PERFCTR_ABI, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(PERFCTR_INFO, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(PERFCTR_CPUS, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(PERFCTR_CPUS_FORBIDDEN, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(VPERFCTR_CREAT, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(VPERFCTR_OPEN, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(VPERFCTR_READ_SUM, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(VPERFCTR_UNLINK, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(VPERFCTR_CONTROL, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(VPERFCTR_IRESUME, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(VPERFCTR_READ_CONTROL, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(GPERFCTR_CONTROL, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(GPERFCTR_READ, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(GPERFCTR_STOP, perfctr_ioctl32_handler);
-+	err |= register_ioctl32_conversion(GPERFCTR_START, perfctr_ioctl32_handler);
-+	if( err )
-+		printk(KERN_ERR "perfctr: register_ioctl32_conversion() failed\n");
-+}
-+
-+static void __exit perfctr_unregister_ioctl32_conversions(void)
-+{
-+	unregister_ioctl32_conversion(PERFCTR_ABI);
-+	unregister_ioctl32_conversion(PERFCTR_INFO);
-+	unregister_ioctl32_conversion(PERFCTR_CPUS);
-+	unregister_ioctl32_conversion(PERFCTR_CPUS_FORBIDDEN);
-+	unregister_ioctl32_conversion(VPERFCTR_CREAT);
-+	unregister_ioctl32_conversion(VPERFCTR_OPEN);
-+	unregister_ioctl32_conversion(VPERFCTR_READ_SUM);
-+	unregister_ioctl32_conversion(VPERFCTR_UNLINK);
-+	unregister_ioctl32_conversion(VPERFCTR_CONTROL);
-+	unregister_ioctl32_conversion(VPERFCTR_IRESUME);
-+	unregister_ioctl32_conversion(VPERFCTR_READ_CONTROL);
-+	unregister_ioctl32_conversion(GPERFCTR_CONTROL);
-+	unregister_ioctl32_conversion(GPERFCTR_READ);
-+	unregister_ioctl32_conversion(GPERFCTR_STOP);
-+	unregister_ioctl32_conversion(GPERFCTR_START);
-+}
-+
-+#else
-+#define perfctr_register_ioctl32_conversions()		do{}while(0)
-+#define perfctr_unregister_ioctl32_conversions()	do{}while(0)
-+#endif
-+
-+static int dev_perfctr_ioctl(struct inode *inode, struct file *filp,
-+			     unsigned int cmd, unsigned long arg)
-+{
-+	switch( cmd ) {
-+	case PERFCTR_ABI:
-+		return sys_perfctr_abi((unsigned int*)arg);
-+	case PERFCTR_INFO:
-+		return sys_perfctr_info((struct perfctr_struct_buf*)arg);
-+	case PERFCTR_CPUS:
-+		return sys_perfctr_cpus((struct perfctr_cpu_mask*)arg);
-+	case PERFCTR_CPUS_FORBIDDEN:
-+		return sys_perfctr_cpus_forbidden((struct perfctr_cpu_mask*)arg);
-+	case VPERFCTR_CREAT:
-+		return vperfctr_attach((int)arg, 1);
-+	case VPERFCTR_OPEN:
-+		return vperfctr_attach((int)arg, 0);
-+	default:
-+		return gperfctr_ioctl(inode, filp, cmd, arg);
-+	}
-+	return -EINVAL;
-+}
-+
-+static struct file_operations dev_perfctr_file_ops = {
-+	.owner = THIS_MODULE,
-+	.ioctl = dev_perfctr_ioctl,
-+};
-+
-+static struct miscdevice dev_perfctr = {
-+	.minor = 182,
-+	.name = "perfctr",
-+	.fops = &dev_perfctr_file_ops,
-+};
-+
-+int __init perfctr_init(void)
-+{
-+	int err;
-+	if( (err = perfctr_cpu_init()) != 0 ) {
-+		printk(KERN_INFO "perfctr: not supported by this processor\n");
-+		return err;
-+	}
-+	if( (err = vperfctr_init()) != 0 )
-+		return err;
-+	gperfctr_init();
-+	if( (err = misc_register(&dev_perfctr)) != 0 ) {
-+		printk(KERN_ERR "/dev/perfctr: failed to register, errno %d\n",
-+		       -err);
-+		return err;
-+	}
-+	perfctr_register_ioctl32_conversions();
-+	printk(KERN_INFO "perfctr: driver %s, cpu type %s at %u kHz\n",
-+	       perfctr_info.driver_version,
-+	       perfctr_cpu_name,
-+	       perfctr_info.cpu_khz);
-+	return 0;
-+}
-+
-+void __exit perfctr_exit(void)
-+{
-+	perfctr_unregister_ioctl32_conversions();
-+	misc_deregister(&dev_perfctr);
-+	vperfctr_exit();
-+	perfctr_cpu_exit();
-+}
-+
-+module_init(perfctr_init)
-+module_exit(perfctr_exit)
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/virtual.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/virtual.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/virtual.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,15 @@
-+/* $Id: virtual.h,v 1.11 2003/10/04 20:29:43 mikpe Exp $
-+ * Virtual per-process performance counters.
-+ *
-+ * Copyright (C) 1999-2003  Mikael Pettersson
-+ */
-+
-+#ifdef CONFIG_PERFCTR_VIRTUAL
-+extern int vperfctr_attach(int, int);
-+extern int vperfctr_init(void);
-+extern void vperfctr_exit(void);
-+#else
-+static inline int vperfctr_attach(int tid, int creat) { return -EINVAL; }
-+static inline int vperfctr_init(void) { return 0; }
-+static inline void vperfctr_exit(void) { }
-+#endif
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/marshal.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/marshal.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/marshal.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,722 @@
-+/* $Id: marshal.c,v 1.6.2.1 2004/08/02 22:24:58 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Structure marshalling support.
-+ *
-+ * Copyright (C) 2003-2004  Mikael Pettersson
-+ */
-+#ifdef __KERNEL__
-+#include <linux/config.h>
-+struct inode;
-+#include <linux/sched.h>
-+#include <linux/perfctr.h>
-+#include <linux/errno.h>
-+#include <linux/stddef.h>
-+#include <linux/string.h>
-+#include <asm/uaccess.h>
-+#else	/* !__KERNEL__ */
-+#define CONFIG_KPERFCTR
-+#include <linux/perfctr.h>
-+#include <sys/ioctl.h>
-+#include <errno.h>
-+#include <stddef.h>
-+#include <string.h>
-+#define put_user(w, p)	(*(p) = (w), 0)
-+#define get_user(w, p)	((w) = *(p), 0)
-+#endif	/* !__KERNEL__ */
-+
-+#include "marshal.h"
-+
-+/****************************************************************
-+ *								*
-+ * Struct encoding support.					*
-+ *								*
-+ ****************************************************************/
-+
-+static void stream_write(struct perfctr_marshal_stream *stream, unsigned int word)
-+{
-+	if( !stream->error ) {
-+		if( stream->pos >= stream->size )
-+			stream->error = -EOVERFLOW;
-+		else if( put_user(word, &stream->buffer[stream->pos]) )
-+			stream->error = -EFAULT;
-+	}
-+	++stream->pos;
-+}
-+
-+static void encode_field(const void *address,
-+			 const struct perfctr_field_desc *field,
-+			 struct perfctr_marshal_stream *stream)
-+{
-+	unsigned int base_type = PERFCTR_TYPE_BASE(field->type);
-+	unsigned int nr_items = PERFCTR_TYPE_NRITEMS(field->type);
-+	unsigned int tag = field->tag;
-+	const char *pointer = (const char*)address + field->offset;
-+	unsigned int uint32_val;
-+	union {
-+		unsigned long long ull;
-+		unsigned int ui[2];
-+	} uint64_val;
-+	unsigned int i = 0;
-+
-+	do {
-+		if( base_type == PERFCTR_TYPE_UINT64 ) {
-+			uint64_val.ull = *(unsigned long long*)pointer;
-+			pointer += sizeof(long long);
-+			if( !uint64_val.ull )
-+				continue;
-+			stream_write(stream, PERFCTR_HEADER(PERFCTR_HEADER_UINT64, tag, i));
-+			stream_write(stream, uint64_val.ui[0]);
-+			stream_write(stream, uint64_val.ui[1]);
-+		} else {		/* PERFCTR_TYPE_BYTES4 */
-+			memcpy(&uint32_val, pointer, sizeof(int));
-+			pointer += sizeof(int);	
-+			if( !uint32_val )
-+				continue;
-+			stream_write(stream, PERFCTR_HEADER(PERFCTR_HEADER_UINT32, tag, i));
-+			stream_write(stream, uint32_val);
-+		}
-+	} while( ++i < nr_items );
-+}
-+
-+void perfctr_encode_struct(const void *address,
-+			   const struct perfctr_struct_desc *sdesc,
-+			   struct perfctr_marshal_stream *stream)
-+{
-+	unsigned int i;
-+
-+	for(i = 0; i < sdesc->nrfields; ++i)
-+		encode_field(address, &sdesc->fields[i], stream);
-+	for(i = 0; i < sdesc->nrsubs; ++i) {
-+		const struct perfctr_sub_struct_desc *sub = &sdesc->subs[i];
-+		perfctr_encode_struct((char*)address + sub->offset, sub->sdesc, stream);
-+	}
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Struct decoding support.					*
-+ *								*
-+ ****************************************************************/
-+
-+static int stream_read(struct perfctr_marshal_stream *stream, unsigned int *word)
-+{
-+	if( stream->pos >= stream->size )
-+		return 0;
-+	if( get_user(*word, &stream->buffer[stream->pos]) )
-+		return -EFAULT;
-+	++stream->pos;
-+	return 1;
-+}
-+
-+static const struct perfctr_field_desc*
-+find_field(unsigned int *struct_offset,
-+	   const struct perfctr_struct_desc *sdesc,
-+	   unsigned int tag)
-+{
-+	unsigned int low, high, mid, i;
-+	const struct perfctr_field_desc *field;
-+	const struct perfctr_sub_struct_desc *sub;
-+
-+	low = 0;
-+	high = sdesc->nrfields;	/* [low,high[ */
-+	while( low < high ) {
-+		mid = (low + high) / 2;
-+		field = &sdesc->fields[mid];
-+		if( field->tag == tag )
-+			return field;
-+		if( field->tag < tag )
-+			low = mid + 1;
-+		else
-+			high = mid;
-+	}
-+	for(i = 0; i < sdesc->nrsubs; ++i) {
-+		sub = &sdesc->subs[i];
-+		field = find_field(struct_offset, sub->sdesc, tag);
-+		if( field ) {
-+			*struct_offset += sub->offset;
-+			return field;
-+		}
-+	}
-+	return 0;
-+}
-+
-+int perfctr_decode_struct(void *address,
-+			  const struct perfctr_struct_desc *sdesc,
-+			  struct perfctr_marshal_stream *stream)
-+{
-+	unsigned int header;
-+	int err;
-+	const struct perfctr_field_desc *field;
-+	unsigned int struct_offset;
-+	union {
-+		unsigned long long ull;
-+		unsigned int ui[2];
-+	} val;
-+	char *target;
-+	unsigned int itemnr;
-+
-+	for(;;) {
-+		err = stream_read(stream, &header);
-+		if( err <= 0 )
-+			return err;
-+		struct_offset = 0;
-+		field = find_field(&struct_offset, sdesc, PERFCTR_HEADER_TAG(header));
-+		if( !field )
-+			goto err_eproto;
-+		/* a 64-bit datum must have a 64-bit target field */
-+		if( PERFCTR_HEADER_TYPE(header) != PERFCTR_HEADER_UINT32 &&
-+		    PERFCTR_TYPE_BASE(field->type) != PERFCTR_TYPE_UINT64 )
-+			goto err_eproto;
-+		err = stream_read(stream, &val.ui[0]);
-+		if( err <= 0 )
-+			goto err_err;
-+		target = (char*)address + struct_offset + field->offset;
-+		itemnr = PERFCTR_HEADER_ITEMNR(header);
-+		if( itemnr >= PERFCTR_TYPE_NRITEMS(field->type) )
-+			goto err_eproto;
-+		if( PERFCTR_TYPE_BASE(field->type) == PERFCTR_TYPE_UINT64 ) {
-+			/* a 64-bit field must have a 64-bit datum */
-+			if( PERFCTR_HEADER_TYPE(header) == PERFCTR_HEADER_UINT32 )
-+				goto err_eproto;
-+			err = stream_read(stream, &val.ui[1]);
-+			if( err <= 0 )
-+				goto err_err;
-+			((unsigned long long*)target)[itemnr] = val.ull;
-+		} else
-+			memcpy(&((unsigned int*)target)[itemnr], &val.ui[0], sizeof(int));
-+	}
-+ err_err:	/* err ? err : -EPROTO */
-+	if( err )
-+		return err;
-+ err_eproto:	/* saves object code over inlining it */
-+	return -EPROTO;
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Structure descriptors.					*
-+ *								*
-+ ****************************************************************/
-+
-+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-+#define STRUCT_ARRAY_SIZE(TYPE, MEMBER) ARRAY_SIZE(((TYPE*)0)->MEMBER)
-+
-+#if defined(__i386__) || defined(__x86_64__)
-+
-+#define PERFCTR_TAG_CPU_CONTROL_TSC_ON	32
-+#define PERFCTR_TAG_CPU_CONTROL_NRACTRS	33
-+#define PERFCTR_TAG_CPU_CONTROL_NRICTRS	34
-+#define PERFCTR_TAG_CPU_CONTROL_PMC_MAP	35
-+#define PERFCTR_TAG_CPU_CONTROL_EVNTSEL	36
-+#define PERFCTR_TAG_CPU_CONTROL_IRESET	37
-+#define PERFCTR_TAG_CPU_CONTROL_P4_ESCR	38
-+#define PERFCTR_TAG_CPU_CONTROL_P4_PE	39
-+#define PERFCTR_TAG_CPU_CONTROL_P4_PMV	40
-+#define PERFCTR_TAG_CPU_CONTROL_RSVD1	41
-+#define PERFCTR_TAG_CPU_CONTROL_RSVD2	42
-+#define PERFCTR_TAG_CPU_CONTROL_RSVD3	43
-+#define PERFCTR_TAG_CPU_CONTROL_RSVD4	44
-+#define PERFCTR_CPU_CONTROL_NRFIELDS_0	(7 + STRUCT_ARRAY_SIZE(struct perfctr_cpu_control, pmc_map) + STRUCT_ARRAY_SIZE(struct perfctr_cpu_control, evntsel) + STRUCT_ARRAY_SIZE(struct perfctr_cpu_control, ireset))
-+#define PERFCTR_CPU_CONTROL_NRFIELDS_1	(2 + STRUCT_ARRAY_SIZE(struct perfctr_cpu_control, p4.escr))
-+#define PERFCTR_CPU_CONTROL_NRFIELDS	(PERFCTR_CPU_CONTROL_NRFIELDS_0 + PERFCTR_CPU_CONTROL_NRFIELDS_1)
-+
-+#define PERFCTR_TAG_SUM_CTRS_TSC	48
-+#define PERFCTR_TAG_SUM_CTRS_PMC	49
-+#define PERFCTR_SUM_CTRS_NRFIELDS	(1 + STRUCT_ARRAY_SIZE(struct perfctr_sum_ctrs, pmc))
-+
-+static const struct perfctr_field_desc perfctr_sum_ctrs_fields[] = {
-+	{ .offset = offsetof(struct perfctr_sum_ctrs, tsc),
-+	  .tag = PERFCTR_TAG_SUM_CTRS_TSC,
-+	  .type = PERFCTR_TYPE_UINT64 },
-+	{ .offset = offsetof(struct perfctr_sum_ctrs, pmc),
-+	  .tag = PERFCTR_TAG_SUM_CTRS_PMC,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_sum_ctrs,pmc),
-+				     PERFCTR_TYPE_UINT64) },
-+};
-+
-+const struct perfctr_struct_desc perfctr_sum_ctrs_sdesc = {
-+	.total_sizeof = sizeof(struct perfctr_sum_ctrs),
-+	.total_nrfields = PERFCTR_SUM_CTRS_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(perfctr_sum_ctrs_fields),
-+	.fields = perfctr_sum_ctrs_fields,
-+};
-+
-+static const struct perfctr_field_desc perfctr_cpu_control_fields[] = {
-+	{ .offset = offsetof(struct perfctr_cpu_control, tsc_on),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_TSC_ON,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, nractrs),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_NRACTRS,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, nrictrs),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_NRICTRS,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, pmc_map),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_PMC_MAP,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_cpu_control,pmc_map),
-+				     PERFCTR_TYPE_BYTES4) },
-+	{ .offset = offsetof(struct perfctr_cpu_control, evntsel),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_EVNTSEL,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_cpu_control,evntsel),
-+				     PERFCTR_TYPE_BYTES4) },
-+	{ .offset = offsetof(struct perfctr_cpu_control, ireset),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_IRESET,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_cpu_control,ireset),
-+				     PERFCTR_TYPE_BYTES4) },
-+	{ .offset = offsetof(struct perfctr_cpu_control, p4.escr),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_P4_ESCR,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_cpu_control,p4.escr),
-+				     PERFCTR_TYPE_BYTES4) },
-+	{ .offset = offsetof(struct perfctr_cpu_control, p4.pebs_enable),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_P4_PE,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, p4.pebs_matrix_vert),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_P4_PMV,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, _reserved1),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_RSVD1,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, _reserved2),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_RSVD2,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, _reserved3),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_RSVD3,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, _reserved4),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_RSVD4,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+};
-+
-+const struct perfctr_struct_desc perfctr_cpu_control_sdesc = {
-+	.total_sizeof = sizeof(struct perfctr_cpu_control),
-+	.total_nrfields = PERFCTR_CPU_CONTROL_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(perfctr_cpu_control_fields),
-+	.fields = perfctr_cpu_control_fields,
-+};
-+
-+#endif	/* __i386__ || __x86_64__ */
-+
-+#if defined(__powerpc__)	/* XXX: can be merged with x86/amd64 */
-+
-+#define PERFCTR_TAG_CPU_CONTROL_TSC_ON	32
-+#define PERFCTR_TAG_CPU_CONTROL_NRACTRS	33
-+#define PERFCTR_TAG_CPU_CONTROL_NRICTRS	34
-+#define PERFCTR_TAG_CPU_CONTROL_PMC_MAP	35
-+#define PERFCTR_TAG_CPU_CONTROL_EVNTSEL	36
-+#define PERFCTR_TAG_CPU_CONTROL_IRESET	37
-+#define PERFCTR_TAG_CPU_CONTROL_PPC_MMCR0	38
-+#define PERFCTR_TAG_CPU_CONTROL_PPC_MMCR2	39
-+/* 40: unused */
-+#define PERFCTR_TAG_CPU_CONTROL_RSVD1	41
-+#define PERFCTR_TAG_CPU_CONTROL_RSVD2	42
-+#define PERFCTR_TAG_CPU_CONTROL_RSVD3	43
-+#define PERFCTR_TAG_CPU_CONTROL_RSVD4	44
-+#define PERFCTR_CPU_CONTROL_NRFIELDS_0	(7 + STRUCT_ARRAY_SIZE(struct perfctr_cpu_control, pmc_map) + STRUCT_ARRAY_SIZE(struct perfctr_cpu_control, evntsel) + STRUCT_ARRAY_SIZE(struct perfctr_cpu_control, ireset))
-+#ifdef __powerpc__
-+#define PERFCTR_CPU_CONTROL_NRFIELDS_1	2
-+#endif
-+#define PERFCTR_CPU_CONTROL_NRFIELDS	(PERFCTR_CPU_CONTROL_NRFIELDS_0 + PERFCTR_CPU_CONTROL_NRFIELDS_1)
-+
-+#define PERFCTR_TAG_SUM_CTRS_TSC	48
-+#define PERFCTR_TAG_SUM_CTRS_PMC	49
-+#define PERFCTR_SUM_CTRS_NRFIELDS	(1 + STRUCT_ARRAY_SIZE(struct perfctr_sum_ctrs, pmc))
-+
-+static const struct perfctr_field_desc perfctr_sum_ctrs_fields[] = {
-+	{ .offset = offsetof(struct perfctr_sum_ctrs, tsc),
-+	  .tag = PERFCTR_TAG_SUM_CTRS_TSC,
-+	  .type = PERFCTR_TYPE_UINT64 },
-+	{ .offset = offsetof(struct perfctr_sum_ctrs, pmc),
-+	  .tag = PERFCTR_TAG_SUM_CTRS_PMC,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_sum_ctrs,pmc),
-+				     PERFCTR_TYPE_UINT64) },
-+};
-+
-+const struct perfctr_struct_desc perfctr_sum_ctrs_sdesc = {
-+	.total_sizeof = sizeof(struct perfctr_sum_ctrs),
-+	.total_nrfields = PERFCTR_SUM_CTRS_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(perfctr_sum_ctrs_fields),
-+	.fields = perfctr_sum_ctrs_fields,
-+};
-+
-+static const struct perfctr_field_desc perfctr_cpu_control_fields[] = {
-+	{ .offset = offsetof(struct perfctr_cpu_control, tsc_on),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_TSC_ON,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, nractrs),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_NRACTRS,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, nrictrs),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_NRICTRS,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, pmc_map),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_PMC_MAP,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_cpu_control,pmc_map),
-+				     PERFCTR_TYPE_BYTES4) },
-+	{ .offset = offsetof(struct perfctr_cpu_control, evntsel),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_EVNTSEL,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_cpu_control,evntsel),
-+				     PERFCTR_TYPE_BYTES4) },
-+	{ .offset = offsetof(struct perfctr_cpu_control, ireset),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_IRESET,
-+	  .type = PERFCTR_TYPE_ARRAY(STRUCT_ARRAY_SIZE(struct perfctr_cpu_control,ireset),
-+				     PERFCTR_TYPE_BYTES4) },
-+#ifdef __powerpc__
-+	{ .offset = offsetof(struct perfctr_cpu_control, ppc.mmcr0),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_PPC_MMCR0,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, ppc.mmcr2),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_PPC_MMCR2,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+#endif	/* __powerpc__ */
-+	{ .offset = offsetof(struct perfctr_cpu_control, _reserved1),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_RSVD1,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, _reserved2),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_RSVD2,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, _reserved3),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_RSVD3,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_cpu_control, _reserved4),
-+	  .tag = PERFCTR_TAG_CPU_CONTROL_RSVD4,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+};
-+
-+const struct perfctr_struct_desc perfctr_cpu_control_sdesc = {
-+	.total_sizeof = sizeof(struct perfctr_cpu_control),
-+	.total_nrfields = PERFCTR_CPU_CONTROL_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(perfctr_cpu_control_fields),
-+	.fields = perfctr_cpu_control_fields,
-+};
-+
-+#endif	/* __powerpc__ */
-+
-+#define PERFCTR_TAG_INFO_ABI_VERSION		0
-+#define PERFCTR_TAG_INFO_DRIVER_VERSION		1
-+#define PERFCTR_TAG_INFO_CPU_TYPE		2
-+#define PERFCTR_TAG_INFO_CPU_FEATURES		3
-+#define PERFCTR_TAG_INFO_CPU_KHZ		4
-+#define PERFCTR_TAG_INFO_TSC_TO_CPU_MULT	5
-+#define PERFCTR_TAG_INFO_RSVD2			6
-+#define PERFCTR_TAG_INFO_RSVD3			7
-+#define PERFCTR_TAG_INFO_RSVD4			8
-+#define PERFCTR_INFO_NRFIELDS	(8 + sizeof(((struct perfctr_info*)0)->driver_version)/sizeof(int))
-+
-+#define VPERFCTR_TAG_CONTROL_SIGNO		9
-+#define VPERFCTR_TAG_CONTROL_PRESERVE		10
-+#define VPERFCTR_TAG_CONTROL_RSVD1		11
-+#define VPERFCTR_TAG_CONTROL_RSVD2		12
-+#define VPERFCTR_TAG_CONTROL_RSVD3		13
-+#define VPERFCTR_TAG_CONTROL_RSVD4		14
-+#define VPERFCTR_CONTROL_NRFIELDS		(6 + PERFCTR_CPU_CONTROL_NRFIELDS)
-+
-+#define GPERFCTR_TAG_CPU_CONTROL_CPU		15
-+#define GPERFCTR_TAG_CPU_CONTROL_RSVD1		16
-+#define GPERFCTR_TAG_CPU_CONTROL_RSVD2		17
-+#define GPERFCTR_TAG_CPU_CONTROL_RSVD3		18
-+#define GPERFCTR_TAG_CPU_CONTROL_RSVD4		19
-+#define GPERFCTR_CPU_CONTROL_NRFIELDS		(5 + PERFCTR_CPU_CONTROL_NRFIELDS)
-+
-+#define GPERFCTR_TAG_CPU_STATE_CPU		20
-+#define GPERFCTR_TAG_CPU_STATE_RSVD1		21
-+#define GPERFCTR_TAG_CPU_STATE_RSVD2		22
-+#define GPERFCTR_TAG_CPU_STATE_RSVD3		23
-+#define GPERFCTR_TAG_CPU_STATE_RSVD4		24
-+#define GPERFCTR_CPU_STATE_ONLY_CPU_NRFIELDS	5
-+#define GPERFCTR_CPU_STATE_NRFIELDS	(GPERFCTR_CPU_STATE_ONLY_CPU_NRFIELDS + PERFCTR_CPU_CONTROL_NRFIELDS + PERFCTR_SUM_CTRS_NRFIELDS)
-+
-+static const struct perfctr_field_desc perfctr_info_fields[] = {
-+	{ .offset = offsetof(struct perfctr_info, abi_version),
-+	  .tag = PERFCTR_TAG_INFO_ABI_VERSION,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_info, driver_version),
-+	  .tag = PERFCTR_TAG_INFO_DRIVER_VERSION,
-+	  .type = PERFCTR_TYPE_ARRAY(sizeof(((struct perfctr_info*)0)->driver_version)/sizeof(int), PERFCTR_TYPE_BYTES4) },
-+	{ .offset = offsetof(struct perfctr_info, cpu_type),
-+	  .tag = PERFCTR_TAG_INFO_CPU_TYPE,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_info, cpu_features),
-+	  .tag = PERFCTR_TAG_INFO_CPU_FEATURES,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_info, cpu_khz),
-+	  .tag = PERFCTR_TAG_INFO_CPU_KHZ,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_info, tsc_to_cpu_mult),
-+	  .tag = PERFCTR_TAG_INFO_TSC_TO_CPU_MULT,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_info, _reserved2),
-+	  .tag = PERFCTR_TAG_INFO_RSVD2,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_info, _reserved3),
-+	  .tag = PERFCTR_TAG_INFO_RSVD3,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct perfctr_info, _reserved4),
-+	  .tag = PERFCTR_TAG_INFO_RSVD4,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+};
-+
-+const struct perfctr_struct_desc perfctr_info_sdesc = {
-+	.total_sizeof = sizeof(struct perfctr_info),
-+	.total_nrfields = PERFCTR_INFO_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(perfctr_info_fields),
-+	.fields = perfctr_info_fields,
-+};
-+
-+#if defined(CONFIG_PERFCTR_VIRTUAL) || !defined(__KERNEL__)
-+static const struct perfctr_field_desc vperfctr_control_fields[] = {
-+	{ .offset = offsetof(struct vperfctr_control, si_signo),
-+	  .tag = VPERFCTR_TAG_CONTROL_SIGNO,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct vperfctr_control, preserve),
-+	  .tag = VPERFCTR_TAG_CONTROL_PRESERVE,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct vperfctr_control, _reserved1),
-+	  .tag = VPERFCTR_TAG_CONTROL_RSVD1,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct vperfctr_control, _reserved2),
-+	  .tag = VPERFCTR_TAG_CONTROL_RSVD2,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct vperfctr_control, _reserved3),
-+	  .tag = VPERFCTR_TAG_CONTROL_RSVD3,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct vperfctr_control, _reserved4),
-+	  .tag = VPERFCTR_TAG_CONTROL_RSVD4,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+};
-+
-+static const struct perfctr_sub_struct_desc vperfctr_control_subs[] = {
-+	{ .offset = offsetof(struct vperfctr_control, cpu_control),
-+	  .sdesc = &perfctr_cpu_control_sdesc },
-+};
-+
-+const struct perfctr_struct_desc vperfctr_control_sdesc = {
-+	.total_sizeof = sizeof(struct vperfctr_control),
-+	.total_nrfields = VPERFCTR_CONTROL_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(vperfctr_control_fields),
-+	.fields = vperfctr_control_fields,
-+	.nrsubs = ARRAY_SIZE(vperfctr_control_subs),
-+	.subs = vperfctr_control_subs,
-+};
-+#endif	/* CONFIG_PERFCTR_VIRTUAL || !__KERNEL__ */
-+
-+#if defined(CONFIG_PERFCTR_GLOBAL) || !defined(__KERNEL__)
-+static const struct perfctr_field_desc gperfctr_cpu_control_fields[] = {
-+	{ .offset = offsetof(struct gperfctr_cpu_control, cpu),
-+	  .tag = GPERFCTR_TAG_CPU_CONTROL_CPU,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct gperfctr_cpu_control, _reserved1),
-+	  .tag = GPERFCTR_TAG_CPU_CONTROL_RSVD1,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct gperfctr_cpu_control, _reserved2),
-+	  .tag = GPERFCTR_TAG_CPU_CONTROL_RSVD2,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct gperfctr_cpu_control, _reserved3),
-+	  .tag = GPERFCTR_TAG_CPU_CONTROL_RSVD3,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct gperfctr_cpu_control, _reserved4),
-+	  .tag = GPERFCTR_TAG_CPU_CONTROL_RSVD4,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+};
-+
-+static const struct perfctr_sub_struct_desc gperfctr_cpu_control_subs[] = {
-+	{ .offset = offsetof(struct gperfctr_cpu_control, cpu_control),
-+	  .sdesc = &perfctr_cpu_control_sdesc },
-+};
-+
-+const struct perfctr_struct_desc gperfctr_cpu_control_sdesc = {
-+	.total_sizeof = sizeof(struct gperfctr_cpu_control),
-+	.total_nrfields = GPERFCTR_CPU_CONTROL_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(gperfctr_cpu_control_fields),
-+	.fields = gperfctr_cpu_control_fields,
-+	.nrsubs = ARRAY_SIZE(gperfctr_cpu_control_subs),
-+	.subs = gperfctr_cpu_control_subs,
-+};
-+
-+static const struct perfctr_field_desc gperfctr_cpu_state_fields[] = {
-+	{ .offset = offsetof(struct gperfctr_cpu_state, cpu),
-+	  .tag = GPERFCTR_TAG_CPU_STATE_CPU,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct gperfctr_cpu_state, _reserved1),
-+	  .tag = GPERFCTR_TAG_CPU_STATE_RSVD1,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct gperfctr_cpu_state, _reserved2),
-+	  .tag = GPERFCTR_TAG_CPU_STATE_RSVD2,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct gperfctr_cpu_state, _reserved3),
-+	  .tag = GPERFCTR_TAG_CPU_STATE_RSVD3,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+	{ .offset = offsetof(struct gperfctr_cpu_state, _reserved4),
-+	  .tag = GPERFCTR_TAG_CPU_STATE_RSVD4,
-+	  .type = PERFCTR_TYPE_BYTES4 },
-+};
-+
-+static const struct perfctr_sub_struct_desc gperfctr_cpu_state_subs[] = {
-+	{ .offset = offsetof(struct gperfctr_cpu_state, cpu_control),
-+	  .sdesc = &perfctr_cpu_control_sdesc },
-+	{ .offset = offsetof(struct gperfctr_cpu_state, sum),
-+	  .sdesc = &perfctr_sum_ctrs_sdesc },
-+};
-+
-+const struct perfctr_struct_desc gperfctr_cpu_state_only_cpu_sdesc = {
-+	.total_sizeof = sizeof(struct gperfctr_cpu_state),
-+	.total_nrfields = GPERFCTR_CPU_STATE_ONLY_CPU_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(gperfctr_cpu_state_fields),
-+	.fields = gperfctr_cpu_state_fields,
-+};
-+
-+const struct perfctr_struct_desc gperfctr_cpu_state_sdesc = {
-+	.total_sizeof = sizeof(struct gperfctr_cpu_state),
-+	.total_nrfields = GPERFCTR_CPU_STATE_NRFIELDS,
-+	.nrfields = ARRAY_SIZE(gperfctr_cpu_state_fields),
-+	.fields = gperfctr_cpu_state_fields,
-+	.nrsubs = ARRAY_SIZE(gperfctr_cpu_state_subs),
-+	.subs = gperfctr_cpu_state_subs,
-+};
-+#endif	/* CONFIG_PERFCTR_GLOBAL || !__KERNEL__ */
-+
-+#ifdef __KERNEL__
-+
-+int perfctr_copy_from_user(void *struct_address,
-+			   struct perfctr_struct_buf *argp,
-+			   const struct perfctr_struct_desc *sdesc)
-+{
-+	struct perfctr_marshal_stream stream;
-+
-+	if( get_user(stream.size, &argp->rdsize) )
-+		return -EFAULT;
-+	stream.buffer = argp->buffer;
-+	stream.pos = 0;
-+	stream.error = 0;
-+	memset(struct_address, 0, sdesc->total_sizeof);
-+	return perfctr_decode_struct(struct_address, sdesc, &stream);
-+}
-+
-+int perfctr_copy_to_user(struct perfctr_struct_buf *argp,
-+			 void *struct_address,
-+			 const struct perfctr_struct_desc *sdesc)
-+{
-+	struct perfctr_marshal_stream stream;
-+
-+	if( get_user(stream.size, &argp->wrsize) )
-+		return -EFAULT;
-+	stream.buffer = argp->buffer;
-+	stream.pos = 0;
-+	stream.error = 0;
-+	perfctr_encode_struct(struct_address, sdesc, &stream);
-+	if( stream.error )
-+		return stream.error;
-+	if( put_user(stream.pos, &argp->rdsize) )
-+		return -EFAULT;
-+	return 0;
-+}
-+
-+#else	/* !__KERNEL__ */
-+
-+#define sdesc_bufsize(sdesc)	((sdesc)->total_nrfields + (sdesc)->total_sizeof/sizeof(int))
-+
-+static int common_ioctl_w(const void *arg,
-+			  const struct perfctr_struct_desc *sdesc,
-+			  struct perfctr_struct_buf *buf,
-+			  unsigned int bufsize)
-+{
-+	struct perfctr_marshal_stream stream;
-+
-+	stream.size = bufsize;
-+	stream.buffer = buf->buffer;
-+	stream.pos = 0;
-+	stream.error = 0;
-+	perfctr_encode_struct(arg, sdesc, &stream);
-+	if( stream.error ) {
-+		errno = -stream.error;
-+		return -1;
-+	}
-+	buf->rdsize = stream.pos;
-+	return 0;
-+}
-+
-+int perfctr_ioctl_w(int fd, unsigned int cmd, const void *arg,
-+		    const struct perfctr_struct_desc *sdesc)
-+{
-+	unsigned int bufsize = sdesc_bufsize(sdesc);
-+	union {
-+		struct perfctr_struct_buf buf;
-+		struct {
-+			unsigned int rdsize;
-+			unsigned int wrsize;
-+			unsigned int buffer[bufsize];
-+		} buf_bufsize;
-+	} u;
-+	int err;
-+
-+	err = common_ioctl_w(arg, sdesc, &u.buf, bufsize);
-+	if( err < 0 )
-+		return err;
-+	u.buf.wrsize = 0;
-+	return ioctl(fd, cmd, &u.buf);
-+}
-+
-+static int common_ioctl_r(int fd, unsigned int cmd, void *res,
-+			   const struct perfctr_struct_desc *sdesc,
-+			   struct perfctr_struct_buf *buf)
-+{
-+	struct perfctr_marshal_stream stream;
-+	int err;
-+
-+	if( ioctl(fd, cmd, buf) < 0 )
-+		return -1;
-+	stream.size = buf->rdsize;
-+	stream.buffer = buf->buffer;
-+	stream.pos = 0;
-+	stream.error = 0;
-+	memset(res, 0, sdesc->total_sizeof);
-+	err = perfctr_decode_struct(res, sdesc, &stream);
-+	if( err < 0 ) {
-+		errno = -err;
-+		return -1;
-+	}
-+	return 0;
-+}
-+
-+int perfctr_ioctl_r(int fd, unsigned int cmd, void *res,
-+		    const struct perfctr_struct_desc *sdesc)
-+{
-+	unsigned int bufsize = sdesc_bufsize(sdesc);
-+	union {
-+		struct perfctr_struct_buf buf;
-+		struct {
-+			unsigned int rdsize;
-+			unsigned int wrsize;
-+			unsigned int buffer[bufsize];
-+		} buf_bufsize;
-+	} u;
-+
-+	u.buf.rdsize = 0;
-+	u.buf.wrsize = bufsize;
-+	return common_ioctl_r(fd, cmd, res, sdesc, &u.buf);
-+}
-+
-+int perfctr_ioctl_wr(int fd, unsigned int cmd, void *argres,
-+		     const struct perfctr_struct_desc *arg_sdesc,
-+		     const struct perfctr_struct_desc *res_sdesc)
-+{
-+	unsigned int arg_bufsize = sdesc_bufsize(arg_sdesc);
-+	unsigned int res_bufsize = sdesc_bufsize(res_sdesc);
-+	unsigned int bufsize = arg_bufsize > res_bufsize ? arg_bufsize : res_bufsize;
-+	union {
-+		struct perfctr_struct_buf buf;
-+		struct {
-+			unsigned int rdsize;
-+			unsigned int wrsize;
-+			unsigned int buffer[bufsize];
-+		} buf_bufsize;
-+	} u;
-+	int err;
-+
-+	err = common_ioctl_w(argres, arg_sdesc, &u.buf, arg_bufsize);
-+	if( err < 0 )
-+		return err;
-+	u.buf.wrsize = res_bufsize;
-+	return common_ioctl_r(fd, cmd, argres, res_sdesc, &u.buf);
-+}
-+
-+#endif /* !__KERNEL__ */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc_compat.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/ppc_compat.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc_compat.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,62 @@
-+/* $Id: ppc_compat.h,v 1.1.2.1 2004/06/21 22:32:14 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * PPC32-specific compatibility definitions for 2.4/2.6 kernels.
-+ *
-+ * Copyright (C) 2004  Mikael Pettersson
-+ */
-+
-+#define SPRN_MMCR0	0x3B8	/* 604 and up */
-+#define SPRN_PMC1	0x3B9	/* 604 and up */
-+#define SPRN_PMC2	0x3BA	/* 604 and up */
-+#define SPRN_SIA	0x3BB	/* 604 and up */
-+#define SPRN_MMCR1	0x3BC	/* 604e and up */
-+#define SPRN_PMC3	0x3BD	/* 604e and up */
-+#define SPRN_PMC4	0x3BE	/* 604e and up */
-+#define SPRN_MMCR2	0x3B0	/* 7400 and up */
-+#define SPRN_BAMR	0x3B7	/* 7400 and up */
-+#define SPRN_PMC5	0x3B1	/* 7450 and up */
-+#define SPRN_PMC6	0x3B2	/* 7450 and up */
-+
-+/* MMCR0 layout (74xx terminology) */
-+#define MMCR0_FC		0x80000000 /* Freeze counters unconditionally. */
-+#define MMCR0_FCS		0x40000000 /* Freeze counters while MSR[PR]=0 (supervisor mode). */
-+#define MMCR0_FCP		0x20000000 /* Freeze counters while MSR[PR]=1 (user mode). */
-+#define MMCR0_FCM1		0x10000000 /* Freeze counters while MSR[PM]=1. */
-+#define MMCR0_FCM0		0x08000000 /* Freeze counters while MSR[PM]=0. */
-+#define MMCR0_PMXE		0x04000000 /* Enable performance monitor exceptions.
-+					    * Cleared by hardware when a PM exception occurs.
-+					    * 604: PMXE is not cleared by hardware.
-+					    */
-+#define MMCR0_FCECE		0x02000000 /* Freeze counters on enabled condition or event.
-+					    * FCECE is treated as 0 if TRIGGER is 1.
-+					    * 74xx: FC is set when the event occurs.
-+					    * 604/750: ineffective when PMXE=0.
-+					    */
-+#define MMCR0_TBSEL		0x01800000 /* Time base lower (TBL) bit selector.
-+					    * 00: bit 31, 01: bit 23, 10: bit 19, 11: bit 15.
-+					    */
-+#define MMCR0_TBEE		0x00400000 /* Enable event on TBL bit transition from 0 to 1. */
-+#define MMCR0_THRESHOLD		0x003F0000 /* Threshold value for certain events. */
-+#define MMCR0_PMC1CE		0x00008000 /* Enable event on PMC1 overflow. */
-+#define MMCR0_PMCjCE		0x00004000 /* Enable event on PMC2-PMC6 overflow.
-+					    * 604/750: Overrides FCECE (DISCOUNT).
-+					    */
-+#define MMCR0_TRIGGER		0x00002000 /* Disable PMC2-PMC6 until PMC1 overflow or other event.
-+					    * 74xx: cleared by hardware when the event occurs.
-+					    */
-+#define MMCR0_PMC1SEL		0x00001FB0 /* PMC1 event selector, 7 bits. */
-+#define MMCR0_PMC2SEL		0x0000003F /* PMC2 event selector, 6 bits. */
-+
-+/* MMCR1 layout (604e-7457) */
-+#define MMCR1_PMC3SEL		0xF8000000 /* PMC3 event selector, 5 bits. */
-+#define MMCR1_PMC4SEL		0x07B00000 /* PMC4 event selector, 5 bits. */
-+#define MMCR1_PMC5SEL		0x003E0000 /* PMC5 event selector, 5 bits. (745x only) */
-+#define MMCR1_PMC6SEL		0x0001F800 /* PMC6 event selector, 6 bits. (745x only) */
-+#define MMCR1__RESERVED		0x000007FF /* should be zero */
-+
-+/* MMCR2 layout (7400-7457) */
-+#define MMCR2_THRESHMULT	0x80000000 /* MMCR0[THRESHOLD] multiplier. */
-+#define MMCR2_SMCNTEN		0x40000000 /* 7400/7410 only, should be zero. */
-+#define MMCR2_SMINTEN		0x20000000 /* 7400/7410 only, should be zero. */
-+#define MMCR2__RESERVED		0x1FFFFFFF /* should be zero */
-+#define MMCR2_RESERVED		(MMCR2_SMCNTEN | MMCR2_SMINTEN | MMCR2__RESERVED)
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/compat.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/compat.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/compat.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,23 @@
-+/* $Id: compat.h,v 1.42 2004/05/02 22:52:13 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Compatibility definitions for 2.6 kernels.
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-+#include "compat24.h"
-+#else
-+
-+#include "cpumask.h"
-+
-+#define EXPORT_SYMBOL_mmu_cr4_features	EXPORT_SYMBOL(mmu_cr4_features)
-+#define EXPORT_SYMBOL___put_task_struct	EXPORT_SYMBOL(__put_task_struct)
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)	/* names changed in 2.6.4-rc2 */
-+#define sysdev_register(dev)	sys_device_register((dev))
-+#define sysdev_unregister(dev)	sys_device_unregister((dev))
-+#endif
-+
-+#endif
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/Config.in
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/Config.in	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/Config.in	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,15 @@
-+# $Id: Config.in,v 1.15 2002/11/25 13:01:46 mikpe Exp $
-+# Performance-monitoring counters driver configuration
-+#
-+
-+mainmenu_option next_comment
-+comment 'Performance-monitoring counters support'
-+tristate 'Performance-monitoring counters support' CONFIG_PERFCTR
-+if [ "$CONFIG_PERFCTR" != "n" ]; then
-+   define_bool CONFIG_KPERFCTR y
-+   bool '  Additional internal consistency checks' CONFIG_PERFCTR_DEBUG
-+   bool '  Init-time hardware tests' CONFIG_PERFCTR_INIT_TESTS
-+   bool '  Virtual performance counters support' CONFIG_PERFCTR_VIRTUAL $CONFIG_PERFCTR
-+   bool '  Global performance counters support' CONFIG_PERFCTR_GLOBAL $CONFIG_PERFCTR
-+fi
-+endmenu
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/global.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/global.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/global.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,244 @@
-+/* $Id: global.c,v 1.38 2004/01/25 14:45:35 mikpe Exp $
-+ * Global-mode performance-monitoring counters via /dev/perfctr.
-+ *
-+ * Copyright (C) 2000-2003  Mikael Pettersson
-+ *
-+ * XXX: Doesn't do any authentication yet. Should we limit control
-+ * to root, or base it on having write access to /dev/perfctr?
-+ */
-+#include <linux/config.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/perfctr.h>
-+
-+#include <asm/uaccess.h>
-+
-+#include "compat.h"
-+#include "global.h"
-+#include "marshal.h"
-+
-+static const char this_service[] = __FILE__;
-+static int hardware_is_ours = 0;
-+static struct timer_list sampling_timer;
-+static DECLARE_MUTEX(control_mutex);
-+static unsigned int nr_active_cpus = 0;
-+
-+struct gperfctr {
-+	struct perfctr_cpu_state cpu_state;
-+	spinlock_t lock;
-+} ____cacheline_aligned;
-+
-+static struct gperfctr per_cpu_gperfctr[NR_CPUS] __cacheline_aligned;
-+
-+static int reserve_hardware(void)
-+{
-+	const char *other;
-+
-+	if( hardware_is_ours )
-+		return 0;
-+	other = perfctr_cpu_reserve(this_service);
-+	if( other ) {
-+		printk(KERN_ERR __FILE__ ":%s: failed because hardware is taken by '%s'\n",
-+		       __FUNCTION__, other);
-+		return -EBUSY;
-+	}
-+	hardware_is_ours = 1;
-+	__module_get(THIS_MODULE);
-+	return 0;
-+}
-+
-+static void release_hardware(void)
-+{
-+	int i;
-+
-+	nr_active_cpus = 0;
-+	if( hardware_is_ours ) {
-+		hardware_is_ours = 0;
-+		del_timer(&sampling_timer);
-+		sampling_timer.data = 0;
-+		perfctr_cpu_release(this_service);
-+		module_put(THIS_MODULE);
-+		for(i = 0; i < NR_CPUS; ++i)
-+			per_cpu_gperfctr[i].cpu_state.cstatus = 0;
-+	}
-+}
-+
-+static void sample_this_cpu(void *unused)
-+{
-+	/* PREEMPT note: when called via smp_call_function(),
-+	   this is in IRQ context with preemption disabled. */
-+	struct gperfctr *perfctr;
-+
-+	perfctr = &per_cpu_gperfctr[smp_processor_id()];
-+	if( !perfctr_cstatus_enabled(perfctr->cpu_state.cstatus) )
-+		return;
-+	spin_lock(&perfctr->lock);
-+	perfctr_cpu_sample(&perfctr->cpu_state);
-+	spin_unlock(&perfctr->lock);
-+}
-+
-+static void sample_all_cpus(void)
-+{
-+	on_each_cpu(sample_this_cpu, NULL, 1, 1);
-+}
-+
-+static void sampling_timer_function(unsigned long interval)
-+{	
-+	sample_all_cpus();
-+	sampling_timer.expires = jiffies + interval;
-+	add_timer(&sampling_timer);
-+}
-+
-+static unsigned long usectojiffies(unsigned long usec)
-+{
-+	usec += 1000000 / HZ - 1;
-+	usec /= 1000000 / HZ;
-+	return usec;
-+}
-+
-+static void start_sampling_timer(unsigned long interval_usec)
-+{
-+	if( interval_usec > 0 ) {
-+		unsigned long interval = usectojiffies(interval_usec);
-+		init_timer(&sampling_timer);
-+		sampling_timer.function = sampling_timer_function;
-+		sampling_timer.data = interval;
-+		sampling_timer.expires = jiffies + interval;
-+		add_timer(&sampling_timer);
-+	}
-+}
-+
-+static void start_this_cpu(void *unused)
-+{
-+	/* PREEMPT note: when called via smp_call_function(),
-+	   this is in IRQ context with preemption disabled. */
-+	struct gperfctr *perfctr;
-+
-+	perfctr = &per_cpu_gperfctr[smp_processor_id()];
-+	if( perfctr_cstatus_enabled(perfctr->cpu_state.cstatus) )
-+		perfctr_cpu_resume(&perfctr->cpu_state);
-+}
-+
-+static void start_all_cpus(void)
-+{
-+	on_each_cpu(start_this_cpu, NULL, 1, 1);
-+}
-+
-+static int gperfctr_control(struct perfctr_struct_buf *argp)
-+{
-+	int ret;
-+	struct gperfctr *perfctr;
-+	struct gperfctr_cpu_control cpu_control;
-+
-+	ret = perfctr_copy_from_user(&cpu_control, argp, &gperfctr_cpu_control_sdesc);
-+	if( ret )
-+		return ret;
-+	if( cpu_control.cpu >= NR_CPUS ||
-+	    !cpu_online(cpu_control.cpu) ||
-+	    perfctr_cpu_is_forbidden(cpu_control.cpu) )
-+		return -EINVAL;
-+	/* we don't permit i-mode counters */
-+	if( cpu_control.cpu_control.nrictrs != 0 )
-+		return -EPERM;
-+	down(&control_mutex);
-+	ret = -EBUSY;
-+	if( hardware_is_ours )
-+		goto out_up;	/* you have to stop them first */
-+	perfctr = &per_cpu_gperfctr[cpu_control.cpu];
-+	spin_lock(&perfctr->lock);
-+	perfctr->cpu_state.tsc_start = 0;
-+	perfctr->cpu_state.tsc_sum = 0;
-+	memset(&perfctr->cpu_state.pmc, 0, sizeof perfctr->cpu_state.pmc);
-+	perfctr->cpu_state.control = cpu_control.cpu_control;
-+	ret = perfctr_cpu_update_control(&perfctr->cpu_state, 1);
-+	spin_unlock(&perfctr->lock);
-+	if( ret < 0 )
-+		goto out_up;
-+	if( perfctr_cstatus_enabled(perfctr->cpu_state.cstatus) )
-+		++nr_active_cpus;
-+	ret = nr_active_cpus;
-+ out_up:
-+	up(&control_mutex);
-+	return ret;
-+}
-+
-+static int gperfctr_start(unsigned int interval_usec)
-+{
-+	int ret;
-+
-+	if( interval_usec < 10000 )
-+		return -EINVAL;
-+	down(&control_mutex);
-+	ret = nr_active_cpus;
-+	if( ret > 0 ) {
-+		if( reserve_hardware() < 0 ) {
-+			ret = -EBUSY;
-+		} else {
-+			start_all_cpus();
-+			start_sampling_timer(interval_usec);
-+		}
-+	}
-+	up(&control_mutex);
-+	return ret;
-+}
-+
-+static int gperfctr_stop(void)
-+{
-+	down(&control_mutex);
-+	release_hardware();
-+	up(&control_mutex);
-+	return 0;
-+}
-+
-+static int gperfctr_read(struct perfctr_struct_buf *argp)
-+{
-+	struct gperfctr *perfctr;
-+	struct gperfctr_cpu_state state;
-+	int err;
-+
-+	// XXX: sample_all_cpus() ???
-+	err = perfctr_copy_from_user(&state, argp, &gperfctr_cpu_state_only_cpu_sdesc);
-+	if( err )
-+		return err;
-+	if( state.cpu >= NR_CPUS || !cpu_online(state.cpu) )
-+		return -EINVAL;
-+	perfctr = &per_cpu_gperfctr[state.cpu];
-+	spin_lock(&perfctr->lock);
-+	state.cpu_control = perfctr->cpu_state.control;
-+	//state.sum = perfctr->cpu_state.sum;
-+	{
-+		int j;
-+		state.sum.tsc = perfctr->cpu_state.tsc_sum;
-+		for(j = 0; j < ARRAY_SIZE(state.sum.pmc); ++j)
-+			state.sum.pmc[j] = perfctr->cpu_state.pmc[j].sum;
-+	}
-+	spin_unlock(&perfctr->lock);
-+	return perfctr_copy_to_user(argp, &state, &gperfctr_cpu_state_sdesc);
-+}
-+
-+int gperfctr_ioctl(struct inode *inode, struct file *filp,
-+		   unsigned int cmd, unsigned long arg)
-+{
-+	switch( cmd ) {
-+	case GPERFCTR_CONTROL:
-+		return gperfctr_control((struct perfctr_struct_buf*)arg);
-+	case GPERFCTR_READ:
-+		return gperfctr_read((struct perfctr_struct_buf*)arg);
-+	case GPERFCTR_STOP:
-+		return gperfctr_stop();
-+	case GPERFCTR_START:
-+		return gperfctr_start(arg);
-+	}
-+	return -EINVAL;
-+}
-+
-+void __init gperfctr_init(void)
-+{
-+	int i;
-+
-+	for(i = 0; i < NR_CPUS; ++i)
-+		per_cpu_gperfctr[i].lock = SPIN_LOCK_UNLOCKED;
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64_tests.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_64_tests.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64_tests.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,14 @@
-+/* $Id: x86_64_tests.h,v 1.1 2003/05/14 21:51:57 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Optional x86_64-specific init-time tests.
-+ *
-+ * Copyright (C) 2003  Mikael Pettersson
-+ */
-+
-+#ifdef CONFIG_PERFCTR_INIT_TESTS
-+extern void perfctr_k8_init_tests(void);
-+extern void perfctr_generic_init_tests(void);
-+#else
-+#define perfctr_k8_init_tests()
-+#define perfctr_generic_init_tests()
-+#endif
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/Kconfig
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/Kconfig	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/Kconfig	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,79 @@
-+# $Id: Kconfig,v 1.7 2003/05/14 21:51:32 mikpe Exp $
-+# Performance-monitoring counters driver configuration
-+#
-+
-+menu "Performance-monitoring counters support"
-+
-+config PERFCTR
-+	tristate "Performance monitoring counters support"
-+	help
-+	  This driver provides access to the performance-monitoring counter
-+	  registers available in some (but not all) modern processors.
-+	  These special-purpose registers can be programmed to count low-level
-+	  performance-related events which occur during program execution,
-+	  such as cache misses, pipeline stalls, etc.
-+
-+	  You can safely say Y here, even if you intend to run the kernel
-+	  on a processor without performance-monitoring counters.
-+
-+	  You can also say M here to compile the driver as a module; the
-+	  module will be called `perfctr'.
-+
-+config KPERFCTR
-+	bool
-+	depends on PERFCTR
-+	default y
-+
-+config PERFCTR_DEBUG
-+	bool "Additional internal consistency checks"
-+	depends on PERFCTR
-+	help
-+	  This option enables additional internal consistency checking in
-+	  the perfctr driver. The scope of these checks is unspecified and
-+	  may vary between different versions of the driver.
-+
-+	  Enabling this option will reduce performance, so say N unless you
-+	  are debugging the driver.
-+
-+config PERFCTR_INIT_TESTS
-+	bool "Init-time hardware tests"
-+	depends on PERFCTR
-+	help
-+	  This option makes the driver perform additional hardware tests
-+	  during initialisation, and log their results in the kernel's
-+	  message buffer. For most supported processors, these tests simply
-+	  measure the runtime overheads of performance counter operations.
-+
-+	  If you have a less well-known processor (one not listed in the
-+	  etc/costs/ directory in the user-space package), you should enable
-+	  this option and email the results to the perfctr developers.
-+
-+	  If unsure, say N.
-+
-+config PERFCTR_VIRTUAL
-+	bool "Virtual performance counters support"
-+	depends on PERFCTR
-+	help
-+	  The processor's performance-monitoring counters are special-purpose
-+	  global registers. This option adds support for virtual per-process
-+	  performance-monitoring counters which only run when the process
-+	  to which they belong is executing. This improves the accuracy of
-+	  performance measurements by reducing "noise" from other processes.
-+
-+	  Say Y.
-+
-+config PERFCTR_GLOBAL
-+	bool "Global performance counters support"
-+	depends on PERFCTR
-+	help
-+	  This option adds driver support for global-mode (system-wide)
-+	  performance-monitoring counters. In this mode, the driver allows
-+	  each performance-monitoring counter on each processor to be
-+	  controlled and read. The driver provides a sampling timer to
-+	  maintain 64-bit accumulated event counts.
-+
-+	  Global-mode performance counters cannot be used if some process
-+	  is currently using virtual-mode performance counters, and vice versa.
-+
-+	  Say Y.
-+endmenu
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/marshal.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/marshal.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/marshal.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,104 @@
-+/* $Id: marshal.h,v 1.1 2003/08/19 13:37:07 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Structure marshalling support.
-+ *
-+ * Copyright (C) 2003  Mikael Pettersson
-+ */
-+
-+/*
-+ * Each encoded datum starts with a 32-bit header word, containing
-+ * the datum's type (1 bit: UINT32 or UINT64), the target's field
-+ * tag (16 bits), and the target field's array index (15 bits).
-+ *
-+ * After the header follows the datum's value, in one (for UINT32)
-+ * or two (for UINT64) words. Multi-word values are emitted in
-+ * native word order.
-+ *
-+ * To encode a struct, encode each field with a non-zero value,
-+ * and place the encodings in sequence. The field order is arbitrary.
-+ *
-+ * To decode an encoded struct, first memset() the target struct
-+ * to zero. Then decode each encoded field in the sequence and
-+ * update the corresponding field in the target struct.
-+ */
-+#define PERFCTR_HEADER(TYPE,TAG,ITEMNR) (((TAG)<<16)|((ITEMNR)<<1)|(TYPE))
-+#define PERFCTR_HEADER_TYPE(H)		((H) & 0x1)
-+#define PERFCTR_HEADER_ITEMNR(H)	(((H) >> 1) & 0x7FFF)
-+#define PERFCTR_HEADER_TAG(H)		((H) >> 16)
-+
-+#define PERFCTR_HEADER_UINT32		0
-+#define PERFCTR_HEADER_UINT64		1
-+
-+/*
-+ * A field descriptor describes a struct field to the
-+ * encoding and decoding procedures.
-+ *
-+ * To keep the descriptors small, field tags and array sizes
-+ * are currently restricted to 8 and 7 bits, respectively.
-+ * This does not change the encoded format.
-+ */
-+struct perfctr_field_desc {
-+	unsigned short offset;	/* offsetof() for this field */
-+	unsigned char tag;	/* identifying tag in encoded format */
-+	unsigned char type;	/* base type (1 bit), array size - 1 (7 bits) */
-+};
-+
-+#define PERFCTR_TYPE_ARRAY(N,T)	((((N) - 1) << 1) | (T))
-+#define PERFCTR_TYPE_BASE(T)	((T) & 0x1)
-+#define PERFCTR_TYPE_NRITEMS(T)	(((T) >> 1) + 1)
-+
-+#define PERFCTR_TYPE_BYTES4	0	/* uint32 or char[4] */
-+#define PERFCTR_TYPE_UINT64	1	/* long long */
-+
-+struct perfctr_struct_desc {
-+	unsigned short total_sizeof;	/* for buffer allocation and decode memset() */
-+	unsigned short total_nrfields;	/* for buffer allocation */
-+	unsigned short nrfields;
-+	unsigned short nrsubs;
-+	/* Note: the fields must be in ascending tag order */
-+	const struct perfctr_field_desc *fields;
-+	const struct perfctr_sub_struct_desc {
-+		unsigned short offset;
-+		const struct perfctr_struct_desc *sdesc;
-+	} *subs;
-+};
-+
-+struct perfctr_marshal_stream {
-+	unsigned int size;
-+	unsigned int *buffer;
-+	unsigned int pos;
-+	unsigned int error;
-+};
-+
-+extern void perfctr_encode_struct(const void *address,
-+				  const struct perfctr_struct_desc *sdesc,
-+				  struct perfctr_marshal_stream *stream);
-+
-+extern int perfctr_decode_struct(void *address,
-+				 const struct perfctr_struct_desc *sdesc,
-+				 struct perfctr_marshal_stream *stream);
-+
-+extern const struct perfctr_struct_desc perfctr_sum_ctrs_sdesc;
-+extern const struct perfctr_struct_desc perfctr_cpu_control_sdesc;
-+extern const struct perfctr_struct_desc perfctr_info_sdesc;
-+extern const struct perfctr_struct_desc vperfctr_control_sdesc;
-+extern const struct perfctr_struct_desc gperfctr_cpu_control_sdesc;
-+extern const struct perfctr_struct_desc gperfctr_cpu_state_only_cpu_sdesc;
-+extern const struct perfctr_struct_desc gperfctr_cpu_state_sdesc;
-+
-+#ifdef __KERNEL__
-+extern int perfctr_copy_to_user(struct perfctr_struct_buf *argp,
-+				void *struct_address,
-+				const struct perfctr_struct_desc *sdesc);
-+extern int perfctr_copy_from_user(void *struct_address,
-+				  struct perfctr_struct_buf *argp,
-+				  const struct perfctr_struct_desc *sdesc);
-+#else
-+extern int perfctr_ioctl_w(int fd, unsigned int cmd, const void *arg,
-+			   const struct perfctr_struct_desc *sdesc);
-+extern int perfctr_ioctl_r(int fd, unsigned int cmd, void *res,
-+			   const struct perfctr_struct_desc *sdesc);
-+extern int perfctr_ioctl_wr(int fd, unsigned int cmd, void *argres,
-+			    const struct perfctr_struct_desc *arg_sdesc,
-+			    const struct perfctr_struct_desc *res_sdesc);
-+#endif /* __KERNEL__ */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/virtual_stub.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/virtual_stub.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/virtual_stub.c	2004-11-18 23:52:29.000000000 -0500
-@@ -0,0 +1,67 @@
-+/* $Id: virtual_stub.c,v 1.26 2003/10/04 22:53:42 mikpe Exp $
-+ * Kernel stub used to support virtual perfctrs when the
-+ * perfctr driver is built as a module.
-+ *
-+ * Copyright (C) 2000-2003  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/perfctr.h>
-+#include "compat.h"
-+
-+static void bug_void_perfctr(struct vperfctr *perfctr)
-+{
-+	current->thread.perfctr = NULL;
-+	BUG();
-+}
-+
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+static void bug_set_cpus_allowed(struct task_struct *owner, struct vperfctr *perfctr, cpumask_t new_mask)
-+{
-+	owner->thread.perfctr = NULL;
-+	BUG();
-+}
-+#endif
-+
-+struct vperfctr_stub vperfctr_stub = {
-+	.exit = bug_void_perfctr,
-+	.suspend = bug_void_perfctr,
-+	.resume = bug_void_perfctr,
-+	.sample = bug_void_perfctr,
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+	.set_cpus_allowed = bug_set_cpus_allowed,
-+#endif
-+};
-+
-+/*
-+ * exit_thread() calls __vperfctr_exit() via vperfctr_stub.exit().
-+ * If the process' reference was the last reference to this
-+ * vperfctr object, and this was the last live vperfctr object,
-+ * then the perfctr module's use count will drop to zero.
-+ * This is Ok, except for the fact that code is still running
-+ * in the module (pending returns back to exit_thread()). This
-+ * could race with rmmod in a preemptive UP kernel, leading to
-+ * code running in freed memory. The race also exists in SMP
-+ * kernels, but the time window is extremely small.
-+ *
-+ * Since exit() isn't performance-critical, we wrap the call to
-+ * vperfctr_stub.exit() with code to increment the module's use
-+ * count before the call, and decrement it again afterwards. Thus,
-+ * the final drop to zero occurs here and not in the module itself.
-+ * (All other code paths that drop the use count do so via a file
-+ * object, and VFS in 2.4+ kernels also refcount the module.)
-+ */
-+void _vperfctr_exit(struct vperfctr *perfctr)
-+{
-+	__module_get(vperfctr_stub.owner);
-+	vperfctr_stub.exit(perfctr);
-+	module_put(vperfctr_stub.owner);
-+}
-+
-+EXPORT_SYMBOL(vperfctr_stub);
-+
-+#include <linux/mm.h> /* for 2.4.15 and up, except 2.4.20-8-redhat */
-+#include <linux/ptrace.h> /* for 2.5.32 and up, and 2.4.20-8-redhat */
-+EXPORT_SYMBOL(ptrace_check_attach);
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc_tests.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/ppc_tests.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc_tests.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,292 @@
-+/* $Id: ppc_tests.c,v 1.1.2.3 2004/07/27 16:42:03 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Optional PPC32-specific init-time tests.
-+ *
-+ * Copyright (C) 2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/perfctr.h>
-+#include <asm/processor.h>
-+#include <asm/time.h>	/* for tb_ticks_per_jiffy */
-+#include "compat.h"
-+#include "ppc_compat.h"
-+#include "ppc_tests.h"
-+
-+#define NITER	256
-+#define X2(S)	S"; "S
-+#define X8(S)	X2(X2(X2(S)))
-+
-+static void __init do_read_tbl(unsigned int unused)
-+{
-+	unsigned int i, dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mftbl %0") : "=r"(dummy));
-+}
-+
-+static void __init do_read_pmc1(unsigned int unused)
-+{
-+	unsigned int i, dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC1)) : "=r"(dummy));
-+}
-+
-+static void __init do_read_pmc2(unsigned int unused)
-+{
-+	unsigned int i, dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC2)) : "=r"(dummy));
-+}
-+
-+static void __init do_read_pmc3(unsigned int unused)
-+{
-+	unsigned int i, dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC3)) : "=r"(dummy));
-+}
-+
-+static void __init do_read_pmc4(unsigned int unused)
-+{
-+	unsigned int i, dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_PMC4)) : "=r"(dummy));
-+}
-+
-+static void __init do_read_mmcr0(unsigned int unused)
-+{
-+	unsigned int i, dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_MMCR0)) : "=r"(dummy));
-+}
-+
-+static void __init do_read_mmcr1(unsigned int unused)
-+{
-+	unsigned int i, dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mfspr %0," __stringify(SPRN_MMCR1)) : "=r"(dummy));
-+}
-+
-+static void __init do_write_pmc2(unsigned int arg)
-+{
-+	unsigned int i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC2) ",%0") : : "r"(arg));
-+}
-+
-+static void __init do_write_pmc3(unsigned int arg)
-+{
-+	unsigned int i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC3) ",%0") : : "r"(arg));
-+}
-+
-+static void __init do_write_pmc4(unsigned int arg)
-+{
-+	unsigned int i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_PMC4) ",%0") : : "r"(arg));
-+}
-+
-+static void __init do_write_mmcr1(unsigned int arg)
-+{
-+	unsigned int i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_MMCR1) ",%0") : : "r"(arg));
-+}
-+
-+static void __init do_write_mmcr0(unsigned int arg)
-+{
-+	unsigned int i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("mtspr " __stringify(SPRN_MMCR0) ",%0") : : "r"(arg));
-+}
-+
-+static void __init do_empty_loop(unsigned int unused)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__("" : : );
-+}
-+
-+static unsigned __init run(void (*doit)(unsigned int), unsigned int arg)
-+{
-+	unsigned int start, stop;
-+	start = mfspr(SPRN_PMC1);
-+	(*doit)(arg);	/* should take < 2^32 cycles to complete */
-+	stop = mfspr(SPRN_PMC1);
-+	return stop - start;
-+}
-+
-+static void __init init_tests_message(void)
-+{
-+	unsigned int pvr = mfspr(SPRN_PVR);
-+	printk(KERN_INFO "Please email the following PERFCTR INIT lines "
-+	       "to mikpe@csd.uu.se\n"
-+	       KERN_INFO "To remove this message, rebuild the driver "
-+	       "with CONFIG_PERFCTR_INIT_TESTS=n\n");
-+	printk(KERN_INFO "PERFCTR INIT: PVR 0x%08x, CPU clock %u kHz, TB clock %u kHz\n",
-+	       pvr,
-+	       perfctr_info.cpu_khz,
-+	       tb_ticks_per_jiffy*(HZ/10)/(1000/10));
-+}
-+
-+static void __init clear(int have_mmcr1)
-+{
-+	mtspr(SPRN_MMCR0, 0);
-+	mtspr(SPRN_PMC1, 0);
-+	mtspr(SPRN_PMC2, 0);
-+	if (have_mmcr1) {
-+		mtspr(SPRN_MMCR1, 0);
-+		mtspr(SPRN_PMC3, 0);
-+		mtspr(SPRN_PMC4, 0);
-+	}
-+}
-+
-+static void __init check_fcece(unsigned int pmc1ce)
-+{
-+	unsigned int mmcr0;
-+
-+	/*
-+	 * This test checks if MMCR0[FC] is set after PMC1 overflows
-+	 * when MMCR0[FCECE] is set.
-+	 * 74xx documentation states this behaviour, while documentation
-+	 * for 604/750 processors doesn't mention this at all.
-+	 *
-+	 * Also output the value of PMC1 shortly after the overflow.
-+	 * This tells us if PMC1 really was frozen. On 604/750, it may not
-+	 * freeze since we don't enable PMIs. [No freeze confirmed on 750.]
-+	 *
-+	 * When pmc1ce == 0, MMCR0[PMC1CE] is zero. It's unclear whether
-+	 * this masks all PMC1 overflow events or just PMC1 PMIs.
-+	 *
-+	 * PMC1 counts processor cycles, with 100 to go before overflowing.
-+	 * FCECE is set.
-+	 * PMC1CE is clear if !pmc1ce, otherwise set.
-+	 */
-+	mtspr(SPRN_PMC1, 0x80000000-100);
-+	mmcr0 = (1<<(31-6)) | (0x01 << 6);
-+	if (pmc1ce)
-+		mmcr0 |= (1<<(31-16));
-+	mtspr(SPRN_MMCR0, mmcr0);
-+	do {
-+		do_empty_loop(0);
-+	} while (!(mfspr(SPRN_PMC1) & 0x80000000));
-+	do_empty_loop(0);
-+	printk(KERN_INFO "PERFCTR INIT: %s(%u): MMCR0[FC] is %u, PMC1 is %#x\n",
-+	       __FUNCTION__, pmc1ce,
-+	       !!(mfspr(SPRN_MMCR0) & (1<<(31-0))), mfspr(SPRN_PMC1));
-+	mtspr(SPRN_MMCR0, 0);
-+	mtspr(SPRN_PMC1, 0);
-+}
-+
-+static void __init check_trigger(unsigned int pmc1ce)
-+{
-+	unsigned int mmcr0;
-+
-+	/*
-+	 * This test checks if MMCR0[TRIGGER] is reset after PMC1 overflows.
-+	 * 74xx documentation states this behaviour, while documentation
-+	 * for 604/750 processors doesn't mention this at all.
-+	 * [No reset confirmed on 750.]
-+	 *
-+	 * Also output the values of PMC1 and PMC2 shortly after the overflow.
-+	 * PMC2 should be equal to PMC1-0x80000000.
-+	 *
-+	 * When pmc1ce == 0, MMCR0[PMC1CE] is zero. It's unclear whether
-+	 * this masks all PMC1 overflow events or just PMC1 PMIs.
-+	 *
-+	 * PMC1 counts processor cycles, with 100 to go before overflowing.
-+	 * PMC2 counts processor cycles, starting from 0.
-+	 * TRIGGER is set, so PMC2 doesn't start until PMC1 overflows.
-+	 * PMC1CE is clear if !pmc1ce, otherwise set.
-+	 */
-+	mtspr(SPRN_PMC2, 0);
-+	mtspr(SPRN_PMC1, 0x80000000-100);
-+	mmcr0 = (1<<(31-18)) | (0x01 << 6) | (0x01 << 0);
-+	if (pmc1ce)
-+		mmcr0 |= (1<<(31-16));
-+	mtspr(SPRN_MMCR0, mmcr0);
-+	do {
-+		do_empty_loop(0);
-+	} while (!(mfspr(SPRN_PMC1) & 0x80000000));
-+	do_empty_loop(0);
-+	printk(KERN_INFO "PERFCTR INIT: %s(%u): MMCR0[TRIGGER] is %u, PMC1 is %#x, PMC2 is %#x\n",
-+	       __FUNCTION__, pmc1ce,
-+	       !!(mfspr(SPRN_MMCR0) & (1<<(31-18))), mfspr(SPRN_PMC1), mfspr(SPRN_PMC2));
-+	mtspr(SPRN_MMCR0, 0);
-+	mtspr(SPRN_PMC1, 0);
-+	mtspr(SPRN_PMC2, 0);
-+}
-+
-+static void __init
-+measure_overheads(int have_mmcr1)
-+{
-+	int i;
-+	unsigned int mmcr0, loop, ticks[12];
-+	const char *name[12];
-+
-+	clear(have_mmcr1);
-+
-+	/* PMC1 = "processor cycles",
-+	   PMC2 = "completed instructions",
-+	   not disabled in any mode,
-+	   no interrupts */
-+	mmcr0 = (0x01 << 6) | (0x02 << 0);
-+	mtspr(SPRN_MMCR0, mmcr0);
-+
-+	name[0] = "mftbl";
-+	ticks[0] = run(do_read_tbl, 0);
-+	name[1] = "mfspr (pmc1)";
-+	ticks[1] = run(do_read_pmc1, 0);
-+	name[2] = "mfspr (pmc2)";
-+	ticks[2] = run(do_read_pmc2, 0);
-+	name[3] = "mfspr (pmc3)";
-+	ticks[3] = have_mmcr1 ? run(do_read_pmc3, 0) : 0;
-+	name[4] = "mfspr (pmc4)";
-+	ticks[4] = have_mmcr1 ? run(do_read_pmc4, 0) : 0;
-+	name[5] = "mfspr (mmcr0)";
-+	ticks[5] = run(do_read_mmcr0, 0);
-+	name[6] = "mfspr (mmcr1)";
-+	ticks[6] = have_mmcr1 ? run(do_read_mmcr1, 0) : 0;
-+	name[7] = "mtspr (pmc2)";
-+	ticks[7] = run(do_write_pmc2, 0);
-+	name[8] = "mtspr (pmc3)";
-+	ticks[8] = have_mmcr1 ? run(do_write_pmc3, 0) : 0;
-+	name[9] = "mtspr (pmc4)";
-+	ticks[9] = have_mmcr1 ? run(do_write_pmc4, 0) : 0;
-+	name[10] = "mtspr (mmcr1)";
-+	ticks[10] = have_mmcr1 ? run(do_write_mmcr1, 0) : 0;
-+	name[11] = "mtspr (mmcr0)";
-+	ticks[11] = run(do_write_mmcr0, mmcr0);
-+
-+	loop = run(do_empty_loop, 0);
-+
-+	clear(have_mmcr1);
-+
-+	init_tests_message();
-+	printk(KERN_INFO "PERFCTR INIT: NITER == %u\n", NITER);
-+	printk(KERN_INFO "PERFCTR INIT: loop overhead is %u cycles\n", loop);
-+	for(i = 0; i < ARRAY_SIZE(ticks); ++i) {
-+		unsigned int x;
-+		if (!ticks[i])
-+			continue;
-+		x = ((ticks[i] - loop) * 10) / NITER;
-+		printk(KERN_INFO "PERFCTR INIT: %s cost is %u.%u cycles (%u total)\n",
-+		       name[i], x/10, x%10, ticks[i]);
-+	}
-+	check_fcece(0);
-+	check_fcece(1);
-+	check_trigger(0);
-+	check_trigger(1);
-+}
-+
-+void __init perfctr_ppc_init_tests(int have_mmcr1)
-+{
-+	preempt_disable();
-+	measure_overheads(have_mmcr1);
-+	preempt_enable();
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_setup.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_setup.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_setup.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,116 @@
-+/* $Id: x86_setup.c,v 1.47.2.2 2004/08/02 19:38:51 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * x86/x86_64-specific kernel-resident code.
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <asm/processor.h>
-+#include <asm/perfctr.h>
-+#include <asm/fixmap.h>
-+#include <asm/apic.h>
-+#include "x86_compat.h"
-+#include "compat.h"
-+
-+/* XXX: belongs to a virtual_compat.c file */
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED && defined(CONFIG_PERFCTR_VIRTUAL) && LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) && !defined(HAVE_SET_CPUS_ALLOWED)
-+/**
-+ * set_cpus_allowed() - change a given task's processor affinity
-+ * @p: task to bind
-+ * @new_mask: bitmask of allowed processors
-+ *
-+ * Upon return, the task is running on a legal processor.  Note the caller
-+ * must have a valid reference to the task: it must not exit() prematurely.
-+ * This call can sleep; do not hold locks on call.
-+ */
-+void set_cpus_allowed(struct task_struct *p, unsigned long new_mask)
-+{
-+	new_mask &= cpu_online_map;
-+	BUG_ON(!new_mask);
-+
-+	/* This must be our own, safe, call from sys_vperfctr_control(). */
-+
-+	p->cpus_allowed = new_mask;
-+
-+	/*
-+	 * If the task is on a no-longer-allowed processor, we need to move
-+	 * it.  If the task is not current, then set need_resched and send
-+	 * its processor an IPI to reschedule.
-+	 */
-+	if (!(p->cpus_runnable & p->cpus_allowed)) {
-+		if (p != current) {
-+			p->need_resched = 1;
-+			smp_send_reschedule(p->processor);
-+		}
-+		/*
-+		 * Wait until we are on a legal processor.  If the task is
-+		 * current, then we should be on a legal processor the next
-+		 * time we reschedule.  Otherwise, we need to wait for the IPI.
-+		 */
-+		while (!(p->cpus_runnable & p->cpus_allowed))
-+			schedule();
-+	}
-+}
-+EXPORT_SYMBOL(set_cpus_allowed);
-+#endif
-+
-+#ifdef CONFIG_X86_LOCAL_APIC
-+static void perfctr_default_ihandler(unsigned long pc)
-+{
-+}
-+
-+static perfctr_ihandler_t perfctr_ihandler = perfctr_default_ihandler;
-+
-+asmlinkage void smp_perfctr_interrupt(struct pt_regs *regs)
-+{
-+	/* PREEMPT note: invoked via an interrupt gate, which
-+	   masks interrupts. We're still on the originating CPU. */
-+	/* XXX: recursive interrupts? delay the ACK, mask LVTPC, or queue? */
-+	ack_APIC_irq();
-+	irq_enter();
-+	(*perfctr_ihandler)(instruction_pointer(regs));
-+	irq_exit();
-+}
-+
-+void perfctr_cpu_set_ihandler(perfctr_ihandler_t ihandler)
-+{
-+	perfctr_ihandler = ihandler ? ihandler : perfctr_default_ihandler;
-+}
-+#endif
-+
-+#ifdef __x86_64__
-+extern unsigned int cpu_khz;
-+#else
-+extern unsigned long cpu_khz;
-+#endif
-+
-+/* Wrapper to avoid namespace clash in RedHat 8.0's 2.4.18-14 kernel. */
-+unsigned int perfctr_cpu_khz(void)
-+{
-+	return cpu_khz;
-+}
-+
-+#ifdef CONFIG_PERFCTR_MODULE
-+EXPORT_SYMBOL_mmu_cr4_features;
-+EXPORT_SYMBOL(perfctr_cpu_khz);
-+
-+#ifdef CONFIG_X86_LOCAL_APIC
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)
-+EXPORT_SYMBOL(nmi_perfctr_msr);
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,67) && defined(CONFIG_PM)
-+EXPORT_SYMBOL(apic_pm_register);
-+EXPORT_SYMBOL(apic_pm_unregister);
-+EXPORT_SYMBOL(nmi_pmdev);
-+#endif
-+
-+EXPORT_SYMBOL(perfctr_cpu_set_ihandler);
-+#endif /* CONFIG_X86_LOCAL_APIC */
-+
-+#endif /* MODULE */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/global.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/global.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/global.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,17 @@
-+/* $Id: global.h,v 1.7 2003/10/02 20:04:35 mikpe Exp $
-+ * Global-mode performance-monitoring counters.
-+ *
-+ * Copyright (C) 2000-2003  Mikael Pettersson
-+ */
-+
-+#ifdef CONFIG_PERFCTR_GLOBAL
-+extern int gperfctr_ioctl(struct inode*, struct file*, unsigned int, unsigned long);
-+extern void gperfctr_init(void);
-+#else
-+extern int gperfctr_ioctl(struct inode *inode, struct file *filp,
-+			  unsigned int cmd, unsigned long arg)
-+{
-+	return -EINVAL;
-+}
-+static inline void gperfctr_init(void) { }
-+#endif
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/cpumask.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/cpumask.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/cpumask.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,81 @@
-+/* $Id: cpumask.h,v 1.6.2.1 2004/07/12 21:09:45 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Partial simulation of cpumask_t on non-cpumask_t kernels.
-+ * Extension to allow inspecting a cpumask_t as array of ulong.
-+ * Appropriate definition of perfctr_cpus_forbidden_mask.
-+ *
-+ * Copyright (C) 2003-2004  Mikael Pettersson
-+ */
-+
-+/* 2.6.0-test4 changed set-of-CPUs values from ulong to cpumask_t */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-+
-+#if !defined(PERFCTR_HAVE_CPUMASK_T) && !defined(HAVE_CPUMASK_T)
-+typedef unsigned long cpumask_t;
-+#endif
-+
-+/* RH/FC1 kernel 2.4.22-1.2115.nptl added cpumask_t, but with
-+   an incomplete API and a broken cpus_and() [misspelled parameter
-+   in its body]. Sigh.
-+   Assume cpumask_t is unsigned long and use our own code. */
-+#undef cpu_set
-+#define cpu_set(cpu, map)	atomic_set_mask((1UL << (cpu)), &(map))
-+#undef cpu_isset
-+#define cpu_isset(cpu, map)	((map) & (1UL << (cpu)))
-+#undef cpus_and
-+#define cpus_and(dst,src1,src2)	do { (dst) = (src1) & (src2); } while(0)
-+#undef cpus_clear
-+#define cpus_clear(map)		do { (map) = 0UL; } while(0)
-+#undef cpus_complement
-+#define cpus_complement(map)	do { (map) = ~(map); } while(0)
-+#undef cpus_empty
-+#define cpus_empty(map)		((map) == 0UL)
-+#undef cpus_equal
-+#define cpus_equal(map1, map2)	((map1) == (map2))
-+#undef cpus_addr
-+#define cpus_addr(map)		(&(map))
-+
-+#undef CPU_MASK_NONE
-+#define CPU_MASK_NONE		0UL
-+
-+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,1)
-+
-+/* 2.6.1-rc1 introduced cpus_addr() */
-+#ifdef CPU_ARRAY_SIZE
-+#define cpus_addr(map)		((map).mask)
-+#else
-+#define cpus_addr(map)		(&(map))
-+#endif
-+
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8) && !defined(cpus_andnot)
-+#define cpus_andnot(dst, src1, src2) \
-+do { \
-+    cpumask_t _tmp2; \
-+    _tmp2 = (src2); \
-+    cpus_complement(_tmp2); \
-+    cpus_and((dst), (src1), _tmp2); \
-+} while(0)
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) && !defined(CONFIG_SMP)
-+#undef cpu_online_map
-+#define cpu_online_map	cpumask_of_cpu(0)
-+#endif
-+
-+#ifdef CPU_ARRAY_SIZE
-+#define PERFCTR_CPUMASK_NRLONGS	CPU_ARRAY_SIZE
-+#else
-+#define PERFCTR_CPUMASK_NRLONGS	1
-+#endif
-+
-+/* `perfctr_cpus_forbidden_mask' used to be defined in <asm/perfctr.h>,
-+   but cpumask_t compatibility issues forced it to be moved here. */
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+extern cpumask_t perfctr_cpus_forbidden_mask;
-+#define perfctr_cpu_is_forbidden(cpu)	cpu_isset((cpu), perfctr_cpus_forbidden_mask)
-+#else
-+#define perfctr_cpus_forbidden_mask	CPU_MASK_NONE
-+#define perfctr_cpu_is_forbidden(cpu)	0 /* cpu_isset() needs an lvalue :-( */
-+#endif
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_compat.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_compat.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_compat.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,41 @@
-+/* $Id: x86_compat.h,v 1.33 2004/02/29 16:03:03 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * x86/x86_64-specific compatibility definitions for 2.4/2.6 kernels.
-+ *
-+ * Copyright (C) 2000-2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#include <linux/version.h>
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,18)
-+
-+/* missing from <asm-i386/cpufeature.h> */
-+#define cpu_has_msr	boot_cpu_has(X86_FEATURE_MSR)
-+
-+#else	/* 2.4 */
-+
-+/* missing from <asm-i386/processor.h> */
-+#ifndef cpu_has_mmx	/* added in 2.4.22-pre3 */
-+#define cpu_has_mmx	(test_bit(X86_FEATURE_MMX,  boot_cpu_data.x86_capability))
-+#endif
-+#define cpu_has_msr	(test_bit(X86_FEATURE_MSR,  boot_cpu_data.x86_capability))
-+#ifndef cpu_has_ht	/* added in 2.4.22-pre3 */
-+#define cpu_has_ht	(test_bit(28, boot_cpu_data.x86_capability))
-+#endif
-+
-+#endif	/* 2.4 */
-+
-+/* irq_enter() and irq_exit() take two parameters in 2.4. However,
-+   we only use them to disable preemption in the interrupt handler,
-+   which isn't needed in non-preemptive 2.4 kernels. */
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-+#ifdef CONFIG_PREEMPT
-+#error "not yet ported to 2.4+PREEMPT"
-+#endif
-+#undef irq_enter
-+#undef irq_exit
-+#define irq_enter()	do{}while(0)
-+#define irq_exit()	do{}while(0)
-+#endif
-+
-+extern unsigned int perfctr_cpu_khz(void);
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/Makefile24
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/Makefile24	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/Makefile24	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,39 @@
-+# $Id: Makefile24,v 1.7.2.1 2004/08/02 22:24:58 mikpe Exp $
-+# Performance-monitoring counters driver Makefile for 2.4 kernels.
-+
-+# construct various object file lists:
-+# kernel-objs-y		kernel objects exporting symbols
-+# y-objs-y		kernel objects not exporting symbols
-+# m-objs-m		perfctr.o if driver is module, empty otherwise
-+# driver-objs-y		objects for perfctr.o module, or empty
-+
-+# This also covers x86_64.
-+driver-objs-$(CONFIG_X86) := x86.o
-+tests-objs-$(CONFIG_X86) := x86_tests.o
-+kernel-objs-$(CONFIG_X86) := x86_setup.o
-+
-+driver-objs-$(CONFIG_PPC32) := ppc.o
-+tests-objs-$(CONFIG_PPC32) := ppc_tests.o
-+kernel-objs-$(CONFIG_PPC32) := ppc_setup.o
-+
-+driver-objs-y += init.o marshal.o
-+driver-objs-$(CONFIG_PERFCTR_INIT_TESTS) += $(tests-objs-y)
-+driver-objs-$(CONFIG_PERFCTR_VIRTUAL) += virtual.o
-+stub-objs-$(CONFIG_PERFCTR)-$(CONFIG_PERFCTR_VIRTUAL) := virtual_stub.o
-+driver-objs-$(CONFIG_PERFCTR_GLOBAL) += global.o
-+m-objs-$(CONFIG_PERFCTR) := perfctr.o
-+y-objs-$(CONFIG_PERFCTR) := $(driver-objs-y)
-+kernel-objs-y += $(stub-objs-m-y)
-+
-+perfctr-objs		:= $(driver-objs-y)
-+obj-m			+= $(m-objs-m)
-+
-+export-objs		:= $(kernel-objs-y)
-+O_TARGET		:= kperfctr.o
-+obj-y			:= $(kernel-objs-y) $(y-objs-y)
-+list-multi		:= perfctr.o
-+
-+include $(TOPDIR)/Rules.make
-+
-+perfctr.o:	$(perfctr-objs)
-+	$(LD) -r -o $@ $(perfctr-objs)
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_tests.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_tests.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_tests.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,310 @@
-+/* $Id: x86_tests.c,v 1.23.2.5 2004/08/02 22:24:58 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Optional x86/x86_64-specific init-time tests.
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/perfctr.h>
-+#include <asm/msr.h>
-+#undef MSR_P6_PERFCTR0
-+#undef MSR_P4_IQ_CCCR0
-+#undef MSR_P4_CRU_ESCR0
-+#include <asm/fixmap.h>
-+#include <asm/apic.h>
-+#include "x86_compat.h"
-+#include "x86_tests.h"
-+
-+#define MSR_P5_CESR		0x11
-+#define MSR_P5_CTR0		0x12
-+#define P5_CESR_VAL		(0x16 | (3<<6))
-+#define MSR_P6_PERFCTR0		0xC1
-+#define MSR_P6_EVNTSEL0		0x186
-+#define P6_EVNTSEL0_VAL		(0xC0 | (3<<16) | (1<<22))
-+#define MSR_K7_EVNTSEL0		0xC0010000
-+#define MSR_K7_PERFCTR0		0xC0010004
-+#define K7_EVNTSEL0_VAL		(0xC0 | (3<<16) | (1<<22))
-+#define VC3_EVNTSEL1_VAL	0xC0
-+#define MSR_P4_IQ_COUNTER0	0x30C
-+#define MSR_P4_IQ_CCCR0		0x36C
-+#define MSR_P4_CRU_ESCR0	0x3B8
-+#define P4_CRU_ESCR0_VAL	((2<<25) | (1<<9) | (0x3<<2))
-+#define P4_IQ_CCCR0_VAL		((0x3<<16) | (4<<13) | (1<<12))
-+
-+#define NITER	64
-+#define X2(S)	S";"S
-+#define X8(S)	X2(X2(X2(S)))
-+
-+#ifdef __x86_64__
-+#define CR4MOV	"movq"
-+#else
-+#define CR4MOV	"movl"
-+#endif
-+
-+#ifndef CONFIG_X86_LOCAL_APIC
-+#undef apic_write
-+#define apic_write(reg,vector)			do{}while(0)
-+#endif
-+
-+#if !defined(__x86_64__)
-+/* Avoid speculative execution by the CPU */
-+extern inline void sync_core(void)
-+{
-+	int tmp;
-+	asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory");
-+}
-+#endif
-+
-+static void __init do_rdpmc(unsigned pmc, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("rdpmc") : : "c"(pmc) : "eax", "edx");
-+}
-+
-+static void __init do_rdmsr(unsigned msr, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("rdmsr") : : "c"(msr) : "eax", "edx");
-+}
-+
-+static void __init do_wrmsr(unsigned msr, unsigned data)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("wrmsr") : : "c"(msr), "a"(data), "d"(0));
-+}
-+
-+static void __init do_rdcr4(unsigned unused1, unsigned unused2)
-+{
-+	unsigned i;
-+	unsigned long dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8(CR4MOV" %%cr4,%0") : "=r"(dummy));
-+}
-+
-+static void __init do_wrcr4(unsigned cr4, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8(CR4MOV" %0,%%cr4") : : "r"((long)cr4));
-+}
-+
-+static void __init do_rdtsc(unsigned unused1, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("rdtsc") : : : "eax", "edx");
-+}
-+
-+static void __init do_wrlvtpc(unsigned val, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i) {
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+	}
-+}
-+
-+static void __init do_sync_core(unsigned unused1, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i) {
-+		sync_core();
-+		sync_core();
-+		sync_core();
-+		sync_core();
-+		sync_core();
-+		sync_core();
-+		sync_core();
-+		sync_core();
-+	}
-+}
-+
-+static void __init do_empty_loop(unsigned unused1, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__("" : : "c"(0));
-+}
-+
-+static unsigned __init run(void (*doit)(unsigned, unsigned),
-+			   unsigned arg1, unsigned arg2)
-+{
-+	unsigned start, dummy, stop;
-+	sync_core();
-+	rdtsc(start, dummy);
-+	(*doit)(arg1, arg2);	/* should take < 2^32 cycles to complete */
-+	sync_core();
-+	rdtsc(stop, dummy);
-+	return stop - start;
-+}
-+
-+static void __init init_tests_message(void)
-+{
-+	printk(KERN_INFO "Please email the following PERFCTR INIT lines "
-+	       "to mikpe@csd.uu.se\n"
-+	       KERN_INFO "To remove this message, rebuild the driver "
-+	       "with CONFIG_PERFCTR_INIT_TESTS=n\n");
-+	printk(KERN_INFO "PERFCTR INIT: vendor %u, family %u, model %u, stepping %u, clock %u kHz\n",
-+	       current_cpu_data.x86_vendor,
-+	       current_cpu_data.x86,
-+	       current_cpu_data.x86_model,
-+	       current_cpu_data.x86_mask,
-+	       perfctr_cpu_khz());
-+}
-+
-+static void __init
-+measure_overheads(unsigned msr_evntsel0, unsigned evntsel0, unsigned msr_perfctr0,
-+		  unsigned msr_cccr, unsigned cccr_val)
-+{
-+	int i;
-+	unsigned int loop, ticks[13];
-+	const char *name[13];
-+
-+	if (msr_evntsel0)
-+		wrmsr(msr_evntsel0, 0, 0);
-+	if (msr_cccr)
-+		wrmsr(msr_cccr, 0, 0);
-+
-+	name[0] = "rdtsc";
-+	ticks[0] = run(do_rdtsc, 0, 0);
-+	name[1] = "rdpmc";
-+	ticks[1] = (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
-+		? run(do_rdpmc,1,0) : 0;
-+	name[2] = "rdmsr (counter)";
-+	ticks[2] = msr_perfctr0 ? run(do_rdmsr, msr_perfctr0, 0) : 0;
-+	name[3] = msr_cccr ? "rdmsr (escr)" : "rdmsr (evntsel)";
-+	ticks[3] = msr_evntsel0 ? run(do_rdmsr, msr_evntsel0, 0) : 0;
-+	name[4] = "wrmsr (counter)";
-+	ticks[4] = msr_perfctr0 ? run(do_wrmsr, msr_perfctr0, 0) : 0;
-+	name[5] = msr_cccr ? "wrmsr (escr)" : "wrmsr (evntsel)";
-+	ticks[5] = msr_evntsel0 ? run(do_wrmsr, msr_evntsel0, evntsel0) : 0;
-+	name[6] = "read cr4";
-+	ticks[6] = run(do_rdcr4, 0, 0);
-+	name[7] = "write cr4";
-+	ticks[7] = run(do_wrcr4, read_cr4(), 0);
-+	name[8] = "rdpmc (fast)";
-+	ticks[8] = msr_cccr ? run(do_rdpmc, 0x80000001, 0) : 0;
-+	name[9] = "rdmsr (cccr)";
-+	ticks[9] = msr_cccr ? run(do_rdmsr, msr_cccr, 0) : 0;
-+	name[10] = "wrmsr (cccr)";
-+	ticks[10] = msr_cccr ? run(do_wrmsr, msr_cccr, cccr_val) : 0;
-+	name[11] = "write LVTPC";
-+	ticks[11] = (perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
-+		? run(do_wrlvtpc, APIC_DM_NMI|APIC_LVT_MASKED, 0) : 0;
-+	name[12] = "sync_core";
-+	ticks[12] = run(do_sync_core, 0, 0);
-+
-+	loop = run(do_empty_loop, 0, 0);
-+
-+	if (msr_evntsel0)
-+		wrmsr(msr_evntsel0, 0, 0);
-+	if (msr_cccr)
-+		wrmsr(msr_cccr, 0, 0);
-+
-+	init_tests_message();
-+	printk(KERN_INFO "PERFCTR INIT: NITER == %u\n", NITER);
-+	printk(KERN_INFO "PERFCTR INIT: loop overhead is %u cycles\n", loop);
-+	for(i = 0; i < ARRAY_SIZE(ticks); ++i) {
-+		unsigned int x;
-+		if (!ticks[i])
-+			continue;
-+		x = ((ticks[i] - loop) * 10) / NITER;
-+		printk(KERN_INFO "PERFCTR INIT: %s cost is %u.%u cycles (%u total)\n",
-+		       name[i], x/10, x%10, ticks[i]);
-+	}
-+}
-+
-+#ifndef __x86_64__
-+static inline void perfctr_p5_init_tests(void)
-+{
-+	measure_overheads(MSR_P5_CESR, P5_CESR_VAL, MSR_P5_CTR0, 0, 0);
-+}
-+
-+static inline void perfctr_p6_init_tests(void)
-+{
-+	measure_overheads(MSR_P6_EVNTSEL0, P6_EVNTSEL0_VAL, MSR_P6_PERFCTR0, 0, 0);
-+}
-+
-+#if !defined(CONFIG_X86_TSC)
-+static inline void perfctr_c6_init_tests(void)
-+{
-+	unsigned int cesr, dummy;
-+
-+	rdmsr(MSR_P5_CESR, cesr, dummy);
-+	init_tests_message();
-+	printk(KERN_INFO "PERFCTR INIT: boot CESR == %#08x\n", cesr);
-+}
-+#endif
-+
-+static inline void perfctr_vc3_init_tests(void)
-+{
-+	measure_overheads(MSR_P6_EVNTSEL0+1, VC3_EVNTSEL1_VAL, MSR_P6_PERFCTR0+1, 0, 0);
-+}
-+#endif /* !__x86_64__ */
-+
-+static inline void perfctr_p4_init_tests(void)
-+{
-+	measure_overheads(MSR_P4_CRU_ESCR0, P4_CRU_ESCR0_VAL, MSR_P4_IQ_COUNTER0,
-+			  MSR_P4_IQ_CCCR0, P4_IQ_CCCR0_VAL);
-+}
-+
-+static inline void perfctr_k7_init_tests(void)
-+{
-+	measure_overheads(MSR_K7_EVNTSEL0, K7_EVNTSEL0_VAL, MSR_K7_PERFCTR0, 0, 0);
-+}
-+
-+static inline void perfctr_generic_init_tests(void)
-+{
-+	measure_overheads(0, 0, 0, 0, 0);
-+}
-+
-+enum perfctr_x86_tests_type perfctr_x86_tests_type __initdata = PTT_UNKNOWN;
-+
-+void __init perfctr_x86_init_tests(void)
-+{
-+	switch (perfctr_x86_tests_type) {
-+#ifndef __x86_64__
-+	case PTT_P5: /* Intel P5, P5MMX; Cyrix 6x86MX, MII, III */
-+		perfctr_p5_init_tests();
-+		break;
-+	case PTT_P6: /* Intel PPro, PII, PIII, PENTM */
-+		perfctr_p6_init_tests();
-+		break;
-+#if !defined(CONFIG_X86_TSC)
-+	case PTT_WINCHIP: /* WinChip C6, 2, 3 */
-+		perfctr_c6_init_tests();
-+		break;
-+#endif
-+	case PTT_VC3: /* VIA C3 */
-+		perfctr_vc3_init_tests();
-+		break;
-+#endif /* !__x86_64__ */
-+	case PTT_P4: /* Intel P4 */
-+		perfctr_p4_init_tests();
-+		break;
-+	case PTT_AMD: /* AMD K7, K8 */
-+		perfctr_k7_init_tests();
-+		break;
-+	case PTT_GENERIC:
-+		perfctr_generic_init_tests();
-+		break;
-+	default:
-+		printk(KERN_INFO "%s: unknown CPU type %u\n",
-+		       __FUNCTION__, perfctr_x86_tests_type);
-+		break;
-+	}
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/ppc.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,925 @@
-+/* $Id: ppc.c,v 1.3.2.8 2004/10/19 15:18:21 mikpe Exp $
-+ * PPC32 performance-monitoring counters driver.
-+ *
-+ * Copyright (C) 2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/perfctr.h>
-+#include <asm/prom.h>
-+#include <asm/time.h>		/* tb_ticks_per_jiffy, get_tbl() */
-+
-+#include "compat.h"
-+#include "ppc_compat.h"
-+#include "ppc_tests.h"
-+
-+/* Support for lazy evntsel and perfctr SPR updates. */
-+struct per_cpu_cache {	/* roughly a subset of perfctr_cpu_state */
-+	union {
-+		unsigned int id;	/* cache owner id */
-+	} k1;
-+	/* Physically indexed cache of the MMCRs. */
-+	unsigned int ppc_mmcr[3];
-+} ____cacheline_aligned;
-+static struct per_cpu_cache per_cpu_cache[NR_CPUS] __cacheline_aligned;
-+#define get_cpu_cache()	(&per_cpu_cache[smp_processor_id()])
-+
-+/* Structure for counter snapshots, as 32-bit values. */
-+struct perfctr_low_ctrs {
-+	unsigned int tsc;
-+	unsigned int pmc[6];
-+};
-+
-+enum pm_type {
-+	PM_NONE,
-+	PM_604,
-+	PM_604e,
-+	PM_750,	/* XXX: Minor event set diffs between IBM and Moto. */
-+	PM_7400,
-+	PM_7450,
-+};
-+static enum pm_type pm_type;
-+
-+/* Bits users shouldn't set in control.ppc.mmcr0:
-+ * - PMXE because we don't yet support overflow interrupts
-+ * - PMC1SEL/PMC2SEL because event selectors are in control.evntsel[]
-+ */
-+#define MMCR0_RESERVED		(MMCR0_PMXE | MMCR0_PMC1SEL | MMCR0_PMC2SEL)
-+
-+static unsigned int new_id(void)
-+{
-+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
-+	static unsigned int counter;
-+	int id;
-+
-+	spin_lock(&lock);
-+	id = ++counter;
-+	spin_unlock(&lock);
-+	return id;
-+}
-+
-+#ifndef PERFCTR_INTERRUPT_SUPPORT
-+#define perfctr_cstatus_has_ictrs(cstatus)	0
-+#endif
-+
-+#if defined(CONFIG_SMP) && defined(PERFCTR_INTERRUPT_SUPPORT)
-+
-+static inline void
-+set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu)
-+{
-+	state->k1.isuspend_cpu = cpu;
-+}
-+
-+static inline int
-+is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu)
-+{
-+	return state->k1.isuspend_cpu == cpu;
-+}
-+
-+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state)
-+{
-+	state->k1.isuspend_cpu = NR_CPUS;
-+}
-+
-+#else
-+static inline void set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) { }
-+static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) { return 1; }
-+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { }
-+#endif
-+
-+/* The ppc driver internally uses cstatus & (1<<30) to record that
-+   a context has an asynchronously changing MMCR0. */
-+static inline unsigned int perfctr_cstatus_set_mmcr0_quirk(unsigned int cstatus)
-+{
-+	return cstatus | (1 << 30);
-+}
-+
-+static inline int perfctr_cstatus_has_mmcr0_quirk(unsigned int cstatus)
-+{
-+	return cstatus & (1 << 30);
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Driver procedures.						*
-+ *								*
-+ ****************************************************************/
-+
-+/*
-+ * The PowerPC 604/750/74xx family.
-+ *
-+ * Common features
-+ * ---------------
-+ * - Per counter event selection data in subfields of control registers.
-+ *   MMCR0 contains both global control and PMC1/PMC2 event selectors.
-+ * - Overflow interrupt support is present in all processors, but an
-+ *   erratum makes it difficult to use in 750/7400/7410 processors.
-+ * - There is no concept of per-counter qualifiers:
-+ *   - User-mode/supervisor-mode restrictions are global.
-+ *   - Two groups of counters, PMC1 and PMC2-PMC<highest>. Each group
-+ *     has a single overflow interrupt/event enable/disable flag.
-+ * - The instructions used to read (mfspr) and write (mtspr) the control
-+ *   and counter registers (SPRs) only support hardcoded register numbers.
-+ *   There is no support for accessing an SPR via a runtime value.
-+ * - Each counter supports its own unique set of events. However, events
-+ *   0-1 are common for PMC1-PMC4, and events 2-4 are common for PMC1-PMC4.
-+ * - There is no separate high-resolution core clock counter.
-+ *   The time-base counter is available, but it typically runs an order of
-+ *   magnitude slower than the core clock.
-+ *   Any performance counter can be programmed to count core clocks, but
-+ *   doing this (a) reserves one PMC, and (b) needs indirect accesses
-+ *   since the SPR number in general isn't known at compile-time.
-+ *
-+ * Driver notes
-+ * ------------
-+ * - The driver currently does not support performance monitor interrupts,
-+ *   mostly because of the 750/7400/7410 erratum. Working around it would
-+ *   require disabling the decrementer interrupt, reserving a performance
-+ *   counter and setting it up for TBL bit-flip events, and having the PMI
-+ *   handler invoke the decrementer handler.
-+ *
-+ * 604
-+ * ---
-+ * 604 has MMCR0, PMC1, PMC2, SIA, and SDA.
-+ *
-+ * MMCR0[THRESHOLD] is not automatically multiplied.
-+ *
-+ * On the 604, software must always reset MMCR0[ENINT] after
-+ * taking a PMI. This is not the case for the 604e.
-+ *
-+ * 604e
-+ * ----
-+ * 604e adds MMCR1, PMC3, and PMC4.
-+ * Bus-to-core multiplier is available via HID1[PLL_CFG].
-+ *
-+ * MMCR0[THRESHOLD] is automatically multiplied by 4.
-+ *
-+ * When the 604e vectors to the PMI handler, it automatically
-+ * clears any pending PMIs. Unlike the 604, the 604e does not
-+ * require MMCR0[ENINT] to be cleared (and possibly reset)
-+ * before external interrupts can be re-enabled.
-+ *
-+ * 750
-+ * ---
-+ * 750 adds user-readable MMCRn/PMCn/SIA registers, and removes SDA.
-+ *
-+ * MMCR0[THRESHOLD] is not automatically multiplied.
-+ *
-+ * Motorola MPC750UM.pdf, page C-78, states: "The performance monitor
-+ * of the MPC755 functions the same as that of the MPC750, (...), except
-+ * that for both the MPC750 and MPC755, no combination of the thermal
-+ * assist unit, the decrementer register, and the performance monitor
-+ * can be used at any one time. If exceptions for any two of these
-+ * functional blocks are enabled together, multiple exceptions caused
-+ * by any of these three blocks cause unpredictable results."
-+ *
-+ * IBM 750CXe_Err_DD2X.pdf, Erratum #13, states that a PMI which
-+ * occurs immediately after a delayed decrementer exception can
-+ * corrupt SRR0, causing the processor to hang. It also states that
-+ * PMIs via TB bit transitions can be used to simulate the decrementer.
-+ *
-+ * 750FX adds dual-PLL support and programmable core frequency switching.
-+ *
-+ * 74xx
-+ * ----
-+ * 7400 adds MMCR2 and BAMR.
-+ *
-+ * MMCR0[THRESHOLD] is multiplied by 2 or 32, as specified
-+ * by MMCR2[THRESHMULT].
-+ *
-+ * 74xx changes the semantics of several MMCR0 control bits,
-+ * compared to 604/750.
-+ *
-+ * PPC7410 Erratum No. 10: Like the MPC750 TAU/DECR/PMI erratum.
-+ * Erratum No. 14 marks TAU as unsupported in 7410, but this leaves
-+ * perfmon and decrementer interrupts as being mutually exclusive.
-+ * Affects PPC7410 1.0-1.2 (PVR 0x800C1100-0x800C1102). 1.3 and up
-+ * (PVR 0x800C1103 up) are Ok.
-+ *
-+ * 7450 adds PMC5 and PMC6.
-+ *
-+ * 7455/7445 V3.3 (PVR 80010303) and later use the 7457 PLL table,
-+ * earlier revisions use the 7450 PLL table
-+ */
-+
-+static inline unsigned int read_pmc(unsigned int pmc)
-+{
-+	switch (pmc) {
-+	default: /* impossible, but silences gcc warning */
-+	case 0:
-+		return mfspr(SPRN_PMC1);
-+	case 1:
-+		return mfspr(SPRN_PMC2);
-+	case 2:
-+		return mfspr(SPRN_PMC3);
-+	case 3:
-+		return mfspr(SPRN_PMC4);
-+	case 4:
-+		return mfspr(SPRN_PMC5);
-+	case 5:
-+		return mfspr(SPRN_PMC6);
-+	}
-+}
-+
-+static void ppc_read_counters(struct perfctr_cpu_state *state,
-+			      struct perfctr_low_ctrs *ctrs)
-+{
-+	unsigned int cstatus, nrctrs, i;
-+
-+	cstatus = state->cstatus;
-+	if (perfctr_cstatus_has_tsc(cstatus))
-+		ctrs->tsc = get_tbl();
-+	nrctrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int pmc = state->pmc[i].map;
-+		ctrs->pmc[i] = read_pmc(pmc);
-+	}
-+}
-+
-+static unsigned int pmc_max_event(unsigned int pmc)
-+{
-+	switch (pmc) {
-+	default: /* impossible, but silences gcc warning */
-+	case 0:
-+		return 127;
-+	case 1:
-+		return 63;
-+	case 2:
-+		return 31;
-+	case 3:
-+		return 31;
-+	case 4:
-+		return 31;
-+	case 5:
-+		return 63;
-+	}
-+}
-+
-+static unsigned int get_nr_pmcs(void)
-+{
-+	switch (pm_type) {
-+	case PM_7450:
-+		return 6;
-+	case PM_7400:
-+	case PM_750:
-+	case PM_604e:
-+		return 4;
-+	case PM_604:
-+		return 2;
-+	default: /* PM_NONE, but silences gcc warning */
-+		return 0;
-+	}
-+}
-+
-+static int ppc_check_control(struct perfctr_cpu_state *state)
-+{
-+	unsigned int i, nrctrs, pmc_mask, pmc;
-+	unsigned int nr_pmcs, evntsel[6];
-+
-+	nr_pmcs = get_nr_pmcs();
-+	nrctrs = state->control.nractrs;
-+	if (state->control.nrictrs || nrctrs > nr_pmcs)
-+		return -EINVAL;
-+
-+	pmc_mask = 0;
-+	memset(evntsel, 0, sizeof evntsel);
-+	for(i = 0; i < nrctrs; ++i) {
-+		pmc = state->control.pmc_map[i];
-+		state->pmc[i].map = pmc;
-+		if (pmc >= nr_pmcs || (pmc_mask & (1<<pmc)))
-+			return -EINVAL;
-+		pmc_mask |= (1<<pmc);
-+
-+		evntsel[pmc] = state->control.evntsel[i];
-+		if (evntsel[pmc] > pmc_max_event(pmc))
-+			return -EINVAL;
-+	}
-+
-+	switch (pm_type) {
-+	case PM_7450:
-+	case PM_7400:
-+		if (state->control.ppc.mmcr2 & MMCR2_RESERVED)
-+			return -EINVAL;
-+		state->ppc_mmcr[2] = state->control.ppc.mmcr2;
-+		break;
-+	default:
-+		if (state->control.ppc.mmcr2)
-+			return -EINVAL;
-+		state->ppc_mmcr[2] = 0;
-+	}
-+
-+	if (state->control.ppc.mmcr0 & MMCR0_RESERVED)
-+		return -EINVAL;
-+	state->ppc_mmcr[0] = (state->control.ppc.mmcr0
-+			      | (evntsel[0] << (31-25))
-+			      | (evntsel[1] << (31-31)));
-+
-+	state->ppc_mmcr[1] = ((  evntsel[2] << (31-4))
-+			      | (evntsel[3] << (31-9))
-+			      | (evntsel[4] << (31-14))
-+			      | (evntsel[5] << (31-20)));
-+
-+	state->k1.id = new_id();
-+
-+	/*
-+	 * MMCR0[FC] and MMCR0[TRIGGER] may change on 74xx if FCECE or
-+	 * TRIGGER is set. At suspends we must read MMCR0 back into
-+	 * the state and the cache and then freeze the counters, and
-+	 * at resumes we must unfreeze the counters and reload MMCR0.
-+	 */
-+	switch (pm_type) {
-+	case PM_7450:
-+	case PM_7400:
-+		if (state->ppc_mmcr[0] & (MMCR0_FCECE | MMCR0_TRIGGER))
-+			state->cstatus = perfctr_cstatus_set_mmcr0_quirk(state->cstatus);
-+	default:
-+		;
-+	}
-+
-+	return 0;
-+}
-+
-+#ifdef PERFCTR_INTERRUPT_SUPPORT
-+static void ppc_isuspend(struct perfctr_cpu_state *state)
-+{
-+	// XXX
-+}
-+
-+static void ppc_iresume(const struct perfctr_cpu_state *state)
-+{
-+	// XXX
-+}
-+#endif
-+
-+static void ppc_write_control(const struct perfctr_cpu_state *state)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int value;
-+
-+	cache = get_cpu_cache();
-+	if (cache->k1.id == state->k1.id)
-+		return;
-+	/*
-+	 * Order matters here: update threshmult and event
-+	 * selectors before updating global control, which
-+	 * potentially enables PMIs.
-+	 *
-+	 * Since mtspr doesn't accept a runtime value for the
-+	 * SPR number, unroll the loop so each mtspr targets
-+	 * a constant SPR.
-+	 *
-+	 * For processors without MMCR2, we ensure that the
-+	 * cache and the state indicate the same value for it,
-+	 * preventing any actual mtspr to it. Ditto for MMCR1.
-+	 */
-+	value = state->ppc_mmcr[2];
-+	if (value != cache->ppc_mmcr[2]) {
-+		cache->ppc_mmcr[2] = value;
-+		mtspr(SPRN_MMCR2, value);
-+	}
-+	value = state->ppc_mmcr[1];
-+	if (value != cache->ppc_mmcr[1]) {
-+		cache->ppc_mmcr[1] = value;
-+		mtspr(SPRN_MMCR1, value);
-+	}
-+	value = state->ppc_mmcr[0];
-+	if (value != cache->ppc_mmcr[0]) {
-+		cache->ppc_mmcr[0] = value;
-+		mtspr(SPRN_MMCR0, value);
-+	}
-+	cache->k1.id = state->k1.id;
-+}
-+
-+static void ppc_clear_counters(void)
-+{
-+	switch (pm_type) {
-+	case PM_7450:
-+	case PM_7400:
-+		mtspr(SPRN_MMCR2, 0);
-+		mtspr(SPRN_BAMR, 0);
-+	case PM_750:
-+	case PM_604e:
-+		mtspr(SPRN_MMCR1, 0);
-+	case PM_604:
-+		mtspr(SPRN_MMCR0, 0);
-+	case PM_NONE:
-+		;
-+	}
-+	switch (pm_type) {
-+	case PM_7450:
-+		mtspr(SPRN_PMC6, 0);
-+		mtspr(SPRN_PMC5, 0);
-+	case PM_7400:
-+	case PM_750:
-+	case PM_604e:
-+		mtspr(SPRN_PMC4, 0);
-+		mtspr(SPRN_PMC3, 0);
-+	case PM_604:
-+		mtspr(SPRN_PMC2, 0);
-+		mtspr(SPRN_PMC1, 0);
-+	case PM_NONE:
-+		;
-+	}
-+}
-+
-+/*
-+ * Driver methods, internal and exported.
-+ */
-+
-+static void perfctr_cpu_write_control(const struct perfctr_cpu_state *state)
-+{
-+	return ppc_write_control(state);
-+}
-+
-+static void perfctr_cpu_read_counters(struct perfctr_cpu_state *state,
-+				      struct perfctr_low_ctrs *ctrs)
-+{
-+	return ppc_read_counters(state, ctrs);
-+}
-+
-+#ifdef PERFCTR_INTERRUPT_SUPPORT
-+static void perfctr_cpu_isuspend(struct perfctr_cpu_state *state)
-+{
-+	return ppc_isuspend(state);
-+}
-+
-+static void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
-+{
-+	return ppc_iresume(state);
-+}
-+
-+/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to
-+   bypass internal caching and force a reload if the I-mode PMCs. */
-+void perfctr_cpu_ireload(struct perfctr_cpu_state *state)
-+{
-+#ifdef CONFIG_SMP
-+	clear_isuspend_cpu(state);
-+#else
-+	get_cpu_cache()->k1.id = 0;
-+#endif
-+}
-+
-+/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */
-+unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state)
-+{
-+	unsigned int cstatus, nrctrs, pmc, pmc_mask;
-+
-+	cstatus = state->cstatus;
-+	pmc = perfctr_cstatus_nractrs(cstatus);
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+
-+	for(pmc_mask = 0; pmc < nrctrs; ++pmc) {
-+		if ((int)state->pmc[pmc].start < 0) { /* PPC-specific */
-+			/* XXX: "+=" to correct for overshots */
-+			state->pmc[pmc].start = state->control.ireset[pmc];
-+			pmc_mask |= (1 << pmc);
-+		}
-+	}
-+	/* XXX: if pmc_mask == 0, then it must have been a TBL bit flip */
-+	/* XXX: HW cleared MMCR0[ENINT]. We presumably cleared the entire
-+	   MMCR0, so the re-enable occurs automatically later, no? */
-+	return pmc_mask;
-+}
-+
-+static inline int check_ireset(const struct perfctr_cpu_state *state)
-+{
-+	unsigned int nrctrs, i;
-+
-+	i = state->control.nractrs;
-+	nrctrs = i + state->control.nrictrs;
-+	for(; i < nrctrs; ++i)
-+		if (state->control.ireset[i] < 0)	/* PPC-specific */
-+			return -EINVAL;
-+	return 0;
-+}
-+
-+static inline void setup_imode_start_values(struct perfctr_cpu_state *state)
-+{
-+	unsigned int cstatus, nrctrs, i;
-+
-+	cstatus = state->cstatus;
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
-+		state->pmc[i].start = state->control.ireset[i];
-+}
-+
-+#else	/* PERFCTR_INTERRUPT_SUPPORT */
-+static inline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) { }
-+static inline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) { }
-+static inline int check_ireset(const struct perfctr_cpu_state *state) { return 0; }
-+static inline void setup_imode_start_values(struct perfctr_cpu_state *state) { }
-+#endif	/* PERFCTR_INTERRUPT_SUPPORT */
-+
-+static int check_control(struct perfctr_cpu_state *state)
-+{
-+	return ppc_check_control(state);
-+}
-+
-+int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	int err;
-+
-+	clear_isuspend_cpu(state);
-+	state->cstatus = 0;
-+
-+	/* disallow i-mode counters if we cannot catch the interrupts */
-+	if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
-+	    && state->control.nrictrs)
-+		return -EPERM;
-+
-+	err = check_ireset(state);
-+	if (err < 0)
-+		return err;
-+	err = check_control(state); /* may initialise state->cstatus */
-+	if (err < 0)
-+		return err;
-+	state->cstatus |= perfctr_mk_cstatus(state->control.tsc_on,
-+					     state->control.nractrs,
-+					     state->control.nrictrs);
-+	setup_imode_start_values(state);
-+	return 0;
-+}
-+
-+void perfctr_cpu_suspend(struct perfctr_cpu_state *state)
-+{
-+	unsigned int i, cstatus, nractrs;
-+	struct perfctr_low_ctrs now;
-+
-+	if (perfctr_cstatus_has_mmcr0_quirk(state->cstatus)) {
-+		unsigned int mmcr0 = mfspr(SPRN_MMCR0);
-+		mtspr(SPRN_MMCR0, mmcr0 | MMCR0_FC);
-+		get_cpu_cache()->ppc_mmcr[0] = mmcr0 | MMCR0_FC;
-+		state->ppc_mmcr[0] = mmcr0;
-+	}
-+	if (perfctr_cstatus_has_ictrs(state->cstatus))
-+		perfctr_cpu_isuspend(state);
-+	perfctr_cpu_read_counters(state, &now);
-+	cstatus = state->cstatus;
-+	if (perfctr_cstatus_has_tsc(cstatus))
-+		state->tsc_sum += now.tsc - state->tsc_start;
-+	nractrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nractrs; ++i)
-+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
-+}
-+
-+void perfctr_cpu_resume(struct perfctr_cpu_state *state)
-+{
-+	if (perfctr_cstatus_has_ictrs(state->cstatus))
-+	    perfctr_cpu_iresume(state);
-+	if (perfctr_cstatus_has_mmcr0_quirk(state->cstatus))
-+		get_cpu_cache()->k1.id = 0; /* force reload of MMCR0 */
-+	perfctr_cpu_write_control(state);
-+	//perfctr_cpu_read_counters(state, &state->start);
-+	{
-+		struct perfctr_low_ctrs now;
-+		unsigned int i, cstatus, nrctrs;
-+		perfctr_cpu_read_counters(state, &now);
-+		cstatus = state->cstatus;
-+		if (perfctr_cstatus_has_tsc(cstatus))
-+			state->tsc_start = now.tsc;
-+		nrctrs = perfctr_cstatus_nractrs(cstatus);
-+		for(i = 0; i < nrctrs; ++i)
-+			state->pmc[i].start = now.pmc[i];
-+	}
-+	/* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
-+}
-+
-+void perfctr_cpu_sample(struct perfctr_cpu_state *state)
-+{
-+	unsigned int i, cstatus, nractrs;
-+	struct perfctr_low_ctrs now;
-+
-+	perfctr_cpu_read_counters(state, &now);
-+	cstatus = state->cstatus;
-+	if (perfctr_cstatus_has_tsc(cstatus)) {
-+		state->tsc_sum += now.tsc - state->tsc_start;
-+		state->tsc_start = now.tsc;
-+	}
-+	nractrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nractrs; ++i) {
-+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
-+		state->pmc[i].start = now.pmc[i];
-+	}
-+}
-+
-+static void perfctr_cpu_clear_counters(void)
-+{
-+	struct per_cpu_cache *cache;
-+
-+	cache = get_cpu_cache();
-+	memset(cache, 0, sizeof *cache);
-+	cache->k1.id = -1;
-+
-+	ppc_clear_counters();
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Processor detection and initialisation procedures.		*
-+ *								*
-+ ****************************************************************/
-+
-+/* Derive CPU core frequency from TB frequency and PLL_CFG. */
-+
-+enum pll_type {
-+	PLL_NONE,	/* for e.g. 604 which has no HID1[PLL_CFG] */
-+	PLL_604e,
-+	PLL_750,
-+	PLL_750FX,
-+	PLL_7400,
-+	PLL_7450,
-+	PLL_7457,
-+};
-+
-+/* These are the known bus-to-core ratios, indexed by PLL_CFG.
-+   Multiplied by 2 since half-multiplier steps are present. */
-+
-+static unsigned char cfg_ratio_604e[16] __initdata = { // *2
-+	2, 2, 14, 2, 4, 13, 5, 9,
-+	6, 11, 8, 10, 3, 12, 7, 0
-+};
-+
-+static unsigned char cfg_ratio_750[16] __initdata = { // *2
-+	5, 15, 14, 2, 4, 13, 20, 9, // 0b0110 is 18 if L1_TSTCLK=0, but that is abnormal
-+	6, 11, 8, 10, 16, 12, 7, 0
-+};
-+
-+static unsigned char cfg_ratio_750FX[32] __initdata = { // *2
-+	0, 0, 2, 2, 4, 5, 6, 7,
-+	8, 9, 10, 11, 12, 13, 14, 15,
-+	16, 17, 18, 19, 20, 22, 24, 26,
-+	28, 30, 32, 34, 36, 38, 40, 0
-+};
-+
-+static unsigned char cfg_ratio_7400[16] __initdata = { // *2
-+	18, 15, 14, 2, 4, 13, 5, 9,
-+	6, 11, 8, 10, 16, 12, 7, 0
-+};
-+
-+static unsigned char cfg_ratio_7450[32] __initdata = { // *2
-+	1, 0, 15, 30, 14, 0, 2, 0,
-+	4, 0, 13, 26, 5, 0, 9, 18,
-+	6, 0, 11, 22, 8, 20, 10, 24,
-+	16, 28, 12, 32, 7, 0, 0, 0
-+};
-+
-+static unsigned char cfg_ratio_7457[32] __initdata = { // *2
-+	23, 34, 15, 30, 14, 36, 2, 40,
-+	4, 42, 13, 26, 17, 48, 19, 18,
-+	6, 21, 11, 22, 8, 20, 10, 24,
-+	16, 28, 12, 32, 27, 56, 0, 25
-+};
-+
-+static unsigned int __init tb_to_core_ratio(enum pll_type pll_type)
-+{
-+	unsigned char *cfg_ratio;
-+	unsigned int shift = 28, mask = 0xF, hid1, pll_cfg, ratio;
-+
-+	switch (pll_type) {
-+	case PLL_604e:
-+		cfg_ratio = cfg_ratio_604e;
-+		break;
-+	case PLL_750:
-+		cfg_ratio = cfg_ratio_750;
-+		break;
-+	case PLL_750FX:
-+		cfg_ratio = cfg_ratio_750FX;
-+		hid1 = mfspr(SPRN_HID1);
-+		switch ((hid1 >> 16) & 0x3) { /* HID1[PI0,PS] */
-+		case 0:		/* PLL0 with external config */
-+			shift = 31-4;	/* access HID1[PCE] */
-+			break;
-+		case 2:		/* PLL0 with internal config */
-+			shift = 31-20;	/* access HID1[PC0] */
-+			break;
-+		case 1: case 3:	/* PLL1 */
-+			shift = 31-28;	/* access HID1[PC1] */
-+			break;
-+		}
-+		mask = 0x1F;
-+		break;
-+	case PLL_7400:
-+		cfg_ratio = cfg_ratio_7400;
-+		break;
-+	case PLL_7450:
-+		cfg_ratio = cfg_ratio_7450;
-+		shift = 12;
-+		mask = 0x1F;
-+		break;
-+	case PLL_7457:
-+		cfg_ratio = cfg_ratio_7457;
-+		shift = 12;
-+		mask = 0x1F;
-+		break;
-+	default:
-+		return 0;
-+	}
-+	hid1 = mfspr(SPRN_HID1);
-+	pll_cfg = (hid1 >> shift) & mask;
-+	ratio = cfg_ratio[pll_cfg];
-+	if (!ratio)
-+		printk(KERN_WARNING "perfctr: unknown PLL_CFG 0x%x\n", pll_cfg);
-+	return (4/2) * ratio;
-+}
-+
-+static unsigned int __init pll_to_core_khz(enum pll_type pll_type)
-+{
-+	unsigned int tb_to_core = tb_to_core_ratio(pll_type);
-+	perfctr_info.tsc_to_cpu_mult = tb_to_core;
-+	return tb_ticks_per_jiffy * tb_to_core * (HZ/10) / (1000/10);
-+}
-+
-+/* Extract core and timebase frequencies from Open Firmware. */
-+
-+static unsigned int __init of_to_core_khz(void)
-+{
-+	struct device_node *cpu;
-+	unsigned int *fp, core, tb;
-+
-+	cpu = find_type_devices("cpu");
-+	if (!cpu)
-+		return 0;
-+	fp = (unsigned int*)get_property(cpu, "clock-frequency", NULL);
-+	if (!fp || !(core = *fp))
-+		return 0;
-+	fp = (unsigned int*)get_property(cpu, "timebase-frequency", NULL);
-+	if (!fp || !(tb = *fp))
-+		return 0;
-+	perfctr_info.tsc_to_cpu_mult = core / tb;
-+	return core / 1000;
-+}
-+
-+static unsigned int __init detect_cpu_khz(enum pll_type pll_type)
-+{
-+	unsigned int khz;
-+
-+	khz = pll_to_core_khz(pll_type);
-+	if (khz)
-+		return khz;
-+
-+	khz = of_to_core_khz();
-+	if (khz)
-+		return khz;
-+
-+	printk(KERN_WARNING "perfctr: unable to determine CPU speed\n");
-+	return 0;
-+}
-+
-+static int __init known_init(void)
-+{
-+	static char known_name[] __initdata = "PowerPC 60x/7xx/74xx";
-+	unsigned int features;
-+	enum pll_type pll_type;
-+	unsigned int pvr;
-+	int have_mmcr1;
-+
-+	features = PERFCTR_FEATURE_RDTSC | PERFCTR_FEATURE_RDPMC;
-+	have_mmcr1 = 1;
-+	pvr = mfspr(SPRN_PVR);
-+	switch (PVR_VER(pvr)) {
-+	case 0x0004: /* 604 */
-+		pm_type = PM_604;
-+		pll_type = PLL_NONE;
-+		features = PERFCTR_FEATURE_RDTSC;
-+		have_mmcr1 = 0;
-+		break;
-+	case 0x0009: /* 604e;  */
-+	case 0x000A: /* 604ev */
-+		pm_type = PM_604e;
-+		pll_type = PLL_604e;
-+		features = PERFCTR_FEATURE_RDTSC;
-+		break;
-+	case 0x0008: /* 750/740 */
-+		pm_type = PM_750;
-+		pll_type = PLL_750;
-+		break;
-+	case 0x7000: case 0x7001: /* IBM750FX */
-+	case 0x7002: /* IBM750GX */
-+		pm_type = PM_750;
-+		pll_type = PLL_750FX;
-+		break;
-+	case 0x000C: /* 7400 */
-+		pm_type = PM_7400;
-+		pll_type = PLL_7400;
-+		break;
-+	case 0x800C: /* 7410 */
-+		pm_type = PM_7400;
-+		pll_type = PLL_7400;
-+		break;
-+	case 0x8000: /* 7451/7441 */
-+		pm_type = PM_7450;
-+		pll_type = PLL_7450;
-+		break;
-+	case 0x8001: /* 7455/7445 */
-+		pm_type = PM_7450;
-+		pll_type = ((pvr & 0xFFFF) < 0x0303) ? PLL_7450 : PLL_7457;
-+		break;
-+	case 0x8002: /* 7457/7447 */
-+		pm_type = PM_7450;
-+		pll_type = PLL_7457;
-+		break;
-+	default:
-+		return -ENODEV;
-+	}
-+	perfctr_info.cpu_features = features;
-+	perfctr_info.cpu_type = 0; /* user-space should inspect PVR */
-+	perfctr_cpu_name = known_name;
-+	perfctr_info.cpu_khz = detect_cpu_khz(pll_type);
-+	perfctr_ppc_init_tests(have_mmcr1);
-+	return 0;
-+}
-+
-+static int __init unknown_init(void)
-+{
-+	static char unknown_name[] __initdata = "Generic PowerPC with TB";
-+	unsigned int khz;
-+
-+	khz = detect_cpu_khz(PLL_NONE);
-+	if (!khz)
-+		return -ENODEV;
-+	perfctr_info.cpu_features = PERFCTR_FEATURE_RDTSC;
-+	perfctr_info.cpu_type = 0;
-+	perfctr_cpu_name = unknown_name;
-+	perfctr_info.cpu_khz = khz;
-+	pm_type = PM_NONE;
-+	return 0;
-+}
-+
-+static void perfctr_cpu_clear_one(void *ignore)
-+{
-+	/* PREEMPT note: when called via on_each_cpu(),
-+	   this is in IRQ context with preemption disabled. */
-+	perfctr_cpu_clear_counters();
-+}
-+
-+static void perfctr_cpu_reset(void)
-+{
-+	on_each_cpu(perfctr_cpu_clear_one, NULL, 1, 1);
-+	perfctr_cpu_set_ihandler(NULL);
-+}
-+
-+int __init perfctr_cpu_init(void)
-+{
-+	int err;
-+
-+	perfctr_info.cpu_features = 0;
-+
-+	err = known_init();
-+	if (err) {
-+		err = unknown_init();
-+		if (err)
-+			goto out;
-+	}
-+
-+	perfctr_cpu_reset();
-+ out:
-+	return err;
-+}
-+
-+void __exit perfctr_cpu_exit(void)
-+{
-+	perfctr_cpu_reset();
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Hardware reservation.					*
-+ *								*
-+ ****************************************************************/
-+
-+static DECLARE_MUTEX(mutex);
-+static const char *current_service = 0;
-+
-+const char *perfctr_cpu_reserve(const char *service)
-+{
-+	const char *ret;
-+
-+	down(&mutex);
-+	ret = current_service;
-+	if (!ret)
-+	{
-+		current_service = service;
-+		__module_get(THIS_MODULE);
-+	}
-+	up(&mutex);
-+	return ret;
-+}
-+
-+void perfctr_cpu_release(const char *service)
-+{
-+	down(&mutex);
-+	if (service != current_service) {
-+		printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n",
-+		       __FUNCTION__, service, current_service);
-+	} else {
-+		/* power down the counters */
-+		perfctr_cpu_reset();
-+		current_service = 0;
-+		module_put(THIS_MODULE);
-+	}
-+	up(&mutex);
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/virtual.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/virtual.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/virtual.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,1049 @@
-+/* $Id: virtual.c,v 1.88.2.2 2004/10/19 15:23:43 mikpe Exp $
-+ * Virtual per-process performance counters.
-+ *
-+ * Copyright (C) 1999-2003  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/compiler.h>	/* for unlikely() in 2.4.18 and older */
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/ptrace.h>
-+#include <linux/fs.h>
-+#include <linux/file.h>
-+#include <linux/perfctr.h>
-+
-+#include <asm/io.h>
-+#include <asm/uaccess.h>
-+
-+#include "compat.h"
-+#include "virtual.h"
-+#include "marshal.h"
-+
-+/****************************************************************
-+ *								*
-+ * Data types and macros.					*
-+ *								*
-+ ****************************************************************/
-+
-+struct vperfctr {
-+/* User-visible fields: (must be first for mmap()) */
-+	struct perfctr_cpu_state cpu_state;
-+/* Kernel-private fields: */
-+	int si_signo;
-+	atomic_t count;
-+	spinlock_t owner_lock;
-+	struct task_struct *owner;
-+	/* sampling_timer and bad_cpus_allowed are frequently
-+	   accessed, so they get to share a cache line */
-+	unsigned int sampling_timer ____cacheline_aligned;
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+	atomic_t bad_cpus_allowed;
-+#endif
-+#if 0 && defined(CONFIG_PERFCTR_DEBUG)
-+	unsigned start_smp_id;
-+	unsigned suspended;
-+#endif
-+#if PERFCTR_INTERRUPT_SUPPORT
-+	unsigned int iresume_cstatus;
-+#endif
-+};
-+#define IS_RUNNING(perfctr)	perfctr_cstatus_enabled((perfctr)->cpu_state.cstatus)
-+
-+/* XXX: disabled: called from switch_to() where printk() is disallowed */
-+#if 0 && defined(CONFIG_PERFCTR_DEBUG)
-+#define debug_free(perfctr) \
-+do { \
-+	int i; \
-+	for(i = 0; i < PAGE_SIZE/sizeof(int); ++i) \
-+		((int*)(perfctr))[i] = 0xfedac0ed; \
-+} while( 0 )
-+#define debug_init(perfctr)	do { (perfctr)->suspended = 1; } while( 0 )
-+#define debug_suspend(perfctr) \
-+do { \
-+	if( (perfctr)->suspended ) \
-+		printk(KERN_ERR "%s: BUG! suspending non-running perfctr (pid %d, comm %s)\n", \
-+		       __FUNCTION__, current->pid, current->comm); \
-+	(perfctr)->suspended = 1; \
-+} while( 0 )
-+#define debug_resume(perfctr) \
-+do { \
-+	if( !(perfctr)->suspended ) \
-+		printk(KERN_ERR "%s: BUG! resuming non-suspended perfctr (pid %d, comm %s)\n", \
-+		       __FUNCTION__, current->pid, current->comm); \
-+	(perfctr)->suspended = 0; \
-+} while( 0 )
-+#define debug_check_smp_id(perfctr) \
-+do { \
-+	if( (perfctr)->start_smp_id != smp_processor_id() ) { \
-+		printk(KERN_ERR "%s: BUG! current cpu %u differs from start cpu %u (pid %d, comm %s)\n", \
-+		       __FUNCTION__, smp_processor_id(), (perfctr)->start_smp_id, \
-+		       current->pid, current->comm); \
-+		return; \
-+	} \
-+} while( 0 )
-+#define debug_set_smp_id(perfctr) \
-+	do { (perfctr)->start_smp_id = smp_processor_id(); } while( 0 )
-+#else	/* CONFIG_PERFCTR_DEBUG */
-+#define debug_free(perfctr)		do{}while(0)
-+#define debug_init(perfctr)		do{}while(0)
-+#define debug_suspend(perfctr)		do{}while(0)
-+#define debug_resume(perfctr)		do{}while(0)
-+#define debug_check_smp_id(perfctr)	do{}while(0)
-+#define debug_set_smp_id(perfctr)	do{}while(0)
-+#endif	/* CONFIG_PERFCTR_DEBUG */
-+
-+#if PERFCTR_INTERRUPT_SUPPORT
-+
-+static void vperfctr_ihandler(unsigned long pc);
-+
-+static inline void vperfctr_set_ihandler(void)
-+{
-+	perfctr_cpu_set_ihandler(vperfctr_ihandler);
-+}
-+
-+static inline void vperfctr_clear_iresume_cstatus(struct vperfctr *perfctr)
-+{
-+	perfctr->iresume_cstatus = 0;
-+}
-+
-+#else
-+static inline void vperfctr_set_ihandler(void) { }
-+static inline void vperfctr_clear_iresume_cstatus(struct vperfctr *perfctr) { }
-+#endif
-+
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+
-+static inline void vperfctr_init_bad_cpus_allowed(struct vperfctr *perfctr)
-+{
-+	atomic_set(&perfctr->bad_cpus_allowed, 0);
-+}
-+
-+/* Concurrent set_cpus_allowed() is possible. The only lock it
-+   can take is the task lock, so we have to take it as well.
-+   task_lock/unlock also disables/enables preemption. */
-+
-+static inline void vperfctr_task_lock(struct task_struct *p)
-+{
-+	task_lock(p);
-+}
-+
-+static inline void vperfctr_task_unlock(struct task_struct *p)
-+{
-+	task_unlock(p);
-+}
-+
-+#else	/* !PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED */
-+
-+static inline void vperfctr_init_bad_cpus_allowed(struct vperfctr *perfctr) { }
-+
-+/* Concurrent set_cpus_allowed() is impossible or irrelevant.
-+   Disabling and enabling preemption suffices for an atomic region. */
-+
-+static inline void vperfctr_task_lock(struct task_struct *p)
-+{
-+	preempt_disable();
-+}
-+
-+static inline void vperfctr_task_unlock(struct task_struct *p)
-+{
-+	preempt_enable();
-+}
-+
-+#endif	/* !PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED */
-+
-+/****************************************************************
-+ *								*
-+ * Resource management.						*
-+ *								*
-+ ****************************************************************/
-+
-+/* XXX: perhaps relax this to number of _live_ perfctrs */
-+static DECLARE_MUTEX(nrctrs_mutex);
-+static int nrctrs;
-+static const char this_service[] = __FILE__;
-+
-+static int inc_nrctrs(void)
-+{
-+	const char *other;
-+
-+	other = NULL;
-+	down(&nrctrs_mutex);
-+	if( ++nrctrs == 1 ) {
-+		other = perfctr_cpu_reserve(this_service);
-+		if( other )
-+			nrctrs = 0;
-+	}
-+	up(&nrctrs_mutex);
-+	if( other ) {
-+		printk(KERN_ERR __FILE__
-+		       ": cannot operate, perfctr hardware taken by '%s'\n",
-+		       other);
-+		return -EBUSY;
-+	}
-+	vperfctr_set_ihandler();
-+	return 0;
-+}
-+
-+static void dec_nrctrs(void)
-+{
-+	down(&nrctrs_mutex);
-+	if( --nrctrs == 0 )
-+		perfctr_cpu_release(this_service);
-+	up(&nrctrs_mutex);
-+}
-+
-+static struct vperfctr *vperfctr_alloc(void)
-+{
-+	unsigned long page;
-+
-+	if( inc_nrctrs() != 0 )
-+		return ERR_PTR(-EBUSY);
-+	page = get_zeroed_page(GFP_KERNEL);
-+	if( !page ) {
-+		dec_nrctrs();
-+		return ERR_PTR(-ENOMEM);
-+	}
-+	SetPageReserved(virt_to_page(page));
-+	return (struct vperfctr*) page;
-+}
-+
-+static void vperfctr_free(struct vperfctr *perfctr)
-+{
-+	debug_free(perfctr);
-+	ClearPageReserved(virt_to_page(perfctr));
-+	free_page((unsigned long)perfctr);
-+	dec_nrctrs();
-+}
-+
-+static struct vperfctr *get_empty_vperfctr(void)
-+{
-+	struct vperfctr *perfctr = vperfctr_alloc();
-+	if( !IS_ERR(perfctr) ) {
-+		atomic_set(&perfctr->count, 1);
-+		vperfctr_init_bad_cpus_allowed(perfctr);
-+		spin_lock_init(&perfctr->owner_lock);
-+		debug_init(perfctr);
-+	}
-+	return perfctr;
-+}
-+
-+static void put_vperfctr(struct vperfctr *perfctr)
-+{
-+	if( atomic_dec_and_test(&perfctr->count) )
-+		vperfctr_free(perfctr);
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Basic counter operations.					*
-+ * These must all be called by the owner process only.		*
-+ * These must all be called with preemption disabled.		*
-+ *								*
-+ ****************************************************************/
-+
-+/* PRE: IS_RUNNING(perfctr)
-+ * Suspend the counters.
-+ * XXX: When called from switch_to(), perfctr belongs to 'prev'
-+ * but current is 'next'. Debug messages will refer to 'next'...
-+ */
-+static inline void vperfctr_suspend(struct vperfctr *perfctr)
-+{
-+	debug_suspend(perfctr);
-+	debug_check_smp_id(perfctr);
-+	perfctr_cpu_suspend(&perfctr->cpu_state);
-+}
-+
-+static inline void vperfctr_reset_sampling_timer(struct vperfctr *perfctr)
-+{
-+	/* XXX: base the value on perfctr_info.cpu_khz instead! */
-+	perfctr->sampling_timer = HZ/2;
-+}
-+
-+/* PRE: perfctr == current->thread.perfctr && IS_RUNNING(perfctr)
-+ * Restart the counters.
-+ */
-+static inline void vperfctr_resume(struct vperfctr *perfctr)
-+{
-+	debug_resume(perfctr);
-+	perfctr_cpu_resume(&perfctr->cpu_state);
-+	vperfctr_reset_sampling_timer(perfctr);
-+	debug_set_smp_id(perfctr);
-+}
-+
-+/* Sample the counters but do not suspend them. */
-+static void vperfctr_sample(struct vperfctr *perfctr)
-+{
-+	if( IS_RUNNING(perfctr) ) {
-+		debug_check_smp_id(perfctr);
-+		perfctr_cpu_sample(&perfctr->cpu_state);
-+		vperfctr_reset_sampling_timer(perfctr);
-+	}
-+}
-+
-+#if PERFCTR_INTERRUPT_SUPPORT
-+/* vperfctr interrupt handler (XXX: add buffering support) */
-+/* PREEMPT note: called in IRQ context with preemption disabled. */
-+static void vperfctr_ihandler(unsigned long pc)
-+{
-+	struct task_struct *tsk = current;
-+	struct vperfctr *perfctr;
-+	unsigned int pmc_mask;
-+	siginfo_t si;
-+
-+	perfctr = tsk->thread.perfctr;
-+	if( !perfctr ) {
-+		printk(KERN_ERR "%s: BUG! pid %d has no vperfctr\n",
-+		       __FUNCTION__, tsk->pid);
-+		return;
-+	}
-+	if( !perfctr_cstatus_has_ictrs(perfctr->cpu_state.cstatus) ) {
-+		printk(KERN_ERR "%s: BUG! vperfctr has cstatus %#x (pid %d, comm %s)\n",
-+		       __FUNCTION__, perfctr->cpu_state.cstatus, tsk->pid, tsk->comm);
-+		return;
-+	}
-+	vperfctr_suspend(perfctr);
-+	pmc_mask = perfctr_cpu_identify_overflow(&perfctr->cpu_state);
-+	if( !pmc_mask ) {
-+		printk(KERN_ERR "%s: BUG! pid %d has unidentifiable overflow source\n",
-+		       __FUNCTION__, tsk->pid);
-+		return;
-+	}
-+	/* suspend a-mode and i-mode PMCs, leaving only TSC on */
-+	/* XXX: some people also want to suspend the TSC */
-+	perfctr->iresume_cstatus = perfctr->cpu_state.cstatus;
-+	if( perfctr_cstatus_has_tsc(perfctr->iresume_cstatus) ) {
-+		perfctr->cpu_state.cstatus = perfctr_mk_cstatus(1, 0, 0);
-+		vperfctr_resume(perfctr);
-+	} else
-+		perfctr->cpu_state.cstatus = 0;
-+	si.si_signo = perfctr->si_signo;
-+	si.si_errno = 0;
-+	si.si_code = SI_PMC_OVF;
-+	si.si_pmc_ovf_mask = pmc_mask;
-+	if( !send_sig_info(si.si_signo, &si, tsk) )
-+		send_sig(si.si_signo, tsk, 1);
-+}
-+#endif
-+
-+/****************************************************************
-+ *								*
-+ * Process management operations.				*
-+ * These must all, with the exception of vperfctr_unlink()	*
-+ * and __vperfctr_set_cpus_allowed(), be called by the owner	*
-+ * process only.						*
-+ *								*
-+ ****************************************************************/
-+
-+/* Called from exit_thread() or sys_vperfctr_unlink().
-+ * If the counters are running, stop them and sample their final values.
-+ * Detach the vperfctr object from its owner task.
-+ * PREEMPT note: exit_thread() does not run with preemption disabled.
-+ */
-+static void vperfctr_unlink(struct task_struct *owner, struct vperfctr *perfctr)
-+{
-+	/* this synchronises with vperfctr_ioctl() */
-+	spin_lock(&perfctr->owner_lock);
-+	perfctr->owner = NULL;
-+	spin_unlock(&perfctr->owner_lock);
-+
-+	/* perfctr suspend+detach must be atomic wrt process suspend */
-+	/* this also synchronises with perfctr_set_cpus_allowed() */
-+	vperfctr_task_lock(owner);
-+	if( IS_RUNNING(perfctr) && owner == current )
-+		vperfctr_suspend(perfctr);
-+	owner->thread.perfctr = NULL;
-+	vperfctr_task_unlock(owner);
-+
-+	perfctr->cpu_state.cstatus = 0;
-+	vperfctr_clear_iresume_cstatus(perfctr);
-+	put_vperfctr(perfctr);
-+}
-+
-+void __vperfctr_exit(struct vperfctr *perfctr)
-+{
-+	vperfctr_unlink(current, perfctr);
-+}
-+
-+/* schedule() --> switch_to() --> .. --> __vperfctr_suspend().
-+ * If the counters are running, suspend them.
-+ * PREEMPT note: switch_to() runs with preemption disabled.
-+ */
-+void __vperfctr_suspend(struct vperfctr *perfctr)
-+{
-+	if( IS_RUNNING(perfctr) )
-+		vperfctr_suspend(perfctr);
-+}
-+
-+/* schedule() --> switch_to() --> .. --> __vperfctr_resume().
-+ * PRE: perfctr == current->thread.perfctr
-+ * If the counters are runnable, resume them.
-+ * PREEMPT note: switch_to() runs with preemption disabled.
-+ */
-+void __vperfctr_resume(struct vperfctr *perfctr)
-+{
-+	if( IS_RUNNING(perfctr) ) {
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+		if( unlikely(atomic_read(&perfctr->bad_cpus_allowed)) &&
-+		    perfctr_cstatus_nrctrs(perfctr->cpu_state.cstatus) ) {
-+			perfctr->cpu_state.cstatus = 0;
-+			vperfctr_clear_iresume_cstatus(perfctr);
-+			BUG_ON(current->state != TASK_RUNNING);
-+			send_sig(SIGILL, current, 1);
-+			return;
-+		}
-+#endif
-+		vperfctr_resume(perfctr);
-+	}
-+}
-+
-+/* Called from update_one_process() [triggered by timer interrupt].
-+ * PRE: perfctr == current->thread.perfctr.
-+ * Sample the counters but do not suspend them.
-+ * Needed to avoid precision loss due to multiple counter
-+ * wraparounds between resume/suspend for CPU-bound processes.
-+ * PREEMPT note: called in IRQ context with preemption disabled.
-+ */
-+void __vperfctr_sample(struct vperfctr *perfctr)
-+{
-+	if( --perfctr->sampling_timer == 0 )
-+		vperfctr_sample(perfctr);
-+}
-+
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+/* Called from set_cpus_allowed().
-+ * PRE: current holds task_lock(owner)
-+ * PRE: owner->thread.perfctr == perfctr
-+ */
-+void __vperfctr_set_cpus_allowed(struct task_struct *owner,
-+				 struct vperfctr *perfctr,
-+				 cpumask_t new_mask)
-+{
-+	cpumask_t tmp;
-+
-+	cpus_and(tmp, new_mask, perfctr_cpus_forbidden_mask);
-+	if( !cpus_empty(tmp) ) {
-+		atomic_set(&perfctr->bad_cpus_allowed, 1);
-+		printk(KERN_WARNING "perfctr: process %d (comm %s) issued unsafe"
-+		       " set_cpus_allowed() on process %d (comm %s)\n",
-+		       current->pid, current->comm, owner->pid, owner->comm);
-+	} else
-+		atomic_set(&perfctr->bad_cpus_allowed, 0);
-+}
-+#endif
-+
-+/****************************************************************
-+ *								*
-+ * Virtual perfctr "system calls".				*
-+ * These can be called by the owner process (tsk == current),	*
-+ * a monitor process which has the owner under ptrace ATTACH	*
-+ * control (tsk && tsk != current), or anyone with a handle to	*
-+ * an unlinked perfctr (!tsk).					*
-+ *								*
-+ ****************************************************************/
-+
-+static int sys_vperfctr_control(struct vperfctr *perfctr,
-+				struct perfctr_struct_buf *argp,
-+				struct task_struct *tsk)
-+{
-+	struct vperfctr_control control;
-+	int err;
-+	unsigned int next_cstatus;
-+	unsigned int nrctrs, i;
-+
-+	if( !tsk )
-+		return -ESRCH;	/* attempt to update unlinked perfctr */
-+
-+	err = perfctr_copy_from_user(&control, argp, &vperfctr_control_sdesc);
-+	if( err )
-+		return err;
-+
-+	if( control.cpu_control.nractrs || control.cpu_control.nrictrs ) {
-+		cpumask_t old_mask, new_mask;
-+
-+		old_mask = tsk->cpus_allowed;
-+		cpus_andnot(new_mask, old_mask, perfctr_cpus_forbidden_mask);
-+
-+		if( cpus_empty(new_mask) )
-+			return -EINVAL;
-+		if( !cpus_equal(new_mask, old_mask) )
-+			set_cpus_allowed(tsk, new_mask);
-+	}
-+
-+	/* PREEMPT note: preemption is disabled over the entire
-+	   region since we're updating an active perfctr. */
-+	preempt_disable();
-+	if( IS_RUNNING(perfctr) ) {
-+		if( tsk == current )
-+			vperfctr_suspend(perfctr);
-+		perfctr->cpu_state.cstatus = 0;
-+		vperfctr_clear_iresume_cstatus(perfctr);
-+	}
-+	perfctr->cpu_state.control = control.cpu_control;
-+	/* remote access note: perfctr_cpu_update_control() is ok */
-+	err = perfctr_cpu_update_control(&perfctr->cpu_state, 0);
-+	if( err < 0 )
-+		goto out;
-+	next_cstatus = perfctr->cpu_state.cstatus;
-+	if( !perfctr_cstatus_enabled(next_cstatus) )
-+		goto out;
-+
-+	/* XXX: validate si_signo? */
-+	perfctr->si_signo = control.si_signo;
-+
-+	if( !perfctr_cstatus_has_tsc(next_cstatus) )
-+		perfctr->cpu_state.tsc_sum = 0;
-+
-+	nrctrs = perfctr_cstatus_nrctrs(next_cstatus);
-+	for(i = 0; i < nrctrs; ++i)
-+		if( !(control.preserve & (1<<i)) )
-+			perfctr->cpu_state.pmc[i].sum = 0;
-+
-+	if( tsk == current )
-+		vperfctr_resume(perfctr);
-+
-+ out:
-+	preempt_enable();
-+	return err;
-+}
-+
-+static int sys_vperfctr_iresume(struct vperfctr *perfctr, const struct task_struct *tsk)
-+{
-+#if PERFCTR_INTERRUPT_SUPPORT
-+	unsigned int iresume_cstatus;
-+
-+	if( !tsk )
-+		return -ESRCH;	/* attempt to update unlinked perfctr */
-+
-+	iresume_cstatus = perfctr->iresume_cstatus;
-+	if( !perfctr_cstatus_has_ictrs(iresume_cstatus) )
-+		return -EPERM;
-+
-+	/* PREEMPT note: preemption is disabled over the entire
-+	   region because we're updating an active perfctr. */
-+	preempt_disable();
-+
-+	if( IS_RUNNING(perfctr) && tsk == current )
-+		vperfctr_suspend(perfctr);
-+
-+	perfctr->cpu_state.cstatus = iresume_cstatus;
-+	perfctr->iresume_cstatus = 0;
-+
-+	/* remote access note: perfctr_cpu_ireload() is ok */
-+	perfctr_cpu_ireload(&perfctr->cpu_state);
-+
-+	if( tsk == current )
-+		vperfctr_resume(perfctr);
-+
-+	preempt_enable();
-+
-+	return 0;
-+#else
-+	return -ENOSYS;
-+#endif
-+}
-+
-+static int sys_vperfctr_unlink(struct vperfctr *perfctr, struct task_struct *tsk)
-+{
-+	if( tsk )
-+		vperfctr_unlink(tsk, perfctr);
-+	return 0;
-+}
-+
-+static int sys_vperfctr_read_sum(struct vperfctr *perfctr,
-+				 struct perfctr_struct_buf *argp,
-+				 const struct task_struct *tsk)
-+{
-+	struct perfctr_sum_ctrs sum;
-+
-+	if( tsk == current ) {
-+		preempt_disable();
-+		vperfctr_sample(perfctr);
-+	}
-+	//sum = perfctr->cpu_state.sum;
-+	{
-+		int j;
-+		sum.tsc = perfctr->cpu_state.tsc_sum;
-+		for(j = 0; j < ARRAY_SIZE(sum.pmc); ++j)
-+			sum.pmc[j] = perfctr->cpu_state.pmc[j].sum;
-+	}
-+	if( tsk == current )
-+		preempt_enable();
-+	return perfctr_copy_to_user(argp, &sum, &perfctr_sum_ctrs_sdesc);
-+}
-+
-+static int sys_vperfctr_read_control(struct vperfctr *perfctr,
-+				     struct perfctr_struct_buf *argp,
-+				     const struct task_struct *tsk)
-+{
-+	struct vperfctr_control control;
-+
-+	/* PREEMPT note: While we're reading our own control, another
-+	   process may ptrace ATTACH to us and update our control.
-+	   Disable preemption to ensure we get a consistent copy.
-+	   Not needed for other cases since the perfctr is either
-+	   unlinked or its owner is ptrace ATTACH suspended by us. */
-+	if( tsk == current )
-+		preempt_disable();
-+	control.si_signo = perfctr->si_signo;
-+	control.cpu_control = perfctr->cpu_state.control;
-+	if( tsk == current )
-+		preempt_enable();
-+	control.preserve = 0;
-+	return perfctr_copy_to_user(argp, &control, &vperfctr_control_sdesc);
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Virtual perfctr file operations.				*
-+ *								*
-+ ****************************************************************/
-+
-+static int vperfctr_mmap(struct file *filp, struct vm_area_struct *vma)
-+{
-+	struct vperfctr *perfctr;
-+
-+	/* Only allow read-only mapping of first page. */
-+	if( (vma->vm_end - vma->vm_start) != PAGE_SIZE ||
-+	    vma->vm_pgoff != 0 ||
-+	    (pgprot_val(vma->vm_page_prot) & _PAGE_RW) ||
-+	    (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) )
-+		return -EPERM;
-+	perfctr = filp->private_data;
-+	if( !perfctr )
-+		return -EPERM;
-+	return remap_page_range(vma, vma->vm_start, virt_to_phys(perfctr),
-+				PAGE_SIZE, vma->vm_page_prot);
-+}
-+
-+static int vperfctr_release(struct inode *inode, struct file *filp)
-+{
-+	struct vperfctr *perfctr = filp->private_data;
-+	filp->private_data = NULL;
-+	if( perfctr )
-+		put_vperfctr(perfctr);
-+	return 0;
-+}
-+
-+static int vperfctr_ioctl(struct inode *inode, struct file *filp,
-+			  unsigned int cmd, unsigned long arg)
-+{
-+	struct vperfctr *perfctr;
-+	struct task_struct *tsk;
-+	int ret;
-+
-+	switch( cmd ) {
-+	case PERFCTR_ABI:
-+		return sys_perfctr_abi((unsigned int*)arg);
-+	case PERFCTR_INFO:
-+		return sys_perfctr_info((struct perfctr_struct_buf*)arg);
-+	case PERFCTR_CPUS:
-+		return sys_perfctr_cpus((struct perfctr_cpu_mask*)arg);
-+	case PERFCTR_CPUS_FORBIDDEN:
-+		return sys_perfctr_cpus_forbidden((struct perfctr_cpu_mask*)arg);
-+	}
-+	perfctr = filp->private_data;
-+	if( !perfctr )
-+		return -EINVAL;
-+	tsk = current;
-+	if( perfctr != current->thread.perfctr ) {
-+		/* this synchronises with vperfctr_unlink() and itself */
-+		spin_lock(&perfctr->owner_lock);
-+		tsk = perfctr->owner;
-+		if( tsk )
-+			get_task_struct(tsk);
-+		spin_unlock(&perfctr->owner_lock);
-+		if( tsk ) {
-+			ret = ptrace_check_attach(tsk, 0);
-+			if( ret < 0 )
-+				goto out;
-+		}
-+	}
-+	switch( cmd ) {
-+	case VPERFCTR_CONTROL:
-+		ret = sys_vperfctr_control(perfctr, (struct perfctr_struct_buf*)arg, tsk);
-+		break;
-+	case VPERFCTR_UNLINK:
-+		ret = sys_vperfctr_unlink(perfctr, tsk);
-+		break;
-+	case VPERFCTR_READ_SUM:
-+		ret = sys_vperfctr_read_sum(perfctr, (struct perfctr_struct_buf*)arg, tsk);
-+		break;
-+	case VPERFCTR_IRESUME:
-+		ret = sys_vperfctr_iresume(perfctr, tsk);
-+		break;
-+	case VPERFCTR_READ_CONTROL:
-+		ret = sys_vperfctr_read_control(perfctr, (struct perfctr_struct_buf*)arg, tsk);
-+		break;
-+	default:
-+		ret = -EINVAL;
-+	}
-+ out:
-+	if( tsk && tsk != current )
-+		put_task_struct(tsk);
-+	return ret;
-+}
-+
-+static struct file_operations vperfctr_file_ops = {
-+	.owner = THIS_MODULE,
-+	.mmap = vperfctr_mmap,
-+	.release = vperfctr_release,
-+	.ioctl = vperfctr_ioctl,
-+};
-+
-+/****************************************************************
-+ *								*
-+ * File system for virtual perfctrs. Based on pipefs.		*
-+ *								*
-+ ****************************************************************/
-+
-+#define VPERFCTRFS_MAGIC (('V'<<24)|('P'<<16)|('M'<<8)|('C'))
-+
-+/* The code to set up a `struct file_system_type' for a pseudo fs
-+   is unfortunately not the same in 2.4 and 2.6. */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-+#include <linux/mount.h> /* needed for 2.6, included by fs.h in 2.4 */
-+
-+/* 2.6 doesn't EXPORT_SYMBOL() fs/libfs.c:get_sb_pseudo().
-+   This is a verbatim copy, only renamed. */
-+#ifdef MODULE
-+static
-+struct super_block *
-+perfctr_get_sb_pseudo(struct file_system_type *fs_type, char *name,
-+	struct super_operations *ops, unsigned long magic)
-+{
-+	struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
-+	static struct super_operations default_ops = {.statfs = simple_statfs};
-+	struct dentry *dentry;
-+	struct inode *root;
-+	struct qstr d_name = {.name = name, .len = strlen(name)};
-+
-+	if (IS_ERR(s))
-+		return s;
-+
-+	s->s_flags = MS_NOUSER;
-+	s->s_maxbytes = ~0ULL;
-+	s->s_blocksize = 1024;
-+	s->s_blocksize_bits = 10;
-+	s->s_magic = magic;
-+	s->s_op = ops ? ops : &default_ops;
-+	root = new_inode(s);
-+	if (!root)
-+		goto Enomem;
-+	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
-+	root->i_uid = root->i_gid = 0;
-+	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
-+	dentry = d_alloc(NULL, &d_name);
-+	if (!dentry) {
-+		iput(root);
-+		goto Enomem;
-+	}
-+	dentry->d_sb = s;
-+	dentry->d_parent = dentry;
-+	d_instantiate(dentry, root);
-+	s->s_root = dentry;
-+	s->s_flags |= MS_ACTIVE;
-+	return s;
-+
-+Enomem:
-+	up_write(&s->s_umount);
-+	deactivate_super(s);
-+	return ERR_PTR(-ENOMEM);
-+}
-+#undef get_sb_pseudo
-+#define get_sb_pseudo perfctr_get_sb_pseudo
-+#endif	/* MODULE */
-+
-+static struct super_block *
-+vperfctrfs_get_sb(struct file_system_type *fs_type,
-+		  int flags, const char *dev_name, void *data)
-+{
-+	return get_sb_pseudo(fs_type, "vperfctr:", NULL, VPERFCTRFS_MAGIC);
-+}
-+
-+static struct file_system_type vperfctrfs_type = {
-+	.name		= "vperfctrfs",
-+	.get_sb		= vperfctrfs_get_sb,
-+	.kill_sb	= kill_anon_super,
-+};
-+
-+#else	/* 2.4 */
-+
-+static int vperfctrfs_statfs(struct super_block *sb, struct statfs *buf)
-+{
-+	buf->f_type = VPERFCTRFS_MAGIC;
-+	buf->f_bsize = 1024;
-+	buf->f_namelen = 255;
-+	return 0;
-+}
-+
-+static struct super_operations vperfctrfs_ops = {
-+	.statfs = vperfctrfs_statfs,
-+};
-+
-+static struct super_block*
-+vperfctrfs_read_super(struct super_block *sb, void *data, int silent)
-+{
-+	static const struct qstr d_name = { "vperfctrfs:", 11, 0 };
-+	struct dentry *dentry;
-+	struct inode *root;
-+
-+	root = new_inode(sb);
-+	if( !root )
-+		return NULL;
-+	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
-+	root->i_uid = root->i_gid = 0;
-+	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
-+	sb->s_blocksize = 1024;
-+	sb->s_blocksize_bits = 10;
-+	sb->s_magic = VPERFCTRFS_MAGIC;
-+	sb->s_op = &vperfctrfs_ops; /* XXX: check if 2.4 really needs this */
-+	sb->s_root = dentry = d_alloc(NULL, &d_name);
-+	if( !dentry ) {
-+		iput(root);
-+		return NULL;
-+	}
-+	dentry->d_sb = sb;
-+	dentry->d_parent = dentry;
-+	d_instantiate(dentry, root);
-+	return sb;
-+}
-+
-+/* DECLARE_FSTYPE() hides 'owner: THIS_MODULE'. kern_mount() increments
-+   owner's use count, and since we're not unmountable from user-space,
-+   the module can't be unloaded because it's use count is >= 1.
-+   So we declare the file_system_type manually without the owner field. */
-+static struct file_system_type vperfctrfs_type = {
-+	.name		= "vperfctrfs",
-+	.read_super	= vperfctrfs_read_super,
-+	.fs_flags	= FS_NOMOUNT,
-+};
-+
-+#endif	/* 2.4 */
-+
-+/* XXX: check if s/vperfctr_mnt/vperfctrfs_type.kern_mnt/ would work */
-+static struct vfsmount *vperfctr_mnt;
-+
-+static int __init vperfctrfs_init(void)
-+{
-+	int err = register_filesystem(&vperfctrfs_type);
-+	if( !err ) {
-+		vperfctr_mnt = kern_mount(&vperfctrfs_type);
-+		if( !IS_ERR(vperfctr_mnt) )
-+			return 0;
-+		err = PTR_ERR(vperfctr_mnt);
-+		unregister_filesystem(&vperfctrfs_type);
-+	}
-+	return err;
-+}
-+
-+static void __exit vperfctrfs_exit(void)
-+{
-+	unregister_filesystem(&vperfctrfs_type);
-+	mntput(vperfctr_mnt);
-+}
-+
-+static struct inode *vperfctr_get_inode(void)
-+{
-+	struct inode *inode;
-+
-+	inode = new_inode(vperfctr_mnt->mnt_sb);
-+	if( !inode )
-+		return NULL;
-+	inode->i_fop = &vperfctr_file_ops;
-+	inode->i_state = I_DIRTY;
-+	inode->i_mode = S_IFCHR | S_IRUSR | S_IWUSR;
-+	inode->i_uid = current->fsuid;
-+	inode->i_gid = current->fsgid;
-+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-+	inode->i_blksize = 0;
-+	return inode;
-+}
-+
-+static int vperfctrfs_delete_dentry(struct dentry *dentry)
-+{
-+	return 1;
-+}
-+
-+static struct dentry_operations vperfctrfs_dentry_operations = {
-+	.d_delete	= vperfctrfs_delete_dentry,
-+};
-+
-+static struct dentry *vperfctr_d_alloc_root(struct inode *inode)
-+{
-+	struct qstr this;
-+	char name[32];
-+	struct dentry *dentry;
-+
-+	sprintf(name, "[%lu]", inode->i_ino);
-+	this.name = name;
-+	this.len = strlen(name);
-+	this.hash = inode->i_ino; /* will go */
-+	dentry = d_alloc(vperfctr_mnt->mnt_sb->s_root, &this);
-+	if( dentry ) {
-+		dentry->d_op = &vperfctrfs_dentry_operations;
-+		d_add(dentry, inode);
-+	}
-+	return dentry;
-+}
-+
-+static struct file *vperfctr_get_filp(void)
-+{
-+	struct file *filp;
-+	struct inode *inode;
-+	struct dentry *dentry;
-+
-+	filp = get_empty_filp();
-+	if( !filp )
-+		goto out;
-+	inode = vperfctr_get_inode();
-+	if( !inode )
-+		goto out_filp;
-+	dentry = vperfctr_d_alloc_root(inode);
-+	if( !dentry )
-+		goto out_inode;
-+
-+	filp->f_vfsmnt = mntget(vperfctr_mnt);
-+	filp->f_dentry = dentry;
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,2)
-+	filp->f_mapping = dentry->d_inode->i_mapping;
-+#endif
-+
-+	filp->f_pos = 0;
-+	filp->f_flags = 0;
-+	filp->f_op = fops_get(&vperfctr_file_ops); /* fops_get() for MODULE */
-+	filp->f_mode = FMODE_READ;
-+	filp->f_version = 0;
-+
-+	return filp;
-+
-+ out_inode:
-+	iput(inode);
-+ out_filp:
-+	put_filp(filp);	/* doesn't run ->release() like fput() does */
-+ out:
-+	return NULL;
-+}
-+
-+/* tid is the actual task/thread id (née pid, stored as ->pid),
-+   pid/tgid is that 2.6 thread group id crap (stored as ->tgid) */
-+int vperfctr_attach(int tid, int creat)
-+{
-+	struct file *filp;
-+	struct task_struct *tsk;
-+	struct vperfctr *perfctr;
-+	int err;
-+	int fd;
-+
-+	filp = vperfctr_get_filp();
-+	if( !filp )
-+		return -ENOMEM;
-+	err = fd = get_unused_fd();
-+	if( err < 0 )
-+		goto err_filp;
-+	perfctr = NULL;
-+	if( creat ) {
-+		perfctr = get_empty_vperfctr(); /* may sleep */
-+		if( IS_ERR(perfctr) ) {
-+			err = PTR_ERR(perfctr);
-+			goto err_fd;
-+		}
-+	}
-+	tsk = current;
-+	if( tid != 0 && tid != tsk->pid ) { /* remote? */
-+		read_lock(&tasklist_lock);
-+		tsk = find_task_by_pid(tid);
-+		if( tsk )
-+			get_task_struct(tsk);
-+		read_unlock(&tasklist_lock);
-+		err = -ESRCH;
-+		if( !tsk )
-+			goto err_perfctr;
-+		err = ptrace_check_attach(tsk, 0);
-+		if( err < 0 )
-+			goto err_tsk;
-+	}
-+	if( creat ) {
-+		/* check+install must be atomic to prevent remote-control races */
-+		vperfctr_task_lock(tsk);
-+		if( !tsk->thread.perfctr ) {
-+			perfctr->owner = tsk;
-+			tsk->thread.perfctr = perfctr;
-+			err = 0;
-+		} else
-+			err = -EEXIST;
-+		vperfctr_task_unlock(tsk);
-+		if( err )
-+			goto err_tsk;
-+	} else {
-+		perfctr = tsk->thread.perfctr;
-+		/* PERFCTR_ABI and PERFCTR_INFO don't need the perfctr.
-+		   Hence no non-NULL check here. */
-+	}
-+	filp->private_data = perfctr;
-+	if( perfctr )
-+		atomic_inc(&perfctr->count);
-+	if( tsk != current )
-+		put_task_struct(tsk);
-+	fd_install(fd, filp);
-+	return fd;
-+ err_tsk:
-+	if( tsk != current )
-+		put_task_struct(tsk);
-+ err_perfctr:
-+	if( perfctr )	/* can only occur if creat != 0 */
-+		put_vperfctr(perfctr);
-+ err_fd:
-+	put_unused_fd(fd);
-+ err_filp:
-+	fput(filp);
-+	return err;
-+}
-+
-+/****************************************************************
-+ *								*
-+ * module_init/exit						*
-+ *								*
-+ ****************************************************************/
-+
-+#ifdef MODULE
-+static struct vperfctr_stub off;
-+
-+static void vperfctr_stub_init(void)
-+{
-+	off = vperfctr_stub;
-+	vperfctr_stub.owner = THIS_MODULE;
-+	vperfctr_stub.exit = __vperfctr_exit;
-+	vperfctr_stub.suspend = __vperfctr_suspend;
-+	vperfctr_stub.resume = __vperfctr_resume;
-+	vperfctr_stub.sample = __vperfctr_sample;
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+	vperfctr_stub.set_cpus_allowed = __vperfctr_set_cpus_allowed;
-+#endif
-+}
-+
-+static void vperfctr_stub_exit(void)
-+{
-+	vperfctr_stub = off;
-+}
-+#else
-+static inline void vperfctr_stub_init(void) { }
-+static inline void vperfctr_stub_exit(void) { }
-+#endif	/* MODULE */
-+
-+int __init vperfctr_init(void)
-+{
-+	int err = vperfctrfs_init();
-+	if( err )
-+		return err;
-+	vperfctr_stub_init();
-+	return 0;
-+}
-+
-+void __exit vperfctr_exit(void)
-+{
-+	vperfctrfs_exit();
-+	vperfctr_stub_exit();
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_tests.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_tests.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_tests.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,30 @@
-+/* $Id: x86_tests.h,v 1.8.2.2 2004/08/02 15:53:19 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Optional x86/x86_64-specific init-time tests.
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+
-+/* 'enum perfctr_x86_tests_type' classifies CPUs according
-+   to relevance for perfctr_x86_init_tests(). */
-+enum perfctr_x86_tests_type {
-+	PTT_UNKNOWN,
-+	PTT_GENERIC,
-+	PTT_P5,
-+	PTT_P6,
-+	PTT_P4,
-+	PTT_AMD,
-+	PTT_WINCHIP,
-+	PTT_VC3,
-+};
-+
-+extern enum perfctr_x86_tests_type perfctr_x86_tests_type;
-+
-+static inline void perfctr_set_tests_type(enum perfctr_x86_tests_type t)
-+{
-+#ifdef CONFIG_PERFCTR_INIT_TESTS
-+	perfctr_x86_tests_type = t;
-+#endif
-+}
-+
-+extern void perfctr_x86_init_tests(void);
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc_setup.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/ppc_setup.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc_setup.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,40 @@
-+/* $Id: ppc_setup.c,v 1.1 2004/01/12 01:59:11 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * PPC32-specific kernel-resident code.
-+ *
-+ * Copyright (C) 2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <asm/processor.h>
-+#include <asm/perfctr.h>
-+#include "ppc_compat.h"
-+#include "compat.h"
-+
-+#if PERFCTR_INTERRUPT_SUPPORT
-+static void perfctr_default_ihandler(unsigned long pc)
-+{
-+}
-+
-+static perfctr_ihandler_t perfctr_ihandler = perfctr_default_ihandler;
-+
-+void do_perfctr_interrupt(struct pt_regs *regs)
-+{
-+	preempt_disable();
-+	(*perfctr_ihandler)(regs->nip);
-+	preempt_enable_no_resched();
-+}
-+
-+void perfctr_cpu_set_ihandler(perfctr_ihandler_t ihandler)
-+{
-+	perfctr_ihandler = ihandler ? ihandler : perfctr_default_ihandler;
-+}
-+
-+#ifdef CONFIG_PERFCTR_MODULE
-+EXPORT_SYMBOL(perfctr_cpu_set_ihandler);
-+#endif /* MODULE */
-+#endif /* PERFCTR_INTERRUPT_SUPPORT */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc_tests.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/ppc_tests.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/ppc_tests.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,12 @@
-+/* $Id: ppc_tests.h,v 1.1.2.1 2004/06/21 22:33:35 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Optional PPC32-specific init-time tests.
-+ *
-+ * Copyright (C) 2004  Mikael Pettersson
-+ */
-+
-+#ifdef CONFIG_PERFCTR_INIT_TESTS
-+extern void perfctr_ppc_init_tests(int have_mmcr1);
-+#else
-+static inline void perfctr_ppc_init_tests(int have_mmcr1) { }
-+#endif
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/version.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/version.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/version.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1 @@
-+#define VERSION "2.6.10.2"
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64_tests.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_64_tests.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64_tests.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,174 @@
-+/* $Id: x86_64_tests.c,v 1.3 2004/02/21 11:04:46 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * Optional x86_64-specific init-time tests.
-+ *
-+ * Copyright (C) 2003-2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/perfctr.h>
-+#include <asm/msr.h>
-+#include <asm/fixmap.h>
-+#include <asm/apic.h>
-+#include "x86_64_compat.h"
-+#include "x86_64_tests.h"
-+
-+#define MSR_K8_EVNTSEL0		0xC0010000
-+#define MSR_K8_PERFCTR0		0xC0010004
-+#define K8_EVNTSEL0_VAL		(0xC0 | (3<<16) | (1<<22))
-+
-+#define NITER	64
-+#define X2(S)	S";"S
-+#define X8(S)	X2(X2(X2(S)))
-+
-+static void __init do_rdpmc(unsigned pmc, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("rdpmc") : : "c"(pmc) : "eax", "edx");
-+}
-+
-+static void __init do_rdmsr(unsigned msr, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("rdmsr") : : "c"(msr) : "eax", "edx");
-+}
-+
-+static void __init do_wrmsr(unsigned msr, unsigned data)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("wrmsr") : : "c"(msr), "a"(data), "d"(0));
-+}
-+
-+static void __init do_rdcr4(unsigned unused1, unsigned unused2)
-+{
-+	unsigned i;
-+	unsigned long dummy;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("movq %%cr4,%0") : "=r"(dummy));
-+}
-+
-+static void __init do_wrcr4(unsigned cr4, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("movq %0,%%cr4") : : "r"((long)cr4));
-+}
-+
-+static void __init do_rdtsc(unsigned unused1, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__(X8("rdtsc") : : : "eax", "edx");
-+}
-+
-+static void __init do_wrlvtpc(unsigned val, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i) {
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+		apic_write(APIC_LVTPC, val);
-+	}
-+}
-+
-+static void __init do_empty_loop(unsigned unused1, unsigned unused2)
-+{
-+	unsigned i;
-+	for(i = 0; i < NITER/8; ++i)
-+		__asm__ __volatile__("" : : "c"(0));
-+}
-+
-+static unsigned __init run(void (*doit)(unsigned, unsigned),
-+			   unsigned arg1, unsigned arg2)
-+{
-+	unsigned start, dummy, stop;
-+	rdtsc(start, dummy);
-+	(*doit)(arg1, arg2);	/* should take < 2^32 cycles to complete */
-+	rdtsc(stop, dummy);
-+	return stop - start;
-+}
-+
-+static void __init init_tests_message(void)
-+{
-+	printk(KERN_INFO "Please email the following PERFCTR INIT lines "
-+	       "to mikpe@csd.uu.se\n"
-+	       KERN_INFO "To remove this message, rebuild the driver "
-+	       "with CONFIG_PERFCTR_INIT_TESTS=n\n");
-+	printk(KERN_INFO "PERFCTR INIT: vendor %u, family %u, model %u, stepping %u, clock %u kHz\n",
-+	       current_cpu_data.x86_vendor,
-+	       current_cpu_data.x86,
-+	       current_cpu_data.x86_model,
-+	       current_cpu_data.x86_mask,
-+	       perfctr_cpu_khz());
-+}
-+
-+static void __init
-+measure_overheads(unsigned msr_evntsel0, unsigned evntsel0, unsigned msr_perfctr0)
-+{
-+	int i;
-+	unsigned int loop, ticks[9];
-+	const char *name[9];
-+
-+	if( msr_evntsel0 )
-+		wrmsr(msr_evntsel0, 0, 0);
-+
-+	name[0] = "rdtsc";
-+	ticks[0] = run(do_rdtsc, 0, 0);
-+	name[1] = "rdpmc";
-+	ticks[1] = (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
-+		? run(do_rdpmc,1,0) : 0;
-+	name[2] = "rdmsr (counter)";
-+	ticks[2] = msr_perfctr0 ? run(do_rdmsr, msr_perfctr0, 0) : 0;
-+	name[3] = "rdmsr (evntsel)";
-+	ticks[3] = msr_evntsel0 ? run(do_rdmsr, msr_evntsel0, 0) : 0;
-+	name[4] = "wrmsr (counter)";
-+	ticks[4] = msr_perfctr0 ? run(do_wrmsr, msr_perfctr0, 0) : 0;
-+	name[5] = "wrmsr (evntsel)";
-+	ticks[5] = msr_evntsel0 ? run(do_wrmsr, msr_evntsel0, evntsel0) : 0;
-+	name[6] = "read cr4";
-+	ticks[6] = run(do_rdcr4, 0, 0);
-+	name[7] = "write cr4";
-+	ticks[7] = run(do_wrcr4, read_cr4(), 0);
-+	name[8] = "write LVTPC";
-+	ticks[8] = (perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
-+		? run(do_wrlvtpc, APIC_DM_NMI|APIC_LVT_MASKED, 0) : 0;
-+
-+	loop = run(do_empty_loop, 0, 0);
-+
-+	if( msr_evntsel0 )
-+		wrmsr(msr_evntsel0, 0, 0);
-+
-+	init_tests_message();
-+	printk(KERN_INFO "PERFCTR INIT: NITER == %u\n", NITER);
-+	printk(KERN_INFO "PERFCTR INIT: loop overhead is %u cycles\n", loop);
-+	for(i = 0; i < ARRAY_SIZE(ticks); ++i) {
-+		unsigned int x;
-+		if( !ticks[i] )
-+			continue;
-+		x = ((ticks[i] - loop) * 10) / NITER;
-+		printk(KERN_INFO "PERFCTR INIT: %s cost is %u.%u cycles (%u total)\n",
-+		       name[i], x/10, x%10, ticks[i]);
-+	}
-+}
-+
-+void __init perfctr_k8_init_tests(void)
-+{
-+	measure_overheads(MSR_K8_EVNTSEL0, K8_EVNTSEL0_VAL, MSR_K8_PERFCTR0);
-+}
-+
-+void __init perfctr_generic_init_tests(void)
-+{
-+	measure_overheads(0, 0, 0);
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64_setup.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_64_setup.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64_setup.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,63 @@
-+/* $Id: x86_64_setup.c,v 1.9 2004/02/21 11:56:53 mikpe Exp $
-+ * Performance-monitoring counters driver.
-+ * x86_86-specific kernel-resident code.
-+ *
-+ * Copyright (C) 2003-2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <asm/processor.h>
-+#include <asm/perfctr.h>
-+#include <asm/fixmap.h>
-+#include <asm/apic.h>
-+#include "x86_64_compat.h"
-+#include "compat.h"
-+
-+static void perfctr_default_ihandler(unsigned long pc)
-+{
-+}
-+
-+static perfctr_ihandler_t perfctr_ihandler = perfctr_default_ihandler;
-+
-+asmlinkage void smp_perfctr_interrupt(struct pt_regs *regs)
-+{
-+	/* PREEMPT note: invoked via an interrupt gate, which
-+	   masks interrupts. We're still on the originating CPU. */
-+	ack_APIC_irq();
-+	irq_enter();
-+	(*perfctr_ihandler)(regs->rip);
-+	irq_exit();
-+}
-+
-+void perfctr_cpu_set_ihandler(perfctr_ihandler_t ihandler)
-+{
-+	perfctr_ihandler = ihandler ? ihandler : perfctr_default_ihandler;
-+}
-+
-+extern unsigned int cpu_khz;
-+
-+/* Wrapper to avoid namespace clash in RedHat 8.0's 2.4.18-14 kernel. */
-+unsigned int perfctr_cpu_khz(void)
-+{
-+	return cpu_khz;
-+}
-+
-+#ifdef CONFIG_PERFCTR_MODULE
-+EXPORT_SYMBOL_mmu_cr4_features;
-+EXPORT_SYMBOL(perfctr_cpu_khz);
-+
-+EXPORT_SYMBOL(nmi_perfctr_msr);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71) && defined(CONFIG_PM)
-+EXPORT_SYMBOL(apic_pm_register);
-+EXPORT_SYMBOL(apic_pm_unregister);
-+EXPORT_SYMBOL(nmi_pmdev);
-+#endif
-+
-+EXPORT_SYMBOL(perfctr_cpu_set_ihandler);
-+
-+#endif /* MODULE */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86_64.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86_64.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,776 @@
-+/* $Id: x86_64.c,v 1.22.2.1 2004/05/29 22:25:22 mikpe Exp $
-+ * x86_64 performance-monitoring counters driver.
-+ *
-+ * Copyright (C) 2003-2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/perfctr.h>
-+
-+#include <asm/msr.h>
-+#include <asm/fixmap.h>
-+#include <asm/apic.h>
-+struct hw_interrupt_type;
-+#include <asm/hw_irq.h>
-+
-+#include "compat.h"
-+#include "x86_compat.h"
-+#include "x86_tests.h"
-+
-+/* Support for lazy evntsel and perfctr MSR updates. */
-+struct per_cpu_cache {	/* roughly a subset of perfctr_cpu_state */
-+	union {
-+		unsigned int id;	/* cache owner id */
-+	} k1;
-+	struct {
-+		/* NOTE: these caches have physical indices, not virtual */
-+		unsigned int evntsel[4];
-+	} control;
-+} ____cacheline_aligned;
-+static struct per_cpu_cache per_cpu_cache[NR_CPUS] __cacheline_aligned;
-+
-+/* Structure for counter snapshots, as 32-bit values. */
-+struct perfctr_low_ctrs {
-+	unsigned int tsc;
-+	unsigned int pmc[4];
-+};
-+
-+/* AMD K8 */
-+#define MSR_K8_EVNTSEL0		0xC0010000	/* .. 0xC0010003 */
-+#define MSR_K8_PERFCTR0		0xC0010004	/* .. 0xC0010007 */
-+#define K8_EVNTSEL_ENABLE	0x00400000
-+#define K8_EVNTSEL_INT		0x00100000
-+#define K8_EVNTSEL_CPL		0x00030000
-+#define K8_EVNTSEL_RESERVED	0x00280000
-+
-+#define rdpmc_low(ctr,low) \
-+	__asm__ __volatile__("rdpmc" : "=a"(low) : "c"(ctr) : "edx")
-+
-+static void clear_msr_range(unsigned int base, unsigned int n)
-+{
-+	unsigned int i;
-+
-+	for(i = 0; i < n; ++i)
-+		wrmsr(base+i, 0, 0);
-+}
-+
-+static inline void set_in_cr4_local(unsigned int mask)
-+{
-+	write_cr4(read_cr4() | mask);
-+}
-+
-+static inline void clear_in_cr4_local(unsigned int mask)
-+{
-+	write_cr4(read_cr4() & ~mask);
-+}
-+
-+static unsigned int new_id(void)
-+{
-+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
-+	static unsigned int counter;
-+	int id;
-+
-+	spin_lock(&lock);
-+	id = ++counter;
-+	spin_unlock(&lock);
-+	return id;
-+}
-+
-+#if defined(CONFIG_SMP)
-+
-+static inline void set_isuspend_cpu(struct perfctr_cpu_state *state,
-+				    int cpu)
-+{
-+	state->k1.isuspend_cpu = cpu;
-+}
-+
-+static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state,
-+				  int cpu)
-+{
-+	return state->k1.isuspend_cpu == cpu;
-+}
-+
-+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state)
-+{
-+	state->k1.isuspend_cpu = NR_CPUS;
-+}
-+
-+#else
-+static inline void set_isuspend_cpu(struct perfctr_cpu_state *state,
-+				    int cpu) { }
-+static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state,
-+				  int cpu) { return 1; }
-+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { }
-+#endif
-+
-+/* XXX: disabled: called from switch_to() where printk() is disallowed */
-+#if 0 && defined(CONFIG_PERFCTR_DEBUG)
-+static void debug_evntsel_cache(const struct perfctr_cpu_state *state,
-+				const struct per_cpu_cache *cache)
-+{
-+	unsigned int nrctrs, i;
-+
-+	nrctrs = perfctr_cstatus_nrctrs(state->cstatus);
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int evntsel = state->control.evntsel[i];
-+		unsigned int pmc = state->control.pmc_map[i];
-+		if( evntsel != cache->control.evntsel[pmc] ) {
-+			printk(KERN_ERR "perfctr: (pid %d, comm %s) "
-+			       "evntsel[%u] is %#x, should be %#x\n",
-+			       current->pid, current->comm,
-+			       i, cache->control.evntsel[pmc], evntsel);
-+			return;
-+		}
-+	}
-+}
-+#else
-+static inline void debug_evntsel_cache(const struct perfctr_cpu_state *s,
-+				       const struct per_cpu_cache *c)
-+{ }
-+#endif
-+
-+/****************************************************************
-+ *								*
-+ * Driver procedures.						*
-+ *								*
-+ ****************************************************************/
-+
-+static void perfctr_cpu_read_counters(const struct perfctr_cpu_state *state,
-+				      struct perfctr_low_ctrs *ctrs)
-+{
-+	unsigned int cstatus, nrctrs, i;
-+
-+	cstatus = state->cstatus;
-+	if( perfctr_cstatus_has_tsc(cstatus) )
-+		rdtscl(ctrs->tsc);
-+	nrctrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int pmc = state->pmc[i].map;
-+		rdpmc_low(pmc, ctrs->pmc[i]);
-+	}
-+}
-+
-+static int k8_check_control(struct perfctr_cpu_state *state)
-+{
-+	unsigned int evntsel, i, nractrs, nrctrs, pmc_mask, pmc;
-+
-+	nractrs = state->control.nractrs;
-+	nrctrs = nractrs + state->control.nrictrs;
-+	if( nrctrs < nractrs || nrctrs > 4 )
-+		return -EINVAL;
-+
-+	pmc_mask = 0;
-+	for(i = 0; i < nrctrs; ++i) {
-+		pmc = state->control.pmc_map[i];
-+		state->pmc[i].map = pmc;
-+		if( pmc >= 4 || (pmc_mask & (1<<pmc)) )
-+			return -EINVAL;
-+		pmc_mask |= (1<<pmc);
-+		evntsel = state->control.evntsel[i];
-+		/* protect reserved bits */
-+		if( evntsel & K8_EVNTSEL_RESERVED )
-+			return -EPERM;
-+		/* ENable bit must be set in each evntsel */
-+		if( !(evntsel & K8_EVNTSEL_ENABLE) )
-+			return -EINVAL;
-+		/* the CPL field must be non-zero */
-+		if( !(evntsel & K8_EVNTSEL_CPL) )
-+			return -EINVAL;
-+		/* INT bit must be off for a-mode and on for i-mode counters */
-+		if( evntsel & K8_EVNTSEL_INT ) {
-+			if( i < nractrs )
-+				return -EINVAL;
-+		} else {
-+			if( i >= nractrs )
-+				return -EINVAL;
-+		}
-+	}
-+	state->k1.id = new_id();
-+	return 0;
-+}
-+
-+static void perfctr_cpu_isuspend(struct perfctr_cpu_state *state)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int cstatus, nrctrs, i;
-+	int cpu;
-+
-+	cpu = smp_processor_id();
-+	cache = &per_cpu_cache[cpu];
-+	cstatus = state->cstatus;
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
-+		unsigned int pmc, now;
-+		pmc = state->pmc[i].map;
-+		cache->control.evntsel[pmc] = 0;
-+		wrmsr(MSR_K8_EVNTSEL0+pmc, 0, 0);
-+		rdpmc_low(pmc, now);
-+		state->pmc[i].sum += now - state->pmc[i].start;
-+		state->pmc[i].start = now;
-+	}
-+	/* cache->k1.id is still == state->k1.id */
-+	set_isuspend_cpu(state, cpu);
-+}
-+
-+static void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int cstatus, nrctrs, i;
-+	int cpu;
-+
-+	cpu = smp_processor_id();
-+	cache = &per_cpu_cache[cpu];
-+	if( cache->k1.id == state->k1.id ) {
-+		cache->k1.id = 0; /* force reload of cleared EVNTSELs */
-+		if( is_isuspend_cpu(state, cpu) )
-+			return; /* skip reload of PERFCTRs */
-+	}
-+	cstatus = state->cstatus;
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
-+		unsigned int pmc = state->pmc[i].map;
-+		/* If the control wasn't ours we must disable the evntsels
-+		   before reinitialising the counters, to prevent unexpected
-+		   counter increments and missed overflow interrupts. */
-+		if( cache->control.evntsel[pmc] ) {
-+			cache->control.evntsel[pmc] = 0;
-+			wrmsr(MSR_K8_EVNTSEL0+pmc, 0, 0);
-+		}
-+		wrmsr(MSR_K8_PERFCTR0+pmc, state->pmc[i].start, -1);
-+	}
-+	/* cache->k1.id remains != state->k1.id */
-+}
-+
-+static void perfctr_cpu_write_control(const struct perfctr_cpu_state *state)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int nrctrs, i;
-+
-+	cache = &per_cpu_cache[smp_processor_id()];
-+	if( cache->k1.id == state->k1.id ) {
-+		debug_evntsel_cache(state, cache);
-+		return;
-+	}
-+	nrctrs = perfctr_cstatus_nrctrs(state->cstatus);
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int evntsel = state->control.evntsel[i];
-+		unsigned int pmc = state->pmc[i].map;
-+		if( evntsel != cache->control.evntsel[pmc] ) {
-+			cache->control.evntsel[pmc] = evntsel;
-+			wrmsr(MSR_K8_EVNTSEL0+pmc, evntsel, 0);
-+		}
-+	}
-+	cache->k1.id = state->k1.id;
-+}
-+
-+static void k8_clear_counters(void)
-+{
-+	clear_msr_range(MSR_K8_EVNTSEL0, 4+4);
-+}
-+
-+/*
-+ * Generic driver for any x86-64 with a working TSC.
-+ * (Mainly for testing with Screwdriver.)
-+ */
-+
-+static int generic_check_control(struct perfctr_cpu_state *state)
-+{
-+	if( state->control.nractrs || state->control.nrictrs )
-+		return -EINVAL;
-+	return 0;
-+}
-+
-+static void generic_clear_counters(void)
-+{
-+}
-+
-+/*
-+ * Driver methods, internal and exported.
-+ */
-+
-+/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to
-+   bypass internal caching and force a reload if the I-mode PMCs. */
-+void perfctr_cpu_ireload(struct perfctr_cpu_state *state)
-+{
-+#ifdef CONFIG_SMP
-+	clear_isuspend_cpu(state);
-+#else
-+	per_cpu_cache[smp_processor_id()].k1.id = 0;
-+#endif
-+}
-+
-+/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */
-+unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state)
-+{
-+	unsigned int cstatus, nrctrs, pmc, pmc_mask;
-+
-+	cstatus = state->cstatus;
-+	pmc = perfctr_cstatus_nractrs(cstatus);
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+
-+	for(pmc_mask = 0; pmc < nrctrs; ++pmc) {
-+		if( (int)state->pmc[pmc].start >= 0 ) { /* XXX: ">" ? */
-+			/* XXX: "+=" to correct for overshots */
-+			state->pmc[pmc].start = state->control.ireset[pmc];
-+			pmc_mask |= (1 << pmc);
-+		}
-+	}
-+	return pmc_mask;
-+}
-+
-+static inline int check_ireset(const struct perfctr_cpu_state *state)
-+{
-+	unsigned int nrctrs, i;
-+
-+	i = state->control.nractrs;
-+	nrctrs = i + state->control.nrictrs;
-+	for(; i < nrctrs; ++i)
-+		if( state->control.ireset[i] >= 0 )
-+			return -EINVAL;
-+	return 0;
-+}
-+
-+static inline void setup_imode_start_values(struct perfctr_cpu_state *state)
-+{
-+	unsigned int cstatus, nrctrs, i;
-+
-+	cstatus = state->cstatus;
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
-+		state->pmc[i].start = state->control.ireset[i];
-+}
-+
-+static inline void debug_no_imode(const struct perfctr_cpu_state *state)
-+{
-+#ifdef CONFIG_PERFCTR_DEBUG
-+	if( perfctr_cstatus_has_ictrs(state->cstatus) )
-+		printk(KERN_ERR "perfctr: BUG! updating control in"
-+		       " perfctr %p on cpu %u while it has cstatus %x"
-+		       " (pid %d, comm %s)\n",
-+		       state, smp_processor_id(), state->cstatus,
-+		       current->pid, current->comm);
-+#endif
-+}
-+
-+static int (*check_control)(struct perfctr_cpu_state*);
-+int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	int err;
-+
-+	debug_no_imode(state);
-+	clear_isuspend_cpu(state);
-+	state->cstatus = 0;
-+
-+	/* disallow i-mode counters if we cannot catch the interrupts */
-+	if( !(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
-+	    && state->control.nrictrs )
-+		return -EPERM;
-+
-+	err = check_control(state);
-+	if( err < 0 )
-+		return err;
-+	err = check_ireset(state);
-+	if( err < 0 )
-+		return err;
-+	state->cstatus = perfctr_mk_cstatus(state->control.tsc_on,
-+					    state->control.nractrs,
-+					    state->control.nrictrs);
-+	setup_imode_start_values(state);
-+	return 0;
-+}
-+
-+void perfctr_cpu_suspend(struct perfctr_cpu_state *state)
-+{
-+	unsigned int i, cstatus, nractrs;
-+	struct perfctr_low_ctrs now;
-+
-+	if( perfctr_cstatus_has_ictrs(state->cstatus) )
-+	    perfctr_cpu_isuspend(state);
-+	perfctr_cpu_read_counters(state, &now);
-+	cstatus = state->cstatus;
-+	if( perfctr_cstatus_has_tsc(cstatus) )
-+		state->tsc_sum += now.tsc - state->tsc_start;
-+	nractrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nractrs; ++i)
-+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
-+}
-+
-+void perfctr_cpu_resume(struct perfctr_cpu_state *state)
-+{
-+	if( perfctr_cstatus_has_ictrs(state->cstatus) )
-+	    perfctr_cpu_iresume(state);
-+	perfctr_cpu_write_control(state);
-+	//perfctr_cpu_read_counters(state, &state->start);
-+	{
-+		struct perfctr_low_ctrs now;
-+		unsigned int i, cstatus, nrctrs;
-+		perfctr_cpu_read_counters(state, &now);
-+		cstatus = state->cstatus;
-+		if( perfctr_cstatus_has_tsc(cstatus) )
-+			state->tsc_start = now.tsc;
-+		nrctrs = perfctr_cstatus_nractrs(cstatus);
-+		for(i = 0; i < nrctrs; ++i)
-+			state->pmc[i].start = now.pmc[i];
-+	}
-+	/* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
-+}
-+
-+void perfctr_cpu_sample(struct perfctr_cpu_state *state)
-+{
-+	unsigned int i, cstatus, nractrs;
-+	struct perfctr_low_ctrs now;
-+
-+	perfctr_cpu_read_counters(state, &now);
-+	cstatus = state->cstatus;
-+	if( perfctr_cstatus_has_tsc(cstatus) ) {
-+		state->tsc_sum += now.tsc - state->tsc_start;
-+		state->tsc_start = now.tsc;
-+	}
-+	nractrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nractrs; ++i) {
-+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
-+		state->pmc[i].start = now.pmc[i];
-+	}
-+}
-+
-+static void (*clear_counters)(void);
-+static void perfctr_cpu_clear_counters(void)
-+{
-+	return clear_counters();
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Processor detection and initialisation procedures.		*
-+ *								*
-+ ****************************************************************/
-+
-+static int __init amd_init(void)
-+{
-+	static char k8_name[] __initdata = "AMD K8";
-+	static char k8c_name[] __initdata = "AMD K8C";
-+
-+	if( !cpu_has_tsc )
-+		return -ENODEV;
-+	if( boot_cpu_data.x86 != 15 )
-+		return -ENODEV;
-+	if( (boot_cpu_data.x86_model > 5) ||
-+	    (boot_cpu_data.x86_model >= 4 && boot_cpu_data.x86_mask >= 8) ) {
-+		perfctr_info.cpu_type = PERFCTR_X86_AMD_K8C;
-+		perfctr_cpu_name = k8c_name;
-+	} else {
-+		perfctr_info.cpu_type = PERFCTR_X86_AMD_K8;
-+		perfctr_cpu_name = k8_name;
-+	}
-+	check_control = k8_check_control;
-+	clear_counters = k8_clear_counters;
-+	if( cpu_has_apic )
-+		perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
-+	return 0;
-+}
-+
-+/* For testing on Screwdriver. */
-+static int __init generic_init(void)
-+{
-+	static char generic_name[] __initdata = "Generic x86-64 with TSC";
-+	if( !cpu_has_tsc )
-+		return -ENODEV;
-+	perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
-+	perfctr_info.cpu_type = PERFCTR_X86_GENERIC;
-+	perfctr_cpu_name = generic_name;
-+	check_control = generic_check_control;
-+	clear_counters = generic_clear_counters;
-+	return 0;
-+}
-+
-+static void perfctr_cpu_init_one(void *ignore)
-+{
-+	/* PREEMPT note: when called via smp_call_function(),
-+	   this is in IRQ context with preemption disabled. */
-+	perfctr_cpu_clear_counters();
-+	if( cpu_has_apic )
-+		apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR);
-+	if( perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC )
-+		set_in_cr4_local(X86_CR4_PCE);
-+}
-+
-+static void perfctr_cpu_exit_one(void *ignore)
-+{
-+	/* PREEMPT note: when called via smp_call_function(),
-+	   this is in IRQ context with preemption disabled. */
-+	perfctr_cpu_clear_counters();
-+	if( cpu_has_apic )
-+		apic_write(APIC_LVTPC, APIC_DM_NMI | APIC_LVT_MASKED);
-+	if( perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC )
-+		clear_in_cr4_local(X86_CR4_PCE);
-+}
-+
-+#if defined(CONFIG_PM)
-+
-+static void perfctr_pm_suspend(void)
-+{
-+	/* XXX: clear control registers */
-+	printk("perfctr: PM suspend\n");
-+}
-+
-+static void perfctr_pm_resume(void)
-+{
-+	/* XXX: reload control registers */
-+	printk("perfctr: PM resume\n");
-+}
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,71)
-+
-+#include <linux/sysdev.h>
-+
-+static int perfctr_device_suspend(struct sys_device *dev, u32 state)
-+{
-+	perfctr_pm_suspend();
-+	return 0;
-+}
-+
-+static int perfctr_device_resume(struct sys_device *dev)
-+{
-+	perfctr_pm_resume();
-+	return 0;
-+}
-+
-+static struct sysdev_class perfctr_sysclass = {
-+	set_kset_name("perfctr"),
-+	.resume		= perfctr_device_resume,
-+	.suspend	= perfctr_device_suspend,
-+};
-+
-+static struct sys_device device_perfctr = {
-+	.id	= 0,
-+	.cls	= &perfctr_sysclass,
-+};
-+
-+static void x86_pm_init(void)
-+{
-+	if( sysdev_class_register(&perfctr_sysclass) == 0 )
-+		sysdev_register(&device_perfctr);
-+}
-+
-+static void x86_pm_exit(void)
-+{
-+	sysdev_unregister(&device_perfctr);
-+	sysdev_class_unregister(&perfctr_sysclass);
-+}
-+
-+#else	/* 2.4 kernel */
-+
-+static int x86_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
-+{
-+	switch( rqst ) {
-+	case PM_SUSPEND:
-+		perfctr_pm_suspend();
-+		break;
-+	case PM_RESUME:
-+		perfctr_pm_resume();
-+		break;
-+	}
-+	return 0;
-+}
-+
-+static struct pm_dev *x86_pmdev;
-+
-+static void x86_pm_init(void)
-+{
-+	x86_pmdev = apic_pm_register(PM_SYS_DEV, 0, x86_pm_callback);
-+}
-+
-+static void x86_pm_exit(void)
-+{
-+	if( x86_pmdev ) {
-+		apic_pm_unregister(x86_pmdev);
-+		x86_pmdev = NULL;
-+	}
-+}
-+
-+#endif	/* 2.4 kernel */
-+
-+#else
-+
-+static inline void x86_pm_init(void) { }
-+static inline void x86_pm_exit(void) { }
-+
-+#endif	/* CONFIG_PM */
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,71)
-+static void disable_lapic_nmi_watchdog(void)
-+{
-+#ifdef CONFIG_PM
-+	if( nmi_pmdev ) {
-+		apic_pm_unregister(nmi_pmdev);
-+		nmi_pmdev = 0;
-+	}
-+#endif
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)
-+static int reserve_lapic_nmi(void)
-+{
-+	int ret = 0;
-+	if( nmi_perfctr_msr ) {
-+		nmi_perfctr_msr = 0;
-+		disable_lapic_nmi_watchdog();
-+		ret = 1;
-+	}
-+	return ret;
-+}
-+
-+static inline void release_lapic_nmi(void) { }
-+#endif
-+
-+static void do_init_tests(void)
-+{
-+#ifdef CONFIG_PERFCTR_INIT_TESTS
-+	if( reserve_lapic_nmi() >= 0 ) {
-+		perfctr_x86_init_tests();
-+		release_lapic_nmi();
-+	}
-+#endif
-+}
-+
-+static void invalidate_per_cpu_cache(void)
-+{
-+	/*
-+	 * per_cpu_cache[] is initialised to contain "impossible"
-+	 * evntsel values guaranteed to differ from anything accepted
-+	 * by perfctr_cpu_update_control(). This way, initialisation of
-+	 * a CPU's evntsel MSRs will happen automatically the first time
-+	 * perfctr_cpu_write_control() executes on it.
-+	 * All-bits-one works for all currently supported processors.
-+	 * The memset also sets the ids to -1, which is intentional.
-+	 */
-+	memset(per_cpu_cache, ~0, sizeof per_cpu_cache);
-+}
-+
-+int __init perfctr_cpu_init(void)
-+{
-+	int err = -ENODEV;
-+
-+	preempt_disable();
-+
-+	/* RDPMC and RDTSC are on by default. They will be disabled
-+	   by the init procedures if necessary. */
-+	perfctr_info.cpu_features = PERFCTR_FEATURE_RDPMC | PERFCTR_FEATURE_RDTSC;
-+
-+	switch( boot_cpu_data.x86_vendor ) {
-+	case X86_VENDOR_AMD:
-+		err = amd_init();
-+		break;
-+	}
-+	if( err ) {
-+		err = generic_init();	/* last resort */
-+		if( err )
-+			goto out;
-+	}
-+	do_init_tests();
-+#if 0
-+	/*
-+	 * Put the hardware in a sane state:
-+	 * - clear perfctr MSRs
-+	 * - set up APIC_LVTPC
-+	 * - set CR4.PCE [on permanently due to __flush_tlb_global()]
-+	 * - install our default interrupt handler
-+	 */
-+	if( perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC )
-+		mmu_cr4_features |= X86_CR4_PCE;
-+	perfctr_cpu_init_one(NULL);
-+	smp_call_function(perfctr_cpu_init_one, NULL, 1, 1);
-+	perfctr_cpu_set_ihandler(NULL);
-+	/*
-+	 * Fix up the connection to the local APIC:
-+	 * - disable and disconnect the NMI watchdog
-+	 * - register our PM callback
-+	 */
-+	disable_nmi_watchdog();
-+	x86_pm_init();
-+#endif
-+
-+	invalidate_per_cpu_cache();
-+
-+	perfctr_info.cpu_khz = perfctr_cpu_khz();
-+	perfctr_info.tsc_to_cpu_mult = 1;
-+
-+ out:
-+	preempt_enable();
-+	return err;
-+}
-+
-+void __exit perfctr_cpu_exit(void)
-+{
-+#if 0
-+	preempt_disable();
-+	if( perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC )
-+		mmu_cr4_features &= ~X86_CR4_PCE;
-+	perfctr_cpu_exit_one(NULL);
-+	smp_call_function(perfctr_cpu_exit_one, NULL, 1, 1);
-+	perfctr_cpu_set_ihandler(NULL);
-+	x86_pm_exit();
-+	/* XXX: restart nmi watchdog? */
-+	preempt_enable();
-+#endif
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Hardware reservation.					*
-+ *								*
-+ ****************************************************************/
-+
-+static DECLARE_MUTEX(mutex);
-+static const char *current_service = 0;
-+
-+const char *perfctr_cpu_reserve(const char *service)
-+{
-+	const char *ret;
-+
-+	down(&mutex);
-+	ret = current_service;
-+	if( ret )
-+		goto out_up;
-+	ret = "unknown driver (oprofile?)";
-+	if( reserve_lapic_nmi() < 0 )
-+		goto out_up;
-+	current_service = service;
-+	__module_get(THIS_MODULE);
-+	if( perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC )
-+		mmu_cr4_features |= X86_CR4_PCE;
-+	on_each_cpu(perfctr_cpu_init_one, NULL, 1, 1);
-+	perfctr_cpu_set_ihandler(NULL);
-+	x86_pm_init();
-+	ret = NULL;
-+ out_up:
-+	up(&mutex);
-+	return ret;
-+}
-+
-+void perfctr_cpu_release(const char *service)
-+{
-+	down(&mutex);
-+	if( service != current_service ) {
-+		printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n",
-+		       __FUNCTION__, service, current_service);
-+		goto out_up;
-+	}
-+	/* power down the counters */
-+	invalidate_per_cpu_cache();
-+	if( perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC )
-+		mmu_cr4_features &= ~X86_CR4_PCE;
-+	on_each_cpu(perfctr_cpu_exit_one, NULL, 1, 1);
-+	perfctr_cpu_set_ihandler(NULL);
-+	x86_pm_exit();
-+	current_service = 0;
-+	release_lapic_nmi();
-+	module_put(THIS_MODULE);
-+ out_up:
-+	up(&mutex);
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/drivers/perfctr/x86.c	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/drivers/perfctr/x86.c	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,1720 @@
-+/* $Id: x86.c,v 1.127.2.13 2004/09/14 17:56:42 mikpe Exp $
-+ * x86/x86_64 performance-monitoring counters driver.
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+#include <linux/config.h>
-+#define __NO_VERSION__
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/fs.h>
-+#include <linux/perfctr.h>
-+
-+#include <asm/msr.h>
-+#undef MSR_P6_PERFCTR0
-+#undef MSR_IA32_MISC_ENABLE
-+#include <asm/fixmap.h>
-+#include <asm/apic.h>
-+struct hw_interrupt_type;
-+#include <asm/hw_irq.h>
-+
-+#include "compat.h"
-+#include "x86_compat.h"
-+#include "x86_tests.h"
-+
-+/* Support for lazy evntsel and perfctr MSR updates. */
-+struct per_cpu_cache {	/* roughly a subset of perfctr_cpu_state */
-+	union {
-+		unsigned int p5_cesr;
-+		unsigned int id;	/* cache owner id */
-+	} k1;
-+	struct {
-+		/* NOTE: these caches have physical indices, not virtual */
-+		unsigned int evntsel[18];
-+		unsigned int escr[0x3E2-0x3A0];
-+		unsigned int pebs_enable;
-+		unsigned int pebs_matrix_vert;
-+	} control;
-+} ____cacheline_aligned;
-+static struct per_cpu_cache per_cpu_cache[NR_CPUS] __cacheline_aligned;
-+#define __get_cpu_cache(cpu) (&per_cpu_cache[cpu])
-+#define get_cpu_cache() __get_cpu_cache(smp_processor_id())
-+
-+/* Structure for counter snapshots, as 32-bit values. */
-+struct perfctr_low_ctrs {
-+	unsigned int tsc;
-+	unsigned int pmc[18];
-+};
-+
-+/* Intel P5, Cyrix 6x86MX/MII/III, Centaur WinChip C6/2/3 */
-+#define MSR_P5_CESR		0x11
-+#define MSR_P5_CTR0		0x12		/* .. 0x13 */
-+#define P5_CESR_CPL		0x00C0
-+#define P5_CESR_RESERVED	(~0x01FF)
-+#define MII_CESR_RESERVED	(~0x05FF)
-+#define C6_CESR_RESERVED	(~0x00FF)
-+
-+/* Intel P6, VIA C3 */
-+#define MSR_P6_PERFCTR0		0xC1		/* .. 0xC2 */
-+#define MSR_P6_EVNTSEL0		0x186		/* .. 0x187 */
-+#define P6_EVNTSEL_ENABLE	0x00400000
-+#define P6_EVNTSEL_INT		0x00100000
-+#define P6_EVNTSEL_CPL		0x00030000
-+#define P6_EVNTSEL_RESERVED	0x00280000
-+#define VC3_EVNTSEL1_RESERVED	(~0x1FF)
-+
-+/* AMD K7 */
-+#define MSR_K7_EVNTSEL0		0xC0010000	/* .. 0xC0010003 */
-+#define MSR_K7_PERFCTR0		0xC0010004	/* .. 0xC0010007 */
-+
-+/* Intel P4, Intel Pentium M */
-+#define MSR_IA32_MISC_ENABLE	0x1A0
-+#define MSR_IA32_MISC_ENABLE_PERF_AVAIL (1<<7)	/* read-only status bit */
-+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1<<12) /* read-only status bit */
-+
-+/* Intel P4 */
-+#define MSR_P4_PERFCTR0		0x300		/* .. 0x311 */
-+#define MSR_P4_CCCR0		0x360		/* .. 0x371 */
-+#define MSR_P4_ESCR0		0x3A0		/* .. 0x3E1, with some gaps */
-+
-+#define MSR_P4_PEBS_ENABLE	0x3F1
-+#define P4_PE_REPLAY_TAG_BITS	0x00000607
-+#define P4_PE_UOP_TAG		0x01000000
-+#define P4_PE_RESERVED		0xFEFFF9F8	/* only allow ReplayTagging */
-+
-+#define MSR_P4_PEBS_MATRIX_VERT	0x3F2
-+#define P4_PMV_REPLAY_TAG_BITS	0x00000003
-+#define P4_PMV_RESERVED		0xFFFFFFFC
-+
-+#define P4_CCCR_OVF		0x80000000
-+#define P4_CCCR_CASCADE		0x40000000
-+#define P4_CCCR_OVF_PMI_T1	0x08000000
-+#define P4_CCCR_OVF_PMI_T0	0x04000000
-+#define P4_CCCR_FORCE_OVF	0x02000000
-+#define P4_CCCR_ACTIVE_THREAD	0x00030000
-+#define P4_CCCR_ENABLE		0x00001000
-+#define P4_CCCR_ESCR_SELECT(X)	(((X) >> 13) & 0x7)
-+#define P4_CCCR_EXTENDED_CASCADE	0x00000800
-+#define P4_CCCR_RESERVED	(0x300007FF|P4_CCCR_OVF|P4_CCCR_OVF_PMI_T1)
-+
-+#define P4_ESCR_CPL_T1		0x00000003
-+#define P4_ESCR_CPL_T0		0x0000000C
-+#define P4_ESCR_TAG_ENABLE	0x00000010
-+#define P4_ESCR_RESERVED	(0x80000000)
-+
-+#define P4_FAST_RDPMC		0x80000000
-+#define P4_MASK_FAST_RDPMC	0x0000001F	/* we only need low 5 bits */
-+
-+#define rdmsr_low(msr,low) \
-+	__asm__ __volatile__("rdmsr" : "=a"(low) : "c"(msr) : "edx")
-+#define rdpmc_low(ctr,low) \
-+	__asm__ __volatile__("rdpmc" : "=a"(low) : "c"(ctr) : "edx")
-+
-+static void clear_msr_range(unsigned int base, unsigned int n)
-+{
-+	unsigned int i;
-+
-+	for(i = 0; i < n; ++i)
-+		wrmsr(base+i, 0, 0);
-+}
-+
-+static inline void set_in_cr4_local(unsigned int mask)
-+{
-+	write_cr4(read_cr4() | mask);
-+}
-+
-+static inline void clear_in_cr4_local(unsigned int mask)
-+{
-+	write_cr4(read_cr4() & ~mask);
-+}
-+
-+static unsigned int new_id(void)
-+{
-+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
-+	static unsigned int counter;
-+	int id;
-+
-+	spin_lock(&lock);
-+	id = ++counter;
-+	spin_unlock(&lock);
-+	return id;
-+}
-+
-+#if !defined(CONFIG_X86_LOCAL_APIC)
-+#define perfctr_cstatus_has_ictrs(cstatus)	0
-+#undef cpu_has_apic
-+#define cpu_has_apic				0
-+#undef apic_write
-+#define apic_write(reg,vector)			do{}while(0)
-+#endif
-+
-+#if defined(CONFIG_SMP)
-+
-+static inline void
-+set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu)
-+{
-+	state->k1.isuspend_cpu = cpu;
-+}
-+
-+static inline int
-+is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu)
-+{
-+	return state->k1.isuspend_cpu == cpu;
-+}
-+
-+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state)
-+{
-+	state->k1.isuspend_cpu = NR_CPUS;
-+}
-+
-+#else
-+static inline void set_isuspend_cpu(struct perfctr_cpu_state *state, int cpu) { }
-+static inline int is_isuspend_cpu(const struct perfctr_cpu_state *state, int cpu) { return 1; }
-+static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { }
-+#endif
-+
-+/****************************************************************
-+ *								*
-+ * Driver procedures.						*
-+ *								*
-+ ****************************************************************/
-+
-+/*
-+ * Intel P5 family (Pentium, family code 5).
-+ * - One TSC and two 40-bit PMCs.
-+ * - A single 32-bit CESR (MSR 0x11) controls both PMCs.
-+ *   CESR has two halves, each controlling one PMC.
-+ *   To keep the API reasonably clean, the user puts 16 bits of
-+ *   control data in each counter's evntsel; the driver combines
-+ *   these to a single 32-bit CESR value.
-+ * - Overflow interrupts are not available.
-+ * - Pentium MMX added the RDPMC instruction. RDPMC has lower
-+ *   overhead than RDMSR and it can be used in user-mode code.
-+ * - The MMX events are not symmetric: some events are only available
-+ *   for some PMC, and some event codes denote different events
-+ *   depending on which PMCs they control.
-+ */
-+
-+/* shared with MII and C6 */
-+static int p5_like_check_control(struct perfctr_cpu_state *state,
-+				 unsigned int reserved_bits, int is_c6)
-+{
-+	unsigned short cesr_half[2];
-+	unsigned int pmc, evntsel, i;
-+
-+	if (state->control.nrictrs != 0 || state->control.nractrs > 2)
-+		return -EINVAL;
-+	cesr_half[0] = 0;
-+	cesr_half[1] = 0;
-+	for(i = 0; i < state->control.nractrs; ++i) {
-+		pmc = state->control.pmc_map[i];
-+		state->pmc[i].map = pmc;
-+		if (pmc > 1 || cesr_half[pmc] != 0)
-+			return -EINVAL;
-+		evntsel = state->control.evntsel[i];
-+		/* protect reserved bits */
-+		if ((evntsel & reserved_bits) != 0)
-+			return -EPERM;
-+		/* the CPL field (if defined) must be non-zero */
-+		if (!is_c6 && !(evntsel & P5_CESR_CPL))
-+			return -EINVAL;
-+		cesr_half[pmc] = evntsel;
-+	}
-+	state->k1.id = (cesr_half[1] << 16) | cesr_half[0];
-+	return 0;
-+}
-+
-+static int p5_check_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	return p5_like_check_control(state, P5_CESR_RESERVED, 0);
-+}
-+
-+/* shared with MII but not C6 */
-+static void p5_write_control(const struct perfctr_cpu_state *state)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int cesr;
-+
-+	cesr = state->k1.id;
-+	if (!cesr)	/* no PMC is on (this test doesn't work on C6) */
-+		return;
-+	cache = get_cpu_cache();
-+	if (cache->k1.p5_cesr != cesr) {
-+		cache->k1.p5_cesr = cesr;
-+		wrmsr(MSR_P5_CESR, cesr, 0);
-+	}
-+}
-+
-+static void p5_read_counters(const struct perfctr_cpu_state *state,
-+			     struct perfctr_low_ctrs *ctrs)
-+{
-+	unsigned int cstatus, nrctrs, i;
-+
-+	/* The P5 doesn't allocate a cache line on a write miss, so do
-+	   a dummy read to avoid a write miss here _and_ a read miss
-+	   later in our caller. */
-+	asm("" : : "r"(ctrs->tsc));
-+
-+	cstatus = state->cstatus;
-+	if (perfctr_cstatus_has_tsc(cstatus))
-+		rdtscl(ctrs->tsc);
-+	nrctrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int pmc = state->pmc[i].map;
-+		rdmsr_low(MSR_P5_CTR0+pmc, ctrs->pmc[i]);
-+	}
-+}
-+
-+/* used by all except pre-MMX P5 */
-+static void rdpmc_read_counters(const struct perfctr_cpu_state *state,
-+				struct perfctr_low_ctrs *ctrs)
-+{
-+	unsigned int cstatus, nrctrs, i;
-+
-+	cstatus = state->cstatus;
-+	if (perfctr_cstatus_has_tsc(cstatus))
-+		rdtscl(ctrs->tsc);
-+	nrctrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int pmc = state->pmc[i].map;
-+		rdpmc_low(pmc, ctrs->pmc[i]);
-+	}
-+}
-+
-+/* shared with MII and C6 */
-+static void p5_clear_counters(void)
-+{
-+	clear_msr_range(MSR_P5_CESR, 1+2);
-+}
-+
-+/*
-+ * Cyrix 6x86/MII/III.
-+ * - Same MSR assignments as P5 MMX. Has RDPMC and two 48-bit PMCs.
-+ * - Event codes and CESR formatting as in the plain P5 subset.
-+ * - Many but not all P5 MMX event codes are implemented.
-+ * - Cyrix adds a few more event codes. The event code is widened
-+ *   to 7 bits, and Cyrix puts the high bit in CESR bit 10
-+ *   (and CESR bit 26 for PMC1).
-+ */
-+
-+static int mii_check_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	return p5_like_check_control(state, MII_CESR_RESERVED, 0);
-+}
-+
-+/*
-+ * Centaur WinChip C6/2/3.
-+ * - Same MSR assignments as P5 MMX. Has RDPMC and two 40-bit PMCs.
-+ * - CESR is formatted with two halves, like P5. However, there
-+ *   are no defined control fields for e.g. CPL selection, and
-+ *   there is no defined method for stopping the counters.
-+ * - Only a few event codes are defined.
-+ * - The 64-bit TSC is synthesised from the low 32 bits of the
-+ *   two PMCs, and CESR has to be set up appropriately.
-+ *   Reprogramming CESR causes RDTSC to yield invalid results.
-+ *   (The C6 may also hang in this case, due to C6 erratum I-13.)
-+ *   Therefore, using the PMCs on any of these processors requires
-+ *   that the TSC is not accessed at all:
-+ *   1. The kernel must be configured or a TSC-less processor, i.e.
-+ *      generic 586 or less.
-+ *   2. The "notsc" boot parameter must be passed to the kernel.
-+ *   3. User-space libraries and code must also be configured and
-+ *      compiled for a generic 586 or less.
-+ */
-+
-+#if !defined(CONFIG_X86_TSC)
-+static int c6_check_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	if (state->control.tsc_on)
-+		return -EINVAL;
-+	return p5_like_check_control(state, C6_CESR_RESERVED, 1);
-+}
-+
-+static void c6_write_control(const struct perfctr_cpu_state *state)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int cesr;
-+
-+	if (perfctr_cstatus_nractrs(state->cstatus) == 0) /* no PMC is on */
-+		return;
-+	cache = get_cpu_cache();
-+	cesr = state->k1.id;
-+	if (cache->k1.p5_cesr != cesr) {
-+		cache->k1.p5_cesr = cesr;
-+		wrmsr(MSR_P5_CESR, cesr, 0);
-+	}
-+}
-+#endif
-+
-+/*
-+ * Intel P6 family (Pentium Pro, Pentium II, and Pentium III cores,
-+ * and Xeon and Celeron versions of Pentium II and III cores).
-+ * - One TSC and two 40-bit PMCs.
-+ * - One 32-bit EVNTSEL MSR for each PMC.
-+ * - EVNTSEL0 contains a global enable/disable bit.
-+ *   That bit is reserved in EVNTSEL1.
-+ * - Each EVNTSEL contains a CPL field.
-+ * - Overflow interrupts are possible, but requires that the
-+ *   local APIC is available. Some Mobile P6s have no local APIC.
-+ * - The PMCs cannot be initialised with arbitrary values, since
-+ *   wrmsr fills the high bits by sign-extending from bit 31.
-+ * - Most events are symmetric, but a few are not.
-+ */
-+
-+/* shared with K7 */
-+static int p6_like_check_control(struct perfctr_cpu_state *state, int is_k7)
-+{
-+	unsigned int evntsel, i, nractrs, nrctrs, pmc_mask, pmc;
-+
-+	nractrs = state->control.nractrs;
-+	nrctrs = nractrs + state->control.nrictrs;
-+	if (nrctrs < nractrs || nrctrs > (is_k7 ? 4 : 2))
-+		return -EINVAL;
-+
-+	pmc_mask = 0;
-+	for(i = 0; i < nrctrs; ++i) {
-+		pmc = state->control.pmc_map[i];
-+		state->pmc[i].map = pmc;
-+		if (pmc >= (is_k7 ? 4 : 2) || (pmc_mask & (1<<pmc)))
-+			return -EINVAL;
-+		pmc_mask |= (1<<pmc);
-+		evntsel = state->control.evntsel[i];
-+		/* protect reserved bits */
-+		if (evntsel & P6_EVNTSEL_RESERVED)
-+			return -EPERM;
-+		/* check ENable bit */
-+		if (is_k7) {
-+			/* ENable bit must be set in each evntsel */
-+			if (!(evntsel & P6_EVNTSEL_ENABLE))
-+				return -EINVAL;
-+		} else {
-+			/* only evntsel[0] has the ENable bit */
-+			if (evntsel & P6_EVNTSEL_ENABLE) {
-+				if (pmc > 0)
-+					return -EPERM;
-+			} else {
-+				if (pmc == 0)
-+					return -EINVAL;
-+			}
-+		}
-+		/* the CPL field must be non-zero */
-+		if (!(evntsel & P6_EVNTSEL_CPL))
-+			return -EINVAL;
-+		/* INT bit must be off for a-mode and on for i-mode counters */
-+		if (evntsel & P6_EVNTSEL_INT) {
-+			if (i < nractrs)
-+				return -EINVAL;
-+		} else {
-+			if (i >= nractrs)
-+				return -EINVAL;
-+		}
-+	}
-+	state->k1.id = new_id();
-+	return 0;
-+}
-+
-+static int p6_check_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	return p6_like_check_control(state, 0);
-+}
-+
-+#ifdef CONFIG_X86_LOCAL_APIC
-+/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */
-+/* shared with K7 and P4 */
-+static void p6_like_isuspend(struct perfctr_cpu_state *state,
-+			     unsigned int msr_evntsel0)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int cstatus, nrctrs, i;
-+	int cpu;
-+
-+	cpu = smp_processor_id();
-+	set_isuspend_cpu(state, cpu); /* early to limit cpu's live range */
-+	cache = __get_cpu_cache(cpu);
-+	cstatus = state->cstatus;
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
-+		unsigned int pmc_raw, pmc_idx, now;
-+		pmc_raw = state->pmc[i].map;
-+		/* Note: P4_MASK_FAST_RDPMC is a no-op for P6 and K7.
-+		   We don't need to make it into a parameter. */
-+		pmc_idx = pmc_raw & P4_MASK_FAST_RDPMC;
-+		cache->control.evntsel[pmc_idx] = 0;
-+		/* On P4 this intensionally also clears the CCCR.OVF flag. */
-+		wrmsr(msr_evntsel0+pmc_idx, 0, 0);
-+		/* P4 erratum N17 does not apply since we read only low 32 bits. */
-+		rdpmc_low(pmc_raw, now);
-+		state->pmc[i].sum += now - state->pmc[i].start;
-+		state->pmc[i].start = now;
-+	}
-+	/* cache->k1.id is still == state->k1.id */
-+}
-+
-+/* PRE: perfctr_cstatus_has_ictrs(state->cstatus) != 0 */
-+/* shared with K7 and P4 */
-+static void p6_like_iresume(const struct perfctr_cpu_state *state,
-+			    unsigned int msr_evntsel0,
-+			    unsigned int msr_perfctr0)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int cstatus, nrctrs, i;
-+	int cpu;
-+
-+	cpu = smp_processor_id();
-+	cache = __get_cpu_cache(cpu);
-+	if (cache->k1.id == state->k1.id) {
-+		cache->k1.id = 0; /* force reload of cleared EVNTSELs */
-+		if (is_isuspend_cpu(state, cpu))
-+			return; /* skip reload of PERFCTRs */
-+	}
-+	cstatus = state->cstatus;
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i) {
-+		/* Note: P4_MASK_FAST_RDPMC is a no-op for P6 and K7.
-+		   We don't need to make it into a parameter. */
-+		unsigned int pmc = state->pmc[i].map & P4_MASK_FAST_RDPMC;
-+		/* If the control wasn't ours we must disable the evntsels
-+		   before reinitialising the counters, to prevent unexpected
-+		   counter increments and missed overflow interrupts. */
-+		if (cache->control.evntsel[pmc]) {
-+			cache->control.evntsel[pmc] = 0;
-+			wrmsr(msr_evntsel0+pmc, 0, 0);
-+		}
-+		/* P4 erratum N15 does not apply since the CCCR is disabled. */
-+		wrmsr(msr_perfctr0+pmc, state->pmc[i].start, -1);
-+	}
-+	/* cache->k1.id remains != state->k1.id */
-+}
-+
-+static void p6_isuspend(struct perfctr_cpu_state *state)
-+{
-+	p6_like_isuspend(state, MSR_P6_EVNTSEL0);
-+}
-+
-+static void p6_iresume(const struct perfctr_cpu_state *state)
-+{
-+	p6_like_iresume(state, MSR_P6_EVNTSEL0, MSR_P6_PERFCTR0);
-+}
-+#endif	/* CONFIG_X86_LOCAL_APIC */
-+
-+/* shared with K7 and VC3 */
-+static void p6_like_write_control(const struct perfctr_cpu_state *state,
-+				  unsigned int msr_evntsel0)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int nrctrs, i;
-+
-+	cache = get_cpu_cache();
-+	if (cache->k1.id == state->k1.id)
-+		return;
-+	nrctrs = perfctr_cstatus_nrctrs(state->cstatus);
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int evntsel = state->control.evntsel[i];
-+		unsigned int pmc = state->pmc[i].map;
-+		if (evntsel != cache->control.evntsel[pmc]) {
-+			cache->control.evntsel[pmc] = evntsel;
-+			wrmsr(msr_evntsel0+pmc, evntsel, 0);
-+		}
-+	}
-+	cache->k1.id = state->k1.id;
-+}
-+
-+/* shared with VC3, Generic*/
-+static void p6_write_control(const struct perfctr_cpu_state *state)
-+{
-+	p6_like_write_control(state, MSR_P6_EVNTSEL0);
-+}
-+
-+static void p6_clear_counters(void)
-+{
-+	clear_msr_range(MSR_P6_EVNTSEL0, 2);
-+	clear_msr_range(MSR_P6_PERFCTR0, 2);
-+}
-+
-+/*
-+ * AMD K7 family (Athlon, Duron).
-+ * - Somewhat similar to the Intel P6 family.
-+ * - Four 48-bit PMCs.
-+ * - Four 32-bit EVNTSEL MSRs with similar layout as in P6.
-+ * - Completely different MSR assignments :-(
-+ * - Fewer countable events defined :-(
-+ * - The events appear to be completely symmetric.
-+ * - The EVNTSEL MSRs are symmetric since each has its own enable bit.
-+ * - Publicly available documentation is incomplete.
-+ * - K7 model 1 does not have a local APIC. AMD Document #22007
-+ *   Revision J hints that it may use debug interrupts instead.
-+ *
-+ * The K8 has the same hardware layout as the K7. It also has
-+ * better documentation and a different set of available events.
-+ */
-+
-+static int k7_check_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	return p6_like_check_control(state, 1);
-+}
-+
-+#ifdef CONFIG_X86_LOCAL_APIC
-+static void k7_isuspend(struct perfctr_cpu_state *state)
-+{
-+	p6_like_isuspend(state, MSR_K7_EVNTSEL0);
-+}
-+
-+static void k7_iresume(const struct perfctr_cpu_state *state)
-+{
-+	p6_like_iresume(state, MSR_K7_EVNTSEL0, MSR_K7_PERFCTR0);
-+}
-+#endif	/* CONFIG_X86_LOCAL_APIC */
-+
-+static void k7_write_control(const struct perfctr_cpu_state *state)
-+{
-+	p6_like_write_control(state, MSR_K7_EVNTSEL0);
-+}
-+
-+static void k7_clear_counters(void)
-+{
-+	clear_msr_range(MSR_K7_EVNTSEL0, 4+4);
-+}
-+
-+/*
-+ * VIA C3 family.
-+ * - A Centaur design somewhat similar to the P6/Celeron.
-+ * - PERFCTR0 is an alias for the TSC, and EVNTSEL0 is read-only.
-+ * - PERFCTR1 is 32 bits wide.
-+ * - EVNTSEL1 has no defined control fields, and there is no
-+ *   defined method for stopping the counter.
-+ * - According to testing, the reserved fields in EVNTSEL1 have
-+ *   no function. We always fill them with zeroes.
-+ * - Only a few event codes are defined.
-+ * - No local APIC or interrupt-mode support.
-+ * - pmc_map[0] must be 1, if nractrs == 1.
-+ */
-+static int vc3_check_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	if (state->control.nrictrs || state->control.nractrs > 1)
-+		return -EINVAL;
-+	if (state->control.nractrs == 1) {
-+		if (state->control.pmc_map[0] != 1)
-+			return -EINVAL;
-+		state->pmc[0].map = 1;
-+		if (state->control.evntsel[0] & VC3_EVNTSEL1_RESERVED)
-+			return -EPERM;
-+		state->k1.id = state->control.evntsel[0];
-+	} else
-+		state->k1.id = 0;
-+	return 0;
-+}
-+
-+static void vc3_clear_counters(void)
-+{
-+	/* Not documented, but seems to be default after boot. */
-+	wrmsr(MSR_P6_EVNTSEL0+1, 0x00070079, 0);
-+}
-+
-+/*
-+ * Intel Pentium 4.
-+ * Current implementation restrictions:
-+ * - No DS/PEBS support.
-+ *
-+ * Known quirks:
-+ * - OVF_PMI+FORCE_OVF counters must have an ireset value of -1.
-+ *   This allows the regular overflow check to also handle FORCE_OVF
-+ *   counters. Not having this restriction would lead to MAJOR
-+ *   complications in the driver's "detect overflow counters" code.
-+ *   There is no loss of functionality since the ireset value doesn't
-+ *   affect the counter's PMI rate for FORCE_OVF counters.
-+ * - In experiments with FORCE_OVF counters, and regular OVF_PMI
-+ *   counters with small ireset values between -8 and -1, it appears
-+ *   that the faulting instruction is subjected to a new PMI before
-+ *   it can complete, ad infinitum. This occurs even though the driver
-+ *   clears the CCCR (and in testing also the ESCR) and invokes a
-+ *   user-space signal handler before restoring the CCCR and resuming
-+ *   the instruction.
-+ */
-+
-+/*
-+ * Table 15-4 in the IA32 Volume 3 manual contains a 18x8 entry mapping
-+ * from counter/CCCR number (0-17) and ESCR SELECT value (0-7) to the
-+ * actual ESCR MSR number. This mapping contains some repeated patterns,
-+ * so we can compact it to a 4x8 table of MSR offsets:
-+ *
-+ * 1. CCCRs 16 and 17 are mapped just like CCCRs 13 and 14, respectively.
-+ *    Thus, we only consider the 16 CCCRs 0-15.
-+ * 2. The CCCRs are organised in pairs, and both CCCRs in a pair use the
-+ *    same mapping. Thus, we only consider the 8 pairs 0-7.
-+ * 3. In each pair of pairs, the second odd-numbered pair has the same domain
-+ *    as the first even-numbered pair, and the range is 1+ the range of the
-+ *    the first even-numbered pair. For example, CCCR(0) and (1) map ESCR
-+ *    SELECT(7) to 0x3A0, and CCCR(2) and (3) map it to 0x3A1.
-+ *    The only exception is that pair (7) [CCCRs 14 and 15] does not have
-+ *    ESCR SELECT(3) in its domain, like pair (6) [CCCRs 12 and 13] has.
-+ *    NOTE: Revisions of IA32 Volume 3 older than #245472-007 had an error
-+ *    in this table: CCCRs 12, 13, and 16 had their mappings for ESCR SELECT
-+ *    values 2 and 3 swapped.
-+ * 4. All MSR numbers are on the form 0x3??. Instead of storing these as
-+ *    16-bit numbers, the table only stores the 8-bit offsets from 0x300.
-+ */
-+
-+static const unsigned char p4_cccr_escr_map[4][8] = {
-+	/* 0x00 and 0x01 as is, 0x02 and 0x03 are +1 */
-+	[0x00/4] {	[7] 0xA0,
-+			[6] 0xA2,
-+			[2] 0xAA,
-+			[4] 0xAC,
-+			[0] 0xB2,
-+			[1] 0xB4,
-+			[3] 0xB6,
-+			[5] 0xC8, },
-+	/* 0x04 and 0x05 as is, 0x06 and 0x07 are +1 */
-+	[0x04/4] {	[0] 0xC0,
-+			[2] 0xC2,
-+			[1] 0xC4, },
-+	/* 0x08 and 0x09 as is, 0x0A and 0x0B are +1 */
-+	[0x08/4] {	[1] 0xA4,
-+			[0] 0xA6,
-+			[5] 0xA8,
-+			[2] 0xAE,
-+			[3] 0xB0, },
-+	/* 0x0C, 0x0D, and 0x10 as is,
-+	   0x0E, 0x0F, and 0x11 are +1 except [3] is not in the domain */
-+	[0x0C/4] {	[4] 0xB8,
-+			[5] 0xCC,
-+			[6] 0xE0,
-+			[0] 0xBA,
-+			[2] 0xBC,
-+			[3] 0xBE,
-+			[1] 0xCA, },
-+};
-+
-+static unsigned int p4_escr_addr(unsigned int pmc, unsigned int cccr_val)
-+{
-+	unsigned int escr_select, pair, escr_offset;
-+
-+	escr_select = P4_CCCR_ESCR_SELECT(cccr_val);
-+	if (pmc > 0x11)
-+		return 0;	/* pmc range error */
-+	if (pmc > 0x0F)
-+		pmc -= 3;	/* 0 <= pmc <= 0x0F */
-+	pair = pmc / 2;		/* 0 <= pair <= 7 */
-+	escr_offset = p4_cccr_escr_map[pair / 2][escr_select];
-+	if (!escr_offset || (pair == 7 && escr_select == 3))
-+		return 0;	/* ESCR SELECT range error */
-+	return escr_offset + (pair & 1) + 0x300;
-+};
-+
-+static int p4_IQ_ESCR_ok;	/* only models <= 2 can use IQ_ESCR{0,1} */
-+static int p4_is_ht;		/* affects several CCCR & ESCR fields */
-+static int p4_extended_cascade_ok;	/* only models >= 2 can use extended cascading */
-+
-+static int p4_check_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	unsigned int i, nractrs, nrctrs, pmc_mask;
-+
-+	nractrs = state->control.nractrs;
-+	nrctrs = nractrs + state->control.nrictrs;
-+	if (nrctrs < nractrs || nrctrs > 18)
-+		return -EINVAL;
-+
-+	pmc_mask = 0;
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int pmc, cccr_val, escr_val, escr_addr;
-+		/* check that pmc_map[] is well-defined;
-+		   pmc_map[i] is what we pass to RDPMC, the PMC itself
-+		   is extracted by masking off the FAST_RDPMC flag */
-+		pmc = state->control.pmc_map[i] & ~P4_FAST_RDPMC;
-+		state->pmc[i].map = state->control.pmc_map[i];
-+		if (pmc >= 18 || (pmc_mask & (1<<pmc)))
-+			return -EINVAL;
-+		pmc_mask |= (1<<pmc);
-+		/* check CCCR contents */
-+		cccr_val = state->control.evntsel[i];
-+		if (cccr_val & P4_CCCR_RESERVED)
-+			return -EPERM;
-+		if (cccr_val & P4_CCCR_EXTENDED_CASCADE) {
-+			if (!p4_extended_cascade_ok)
-+				return -EPERM;
-+			if (!(pmc == 12 || pmc >= 15))
-+				return -EPERM;
-+		}
-+		if ((cccr_val & P4_CCCR_ACTIVE_THREAD) != P4_CCCR_ACTIVE_THREAD && !p4_is_ht)
-+			return -EINVAL;
-+		if (!(cccr_val & (P4_CCCR_ENABLE | P4_CCCR_CASCADE | P4_CCCR_EXTENDED_CASCADE)))
-+			return -EINVAL;
-+		if (cccr_val & P4_CCCR_OVF_PMI_T0) {
-+			if (i < nractrs)
-+				return -EINVAL;
-+			if ((cccr_val & P4_CCCR_FORCE_OVF) &&
-+			    state->control.ireset[i] != -1)
-+				return -EINVAL;
-+		} else {
-+			if (i >= nractrs)
-+				return -EINVAL;
-+		}
-+		/* check ESCR contents */
-+		escr_val = state->control.p4.escr[i];
-+		if (escr_val & P4_ESCR_RESERVED)
-+			return -EPERM;
-+		if ((escr_val & P4_ESCR_CPL_T1) && (!p4_is_ht || !is_global))
-+			return -EINVAL;
-+		/* compute and cache ESCR address */
-+		escr_addr = p4_escr_addr(pmc, cccr_val);
-+		if (!escr_addr)
-+			return -EINVAL;		/* ESCR SELECT range error */
-+		/* IQ_ESCR0 and IQ_ESCR1 only exist in models <= 2 */
-+		if ((escr_addr & ~0x001) == 0x3BA && !p4_IQ_ESCR_ok)
-+			return -EINVAL;
-+		/* XXX: Two counters could map to the same ESCR. Should we
-+		   check that they use the same ESCR value? */
-+		state->p4_escr_map[i] = escr_addr - MSR_P4_ESCR0;
-+	}
-+	/* check ReplayTagging control (PEBS_ENABLE and PEBS_MATRIX_VERT) */
-+	if (state->control.p4.pebs_enable) {
-+		if (!nrctrs)
-+			return -EPERM;
-+		if (state->control.p4.pebs_enable & P4_PE_RESERVED)
-+			return -EPERM;
-+		if (!(state->control.p4.pebs_enable & P4_PE_UOP_TAG))
-+			return -EINVAL;
-+		if (!(state->control.p4.pebs_enable & P4_PE_REPLAY_TAG_BITS))
-+			return -EINVAL;
-+		if (state->control.p4.pebs_matrix_vert & P4_PMV_RESERVED)
-+			return -EPERM;
-+		if (!(state->control.p4.pebs_matrix_vert & P4_PMV_REPLAY_TAG_BITS))
-+			return -EINVAL;
-+	} else if (state->control.p4.pebs_matrix_vert)
-+		return -EPERM;
-+	state->k1.id = new_id();
-+	return 0;
-+}
-+
-+#ifdef CONFIG_X86_LOCAL_APIC
-+static void p4_isuspend(struct perfctr_cpu_state *state)
-+{
-+	return p6_like_isuspend(state, MSR_P4_CCCR0);
-+}
-+
-+static void p4_iresume(const struct perfctr_cpu_state *state)
-+{
-+	return p6_like_iresume(state, MSR_P4_CCCR0, MSR_P4_PERFCTR0);
-+}
-+#endif	/* CONFIG_X86_LOCAL_APIC */
-+
-+static void p4_write_control(const struct perfctr_cpu_state *state)
-+{
-+	struct per_cpu_cache *cache;
-+	unsigned int nrctrs, i;
-+
-+	/* XXX: temporary debug check */
-+	if (cpu_isset(smp_processor_id(), perfctr_cpus_forbidden_mask) &&
-+	    perfctr_cstatus_nrctrs(state->cstatus))
-+		printk(KERN_ERR "%s: BUG! CPU %u is in the forbidden set\n",
-+		       __FUNCTION__, smp_processor_id());
-+	cache = get_cpu_cache();
-+	if (cache->k1.id == state->k1.id)
-+		return;
-+	nrctrs = perfctr_cstatus_nrctrs(state->cstatus);
-+	for(i = 0; i < nrctrs; ++i) {
-+		unsigned int escr_val, escr_off, cccr_val, pmc;
-+		escr_val = state->control.p4.escr[i];
-+		escr_off = state->p4_escr_map[i];
-+		if (escr_val != cache->control.escr[escr_off]) {
-+			cache->control.escr[escr_off] = escr_val;
-+			wrmsr(MSR_P4_ESCR0+escr_off, escr_val, 0);
-+		}
-+		cccr_val = state->control.evntsel[i];
-+		pmc = state->pmc[i].map & P4_MASK_FAST_RDPMC;
-+		if (cccr_val != cache->control.evntsel[pmc]) {
-+			cache->control.evntsel[pmc] = cccr_val;
-+			wrmsr(MSR_P4_CCCR0+pmc, cccr_val, 0);
-+		}
-+	}
-+	if (state->control.p4.pebs_enable != cache->control.pebs_enable) {
-+		cache->control.pebs_enable = state->control.p4.pebs_enable;
-+		wrmsr(MSR_P4_PEBS_ENABLE, state->control.p4.pebs_enable, 0);
-+	}
-+	if (state->control.p4.pebs_matrix_vert != cache->control.pebs_matrix_vert) {
-+		cache->control.pebs_matrix_vert = state->control.p4.pebs_matrix_vert;
-+		wrmsr(MSR_P4_PEBS_MATRIX_VERT, state->control.p4.pebs_matrix_vert, 0);
-+	}
-+	cache->k1.id = state->k1.id;
-+}
-+
-+static void p4_clear_counters(void)
-+{
-+	/* MSR 0x3F0 seems to have a default value of 0xFC00, but current
-+	   docs doesn't fully define it, so leave it alone for now. */
-+	/* clear PEBS_ENABLE and PEBS_MATRIX_VERT; they handle both PEBS
-+	   and ReplayTagging, and should exist even if PEBS is disabled */
-+	clear_msr_range(0x3F1, 2);
-+	clear_msr_range(0x3A0, 26);
-+	if (p4_IQ_ESCR_ok)
-+		clear_msr_range(0x3BA, 2);
-+	clear_msr_range(0x3BC, 3);
-+	clear_msr_range(0x3C0, 6);
-+	clear_msr_range(0x3C8, 6);
-+	clear_msr_range(0x3E0, 2);
-+	clear_msr_range(MSR_P4_CCCR0, 18);
-+	clear_msr_range(MSR_P4_PERFCTR0, 18);
-+}
-+
-+/*
-+ * Generic driver for any x86 with a working TSC.
-+ */
-+
-+static int generic_check_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	if (state->control.nractrs || state->control.nrictrs)
-+		return -EINVAL;
-+	return 0;
-+}
-+
-+static void generic_clear_counters(void)
-+{
-+}
-+
-+/*
-+ * Driver methods, internal and exported.
-+ *
-+ * Frequently called functions (write_control, read_counters,
-+ * isuspend and iresume) are back-patched to invoke the correct
-+ * processor-specific methods directly, thereby saving the
-+ * overheads of indirect function calls.
-+ *
-+ * Backpatchable call sites must have been "finalised" after
-+ * initialisation. The reason for this is that unsynchronised code
-+ * modification doesn't work in multiprocessor systems, due to
-+ * Intel P6 errata. Consequently, all backpatchable call sites
-+ * must be known and local to this file.
-+ *
-+ * Backpatchable calls must initially be to 'noinline' stubs.
-+ * Otherwise the compiler may inline the stubs, which breaks
-+ * redirect_call() and finalise_backpatching().
-+ */
-+
-+static int redirect_call_disable;
-+
-+static noinline void redirect_call(void *ra, void *to)
-+{
-+	/* XXX: make this function __init later */
-+	if (redirect_call_disable)
-+		printk(KERN_ERR __FILE__ ":%s: unresolved call to %p at %p\n",
-+		       __FUNCTION__, to, ra);
-+	/* we can only redirect `call near relative' instructions */
-+	if (*((unsigned char*)ra - 5) != 0xE8) {
-+		printk(KERN_WARNING __FILE__ ":%s: unable to redirect caller %p to %p\n",
-+		       __FUNCTION__, ra, to);
-+		return;
-+	}
-+	*(int*)((char*)ra - 4) = (char*)to - (char*)ra;
-+}
-+
-+static void (*write_control)(const struct perfctr_cpu_state*);
-+static noinline void perfctr_cpu_write_control(const struct perfctr_cpu_state *state)
-+{
-+	redirect_call(__builtin_return_address(0), write_control);
-+	return write_control(state);
-+}
-+
-+static void (*read_counters)(const struct perfctr_cpu_state*,
-+			     struct perfctr_low_ctrs*);
-+static noinline void perfctr_cpu_read_counters(const struct perfctr_cpu_state *state,
-+					       struct perfctr_low_ctrs *ctrs)
-+{
-+	redirect_call(__builtin_return_address(0), read_counters);
-+	return read_counters(state, ctrs);
-+}
-+
-+#ifdef CONFIG_X86_LOCAL_APIC
-+static void (*cpu_isuspend)(struct perfctr_cpu_state*);
-+static noinline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state)
-+{
-+	redirect_call(__builtin_return_address(0), cpu_isuspend);
-+	return cpu_isuspend(state);
-+}
-+
-+static void (*cpu_iresume)(const struct perfctr_cpu_state*);
-+static noinline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state)
-+{
-+	redirect_call(__builtin_return_address(0), cpu_iresume);
-+	return cpu_iresume(state);
-+}
-+
-+/* Call perfctr_cpu_ireload() just before perfctr_cpu_resume() to
-+   bypass internal caching and force a reload if the I-mode PMCs. */
-+void perfctr_cpu_ireload(struct perfctr_cpu_state *state)
-+{
-+#ifdef CONFIG_SMP
-+	clear_isuspend_cpu(state);
-+#else
-+	get_cpu_cache()->k1.id = 0;
-+#endif
-+}
-+
-+/* PRE: the counters have been suspended and sampled by perfctr_cpu_suspend() */
-+static int lvtpc_reinit_needed;
-+unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state *state)
-+{
-+	unsigned int cstatus, nrctrs, pmc, pmc_mask;
-+
-+	cstatus = state->cstatus;
-+	pmc = perfctr_cstatus_nractrs(cstatus);
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+
-+	for(pmc_mask = 0; pmc < nrctrs; ++pmc) {
-+		if ((int)state->pmc[pmc].start >= 0) { /* XXX: ">" ? */
-+			/* XXX: "+=" to correct for overshots */
-+			state->pmc[pmc].start = state->control.ireset[pmc];
-+			pmc_mask |= (1 << pmc);
-+			/* On a P4 we should now clear the OVF flag in the
-+			   counter's CCCR. However, p4_isuspend() already
-+			   did that as a side-effect of clearing the CCCR
-+			   in order to stop the i-mode counters. */
-+		}
-+	}
-+	if (lvtpc_reinit_needed)
-+		apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR);
-+	return pmc_mask;
-+}
-+
-+static inline int check_ireset(const struct perfctr_cpu_state *state)
-+{
-+	unsigned int nrctrs, i;
-+
-+	i = state->control.nractrs;
-+	nrctrs = i + state->control.nrictrs;
-+	for(; i < nrctrs; ++i)
-+		if (state->control.ireset[i] >= 0)
-+			return -EINVAL;
-+	return 0;
-+}
-+
-+static inline void setup_imode_start_values(struct perfctr_cpu_state *state)
-+{
-+	unsigned int cstatus, nrctrs, i;
-+
-+	cstatus = state->cstatus;
-+	nrctrs = perfctr_cstatus_nrctrs(cstatus);
-+	for(i = perfctr_cstatus_nractrs(cstatus); i < nrctrs; ++i)
-+		state->pmc[i].start = state->control.ireset[i];
-+}
-+
-+static inline void debug_no_imode(const struct perfctr_cpu_state *state)
-+{
-+#ifdef CONFIG_PERFCTR_DEBUG
-+	if (perfctr_cstatus_has_ictrs(state->cstatus))
-+		printk(KERN_ERR "perfctr/x86.c: BUG! updating control in"
-+		       " perfctr %p on cpu %u while it has cstatus %x"
-+		       " (pid %d, comm %s)\n",
-+		       state, smp_processor_id(), state->cstatus,
-+		       current->pid, current->comm);
-+#endif
-+}
-+
-+#else	/* CONFIG_X86_LOCAL_APIC */
-+static inline void perfctr_cpu_isuspend(struct perfctr_cpu_state *state) { }
-+static inline void perfctr_cpu_iresume(const struct perfctr_cpu_state *state) { }
-+static inline int check_ireset(const struct perfctr_cpu_state *state) { return 0; }
-+static inline void setup_imode_start_values(struct perfctr_cpu_state *state) { }
-+static inline void debug_no_imode(const struct perfctr_cpu_state *state) { }
-+#endif	/* CONFIG_X86_LOCAL_APIC */
-+
-+static int (*check_control)(struct perfctr_cpu_state*, int);
-+int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global)
-+{
-+	int err;
-+
-+	debug_no_imode(state);
-+	clear_isuspend_cpu(state);
-+	state->cstatus = 0;
-+
-+	/* disallow i-mode counters if we cannot catch the interrupts */
-+	if (!(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
-+	    && state->control.nrictrs)
-+		return -EPERM;
-+
-+	err = check_control(state, is_global);
-+	if (err < 0)
-+		return err;
-+	err = check_ireset(state);
-+	if (err < 0)
-+		return err;
-+	state->cstatus = perfctr_mk_cstatus(state->control.tsc_on,
-+					    state->control.nractrs,
-+					    state->control.nrictrs);
-+	setup_imode_start_values(state);
-+	return 0;
-+}
-+
-+void perfctr_cpu_suspend(struct perfctr_cpu_state *state)
-+{
-+	unsigned int i, cstatus, nractrs;
-+	struct perfctr_low_ctrs now;
-+
-+	if (perfctr_cstatus_has_ictrs(state->cstatus))
-+	    perfctr_cpu_isuspend(state);
-+	perfctr_cpu_read_counters(state, &now);
-+	cstatus = state->cstatus;
-+	if (perfctr_cstatus_has_tsc(cstatus))
-+		state->tsc_sum += now.tsc - state->tsc_start;
-+	nractrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nractrs; ++i)
-+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
-+	/* perfctr_cpu_disable_rdpmc(); */	/* not for x86 */
-+}
-+
-+void perfctr_cpu_resume(struct perfctr_cpu_state *state)
-+{
-+	if (perfctr_cstatus_has_ictrs(state->cstatus))
-+	    perfctr_cpu_iresume(state);
-+	/* perfctr_cpu_enable_rdpmc(); */	/* not for x86 or global-mode */
-+	perfctr_cpu_write_control(state);
-+	//perfctr_cpu_read_counters(state, &state->start);
-+	{
-+		struct perfctr_low_ctrs now;
-+		unsigned int i, cstatus, nrctrs;
-+		perfctr_cpu_read_counters(state, &now);
-+		cstatus = state->cstatus;
-+		if (perfctr_cstatus_has_tsc(cstatus))
-+			state->tsc_start = now.tsc;
-+		nrctrs = perfctr_cstatus_nractrs(cstatus);
-+		for(i = 0; i < nrctrs; ++i)
-+			state->pmc[i].start = now.pmc[i];
-+	}
-+	/* XXX: if (SMP && start.tsc == now.tsc) ++now.tsc; */
-+}
-+
-+void perfctr_cpu_sample(struct perfctr_cpu_state *state)
-+{
-+	unsigned int i, cstatus, nractrs;
-+	struct perfctr_low_ctrs now;
-+
-+	perfctr_cpu_read_counters(state, &now);
-+	cstatus = state->cstatus;
-+	if (perfctr_cstatus_has_tsc(cstatus)) {
-+		state->tsc_sum += now.tsc - state->tsc_start;
-+		state->tsc_start = now.tsc;
-+	}
-+	nractrs = perfctr_cstatus_nractrs(cstatus);
-+	for(i = 0; i < nractrs; ++i) {
-+		state->pmc[i].sum += now.pmc[i] - state->pmc[i].start;
-+		state->pmc[i].start = now.pmc[i];
-+	}
-+}
-+
-+static void (*clear_counters)(void);
-+static void perfctr_cpu_clear_counters(void)
-+{
-+	return clear_counters();
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Processor detection and initialisation procedures.		*
-+ *								*
-+ ****************************************************************/
-+
-+static inline void clear_perfctr_cpus_forbidden_mask(void)
-+{
-+#if !defined(perfctr_cpus_forbidden_mask)
-+	cpus_clear(perfctr_cpus_forbidden_mask);
-+#endif
-+}
-+
-+static inline void set_perfctr_cpus_forbidden_mask(cpumask_t mask)
-+{
-+#if !defined(perfctr_cpus_forbidden_mask)
-+	perfctr_cpus_forbidden_mask = mask;
-+#endif
-+}
-+
-+/* see comment above at redirect_call() */
-+static void __init finalise_backpatching(void)
-+{
-+	struct per_cpu_cache *cache;
-+	struct perfctr_cpu_state state;
-+	cpumask_t old_mask;
-+
-+	old_mask = perfctr_cpus_forbidden_mask;
-+	clear_perfctr_cpus_forbidden_mask();
-+
-+	cache = get_cpu_cache();
-+	memset(cache, 0, sizeof *cache);
-+	memset(&state, 0, sizeof state);
-+	state.cstatus =
-+		(perfctr_info.cpu_features & PERFCTR_FEATURE_PCINT)
-+		? __perfctr_mk_cstatus(0, 1, 0, 0)
-+		: 0;
-+	perfctr_cpu_sample(&state);
-+	perfctr_cpu_resume(&state);
-+	perfctr_cpu_suspend(&state);
-+
-+	set_perfctr_cpus_forbidden_mask(old_mask);
-+
-+	redirect_call_disable = 1;
-+}
-+
-+#ifdef CONFIG_SMP
-+
-+cpumask_t perfctr_cpus_forbidden_mask;
-+
-+static void __init p4_ht_mask_setup_cpu(void *forbidden)
-+{
-+	unsigned int local_apic_physical_id = cpuid_ebx(1) >> 24;
-+	unsigned int logical_processor_id = local_apic_physical_id & 1;
-+	if (logical_processor_id != 0)
-+		/* We rely on cpu_set() being atomic! */
-+		cpu_set(smp_processor_id(), *(cpumask_t*)forbidden);
-+}
-+
-+static int __init p4_ht_smp_init(void)
-+{
-+	cpumask_t forbidden;
-+	unsigned int cpu;
-+
-+	cpus_clear(forbidden);
-+	smp_call_function(p4_ht_mask_setup_cpu, &forbidden, 1, 1);
-+	p4_ht_mask_setup_cpu(&forbidden);
-+	if (cpus_empty(forbidden))
-+		return 0;
-+	perfctr_cpus_forbidden_mask = forbidden;
-+	printk(KERN_INFO "perfctr/x86.c: hyper-threaded P4s detected:"
-+	       " restricting access for CPUs");
-+	for(cpu = 0; cpu < NR_CPUS; ++cpu)
-+		if (cpu_isset(cpu, forbidden))
-+			printk(" %u", cpu);
-+	printk("\n");
-+	return 0;
-+}
-+#else /* SMP */
-+#define p4_ht_smp_init()	(0)
-+#endif /* SMP */
-+
-+static int __init p4_ht_init(void)
-+{
-+	unsigned int nr_siblings;
-+
-+	if (!cpu_has_ht)
-+		return 0;
-+	nr_siblings = (cpuid_ebx(1) >> 16) & 0xFF;
-+	if (nr_siblings > 2) {
-+		printk(KERN_WARNING "perfctr/x86.c: hyper-threaded P4s detected:"
-+		       " unsupported number of siblings: %u -- bailing out\n",
-+		       nr_siblings);
-+		return -ENODEV;
-+	}
-+	if (nr_siblings < 2)
-+		return 0;
-+	p4_is_ht = 1;	/* needed even in a UP kernel */
-+	return p4_ht_smp_init();
-+}
-+
-+static int __init intel_init(void)
-+{
-+	static char p5_name[] __initdata = "Intel P5";
-+	static char p6_name[] __initdata = "Intel P6";
-+	static char p4_name[] __initdata = "Intel P4";
-+	unsigned int misc_enable;
-+
-+	if (!cpu_has_tsc)
-+		return -ENODEV;
-+	switch (current_cpu_data.x86) {
-+	case 5:
-+		if (cpu_has_mmx) {
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_P5MMX;
-+			read_counters = rdpmc_read_counters;
-+
-+			/* Avoid Pentium Erratum 74. */
-+			if (current_cpu_data.x86_model == 4 &&
-+			    (current_cpu_data.x86_mask == 4 ||
-+			     (current_cpu_data.x86_mask == 3 &&
-+			      ((cpuid_eax(1) >> 12) & 0x3) == 1)))
-+				perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
-+		} else {
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_P5;
-+			perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
-+			read_counters = p5_read_counters;
-+		}
-+		perfctr_set_tests_type(PTT_P5);
-+		perfctr_cpu_name = p5_name;
-+		write_control = p5_write_control;
-+		check_control = p5_check_control;
-+		clear_counters = p5_clear_counters;
-+		return 0;
-+	case 6:
-+		if (current_cpu_data.x86_model == 9 ||
-+		    current_cpu_data.x86_model == 13) {	/* Pentium M */
-+			/* Pentium M added the MISC_ENABLE MSR from P4. */
-+			rdmsr_low(MSR_IA32_MISC_ENABLE, misc_enable);
-+			if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL))
-+				break;
-+			/* Erratum Y3 probably does not apply since we
-+			   read only the low 32 bits. */
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_PENTM;
-+		} else if (current_cpu_data.x86_model >= 7) {	/* PIII */
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_PIII;
-+		} else if (current_cpu_data.x86_model >= 3) {	/* PII or Celeron */
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_PII;
-+		} else {
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_P6;
-+
-+			/* Avoid Pentium Pro Erratum 26. */
-+			if (current_cpu_data.x86_mask < 9)
-+				perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
-+		}
-+		perfctr_set_tests_type(PTT_P6);
-+		perfctr_cpu_name = p6_name;
-+		read_counters = rdpmc_read_counters;
-+		write_control = p6_write_control;
-+		check_control = p6_check_control;
-+		clear_counters = p6_clear_counters;
-+#ifdef CONFIG_X86_LOCAL_APIC
-+		if (cpu_has_apic) {
-+			perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
-+			cpu_isuspend = p6_isuspend;
-+			cpu_iresume = p6_iresume;
-+			/* P-M apparently inherited P4's LVTPC auto-masking :-( */
-+			if (current_cpu_data.x86_model == 9 ||
-+			    current_cpu_data.x86_model == 13)
-+				lvtpc_reinit_needed = 1;
-+		}
-+#endif
-+		return 0;
-+	case 15:	/* Pentium 4 */
-+		rdmsr_low(MSR_IA32_MISC_ENABLE, misc_enable);
-+		if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL))
-+			break;
-+		if (p4_ht_init() != 0)
-+			break;
-+		if (current_cpu_data.x86_model <= 2)
-+			p4_IQ_ESCR_ok = 1;
-+		if (current_cpu_data.x86_model >= 2)
-+			p4_extended_cascade_ok = 1;
-+		if (current_cpu_data.x86_model >= 3) {
-+			/* Model 3 removes IQ_ESCR{0,1} and adds one event. */
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_P4M3;
-+		} else if (current_cpu_data.x86_model >= 2) {
-+			/* Model 2 changed the ESCR Event Mask programming
-+			   details for several events. */
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_P4M2;
-+		} else {
-+			perfctr_info.cpu_type = PERFCTR_X86_INTEL_P4;
-+		}
-+		perfctr_set_tests_type(PTT_P4);
-+		perfctr_cpu_name = p4_name;
-+		read_counters = rdpmc_read_counters;
-+		write_control = p4_write_control;
-+		check_control = p4_check_control;
-+		clear_counters = p4_clear_counters;
-+#ifdef CONFIG_X86_LOCAL_APIC
-+		if (cpu_has_apic) {
-+			perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
-+			cpu_isuspend = p4_isuspend;
-+			cpu_iresume = p4_iresume;
-+			lvtpc_reinit_needed = 1;
-+		}
-+#endif
-+		return 0;
-+	}
-+	return -ENODEV;
-+}
-+
-+static int __init amd_init(void)
-+{
-+	static char amd_name[] __initdata = "AMD K7/K8";
-+
-+	if (!cpu_has_tsc)
-+		return -ENODEV;
-+	switch (current_cpu_data.x86) {
-+	case 6: /* K7 */
-+		perfctr_info.cpu_type = PERFCTR_X86_AMD_K7;
-+		break;
-+	case 15: /* K8. Like a K7 with a different event set. */
-+		if ((current_cpu_data.x86_model > 5) ||
-+		    (current_cpu_data.x86_model >= 4 && current_cpu_data.x86_mask >= 8)) {
-+			perfctr_info.cpu_type = PERFCTR_X86_AMD_K8C;
-+		} else {
-+			perfctr_info.cpu_type = PERFCTR_X86_AMD_K8;
-+		}
-+		break;
-+	default:
-+		return -ENODEV;
-+	}
-+	perfctr_set_tests_type(PTT_AMD);
-+	perfctr_cpu_name = amd_name;
-+	read_counters = rdpmc_read_counters;
-+	write_control = k7_write_control;
-+	check_control = k7_check_control;
-+	clear_counters = k7_clear_counters;
-+#ifdef CONFIG_X86_LOCAL_APIC
-+	if (cpu_has_apic) {
-+		perfctr_info.cpu_features |= PERFCTR_FEATURE_PCINT;
-+		cpu_isuspend = k7_isuspend;
-+		cpu_iresume = k7_iresume;
-+	}
-+#endif
-+	return 0;
-+}
-+
-+static int __init cyrix_init(void)
-+{
-+	static char mii_name[] __initdata = "Cyrix 6x86MX/MII/III";
-+	if (!cpu_has_tsc)
-+		return -ENODEV;
-+	switch (current_cpu_data.x86) {
-+	case 6:	/* 6x86MX, MII, or III */
-+		perfctr_info.cpu_type = PERFCTR_X86_CYRIX_MII;
-+		perfctr_set_tests_type(PTT_P5);
-+		perfctr_cpu_name = mii_name;
-+		read_counters = rdpmc_read_counters;
-+		write_control = p5_write_control;
-+		check_control = mii_check_control;
-+		clear_counters = p5_clear_counters;
-+		return 0;
-+	}
-+	return -ENODEV;
-+}
-+
-+static int __init centaur_init(void)
-+{
-+#if !defined(CONFIG_X86_TSC)
-+	static char winchip_name[] __initdata = "WinChip C6/2/3";
-+#endif
-+	static char vc3_name[] __initdata = "VIA C3";
-+	switch (current_cpu_data.x86) {
-+#if !defined(CONFIG_X86_TSC)
-+	case 5:
-+		switch (current_cpu_data.x86_model) {
-+		case 4: /* WinChip C6 */
-+			perfctr_info.cpu_type = PERFCTR_X86_WINCHIP_C6;
-+			break;
-+		case 8: /* WinChip 2, 2A, or 2B */
-+		case 9: /* WinChip 3, a 2A with larger cache and lower voltage */
-+			perfctr_info.cpu_type = PERFCTR_X86_WINCHIP_2;
-+			break;
-+		default:
-+			return -ENODEV;
-+		}
-+		perfctr_set_tests_type(PTT_WINCHIP);
-+		perfctr_cpu_name = winchip_name;
-+		/*
-+		 * TSC must be inaccessible for perfctrs to work.
-+		 */
-+		if (!(read_cr4() & X86_CR4_TSD) || cpu_has_tsc)
-+			return -ENODEV;
-+		perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDTSC;
-+		read_counters = rdpmc_read_counters;
-+		write_control = c6_write_control;
-+		check_control = c6_check_control;
-+		clear_counters = p5_clear_counters;
-+		return 0;
-+#endif
-+	case 6: /* VIA C3 */
-+		if (!cpu_has_tsc)
-+			return -ENODEV;
-+		switch (current_cpu_data.x86_model) {
-+		case 6:	/* Cyrix III */
-+		case 7:	/* Samuel 2, Ezra (steppings >= 8) */
-+		case 8:	/* Ezra-T */
-+		case 9: /* Antaur/Nehemiah */
-+			break;
-+		default:
-+			return -ENODEV;
-+		}
-+		perfctr_info.cpu_type = PERFCTR_X86_VIA_C3;
-+		perfctr_set_tests_type(PTT_VC3);
-+		perfctr_cpu_name = vc3_name;
-+		read_counters = rdpmc_read_counters;
-+		write_control = p6_write_control;
-+		check_control = vc3_check_control;
-+		clear_counters = vc3_clear_counters;
-+		return 0;
-+	}
-+	return -ENODEV;
-+}
-+
-+static int __init generic_init(void)
-+{
-+	static char generic_name[] __initdata = "Generic x86 with TSC";
-+	if (!cpu_has_tsc)
-+		return -ENODEV;
-+	perfctr_info.cpu_features &= ~PERFCTR_FEATURE_RDPMC;
-+	perfctr_info.cpu_type = PERFCTR_X86_GENERIC;
-+	perfctr_set_tests_type(PTT_GENERIC);
-+	perfctr_cpu_name = generic_name;
-+	check_control = generic_check_control;
-+	write_control = p6_write_control;
-+	read_counters = rdpmc_read_counters;
-+	clear_counters = generic_clear_counters;
-+	return 0;
-+}
-+
-+static void perfctr_cpu_invalidate_cache(void)
-+{
-+	/*
-+	 * per_cpu_cache[] is initialised to contain "impossible"
-+	 * evntsel values guaranteed to differ from anything accepted
-+	 * by perfctr_cpu_update_control().
-+	 * All-bits-one works for all currently supported processors.
-+	 * The memset also sets the ids to -1, which is intentional.
-+	 */
-+	memset(get_cpu_cache(), ~0, sizeof(struct per_cpu_cache));
-+}
-+
-+static void perfctr_cpu_init_one(void *ignore)
-+{
-+	/* PREEMPT note: when called via smp_call_function(),
-+	   this is in IRQ context with preemption disabled. */
-+	perfctr_cpu_clear_counters();
-+	perfctr_cpu_invalidate_cache();
-+	if (cpu_has_apic)
-+		apic_write(APIC_LVTPC, LOCAL_PERFCTR_VECTOR);
-+	if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
-+		set_in_cr4_local(X86_CR4_PCE);
-+}
-+
-+static void perfctr_cpu_exit_one(void *ignore)
-+{
-+	/* PREEMPT note: when called via smp_call_function(),
-+	   this is in IRQ context with preemption disabled. */
-+	perfctr_cpu_clear_counters();
-+	perfctr_cpu_invalidate_cache();
-+	if (cpu_has_apic)
-+		apic_write(APIC_LVTPC, APIC_DM_NMI | APIC_LVT_MASKED);
-+	if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
-+		clear_in_cr4_local(X86_CR4_PCE);
-+}
-+
-+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM)
-+
-+static void perfctr_pm_suspend(void)
-+{
-+	/* XXX: clear control registers */
-+	printk("perfctr/x86: PM suspend\n");
-+}
-+
-+static void perfctr_pm_resume(void)
-+{
-+	/* XXX: reload control registers */
-+	printk("perfctr/x86: PM resume\n");
-+}
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,71)
-+
-+#include <linux/sysdev.h>
-+
-+static int perfctr_device_suspend(struct sys_device *dev, u32 state)
-+{
-+	perfctr_pm_suspend();
-+	return 0;
-+}
-+
-+static int perfctr_device_resume(struct sys_device *dev)
-+{
-+	perfctr_pm_resume();
-+	return 0;
-+}
-+
-+static struct sysdev_class perfctr_sysclass = {
-+	set_kset_name("perfctr"),
-+	.resume		= perfctr_device_resume,
-+	.suspend	= perfctr_device_suspend,
-+};
-+
-+static struct sys_device device_perfctr = {
-+	.id	= 0,
-+	.cls	= &perfctr_sysclass,
-+};
-+
-+static void x86_pm_init(void)
-+{
-+	if (sysdev_class_register(&perfctr_sysclass) == 0)
-+		sysdev_register(&device_perfctr);
-+}
-+
-+static void x86_pm_exit(void)
-+{
-+	sysdev_unregister(&device_perfctr);
-+	sysdev_class_unregister(&perfctr_sysclass);
-+}
-+
-+#else	/* 2.4 kernel */
-+
-+static int x86_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
-+{
-+	switch (rqst) {
-+	case PM_SUSPEND:
-+		perfctr_pm_suspend();
-+		break;
-+	case PM_RESUME:
-+		perfctr_pm_resume();
-+		break;
-+	}
-+	return 0;
-+}
-+
-+static struct pm_dev *x86_pmdev;
-+
-+static void x86_pm_init(void)
-+{
-+	x86_pmdev = apic_pm_register(PM_SYS_DEV, 0, x86_pm_callback);
-+}
-+
-+static void x86_pm_exit(void)
-+{
-+	if (x86_pmdev) {
-+		apic_pm_unregister(x86_pmdev);
-+		x86_pmdev = NULL;
-+	}
-+}
-+
-+#endif	/* 2.4 kernel */
-+
-+#else
-+
-+static inline void x86_pm_init(void) { }
-+static inline void x86_pm_exit(void) { }
-+
-+#endif	/* CONFIG_X86_LOCAL_APIC && CONFIG_PM */
-+
-+#ifdef CONFIG_X86_LOCAL_APIC
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,67)
-+static void disable_lapic_nmi_watchdog(void)
-+{
-+#ifdef CONFIG_PM
-+	if (nmi_pmdev) {
-+		apic_pm_unregister(nmi_pmdev);
-+		nmi_pmdev = 0;
-+	}
-+#endif
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)
-+static int reserve_lapic_nmi(void)
-+{
-+	int ret = 0;
-+	if (nmi_perfctr_msr) {
-+		nmi_perfctr_msr = 0;
-+		disable_lapic_nmi_watchdog();
-+		ret = 1;
-+	}
-+	return ret;
-+}
-+
-+static inline void release_lapic_nmi(void) { }
-+#endif
-+
-+#else
-+static inline int reserve_lapic_nmi(void) { return 0; }
-+static inline void release_lapic_nmi(void) { }
-+#endif
-+
-+static void do_init_tests(void)
-+{
-+#ifdef CONFIG_PERFCTR_INIT_TESTS
-+	if (reserve_lapic_nmi() >= 0) {
-+		perfctr_x86_init_tests();
-+		release_lapic_nmi();
-+	}
-+#endif
-+}
-+
-+int __init perfctr_cpu_init(void)
-+{
-+	int err = -ENODEV;
-+
-+	preempt_disable();
-+
-+	/* RDPMC and RDTSC are on by default. They will be disabled
-+	   by the init procedures if necessary. */
-+	perfctr_info.cpu_features = PERFCTR_FEATURE_RDPMC | PERFCTR_FEATURE_RDTSC;
-+
-+	if (cpu_has_msr) {
-+		switch (current_cpu_data.x86_vendor) {
-+		case X86_VENDOR_INTEL:
-+			err = intel_init();
-+			break;
-+		case X86_VENDOR_AMD:
-+			err = amd_init();
-+			break;
-+		case X86_VENDOR_CYRIX:
-+			err = cyrix_init();
-+			break;
-+		case X86_VENDOR_CENTAUR:
-+			err = centaur_init();
-+		}
-+	}
-+	if (err) {
-+		err = generic_init();	/* last resort */
-+		if (err)
-+			goto out;
-+	}
-+	do_init_tests();
-+	finalise_backpatching();
-+
-+	perfctr_info.cpu_khz = perfctr_cpu_khz();
-+	perfctr_info.tsc_to_cpu_mult = 1;
-+
-+ out:
-+	preempt_enable();
-+	return err;
-+}
-+
-+void __exit perfctr_cpu_exit(void)
-+{
-+}
-+
-+/****************************************************************
-+ *								*
-+ * Hardware reservation.					*
-+ *								*
-+ ****************************************************************/
-+
-+static DECLARE_MUTEX(mutex);
-+static const char *current_service = 0;
-+
-+const char *perfctr_cpu_reserve(const char *service)
-+{
-+	const char *ret;
-+
-+	down(&mutex);
-+	ret = current_service;
-+	if (ret)
-+		goto out_up;
-+	ret = "unknown driver (oprofile?)";
-+	if (reserve_lapic_nmi() < 0)
-+		goto out_up;
-+	current_service = service;
-+	__module_get(THIS_MODULE);
-+	if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
-+		mmu_cr4_features |= X86_CR4_PCE;
-+	on_each_cpu(perfctr_cpu_init_one, NULL, 1, 1);
-+	perfctr_cpu_set_ihandler(NULL);
-+	x86_pm_init();
-+	ret = NULL;
-+ out_up:
-+	up(&mutex);
-+	return ret;
-+}
-+
-+void perfctr_cpu_release(const char *service)
-+{
-+	down(&mutex);
-+	if (service != current_service) {
-+		printk(KERN_ERR "%s: attempt by %s to release while reserved by %s\n",
-+		       __FUNCTION__, service, current_service);
-+		goto out_up;
-+	}
-+	/* power down the counters */
-+	if (perfctr_info.cpu_features & PERFCTR_FEATURE_RDPMC)
-+		mmu_cr4_features &= ~X86_CR4_PCE;
-+	on_each_cpu(perfctr_cpu_exit_one, NULL, 1, 1);
-+	perfctr_cpu_set_ihandler(NULL);
-+	x86_pm_exit();
-+	current_service = 0;
-+	release_lapic_nmi();
-+	module_put(THIS_MODULE);
-+ out_up:
-+	up(&mutex);
-+}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/apic.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-i386/apic.h	2004-04-03 22:38:23.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/apic.h	2004-11-18 20:59:11.000000000 -0500
-@@ -99,6 +99,8 @@
- #define NMI_LOCAL_APIC	2
- #define NMI_INVALID	3
- 
-+extern unsigned int nmi_perfctr_msr;
-+
- #endif /* CONFIG_X86_LOCAL_APIC */
- 
- #endif /* __ASM_APIC_H */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/mach-default/irq_vectors.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-i386/mach-default/irq_vectors.h	2004-11-11 10:27:51.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/mach-default/irq_vectors.h	2004-11-18 20:59:11.000000000 -0500
-@@ -59,14 +59,15 @@
-  * sources per level' errata.
-  */
- #define LOCAL_TIMER_VECTOR	0xef
-+#define LOCAL_PERFCTR_VECTOR	0xee
- 
- /*
-- * First APIC vector available to drivers: (vectors 0x30-0xee)
-+ * First APIC vector available to drivers: (vectors 0x30-0xed)
-  * we start at 0x31 to spread out vectors evenly between priority
-  * levels. (0x80 is the syscall vector)
-  */
- #define FIRST_DEVICE_VECTOR	0x31
--#define FIRST_SYSTEM_VECTOR	0xef
-+#define FIRST_SYSTEM_VECTOR	0xee
- 
- #define TIMER_IRQ 0
- 
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/mach-pc9800/irq_vectors.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-i386/mach-pc9800/irq_vectors.h	2004-04-03 22:36:16.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/mach-pc9800/irq_vectors.h	2004-11-18 20:59:11.000000000 -0500
-@@ -59,14 +59,15 @@
-  * sources per level' errata.
-  */
- #define LOCAL_TIMER_VECTOR	0xef
-+#define LOCAL_PERFCTR_VECTOR	0xee
- 
- /*
-- * First APIC vector available to drivers: (vectors 0x30-0xee)
-+ * First APIC vector available to drivers: (vectors 0x30-0xed)
-  * we start at 0x31 to spread out vectors evenly between priority
-  * levels. (0x80 is the syscall vector)
-  */
- #define FIRST_DEVICE_VECTOR	0x31
--#define FIRST_SYSTEM_VECTOR	0xef
-+#define FIRST_SYSTEM_VECTOR	0xee
- 
- #define TIMER_IRQ 0
- 
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/mach-visws/irq_vectors.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-i386/mach-visws/irq_vectors.h	2004-04-03 22:36:18.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/mach-visws/irq_vectors.h	2004-11-18 20:59:11.000000000 -0500
-@@ -35,14 +35,15 @@
-  * sources per level' errata.
-  */
- #define LOCAL_TIMER_VECTOR	0xef
-+#define LOCAL_PERFCTR_VECTOR	0xee
- 
- /*
-- * First APIC vector available to drivers: (vectors 0x30-0xee)
-+ * First APIC vector available to drivers: (vectors 0x30-0xed)
-  * we start at 0x31 to spread out vectors evenly between priority
-  * levels. (0x80 is the syscall vector)
-  */
- #define FIRST_DEVICE_VECTOR	0x31
--#define FIRST_SYSTEM_VECTOR	0xef
-+#define FIRST_SYSTEM_VECTOR	0xee
- 
- #define TIMER_IRQ 0
- 
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/processor.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-i386/processor.h	2004-11-11 10:27:40.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/processor.h	2004-11-18 20:59:11.000000000 -0500
-@@ -427,6 +427,8 @@
- 	unsigned int		saved_fs, saved_gs;
- /* IO permissions */
- 	unsigned long	*io_bitmap_ptr;
-+/* performance counters */
-+	struct vperfctr *perfctr;
- };
- 
- #define INIT_THREAD  {							\
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/perfctr.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-i386/perfctr.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-i386/perfctr.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,189 @@
-+/* $Id: perfctr.h,v 1.48.2.4 2004/08/02 22:24:58 mikpe Exp $
-+ * x86/x86_64 Performance-Monitoring Counters driver
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+#ifndef _ASM_I386_PERFCTR_H
-+#define _ASM_I386_PERFCTR_H
-+
-+struct perfctr_sum_ctrs {
-+	unsigned long long tsc;
-+	unsigned long long pmc[18];
-+};
-+
-+struct perfctr_cpu_control {
-+	unsigned int tsc_on;
-+	unsigned int nractrs;		/* # of a-mode counters */
-+	unsigned int nrictrs;		/* # of i-mode counters */
-+	unsigned int pmc_map[18];
-+	unsigned int evntsel[18];	/* one per counter, even on P5 */
-+	struct {
-+		unsigned int escr[18];
-+		unsigned int pebs_enable;	/* for replay tagging */
-+		unsigned int pebs_matrix_vert;	/* for replay tagging */
-+	} p4;
-+	int ireset[18];			/* < 0, for i-mode counters */
-+	unsigned int _reserved1;
-+	unsigned int _reserved2;
-+	unsigned int _reserved3;
-+	unsigned int _reserved4;
-+};
-+
-+struct perfctr_cpu_state {
-+	unsigned int cstatus;
-+	struct {	/* k1 is opaque in the user ABI */
-+		unsigned int id;
-+		int isuspend_cpu;
-+	} k1;
-+	/* The two tsc fields must be inlined. Placing them in a
-+	   sub-struct causes unwanted internal padding on x86-64. */
-+	unsigned int tsc_start;
-+	unsigned long long tsc_sum;
-+	struct {
-+		unsigned int map;
-+		unsigned int start;
-+		unsigned long long sum;
-+	} pmc[18];	/* the size is not part of the user ABI */
-+#ifdef __KERNEL__
-+	struct perfctr_cpu_control control;
-+	unsigned int p4_escr_map[18];
-+#endif
-+};
-+
-+/* cstatus is a re-encoding of control.tsc_on/nractrs/nrictrs
-+   which should have less overhead in most cases */
-+
-+static inline
-+unsigned int __perfctr_mk_cstatus(unsigned int tsc_on, unsigned int have_ictrs,
-+				  unsigned int nrictrs, unsigned int nractrs)
-+{
-+	return (tsc_on<<31) | (have_ictrs<<16) | ((nractrs+nrictrs)<<8) | nractrs;
-+}
-+
-+static inline
-+unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs,
-+				unsigned int nrictrs)
-+{
-+	return __perfctr_mk_cstatus(tsc_on, nrictrs, nrictrs, nractrs);
-+}
-+
-+static inline unsigned int perfctr_cstatus_enabled(unsigned int cstatus)
-+{
-+	return cstatus;
-+}
-+
-+static inline int perfctr_cstatus_has_tsc(unsigned int cstatus)
-+{
-+	return (int)cstatus < 0;	/* test and jump on sign */
-+}
-+
-+static inline unsigned int perfctr_cstatus_nractrs(unsigned int cstatus)
-+{
-+	return cstatus & 0x7F;		/* and with imm8 */
-+}
-+
-+static inline unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus)
-+{
-+	return (cstatus >> 8) & 0x7F;
-+}
-+
-+static inline unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus)
-+{
-+	return cstatus & (0x7F << 16);
-+}
-+
-+/*
-+ * 'struct siginfo' support for perfctr overflow signals.
-+ * In unbuffered mode, si_code is set to SI_PMC_OVF and a bitmask
-+ * describing which perfctrs overflowed is put in si_pmc_ovf_mask.
-+ * A bitmask is used since more than one perfctr can have overflowed
-+ * by the time the interrupt handler runs.
-+ *
-+ * glibc's <signal.h> doesn't seem to define __SI_FAULT or __SI_CODE(),
-+ * and including <asm/siginfo.h> as well may cause redefinition errors,
-+ * so the user and kernel values are different #defines here.
-+ */
-+#ifdef __KERNEL__
-+#define SI_PMC_OVF	(__SI_FAULT|'P')
-+#else
-+#define SI_PMC_OVF	('P')
-+#endif
-+#define si_pmc_ovf_mask	_sifields._pad[0] /* XXX: use an unsigned field later */
-+
-+/* version number for user-visible CPU-specific data */
-+#define PERFCTR_CPU_VERSION	0x0501	/* 5.1 */
-+
-+#ifdef __KERNEL__
-+
-+#if defined(CONFIG_PERFCTR) || defined(CONFIG_PERFCTR_MODULE)
-+
-+/* Driver init/exit. */
-+extern int perfctr_cpu_init(void);
-+extern void perfctr_cpu_exit(void);
-+
-+/* CPU type name. */
-+extern char *perfctr_cpu_name;
-+
-+/* Hardware reservation. */
-+extern const char *perfctr_cpu_reserve(const char *service);
-+extern void perfctr_cpu_release(const char *service);
-+
-+/* PRE: state has no running interrupt-mode counters.
-+   Check that the new control data is valid.
-+   Update the driver's private control data.
-+   is_global should be zero for per-process counters and non-zero
-+   for global-mode counters. This matters for HT P4s, alas.
-+   Returns a negative error code if the control data is invalid. */
-+extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global);
-+
-+/* Read a-mode counters. Subtract from start and accumulate into sums.
-+   Must be called with preemption disabled. */
-+extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state);
-+
-+/* Write control registers. Read a-mode counters into start.
-+   Must be called with preemption disabled. */
-+extern void perfctr_cpu_resume(struct perfctr_cpu_state *state);
-+
-+/* Perform an efficient combined suspend/resume operation.
-+   Must be called with preemption disabled. */
-+extern void perfctr_cpu_sample(struct perfctr_cpu_state *state);
-+
-+/* The type of a perfctr overflow interrupt handler.
-+   It will be called in IRQ context, with preemption disabled. */
-+typedef void (*perfctr_ihandler_t)(unsigned long pc);
-+
-+#if defined(CONFIG_X86_LOCAL_APIC)
-+#define PERFCTR_INTERRUPT_SUPPORT 1
-+#endif
-+
-+/* Operations related to overflow interrupt handling. */
-+#ifdef CONFIG_X86_LOCAL_APIC
-+extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t);
-+extern void perfctr_cpu_ireload(struct perfctr_cpu_state*);
-+extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*);
-+#else
-+static inline void perfctr_cpu_set_ihandler(perfctr_ihandler_t x) { }
-+#endif
-+
-+#if defined(CONFIG_SMP)
-+/* CPUs in `perfctr_cpus_forbidden_mask' must not use the
-+   performance-monitoring counters. TSC use is unrestricted.
-+   This is needed to prevent resource conflicts on hyper-threaded P4s.
-+   The declaration of `perfctr_cpus_forbidden_mask' is in the driver's
-+   private compat.h, since it needs to handle cpumask_t incompatibilities. */
-+#define PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED 1
-+#endif
-+
-+#endif	/* CONFIG_PERFCTR */
-+
-+#if defined(CONFIG_KPERFCTR) && defined(CONFIG_X86_LOCAL_APIC)
-+asmlinkage void perfctr_interrupt(struct pt_regs*);
-+#define perfctr_vector_init()	\
-+	set_intr_gate(LOCAL_PERFCTR_VECTOR, perfctr_interrupt)
-+#else
-+#define perfctr_vector_init()	do{}while(0)
-+#endif
-+
-+#endif	/* __KERNEL__ */
-+
-+#endif	/* _ASM_I386_PERFCTR_H */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-ppc/processor.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-ppc/processor.h	2004-11-11 10:27:19.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-ppc/processor.h	2004-11-18 20:59:11.000000000 -0500
-@@ -119,6 +119,7 @@
- 	unsigned long	vrsave;
- 	int		used_vr;	/* set if process has used altivec */
- #endif /* CONFIG_ALTIVEC */
-+	struct vperfctr *perfctr;	/* performance counters */
- };
- 
- #define ARCH_MIN_TASKALIGN 16
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-ppc/perfctr.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-ppc/perfctr.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-ppc/perfctr.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,171 @@
-+/* $Id: perfctr.h,v 1.3.2.2 2004/06/21 22:38:30 mikpe Exp $
-+ * PPC32 Performance-Monitoring Counters driver
-+ *
-+ * Copyright (C) 2004  Mikael Pettersson
-+ */
-+#ifndef _ASM_PPC_PERFCTR_H
-+#define _ASM_PPC_PERFCTR_H
-+
-+/* perfctr_info.cpu_type values */
-+#define PERFCTR_PPC_GENERIC	0
-+#define PERFCTR_PPC_604		1
-+#define PERFCTR_PPC_604e	2
-+#define PERFCTR_PPC_750		3
-+#define PERFCTR_PPC_7400	4
-+#define PERFCTR_PPC_7450	5
-+
-+struct perfctr_sum_ctrs {
-+	unsigned long long tsc;
-+	unsigned long long pmc[6];
-+};
-+
-+struct perfctr_cpu_control {
-+	unsigned int tsc_on;
-+	unsigned int nractrs;		/* # of a-mode counters */
-+	unsigned int nrictrs;		/* # of i-mode counters */
-+	unsigned int pmc_map[6];
-+	unsigned int evntsel[6];	/* one per counter, even on P5 */
-+	int ireset[6];			/* [0,0x7fffffff], for i-mode counters */
-+	struct {
-+		unsigned int mmcr0;	/* sans PMC{1,2}SEL */
-+		unsigned int mmcr2;	/* only THRESHMULT */
-+		/* IABR/DABR/BAMR not supported */
-+	} ppc;
-+	unsigned int _reserved1;
-+	unsigned int _reserved2;
-+	unsigned int _reserved3;
-+	unsigned int _reserved4;
-+};
-+
-+struct perfctr_cpu_state {
-+	unsigned int cstatus;
-+	struct {	/* k1 is opaque in the user ABI */
-+		unsigned int id;
-+		int isuspend_cpu;
-+	} k1;
-+	/* The two tsc fields must be inlined. Placing them in a
-+	   sub-struct causes unwanted internal padding on x86-64. */
-+	unsigned int tsc_start;
-+	unsigned long long tsc_sum;
-+	struct {
-+		unsigned int map;
-+		unsigned int start;
-+		unsigned long long sum;
-+	} pmc[6];	/* the size is not part of the user ABI */
-+#ifdef __KERNEL__
-+	unsigned int ppc_mmcr[3];
-+	struct perfctr_cpu_control control;
-+#endif
-+};
-+
-+/* cstatus is a re-encoding of control.tsc_on/nractrs/nrictrs
-+   which should have less overhead in most cases */
-+/* XXX: ppc driver internally also uses cstatus&(1<<30) */
-+
-+static inline
-+unsigned int perfctr_mk_cstatus(unsigned int tsc_on, unsigned int nractrs,
-+				unsigned int nrictrs)
-+{
-+	return (tsc_on<<31) | (nrictrs<<16) | ((nractrs+nrictrs)<<8) | nractrs;
-+}
-+
-+static inline unsigned int perfctr_cstatus_enabled(unsigned int cstatus)
-+{
-+	return cstatus;
-+}
-+
-+static inline int perfctr_cstatus_has_tsc(unsigned int cstatus)
-+{
-+	return (int)cstatus < 0;	/* test and jump on sign */
-+}
-+
-+static inline unsigned int perfctr_cstatus_nractrs(unsigned int cstatus)
-+{
-+	return cstatus & 0x7F;		/* and with imm8 */
-+}
-+
-+static inline unsigned int perfctr_cstatus_nrctrs(unsigned int cstatus)
-+{
-+	return (cstatus >> 8) & 0x7F;
-+}
-+
-+static inline unsigned int perfctr_cstatus_has_ictrs(unsigned int cstatus)
-+{
-+	return cstatus & (0x7F << 16);
-+}
-+
-+/*
-+ * 'struct siginfo' support for perfctr overflow signals.
-+ * In unbuffered mode, si_code is set to SI_PMC_OVF and a bitmask
-+ * describing which perfctrs overflowed is put in si_pmc_ovf_mask.
-+ * A bitmask is used since more than one perfctr can have overflowed
-+ * by the time the interrupt handler runs.
-+ *
-+ * glibc's <signal.h> doesn't seem to define __SI_FAULT or __SI_CODE(),
-+ * and including <asm/siginfo.h> as well may cause redefinition errors,
-+ * so the user and kernel values are different #defines here.
-+ */
-+#ifdef __KERNEL__
-+#define SI_PMC_OVF	(__SI_FAULT|'P')
-+#else
-+#define SI_PMC_OVF	('P')
-+#endif
-+#define si_pmc_ovf_mask	_sifields._pad[0] /* XXX: use an unsigned field later */
-+
-+/* version number for user-visible CPU-specific data */
-+#define PERFCTR_CPU_VERSION	0	/* XXX: not yet cast in stone */
-+
-+#ifdef __KERNEL__
-+
-+#if defined(CONFIG_PERFCTR) || defined(CONFIG_PERFCTR_MODULE)
-+
-+/* Driver init/exit. */
-+extern int perfctr_cpu_init(void);
-+extern void perfctr_cpu_exit(void);
-+
-+/* CPU type name. */
-+extern char *perfctr_cpu_name;
-+
-+/* Hardware reservation. */
-+extern const char *perfctr_cpu_reserve(const char *service);
-+extern void perfctr_cpu_release(const char *service);
-+
-+/* PRE: state has no running interrupt-mode counters.
-+   Check that the new control data is valid.
-+   Update the driver's private control data.
-+   Returns a negative error code if the control data is invalid. */
-+extern int perfctr_cpu_update_control(struct perfctr_cpu_state *state, int is_global);
-+
-+/* Read a-mode counters. Subtract from start and accumulate into sums.
-+   Must be called with preemption disabled. */
-+extern void perfctr_cpu_suspend(struct perfctr_cpu_state *state);
-+
-+/* Write control registers. Read a-mode counters into start.
-+   Must be called with preemption disabled. */
-+extern void perfctr_cpu_resume(struct perfctr_cpu_state *state);
-+
-+/* Perform an efficient combined suspend/resume operation.
-+   Must be called with preemption disabled. */
-+extern void perfctr_cpu_sample(struct perfctr_cpu_state *state);
-+
-+/* The type of a perfctr overflow interrupt handler.
-+   It will be called in IRQ context, with preemption disabled. */
-+typedef void (*perfctr_ihandler_t)(unsigned long pc);
-+
-+/* XXX: The hardware supports overflow interrupts, but the driver
-+   does not yet enable this due to an erratum in 750/7400/7410. */
-+//#define PERFCTR_INTERRUPT_SUPPORT 1
-+
-+#ifdef PERFCTR_INTERRUPT_SUPPORT
-+extern void perfctr_cpu_set_ihandler(perfctr_ihandler_t);
-+extern void perfctr_cpu_ireload(struct perfctr_cpu_state*);
-+extern unsigned int perfctr_cpu_identify_overflow(struct perfctr_cpu_state*);
-+#else
-+static inline void perfctr_cpu_set_ihandler(perfctr_ihandler_t x) { }
-+#endif
-+
-+#endif	/* CONFIG_PERFCTR */
-+
-+#endif	/* __KERNEL__ */
-+
-+#endif	/* _ASM_PPC_PERFCTR_H */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/apic.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-x86_64/apic.h	2004-11-11 10:28:46.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/apic.h	2004-11-18 20:59:11.000000000 -0500
-@@ -96,6 +96,8 @@
- #define NMI_LOCAL_APIC	2
- #define NMI_INVALID	3
- 
-+extern unsigned int nmi_perfctr_msr;
-+
- #endif /* CONFIG_X86_LOCAL_APIC */
- 
- #define esr_disable 0
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/hw_irq.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-x86_64/hw_irq.h	2004-11-11 10:28:31.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/hw_irq.h	2004-11-18 20:59:11.000000000 -0500
-@@ -65,14 +65,15 @@
-  * sources per level' errata.
-  */
- #define LOCAL_TIMER_VECTOR	0xef
-+#define LOCAL_PERFCTR_VECTOR	0xee
- 
- /*
-- * First APIC vector available to drivers: (vectors 0x30-0xee)
-+ * First APIC vector available to drivers: (vectors 0x30-0xed)
-  * we start at 0x31 to spread out vectors evenly between priority
-  * levels. (0x80 is the syscall vector)
-  */
- #define FIRST_DEVICE_VECTOR	0x31
--#define FIRST_SYSTEM_VECTOR	0xef   /* duplicated in irq.h */
-+#define FIRST_SYSTEM_VECTOR	0xee   /* duplicated in irq.h */
- 
- 
- #ifndef __ASSEMBLY__
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/irq.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-x86_64/irq.h	2004-11-11 10:28:46.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/irq.h	2004-11-18 20:59:11.000000000 -0500
-@@ -29,7 +29,7 @@
-  */
- #define NR_VECTORS 256
- 
--#define FIRST_SYSTEM_VECTOR	0xef   /* duplicated in hw_irq.h */
-+#define FIRST_SYSTEM_VECTOR	0xee   /* duplicated in hw_irq.h */
- 
- #ifdef CONFIG_PCI_USE_VECTOR
- #define NR_IRQS FIRST_SYSTEM_VECTOR
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/processor.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-x86_64/processor.h	2004-11-11 10:27:40.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/processor.h	2004-11-18 20:59:11.000000000 -0500
-@@ -258,6 +258,8 @@
- 	unsigned long	*io_bitmap_ptr;
- /* cached TLS descriptors. */
- 	u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
-+/* performance counters */
-+	struct vperfctr *perfctr;
- };
- 
- #define INIT_THREAD  {}
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/perfctr.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/asm-x86_64/perfctr.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/asm-x86_64/perfctr.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1 @@
-+#include <asm-i386/perfctr.h>
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/perfctr.h
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/include/linux/perfctr.h	1969-12-31 19:00:00.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/include/linux/perfctr.h	2004-11-18 20:59:11.000000000 -0500
-@@ -0,0 +1,246 @@
-+/* $Id: perfctr.h,v 1.69 2004/02/20 21:31:02 mikpe Exp $
-+ * Performance-Monitoring Counters driver
-+ *
-+ * Copyright (C) 1999-2004  Mikael Pettersson
-+ */
-+#ifndef _LINUX_PERFCTR_H
-+#define _LINUX_PERFCTR_H
-+
-+#ifdef CONFIG_KPERFCTR	/* don't break archs without <asm/perfctr.h> */
-+
-+#include <asm/perfctr.h>
-+
-+struct perfctr_info {
-+	unsigned int abi_version;
-+	char driver_version[32];
-+	unsigned int cpu_type;
-+	unsigned int cpu_features;
-+	unsigned int cpu_khz;
-+	unsigned int tsc_to_cpu_mult;
-+	unsigned int _reserved2;
-+	unsigned int _reserved3;
-+	unsigned int _reserved4;
-+};
-+
-+struct perfctr_cpu_mask {
-+	unsigned int nrwords;
-+	unsigned int mask[1];	/* actually 'nrwords' */
-+};
-+
-+/* abi_version values: Lower 16 bits contain the CPU data version, upper
-+   16 bits contain the API version. Each half has a major version in its
-+   upper 8 bits, and a minor version in its lower 8 bits. */
-+#define PERFCTR_API_VERSION	0x0501	/* 5.1 */
-+#define PERFCTR_ABI_VERSION	((PERFCTR_API_VERSION<<16)|PERFCTR_CPU_VERSION)
-+
-+/* cpu_type values */
-+#define PERFCTR_X86_GENERIC	0	/* any x86 with rdtsc */
-+#define PERFCTR_X86_INTEL_P5	1	/* no rdpmc */
-+#define PERFCTR_X86_INTEL_P5MMX	2
-+#define PERFCTR_X86_INTEL_P6	3
-+#define PERFCTR_X86_INTEL_PII	4
-+#define PERFCTR_X86_INTEL_PIII	5
-+#define PERFCTR_X86_CYRIX_MII	6
-+#define PERFCTR_X86_WINCHIP_C6	7	/* no rdtsc */
-+#define PERFCTR_X86_WINCHIP_2	8	/* no rdtsc */
-+#define PERFCTR_X86_AMD_K7	9
-+#define PERFCTR_X86_VIA_C3	10	/* no pmc0 */
-+#define PERFCTR_X86_INTEL_P4	11	/* model 0 and 1 */
-+#define PERFCTR_X86_INTEL_P4M2	12	/* model 2 */
-+#define PERFCTR_X86_AMD_K8	13
-+#define PERFCTR_X86_INTEL_PENTM	14	/* Pentium M */
-+#define PERFCTR_X86_AMD_K8C	15	/* Revision C */
-+#define PERFCTR_X86_INTEL_P4M3	16	/* model 3 and above */
-+
-+/* cpu_features flag bits */
-+#define PERFCTR_FEATURE_RDPMC	0x01
-+#define PERFCTR_FEATURE_RDTSC	0x02
-+#define PERFCTR_FEATURE_PCINT	0x04
-+
-+/* user's view of mmap:ed virtual perfctr */
-+struct vperfctr_state {
-+	struct perfctr_cpu_state cpu_state;
-+};
-+
-+/* parameter in VPERFCTR_CONTROL command */
-+struct vperfctr_control {
-+	int si_signo;
-+	struct perfctr_cpu_control cpu_control;
-+	unsigned int preserve;
-+	unsigned int _reserved1;
-+	unsigned int _reserved2;
-+	unsigned int _reserved3;
-+	unsigned int _reserved4;
-+};
-+
-+/* parameter in GPERFCTR_CONTROL command */
-+struct gperfctr_cpu_control {
-+	unsigned int cpu;
-+	struct perfctr_cpu_control cpu_control;
-+	unsigned int _reserved1;
-+	unsigned int _reserved2;
-+	unsigned int _reserved3;
-+	unsigned int _reserved4;
-+};
-+
-+/* returned by GPERFCTR_READ command */
-+struct gperfctr_cpu_state {
-+	unsigned int cpu;
-+	struct perfctr_cpu_control cpu_control;
-+	struct perfctr_sum_ctrs sum;
-+	unsigned int _reserved1;
-+	unsigned int _reserved2;
-+	unsigned int _reserved3;
-+	unsigned int _reserved4;
-+};
-+
-+/* buffer for encodings of most of the above structs */
-+struct perfctr_struct_buf {
-+	unsigned int rdsize;
-+	unsigned int wrsize;
-+	unsigned int buffer[1]; /* actually 'max(rdsize,wrsize)' */
-+};
-+
-+#include <linux/ioctl.h>
-+#define _PERFCTR_IOCTL	0xD0	/* 'P'+128, currently unassigned */
-+
-+#define PERFCTR_ABI		 _IOR(_PERFCTR_IOCTL,0,unsigned int)
-+#define PERFCTR_INFO		 _IOR(_PERFCTR_IOCTL,1,struct perfctr_struct_buf)
-+#define PERFCTR_CPUS		_IOWR(_PERFCTR_IOCTL,2,struct perfctr_cpu_mask)
-+#define PERFCTR_CPUS_FORBIDDEN	_IOWR(_PERFCTR_IOCTL,3,struct perfctr_cpu_mask)
-+#define VPERFCTR_CREAT		  _IO(_PERFCTR_IOCTL,6)/*int tid*/
-+#define VPERFCTR_OPEN		  _IO(_PERFCTR_IOCTL,7)/*int tid*/
-+
-+#define VPERFCTR_READ_SUM	 _IOR(_PERFCTR_IOCTL,8,struct perfctr_struct_buf)
-+#define VPERFCTR_UNLINK		  _IO(_PERFCTR_IOCTL,9)
-+#define VPERFCTR_CONTROL	 _IOW(_PERFCTR_IOCTL,10,struct perfctr_struct_buf)
-+#define VPERFCTR_IRESUME	  _IO(_PERFCTR_IOCTL,11)
-+#define VPERFCTR_READ_CONTROL	 _IOR(_PERFCTR_IOCTL,12,struct perfctr_struct_buf)
-+
-+#define GPERFCTR_CONTROL	_IOWR(_PERFCTR_IOCTL,16,struct perfctr_struct_buf)
-+#define GPERFCTR_READ		_IOWR(_PERFCTR_IOCTL,17,struct perfctr_struct_buf)
-+#define GPERFCTR_STOP		  _IO(_PERFCTR_IOCTL,18)
-+#define GPERFCTR_START		  _IO(_PERFCTR_IOCTL,19)/*unsigned int*/
-+
-+#ifdef __KERNEL__
-+extern struct perfctr_info perfctr_info;
-+extern int sys_perfctr_abi(unsigned int*);
-+extern int sys_perfctr_info(struct perfctr_struct_buf*);
-+extern int sys_perfctr_cpus(struct perfctr_cpu_mask*);
-+extern int sys_perfctr_cpus_forbidden(struct perfctr_cpu_mask*);
-+#endif	/* __KERNEL__ */
-+
-+#endif	/* CONFIG_KPERFCTR */
-+
-+#ifdef __KERNEL__
-+
-+/* Needed for perfctr_set_cpus_allowed() prototype. */
-+#include <linux/version.h>
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) && !defined(HAVE_CPUMASK_T)
-+typedef unsigned long cpumask_t;
-+#define PERFCTR_HAVE_CPUMASK_T
-+#endif
-+
-+#ifdef CONFIG_PERFCTR_VIRTUAL
-+
-+/*
-+ * Virtual per-process performance-monitoring counters.
-+ */
-+struct vperfctr;	/* opaque */
-+
-+/* process management operations */
-+extern struct vperfctr *__vperfctr_copy(struct vperfctr*);
-+extern void __vperfctr_exit(struct vperfctr*);
-+extern void __vperfctr_suspend(struct vperfctr*);
-+extern void __vperfctr_resume(struct vperfctr*);
-+extern void __vperfctr_sample(struct vperfctr*);
-+extern void __vperfctr_set_cpus_allowed(struct task_struct*, struct vperfctr*, cpumask_t);
-+
-+#ifdef CONFIG_PERFCTR_MODULE
-+extern struct vperfctr_stub {
-+	struct module *owner;
-+	void (*exit)(struct vperfctr*);
-+	void (*suspend)(struct vperfctr*);
-+	void (*resume)(struct vperfctr*);
-+	void (*sample)(struct vperfctr*);
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+	void (*set_cpus_allowed)(struct task_struct*, struct vperfctr*, cpumask_t);
-+#endif
-+} vperfctr_stub;
-+extern void _vperfctr_exit(struct vperfctr*);
-+#define _vperfctr_suspend(x)	vperfctr_stub.suspend((x))
-+#define _vperfctr_resume(x)	vperfctr_stub.resume((x))
-+#define _vperfctr_sample(x)	vperfctr_stub.sample((x))
-+#define _vperfctr_set_cpus_allowed(x,y,z) (*vperfctr_stub.set_cpus_allowed)((x),(y),(z))
-+#else	/* !CONFIG_PERFCTR_MODULE */
-+#define _vperfctr_exit(x)	__vperfctr_exit((x))
-+#define _vperfctr_suspend(x)	__vperfctr_suspend((x))
-+#define _vperfctr_resume(x)	__vperfctr_resume((x))
-+#define _vperfctr_sample(x)	__vperfctr_sample((x))
-+#define _vperfctr_set_cpus_allowed(x,y,z) __vperfctr_set_cpus_allowed((x),(y),(z))
-+#endif	/* CONFIG_PERFCTR_MODULE */
-+
-+static inline void perfctr_copy_thread(struct thread_struct *thread)
-+{
-+	thread->perfctr = NULL;
-+}
-+
-+static inline void perfctr_exit_thread(struct thread_struct *thread)
-+{
-+	struct vperfctr *perfctr;
-+	perfctr = thread->perfctr;
-+	if( perfctr )
-+		_vperfctr_exit(perfctr);
-+}
-+
-+static inline void perfctr_suspend_thread(struct thread_struct *prev)
-+{
-+	struct vperfctr *perfctr;
-+	perfctr = prev->perfctr;
-+	if( perfctr )
-+		_vperfctr_suspend(perfctr);
-+}
-+
-+static inline void perfctr_resume_thread(struct thread_struct *next)
-+{
-+	struct vperfctr *perfctr;
-+	perfctr = next->perfctr;
-+	if( perfctr )
-+		_vperfctr_resume(perfctr);
-+}
-+
-+static inline void perfctr_sample_thread(struct thread_struct *thread)
-+{
-+	struct vperfctr *perfctr;
-+	perfctr = thread->perfctr;
-+	if( perfctr )
-+		_vperfctr_sample(perfctr);
-+}
-+
-+static inline void perfctr_set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
-+{
-+#if PERFCTR_CPUS_FORBIDDEN_MASK_NEEDED
-+	struct vperfctr *perfctr;
-+
-+	task_lock(p);
-+	perfctr = p->thread.perfctr;
-+	if( perfctr )
-+		_vperfctr_set_cpus_allowed(p, perfctr, new_mask);
-+	task_unlock(p);
-+#endif
-+}
-+
-+#else	/* !CONFIG_PERFCTR_VIRTUAL */
-+
-+static inline void perfctr_copy_thread(struct thread_struct *t) { }
-+static inline void perfctr_exit_thread(struct thread_struct *t) { }
-+static inline void perfctr_suspend_thread(struct thread_struct *t) { }
-+static inline void perfctr_resume_thread(struct thread_struct *t) { }
-+static inline void perfctr_sample_thread(struct thread_struct *t) { }
-+static inline void perfctr_set_cpus_allowed(struct task_struct *p, cpumask_t m) { }
-+
-+#endif	/* CONFIG_PERFCTR_VIRTUAL */
-+
-+#endif	/* __KERNEL__ */
-+
-+#endif	/* _LINUX_PERFCTR_H */
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/sched.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/kernel/sched.c	2004-11-11 10:28:49.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/sched.c	2004-11-18 20:59:11.000000000 -0500
-@@ -39,6 +39,7 @@
- #include <linux/rcupdate.h>
- #include <linux/cpu.h>
- #include <linux/percpu.h>
-+#include <linux/perfctr.h>
- #include <linux/kthread.h>
- #include <linux/cpuset.h>
- #include <linux/stop_machine.h>
-@@ -3304,6 +3305,8 @@
- 	migration_req_t req;
- 	runqueue_t *rq;
- 
-+	perfctr_set_cpus_allowed(p, new_mask);
-+
- 	rq = task_rq_lock(p, &flags);
- 	if (any_online_cpu(new_mask) == NR_CPUS) {
- 		ret = -EINVAL;
-Index: linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/timer.c
-===================================================================
---- linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891.orig/kernel/timer.c	2004-11-11 10:28:46.000000000 -0500
-+++ linux-2.6.5-SLES9_SP1_BRANCH_2004111114454891/kernel/timer.c	2004-11-18 20:59:11.000000000 -0500
-@@ -31,6 +31,7 @@
- #include <linux/time.h>
- #include <linux/jiffies.h>
- #include <linux/cpu.h>
-+#include <linux/perfctr.h>
- #include <linux/trigevent_hooks.h>
- 
- #include <asm/uaccess.h>
-@@ -844,6 +845,7 @@
- 	do_process_times(p, user, system);
- 	do_it_virt(p, user);
- 	do_it_prof(p);
-+	perfctr_sample_thread(&p->thread);
- }	
- 
- /*
diff --git a/lustre/kernel_patches/patches/uml-export-end_iomem.patch b/lustre/kernel_patches/patches/uml-export-end_iomem.patch
deleted file mode 100644
index ab8a84bc9a..0000000000
--- a/lustre/kernel_patches/patches/uml-export-end_iomem.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-Index: linux-2.4.24-vanilla/arch/um/kernel/ksyms.c
-===================================================================
---- linux-2.4.24-vanilla.orig/arch/um/kernel/ksyms.c	2004-01-10 17:47:10.000000000 +0300
-+++ linux-2.4.24-vanilla/arch/um/kernel/ksyms.c	2004-01-10 18:22:30.000000000 +0300
-@@ -34,6 +34,7 @@
- EXPORT_SYMBOL(host_task_size);
- EXPORT_SYMBOL(arch_validate);
- EXPORT_SYMBOL(get_kmem_end);
-+EXPORT_SYMBOL(end_iomem);
- 
- EXPORT_SYMBOL(high_physmem);
- EXPORT_SYMBOL(empty_zero_page);
diff --git a/lustre/kernel_patches/patches/uml-exprt-clearuser-2.6.12.patch b/lustre/kernel_patches/patches/uml-exprt-clearuser-2.6.12.patch
deleted file mode 100644
index 381b03f3b6..0000000000
--- a/lustre/kernel_patches/patches/uml-exprt-clearuser-2.6.12.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- uml-2.4.24/arch/um/kernel/tt/ksyms.c.orig	2005-05-04 13:59:58.806659456 +0300
-+++ uml-2.4.24/arch/um/kernel/tt/ksyms.c	2005-05-04 14:00:18.358687096 +0300
-@@ -12,6 +12,8 @@
- EXPORT_SYMBOL(__do_strncpy_from_user);
- EXPORT_SYMBOL(__do_strnlen_user); 
- EXPORT_SYMBOL(__do_clear_user);
-+EXPORT_SYMBOL(clear_user_tt);
-+EXPORT_SYMBOL(clear_user_skas);
- 
- EXPORT_SYMBOL(tracing_pid);
- EXPORT_SYMBOL(honeypot);
diff --git a/lustre/kernel_patches/patches/vfs_nointent-2.6-sles10.patch b/lustre/kernel_patches/patches/vfs_nointent-2.6-sles10.patch
deleted file mode 100644
index aba3c8b3da..0000000000
--- a/lustre/kernel_patches/patches/vfs_nointent-2.6-sles10.patch
+++ /dev/null
@@ -1,453 +0,0 @@
-Index: linux-2.6.16.21-0.8/net/unix/af_unix.c
-===================================================================
---- linux-2.6.16.21-0.8.orig/net/unix/af_unix.c	2006-08-03 01:34:33.000000000 -0600
-+++ linux-2.6.16.21-0.8/net/unix/af_unix.c	2006-08-03 01:35:38.000000000 -0600
-@@ -673,6 +673,7 @@
- 	int err = 0;
- 	
- 	if (sunname->sun_path[0]) {
-+		intent_init(&nd.intent, IT_LOOKUP);
- 		err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd);
- 		if (err)
- 			goto fail;
-Index: linux-2.6.16.21-0.8/fs/open.c
-===================================================================
---- linux-2.6.16.21-0.8.orig/fs/open.c	2006-08-03 01:34:33.000000000 -0600
-+++ linux-2.6.16.21-0.8/fs/open.c	2006-08-03 02:54:31.000000000 -0600
-@@ -197,9 +197,10 @@
- }
- 
- int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
--	struct file *filp)
-+	struct file *filp, int called_from_open)
- {
- 	int err;
-+	struct inode_operations *op = dentry->d_inode->i_op;
- 	struct iattr newattrs;
- 
- 	/* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
-@@ -214,7 +215,17 @@
- 	}
- 
- 	mutex_lock(&dentry->d_inode->i_mutex);
--	err = notify_change(dentry, &newattrs);
-+	if (called_from_open)
-+                newattrs.ia_valid |= ATTR_FROM_OPEN;
-+        if (op->setattr_raw) {
-+                newattrs.ia_valid |= ATTR_RAW;
-+                newattrs.ia_ctime = CURRENT_TIME;
-+                down_write(&dentry->d_inode->i_alloc_sem);
-+                err = op->setattr_raw(dentry->d_inode, &newattrs);
-+                up_write(&dentry->d_inode->i_alloc_sem);
-+        } else
-+                err = notify_change(dentry, &newattrs);
-+
- 	mutex_unlock(&dentry->d_inode->i_mutex);
- 	return err;
- }
-@@ -269,7 +280,7 @@
- 	error = locks_verify_truncate(inode, NULL, length);
- 	if (!error) {
- 		DQUOT_INIT(inode);
--		error = do_truncate(nd.dentry, length, 0, NULL);
-+		error = do_truncate(nd.dentry, length, 0, NULL, 0);
- 	}
- 	put_write_access(inode);
- 
-@@ -321,7 +332,7 @@
- 
- 	error = locks_verify_truncate(inode, file, length);
- 	if (!error)
--		error = do_truncate(dentry, length, 0, file);
-+		error = do_truncate(dentry, length, 0, file, 0);
- out_putf:
- 	fput(file);
- out:
-@@ -406,9 +417,20 @@
- 		    (error = vfs_permission(&nd, MAY_WRITE)) != 0)
- 			goto dput_and_out;
- 	}
--	mutex_lock(&inode->i_mutex);
--	error = notify_change(nd.dentry, &newattrs);
--	mutex_unlock(&inode->i_mutex);
-+ 	if (inode->i_op->setattr_raw) {
-+ 		struct inode_operations *op = nd.dentry->d_inode->i_op;
-+
-+ 		newattrs.ia_valid |= ATTR_RAW;
-+ 		error = op->setattr_raw(inode, &newattrs);
-+ 		/* the file system wants to use normal vfs path now */
-+ 		if (error != -EOPNOTSUPP)
-+ 			goto dput_and_out;
-+ 	} else {
-+		mutex_lock(&inode->i_mutex);
-+ 		error = notify_change(nd.dentry, &newattrs);
-+		mutex_unlock(&inode->i_mutex);
-+ 	}
-+
- dput_and_out:
- 	path_release(&nd);
- out:
-@@ -620,36 +642,52 @@
- 	return error;
- }
- 
-+int chmod_common(struct dentry *dentry, mode_t mode)
-+{
-+      struct inode * inode = dentry->d_inode;
-+      struct iattr newattrs;
-+      int error = -EROFS;
-+
-+      if (IS_RDONLY(inode))
-+              goto out;
-+
-+      if (inode->i_op->setattr_raw) {
-+              struct inode_operations *op = dentry->d_inode->i_op;
-+
-+              newattrs.ia_mode = mode;
-+              newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-+              newattrs.ia_valid |= ATTR_RAW;
-+              error = op->setattr_raw(inode, &newattrs);
-+              /* the file system wants to use normal vfs path now */
-+              if (error != -EOPNOTSUPP)
-+                    goto out;
-+      }
-+
-+      error = -EPERM;
-+      if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-+              goto out;
-+
-+      mutex_lock(&inode->i_mutex);
-+      if (mode == (mode_t) -1)
-+              mode = inode->i_mode;
-+      newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
-+      newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-+      error = notify_change(dentry, &newattrs);
-+      mutex_unlock(&inode->i_mutex);
-+out:
-+      return error;
-+}
-+
- asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
- {
--	struct inode * inode;
--	struct dentry * dentry;
- 	struct file * file;
- 	int err = -EBADF;
--	struct iattr newattrs;
- 
- 	file = fget(fd);
- 	if (!file)
- 		goto out;
- 
--	dentry = file->f_dentry;
--	inode = dentry->d_inode;
--
--	err = -EROFS;
--	if (IS_RDONLY(inode))
--		goto out_putf;
--	err = -EPERM;
--	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
--		goto out_putf;
--	mutex_lock(&inode->i_mutex);
--	if (mode == (mode_t) -1)
--		mode = inode->i_mode;
--	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
--	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
--	err = notify_change(dentry, &newattrs);
--	mutex_unlock(&inode->i_mutex);
--
--out_putf:
-+        err = chmod_common(file->f_dentry, mode);
- 	fput(file);
- out:
- 	return err;
-@@ -659,32 +697,12 @@
- 			     mode_t mode)
- {
- 	struct nameidata nd;
--	struct inode * inode;
- 	int error;
--	struct iattr newattrs;
- 
- 	error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
- 	if (error)
- 		goto out;
--	inode = nd.dentry->d_inode;
--
--	error = -EROFS;
--	if (IS_RDONLY(inode))
--		goto dput_and_out;
--
--	error = -EPERM;
--	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
--		goto dput_and_out;
--
--	mutex_lock(&inode->i_mutex);
--	if (mode == (mode_t) -1)
--		mode = inode->i_mode;
--	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
--	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
--	error = notify_change(nd.dentry, &newattrs);
--	mutex_unlock(&inode->i_mutex);
--
--dput_and_out:
-+	error = chmod_common(nd.dentry, mode);
- 	path_release(&nd);
- out:
- 	return error;
-@@ -710,6 +728,18 @@
- 	if (IS_RDONLY(inode))
- 		goto out;
- 	error = -EPERM;
-+	if (inode->i_op->setattr_raw) {
-+		struct inode_operations *op = dentry->d_inode->i_op;
-+
-+		newattrs.ia_uid = user;
-+		newattrs.ia_gid = group;
-+		newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME;
-+		newattrs.ia_valid |= ATTR_RAW;
-+		error = op->setattr_raw(inode, &newattrs);
-+		/* the file system wants to use normal vfs path now */
-+		if (error != -EOPNOTSUPP)
-+			return error;
-+	}
- 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
- 		goto out;
- 	newattrs.ia_valid =  ATTR_CTIME;
-Index: linux-2.6.16.21-0.8/fs/namei.c
-===================================================================
---- linux-2.6.16.21-0.8.orig/fs/namei.c	2006-08-03 01:34:33.000000000 -0600
-+++ linux-2.6.16.21-0.8/fs/namei.c	2006-08-03 02:54:31.000000000 -0600
-@@ -1637,7 +1637,7 @@
- 		if (!error) {
- 			DQUOT_INIT(inode);
- 			
--			error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL);
-+			error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL, 1);
- 		}
- 		put_write_access(inode);
- 		if (error)
-@@ -1911,6 +1911,7 @@
- 	char * tmp;
- 	struct dentry * dentry;
- 	struct nameidata nd;
-+	intent_init(&nd.intent, IT_LOOKUP);
- 
- 	if (S_ISDIR(mode))
- 		return -EPERM;
-@@ -1921,6 +1922,15 @@
- 	error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
- 	if (error)
- 		goto out;
-+
-+	if (nd.dentry->d_inode->i_op->mknod_raw) {
-+		struct inode_operations *op = nd.dentry->d_inode->i_op;
-+		error = op->mknod_raw(&nd, mode, dev);
-+		/* the file system wants to use normal vfs path now */
-+		if (error != -EOPNOTSUPP)
-+			goto out2;
-+	}
-+
- 	dentry = lookup_create(&nd, 0);
- 	error = PTR_ERR(dentry);
- 
-@@ -1947,6 +1957,7 @@
- 		dput(dentry);
- 	}
- 	mutex_unlock(&nd.dentry->d_inode->i_mutex);
-+out2:
- 	path_release(&nd);
- out:
- 	putname(tmp);
-@@ -1992,9 +2003,18 @@
- 		struct dentry *dentry;
- 		struct nameidata nd;
- 
-+ 		intent_init(&nd.intent, IT_LOOKUP);
- 		error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
- 		if (error)
- 			goto out;
-+ 		if (nd.dentry->d_inode->i_op->mkdir_raw) {
-+ 			struct inode_operations *op = nd.dentry->d_inode->i_op;
-+ 			error = op->mkdir_raw(&nd, mode);
-+ 			/* the file system wants to use normal vfs path now */
-+ 			if (error != -EOPNOTSUPP)
-+ 				goto out2;
-+ 		}
-+
- 		dentry = lookup_create(&nd, 1);
- 		error = PTR_ERR(dentry);
- 		if (!IS_ERR(dentry)) {
-@@ -2004,6 +2024,7 @@
- 			dput(dentry);
- 		}
- 		mutex_unlock(&nd.dentry->d_inode->i_mutex);
-+out2:
- 		path_release(&nd);
- out:
- 		putname(tmp);
-@@ -2084,6 +2105,7 @@
- 	char * name;
- 	struct dentry *dentry;
- 	struct nameidata nd;
-+	intent_init(&nd.intent, IT_LOOKUP);
- 
- 	name = getname(pathname);
- 	if(IS_ERR(name))
-@@ -2104,6 +2126,14 @@
- 			error = -EBUSY;
- 			goto exit1;
- 	}
-+	if (nd.dentry->d_inode->i_op->rmdir_raw) {
-+                struct inode_operations *op = nd.dentry->d_inode->i_op;
-+
-+                error = op->rmdir_raw(&nd);
-+                /* the file system wants to use normal vfs path now */
-+                if (error != -EOPNOTSUPP)
-+                        goto exit1;
-+        }
- 	mutex_lock(&nd.dentry->d_inode->i_mutex);
- 	dentry = lookup_hash(&nd);
- 	error = PTR_ERR(dentry);
-@@ -2167,6 +2197,7 @@
- 	struct dentry *dentry;
- 	struct nameidata nd;
- 	struct inode *inode = NULL;
-+	intent_init(&nd.intent, IT_LOOKUP);
- 
- 	name = getname(pathname);
- 	if(IS_ERR(name))
-@@ -2178,6 +2209,13 @@
- 	error = -EISDIR;
- 	if (nd.last_type != LAST_NORM)
- 		goto exit1;
-+	if (nd.dentry->d_inode->i_op->unlink_raw) {
-+        	struct inode_operations *op = nd.dentry->d_inode->i_op;
-+        	error = op->unlink_raw(&nd);
-+                /* the file system wants to use normal vfs path now */
-+        	if (error != -EOPNOTSUPP)
-+                       goto exit1;
-+        }
- 	mutex_lock(&nd.dentry->d_inode->i_mutex);
- 	dentry = lookup_hash(&nd);
- 	error = PTR_ERR(dentry);
-@@ -2260,9 +2298,17 @@
- 		struct dentry *dentry;
- 		struct nameidata nd;
- 
-+ 		intent_init(&nd.intent, IT_LOOKUP);
- 		error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
- 		if (error)
- 			goto out;
-+		if (nd.dentry->d_inode->i_op->symlink_raw) {
-+			struct inode_operations *op = nd.dentry->d_inode->i_op;
-+ 			error = op->symlink_raw(&nd, from);
-+ 			/* the file system wants to use normal vfs path now */
-+ 			if (error != -EOPNOTSUPP)
-+ 				goto out2;
-+ 		}
- 		dentry = lookup_create(&nd, 0);
- 		error = PTR_ERR(dentry);
- 		if (!IS_ERR(dentry)) {
-@@ -2270,6 +2316,7 @@
- 			dput(dentry);
- 		}
- 		mutex_unlock(&nd.dentry->d_inode->i_mutex);
-+out2:
- 		path_release(&nd);
- out:
- 		putname(to);
-@@ -2357,6 +2404,13 @@
- 	error = -EXDEV;
- 	if (old_nd.mnt != nd.mnt)
- 		goto out_release;
-+	if (nd.dentry->d_inode->i_op->link_raw) {
-+		struct inode_operations *op = nd.dentry->d_inode->i_op;
-+		error = op->link_raw(&old_nd, &nd);
-+		/* the file system wants to use normal vfs path now */
-+		if (error != -EOPNOTSUPP)
-+			goto out_release;
-+	}
- 	new_dentry = lookup_create(&nd, 0);
- 	error = PTR_ERR(new_dentry);
- 	if (!IS_ERR(new_dentry)) {
-@@ -2533,6 +2587,8 @@
- 	struct dentry * old_dentry, *new_dentry;
- 	struct dentry * trap;
- 	struct nameidata oldnd, newnd;
-+	intent_init(&oldnd.intent, IT_LOOKUP);
-+	intent_init(&newnd.intent, IT_LOOKUP);
- 
- 	error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd);
- 	if (error)
-@@ -2555,6 +2611,13 @@
- 	if (newnd.last_type != LAST_NORM)
- 		goto exit2;
- 
-+	if (old_dir->d_inode->i_op->rename_raw) {
-+		error = old_dir->d_inode->i_op->rename_raw(&oldnd, &newnd);
-+		/* the file system wants to use normal vfs path now */
-+		if (error != -EOPNOTSUPP)
-+			goto exit2;
-+	}
-+
- 	trap = lock_rename(new_dir, old_dir);
- 
- 	old_dentry = lookup_hash(&oldnd);
-@@ -2586,8 +2649,7 @@
- 	if (new_dentry == trap)
- 		goto exit5;
- 
--	error = vfs_rename(old_dir->d_inode, old_dentry,
--				   new_dir->d_inode, new_dentry);
-+	error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry);
- exit5:
- 	dput(new_dentry);
- exit4:
-Index: linux-2.6.16.21-0.8/fs/exec.c
-===================================================================
---- linux-2.6.16.21-0.8.orig/fs/exec.c	2006-08-03 01:34:33.000000000 -0600
-+++ linux-2.6.16.21-0.8/fs/exec.c	2006-08-03 01:35:38.000000000 -0600
-@@ -1524,7 +1524,7 @@
- 		goto close_fail;
- 	if (!file->f_op->write)
- 		goto close_fail;
--	if (do_truncate(file->f_dentry, 0, 0, file) != 0)
-+	if (do_truncate(file->f_dentry, 0, 0, file, 0) != 0)
- 		goto close_fail;
- 
- 	retval = binfmt->core_dump(signr, regs, file);
-Index: linux-2.6.16.21-0.8/include/linux/fs.h
-===================================================================
---- linux-2.6.16.21-0.8.orig/include/linux/fs.h	2006-08-03 01:34:33.000000000 -0600
-+++ linux-2.6.16.21-0.8/include/linux/fs.h	2006-08-03 01:35:38.000000000 -0600
-@@ -1041,13 +1041,20 @@
- 	int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
- 	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
- 	int (*link) (struct dentry *,struct inode *,struct dentry *);
-+	int (*link_raw) (struct nameidata *,struct nameidata *);
- 	int (*unlink) (struct inode *,struct dentry *);
-+	int (*unlink_raw) (struct nameidata *);
- 	int (*symlink) (struct inode *,struct dentry *,const char *);
-+	int (*symlink_raw) (struct nameidata *,const char *);
- 	int (*mkdir) (struct inode *,struct dentry *,int);
-+	int (*mkdir_raw) (struct nameidata *,int);
- 	int (*rmdir) (struct inode *,struct dentry *);
-+	int (*rmdir_raw) (struct nameidata *);
- 	int (*mknod) (struct inode *,struct dentry *,int,dev_t);
-+	int (*mknod_raw) (struct nameidata *,int,dev_t);
- 	int (*rename) (struct inode *, struct dentry *,
- 			struct inode *, struct dentry *);
-+	int (*rename_raw) (struct nameidata *, struct nameidata *);
- 	int (*readlink) (struct dentry *, char __user *,int);
- 	void * (*follow_link) (struct dentry *, struct nameidata *);
- 	void (*put_link) (struct dentry *, struct nameidata *, void *);
-@@ -1357,7 +1364,7 @@
- /* fs/open.c */
- 
- extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
--		       struct file *filp);
-+		       struct file *filp, int called_from_open);
- extern long do_sys_open(int fdf, const char __user *filename, int flags,
- 			int mode);
- extern struct file *filp_open(const char *, int, int);
-- 
GitLab